0
# Image Processing
1
2
ZXing-C++ provides efficient image data handling through the `ImageView` and `Image` classes. These classes support multiple pixel formats, zero-copy operations, and various image transformations optimized for barcode detection.
3
4
## Core Classes
5
6
### ImageView Class
7
8
The `ImageView` class provides a non-owning view of image data with layout and format information. It's designed for zero-copy operations and supports various pixel formats.
9
10
```cpp { .api }
11
class ImageView {
12
// Constructors
13
ImageView(); // Default null view
14
ImageView(const uint8_t* data, int width, int height, ImageFormat format,
15
int rowStride = 0, int pixStride = 0);
16
ImageView(const uint8_t* data, int size, int width, int height, ImageFormat format,
17
int rowStride = 0, int pixStride = 0); // Bounds-checked version
18
19
// Properties
20
int width() const;
21
int height() const;
22
int pixStride() const;
23
int rowStride() const;
24
ImageFormat format() const;
25
const uint8_t* data() const;
26
const uint8_t* data(int x, int y) const;
27
28
// Transformations
29
ImageView cropped(int left, int top, int width, int height) const;
30
ImageView rotated(int degree) const;
31
ImageView subsampled(int scale) const;
32
};
33
```
34
35
### Image Class
36
37
The `Image` class extends `ImageView` to provide owning image containers with automatic memory management.
38
39
```cpp { .api }
40
class Image : public ImageView {
41
Image(); // Default empty image
42
Image(int w, int h, ImageFormat f = ImageFormat::Lum);
43
};
44
```
45
46
## Pixel Formats
47
48
ZXing-C++ supports various pixel formats through the `ImageFormat` enumeration:
49
50
```cpp { .api }
51
enum class ImageFormat : uint32_t {
52
None = 0,
53
Lum = 0x01000000, // Grayscale (8-bit)
54
LumA = 0x02000000, // Grayscale with alpha (16-bit)
55
RGB = 0x03000102, // RGB color (24-bit)
56
BGR = 0x03020100, // BGR color (24-bit)
57
RGBA = 0x04000102, // RGBA color (32-bit)
58
ARGB = 0x04010203, // ARGB color (32-bit)
59
BGRA = 0x04020100, // BGRA color (32-bit)
60
ABGR = 0x04030201 // ABGR color (32-bit)
61
};
62
```
63
64
### Format Utilities
65
66
```cpp { .api }
67
constexpr int PixStride(ImageFormat format); // Bytes per pixel
68
constexpr int RedIndex(ImageFormat format); // Red channel index
69
constexpr int GreenIndex(ImageFormat format); // Green channel index
70
constexpr int BlueIndex(ImageFormat format); // Blue channel index
71
constexpr uint8_t RGBToLum(unsigned r, unsigned g, unsigned b); // RGB to grayscale
72
```
73
74
## Usage Examples
75
76
### Creating Image Views
77
78
```cpp
79
#include "ZXing/ImageView.h"
80
81
// From existing image data
82
unsigned char* imageData = /* your image data */;
83
int width = 640, height = 480;
84
85
// Grayscale image
86
auto grayImage = ZXing::ImageView(imageData, width, height, ZXing::ImageFormat::Lum);
87
88
// RGB image with default stride
89
auto rgbImage = ZXing::ImageView(imageData, width, height, ZXing::ImageFormat::RGB);
90
91
// RGB image with custom stride (useful for padded rows)
92
int rowStride = width * 3 + 16; // 16 bytes padding per row
93
auto paddedImage = ZXing::ImageView(imageData, width, height, ZXing::ImageFormat::RGB, rowStride);
94
95
// Bounds-checked construction
96
int bufferSize = width * height * 3;
97
auto safeImage = ZXing::ImageView(imageData, bufferSize, width, height, ZXing::ImageFormat::RGB);
98
```
99
100
### Creating Owned Images
101
102
```cpp
103
// Create new image with automatic memory management
104
auto image = ZXing::Image(640, 480, ZXing::ImageFormat::Lum);
105
106
// Access raw data for filling
107
uint8_t* data = const_cast<uint8_t*>(image.data());
108
// Fill with your image data...
109
110
// Convert to ImageView for reading
111
ZXing::ImageView view = image; // Implicit conversion
112
auto result = ZXing::ReadBarcode(view);
113
```
114
115
### Image Transformations
116
117
#### Cropping
118
119
```cpp
120
auto originalImage = ZXing::ImageView(data, 1920, 1080, ZXing::ImageFormat::RGB);
121
122
// Crop to center region
123
int cropWidth = 800, cropHeight = 600;
124
int left = (1920 - cropWidth) / 2;
125
int top = (1080 - cropHeight) / 2;
126
127
auto croppedImage = originalImage.cropped(left, top, cropWidth, cropHeight);
128
129
// Use cropped image for barcode detection
130
auto result = ZXing::ReadBarcode(croppedImage);
131
```
132
133
#### Rotation
134
135
```cpp
136
auto image = ZXing::ImageView(data, width, height, ZXing::ImageFormat::Lum);
137
138
// Rotate image (90, 180, 270 degrees supported)
139
auto rotated90 = image.rotated(90);
140
auto rotated180 = image.rotated(180);
141
auto rotated270 = image.rotated(270);
142
143
// Try all rotations
144
std::vector<ZXing::ImageView> rotations = {
145
image,
146
image.rotated(90),
147
image.rotated(180),
148
image.rotated(270)
149
};
150
151
for (const auto& rotatedImage : rotations) {
152
auto result = ZXing::ReadBarcode(rotatedImage);
153
if (result.isValid()) {
154
std::cout << "Found barcode in rotation" << std::endl;
155
break;
156
}
157
}
158
```
159
160
#### Subsampling
161
162
```cpp
163
auto highResImage = ZXing::ImageView(data, 3840, 2160, ZXing::ImageFormat::RGB);
164
165
// Create downscaled versions for faster processing
166
auto halfScale = highResImage.subsampled(2); // 1920x1080
167
auto quarterScale = highResImage.subsampled(4); // 960x540
168
169
// Try different scales for performance vs accuracy
170
auto options = ZXing::ReaderOptions().setTryHarder(false);
171
auto result = ZXing::ReadBarcode(quarterScale, options);
172
173
if (!result.isValid()) {
174
// Fall back to higher resolution
175
result = ZXing::ReadBarcode(halfScale, options);
176
}
177
178
if (!result.isValid()) {
179
// Final attempt with full resolution
180
options.setTryHarder(true);
181
result = ZXing::ReadBarcode(highResImage, options);
182
}
183
```
184
185
### Multi-format Image Loading
186
187
```cpp
188
// Generic image loader that handles different formats
189
ZXing::ImageView loadImage(const uint8_t* data, int width, int height,
190
int channels, int stride = 0) {
191
ZXing::ImageFormat format;
192
193
switch (channels) {
194
case 1:
195
format = ZXing::ImageFormat::Lum;
196
break;
197
case 3:
198
format = ZXing::ImageFormat::RGB;
199
break;
200
case 4:
201
format = ZXing::ImageFormat::RGBA;
202
break;
203
default:
204
throw std::invalid_argument("Unsupported channel count");
205
}
206
207
int rowStride = stride ? stride : width * channels;
208
return ZXing::ImageView(data, width, height, format, rowStride);
209
}
210
211
// Usage with different image libraries
212
// OpenCV Mat
213
cv::Mat cvImage = cv::imread("barcode.jpg");
214
auto imageView = loadImage(cvImage.data, cvImage.cols, cvImage.rows, cvImage.channels());
215
216
// SFML Image
217
sf::Image sfImage;
218
sfImage.loadFromFile("barcode.png");
219
auto imageView2 = loadImage(sfImage.getPixelsPtr(), sfImage.getSize().x, sfImage.getSize().y, 4);
220
```
221
222
### Format Conversion
223
224
```cpp
225
// Convert RGB to grayscale manually
226
void convertRGBToGray(const ZXing::ImageView& rgb, ZXing::Image& gray) {
227
if (rgb.format() != ZXing::ImageFormat::RGB) {
228
throw std::invalid_argument("Expected RGB format");
229
}
230
231
int width = rgb.width();
232
int height = rgb.height();
233
gray = ZXing::Image(width, height, ZXing::ImageFormat::Lum);
234
235
uint8_t* grayData = const_cast<uint8_t*>(gray.data());
236
237
for (int y = 0; y < height; ++y) {
238
for (int x = 0; x < width; ++x) {
239
const uint8_t* pixel = rgb.data(x, y);
240
uint8_t r = pixel[0];
241
uint8_t g = pixel[1];
242
uint8_t b = pixel[2];
243
244
grayData[y * width + x] = ZXing::RGBToLum(r, g, b);
245
}
246
}
247
}
248
249
// Usage
250
auto rgbImage = ZXing::ImageView(rgbData, width, height, ZXing::ImageFormat::RGB);
251
ZXing::Image grayImage;
252
convertRGBToGray(rgbImage, grayImage);
253
auto result = ZXing::ReadBarcode(grayImage);
254
```
255
256
### Memory Management
257
258
```cpp
259
// RAII wrapper for external image data
260
class ManagedImageView {
261
private:
262
std::unique_ptr<uint8_t[]> data_;
263
ZXing::ImageView view_;
264
265
public:
266
ManagedImageView(int width, int height, ZXing::ImageFormat format)
267
: data_(std::make_unique<uint8_t[]>(width * height * ZXing::PixStride(format))),
268
view_(data_.get(), width, height, format) {
269
}
270
271
ZXing::ImageView& view() { return view_; }
272
const ZXing::ImageView& view() const { return view_; }
273
uint8_t* data() { return data_.get(); }
274
275
// Implicit conversion to ImageView
276
operator const ZXing::ImageView&() const { return view_; }
277
};
278
279
// Usage
280
auto managedImage = ManagedImageView(640, 480, ZXing::ImageFormat::RGB);
281
// Fill managedImage.data() with your image data...
282
auto result = ZXing::ReadBarcode(managedImage);
283
```
284
285
### Advanced Image Operations
286
287
#### Region of Interest (ROI) Processing
288
289
```cpp
290
// Process multiple regions in an image
291
std::vector<ZXing::Barcode> scanRegions(const ZXing::ImageView& image) {
292
std::vector<ZXing::Barcode> results;
293
294
int width = image.width();
295
int height = image.height();
296
int regionSize = 300;
297
298
// Scan overlapping regions
299
for (int y = 0; y <= height - regionSize; y += regionSize / 2) {
300
for (int x = 0; x <= width - regionSize; x += regionSize / 2) {
301
auto region = image.cropped(x, y, regionSize, regionSize);
302
auto result = ZXing::ReadBarcode(region);
303
304
if (result.isValid()) {
305
// Adjust position coordinates back to original image
306
auto position = result.position();
307
// Transform position coordinates...
308
results.push_back(result);
309
}
310
}
311
}
312
313
return results;
314
}
315
```
316
317
#### Multi-scale Processing
318
319
```cpp
320
// Try different scales automatically
321
ZXing::Barcode multiScaleRead(const ZXing::ImageView& image) {
322
std::vector<int> scales = {1, 2, 4};
323
auto options = ZXing::ReaderOptions();
324
325
for (int scale : scales) {
326
ZXing::ImageView scaledImage = (scale == 1) ? image : image.subsampled(scale);
327
328
auto result = ZXing::ReadBarcode(scaledImage, options);
329
if (result.isValid()) {
330
return result;
331
}
332
333
// Increase effort for smaller scales
334
options.setTryHarder(true);
335
}
336
337
return ZXing::Barcode(); // Return invalid result
338
}
339
```
340
341
## Performance Considerations
342
343
### Memory Layout
344
345
- Use `ImageView` for zero-copy operations when possible
346
- Align image data to memory boundaries for better performance
347
- Consider row stride alignment (16 or 32-byte boundaries)
348
349
### Format Selection
350
351
- Use `ImageFormat::Lum` (grayscale) for best performance
352
- Avoid unnecessary format conversions
353
- RGB formats are efficiently handled by the library
354
355
### Transformation Efficiency
356
357
- `cropped()`, `rotated()`, and `subsampled()` create views, not copies
358
- Chain transformations efficiently: `image.cropped(x,y,w,h).rotated(90)`
359
- Use subsampling for initial fast scans, then higher resolution for confirmation
360
361
### Error Handling
362
363
```cpp
364
try {
365
auto image = ZXing::ImageView(nullptr, 640, 480, ZXing::ImageFormat::RGB);
366
} catch (const std::invalid_argument& e) {
367
std::cout << "Invalid image parameters: " << e.what() << std::endl;
368
}
369
370
// Bounds checking
371
try {
372
int bufferSize = 100; // Too small
373
auto image = ZXing::ImageView(data, bufferSize, 640, 480, ZXing::ImageFormat::RGB);
374
} catch (const std::invalid_argument& e) {
375
std::cout << "Buffer too small: " << e.what() << std::endl;
376
}
377
```