0
# Image Processing
1
2
Comprehensive image processing pipeline for converting various image formats to binary representations suitable for barcode detection and decoding.
3
4
## Capabilities
5
6
### LuminanceSource
7
8
Abstract base class for image data sources that provides luminance (grayscale) data for barcode processing.
9
10
```java { .api }
11
/**
12
* Abstract base for accessing luminance data from images
13
* Provides grayscale pixel data in row-major order
14
*/
15
public abstract class LuminanceSource {
16
/**
17
* Get luminance data for a specific row
18
* @param y Row index (0-based)
19
* @param row Optional pre-allocated array for reuse
20
* @return Byte array of luminance values (0=black, 255=white)
21
*/
22
public abstract byte[] getRow(int y, byte[] row);
23
24
/**
25
* Get complete luminance matrix
26
* @return Byte array of all luminance data in row-major order
27
*/
28
public abstract byte[] getMatrix();
29
30
/**
31
* Get image width
32
* @return Width in pixels
33
*/
34
public abstract int getWidth();
35
36
/**
37
* Get image height
38
* @return Height in pixels
39
*/
40
public abstract int getHeight();
41
42
/**
43
* Check if cropping is supported
44
* @return true if crop() can be called
45
*/
46
public boolean isCropSupported();
47
48
/**
49
* Check if rotation is supported
50
* @return true if rotation methods can be called
51
*/
52
public boolean isRotateSupported();
53
54
/**
55
* Crop the image to specified rectangle
56
* @param left Left coordinate
57
* @param top Top coordinate
58
* @param width Crop width
59
* @param height Crop height
60
* @return New LuminanceSource with cropped data
61
*/
62
public LuminanceSource crop(int left, int top, int width, int height);
63
64
/**
65
* Rotate image 90 degrees counterclockwise
66
* @return New LuminanceSource with rotated data
67
*/
68
public LuminanceSource rotateCounterClockwise();
69
70
/**
71
* Rotate image 45 degrees counterclockwise
72
* @return New LuminanceSource with rotated data
73
*/
74
public LuminanceSource rotateCounterClockwise45();
75
76
/**
77
* Invert luminance values (negative image)
78
* @return New LuminanceSource with inverted data
79
*/
80
public LuminanceSource invert();
81
}
82
```
83
84
### RGB Luminance Source
85
86
Luminance source implementation for RGB image data, the most common format for color images.
87
88
```java { .api }
89
/**
90
* LuminanceSource implementation for RGB pixel data
91
* Converts RGB values to grayscale using standard luminance formula
92
*/
93
public final class RGBLuminanceSource extends LuminanceSource {
94
/**
95
* Create from RGB pixel array
96
* @param width Image width
97
* @param height Image height
98
* @param pixels RGB pixel data as int array (0xAARRGGBB format)
99
*/
100
public RGBLuminanceSource(int width, int height, int[] pixels);
101
}
102
```
103
104
**Usage Examples:**
105
106
```java
107
import com.google.zxing.RGBLuminanceSource;
108
import java.awt.image.BufferedImage;
109
110
// From BufferedImage
111
BufferedImage image = ImageIO.read(new File("barcode.png"));
112
int width = image.getWidth();
113
int height = image.getHeight();
114
int[] pixels = image.getRGB(0, 0, width, height, null, 0, width);
115
116
RGBLuminanceSource source = new RGBLuminanceSource(width, height, pixels);
117
118
// From raw RGB data
119
int[] rgbPixels = new int[width * height];
120
// ... populate pixel data ...
121
RGBLuminanceSource source = new RGBLuminanceSource(width, height, rgbPixels);
122
```
123
124
### Planar YUV Luminance Source
125
126
Luminance source for YUV image data, commonly used in camera and video applications.
127
128
```java { .api }
129
/**
130
* LuminanceSource for planar YUV image data
131
* Uses Y channel directly as luminance data
132
*/
133
public final class PlanarYUVLuminanceSource extends LuminanceSource {
134
/**
135
* Create from YUV data
136
* @param yuvData Complete YUV data array
137
* @param dataWidth Width of YUV data
138
* @param dataHeight Height of YUV data
139
* @param left Left crop coordinate
140
* @param top Top crop coordinate
141
* @param width Width of region to use
142
* @param height Height of region to use
143
* @param reverseHorizontal Whether to reverse horizontally
144
*/
145
public PlanarYUVLuminanceSource(byte[] yuvData, int dataWidth, int dataHeight,
146
int left, int top, int width, int height,
147
boolean reverseHorizontal);
148
}
149
```
150
151
### Inverted Luminance Source
152
153
Wrapper that inverts luminance values, useful for negative images or challenging lighting conditions.
154
155
```java { .api }
156
/**
157
* Wrapper that inverts luminance values
158
* Converts black to white and white to black
159
*/
160
public final class InvertedLuminanceSource extends LuminanceSource {
161
/**
162
* Create inverted wrapper around another source
163
* @param delegate Original luminance source to invert
164
*/
165
public InvertedLuminanceSource(LuminanceSource delegate);
166
}
167
```
168
169
### Binarizer
170
171
Abstract base class for converting grayscale luminance data to binary (black/white) representation.
172
173
```java { .api }
174
/**
175
* Abstract base for converting grayscale to binary
176
* Different implementations use different thresholding strategies
177
*/
178
public abstract class Binarizer {
179
/**
180
* Get the associated luminance source
181
* @return Underlying LuminanceSource
182
*/
183
public final LuminanceSource getLuminanceSource();
184
185
/**
186
* Get binarized data for a specific row
187
* @param y Row index
188
* @param row Optional pre-allocated BitArray for reuse
189
* @return BitArray with binary representation of the row
190
* @throws NotFoundException if row cannot be binarized
191
*/
192
public abstract BitArray getBlackRow(int y, BitArray row) throws NotFoundException;
193
194
/**
195
* Get complete binarized matrix
196
* @return BitMatrix with binary representation of entire image
197
* @throws NotFoundException if image cannot be binarized
198
*/
199
public abstract BitMatrix getBlackMatrix() throws NotFoundException;
200
201
/**
202
* Create new Binarizer instance for different LuminanceSource
203
* @param source New luminance source
204
* @return New Binarizer instance
205
*/
206
public abstract Binarizer createBinarizer(LuminanceSource source);
207
208
/**
209
* Get image width
210
* @return Width from underlying luminance source
211
*/
212
public final int getWidth();
213
214
/**
215
* Get image height
216
* @return Height from underlying luminance source
217
*/
218
public final int getHeight();
219
}
220
```
221
222
### Global Histogram Binarizer
223
224
Binarizer that uses global thresholding based on luminance histogram analysis.
225
226
```java { .api }
227
/**
228
* Binarizer using global threshold determined from luminance histogram
229
* Fast but may not work well with uneven lighting
230
*/
231
public final class GlobalHistogramBinarizer extends Binarizer {
232
/**
233
* Create binarizer with global histogram thresholding
234
* @param source Luminance source to binarize
235
*/
236
public GlobalHistogramBinarizer(LuminanceSource source);
237
}
238
```
239
240
**Usage Examples:**
241
242
```java
243
import com.google.zxing.common.GlobalHistogramBinarizer;
244
245
// Simple global thresholding (fast)
246
LuminanceSource source = new RGBLuminanceSource(width, height, pixels);
247
Binarizer binarizer = new GlobalHistogramBinarizer(source);
248
```
249
250
### Hybrid Binarizer
251
252
Advanced binarizer that combines global and local thresholding for better performance with challenging images.
253
254
```java { .api }
255
/**
256
* Hybrid binarizer using both global and local thresholding
257
* More robust for images with uneven lighting or poor contrast
258
* Recommended for most use cases
259
*/
260
public final class HybridBinarizer extends Binarizer {
261
/**
262
* Create hybrid binarizer with adaptive thresholding
263
* @param source Luminance source to binarize
264
*/
265
public HybridBinarizer(LuminanceSource source);
266
}
267
```
268
269
**Usage Examples:**
270
271
```java
272
import com.google.zxing.common.HybridBinarizer;
273
274
// Hybrid approach (recommended for most cases)
275
LuminanceSource source = new RGBLuminanceSource(width, height, pixels);
276
Binarizer binarizer = new HybridBinarizer(source);
277
```
278
279
### BinaryBitmap
280
281
Final binary representation used by barcode readers, combining luminance source and binarizer.
282
283
```java { .api }
284
/**
285
* Binary bitmap representation for barcode decoding
286
* Combines luminance source with binarization strategy
287
*/
288
public final class BinaryBitmap {
289
/**
290
* Create binary bitmap from binarizer
291
* @param binarizer Binarizer containing luminance source and thresholding logic
292
*/
293
public BinaryBitmap(Binarizer binarizer);
294
295
/**
296
* Get image width
297
* @return Width in pixels
298
*/
299
public int getWidth();
300
301
/**
302
* Get image height
303
* @return Height in pixels
304
*/
305
public int getHeight();
306
307
/**
308
* Get binary row data (for 1D barcode decoding)
309
* @param y Row index
310
* @param row Optional pre-allocated BitArray
311
* @return BitArray with binary row data
312
* @throws NotFoundException if row cannot be binarized
313
*/
314
public BitArray getBlackRow(int y, BitArray row) throws NotFoundException;
315
316
/**
317
* Get complete binary matrix (for 2D barcode decoding)
318
* @return BitMatrix with complete binary image
319
* @throws NotFoundException if image cannot be binarized
320
*/
321
public BitMatrix getBlackMatrix() throws NotFoundException;
322
323
/**
324
* Check if cropping is supported
325
* @return true if crop operations are available
326
*/
327
public boolean isCropSupported();
328
329
/**
330
* Crop to specified rectangle
331
* @param left Left coordinate
332
* @param top Top coordinate
333
* @param width Crop width
334
* @param height Crop height
335
* @return New BinaryBitmap with cropped region
336
*/
337
public BinaryBitmap crop(int left, int top, int width, int height);
338
339
/**
340
* Check if rotation is supported
341
* @return true if rotation operations are available
342
*/
343
public boolean isRotateSupported();
344
345
/**
346
* Rotate 90 degrees counterclockwise
347
* @return New BinaryBitmap with rotated image
348
*/
349
public BinaryBitmap rotateCounterClockwise();
350
351
/**
352
* Rotate 45 degrees counterclockwise
353
* @return New BinaryBitmap with rotated image
354
*/
355
public BinaryBitmap rotateCounterClockwise45();
356
}
357
```
358
359
**Complete Processing Pipeline Example:**
360
361
```java
362
import com.google.zxing.*;
363
import com.google.zxing.common.*;
364
import java.awt.image.BufferedImage;
365
import javax.imageio.ImageIO;
366
367
// Complete image processing pipeline
368
public class BarcodeImageProcessor {
369
370
public Result decodeFromFile(String imagePath) throws Exception {
371
// 1. Load image
372
BufferedImage image = ImageIO.read(new File(imagePath));
373
374
// 2. Convert to luminance source
375
int width = image.getWidth();
376
int height = image.getHeight();
377
int[] pixels = image. (0, 0, width, height, null, 0, width);
378
LuminanceSource source = new RGBLuminanceSource(width, height, pixels);
379
380
// 3. Apply binarization
381
Binarizer binarizer = new HybridBinarizer(source);
382
383
// 4. Create binary bitmap
384
BinaryBitmap bitmap = new BinaryBitmap(binarizer);
385
386
// 5. Decode barcode
387
MultiFormatReader reader = new MultiFormatReader();
388
return reader.decode(bitmap);
389
}
390
391
public Result decodeWithPreprocessing(BufferedImage image) throws Exception {
392
// Try different processing approaches
393
List<LuminanceSource> sources = new ArrayList<>();
394
395
// Original image
396
int width = image.getWidth();
397
int height = image.getHeight();
398
int[] pixels = image.getRGB(0, 0, width, height, null, 0, width);
399
sources.add(new RGBLuminanceSource(width, height, pixels));
400
401
// Inverted image (for negative barcodes)
402
sources.add(new InvertedLuminanceSource(sources.get(0)));
403
404
// Try both binarization methods
405
List<Binarizer> binarizers = Arrays.asList(
406
GlobalHistogramBinarizer.class,
407
HybridBinarizer.class
408
);
409
410
MultiFormatReader reader = new MultiFormatReader();
411
412
for (LuminanceSource source : sources) {
413
for (Class<? extends Binarizer> binarizerClass : binarizers) {
414
try {
415
Binarizer binarizer = binarizerClass
416
.getConstructor(LuminanceSource.class)
417
.newInstance(source);
418
419
BinaryBitmap bitmap = new BinaryBitmap(binarizer);
420
return reader.decode(bitmap);
421
} catch (NotFoundException e) {
422
// Try next combination
423
continue;
424
}
425
}
426
}
427
428
throw new NotFoundException("No barcode found with any processing method");
429
}
430
}
431
```
432
433
## Processing Best Practices
434
435
### Image Quality Optimization
436
437
1. **Resolution**: Ensure adequate resolution (minimum 150 DPI for print)
438
2. **Contrast**: Maintain good contrast between barcode and background
439
3. **Focus**: Use sharp, focused images
440
4. **Lighting**: Provide even lighting without shadows or glare
441
442
### Binarization Strategy Selection
443
444
- **GlobalHistogramBinarizer**: Fast, good for high-contrast images with even lighting
445
- **HybridBinarizer**: Slower but more robust, handles uneven lighting better
446
- Try both if initial decoding fails
447
448
### Preprocessing Techniques
449
450
```java
451
// Crop to region of interest before processing
452
if (bitmap.isCropSupported()) {
453
BinaryBitmap cropped = bitmap.crop(x, y, width, height);
454
}
455
456
// Try rotation for skewed images
457
if (bitmap.isRotateSupported()) {
458
BinaryBitmap rotated = bitmap.rotateCounterClockwise();
459
}
460
461
// Handle negative/inverted images
462
LuminanceSource inverted = new InvertedLuminanceSource(originalSource);
463
```
464
465
### Performance Considerations
466
467
- Reuse BitArray objects for row-by-row processing
468
- Cache BinaryBitmap instances when processing multiple formats
469
- Consider image size vs. processing time trade-offs
470
- Use appropriate hint settings to optimize for specific scenarios