or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

data-structures.mdimage-processing.mdindex.mdqrcode-support.mdreading-decoding.mdresult-processing.mdwriting-encoding.md

image-processing.mddocs/

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