or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

configuration.mdexperimental-writing.mdimage-processing.mdindex.mdlegacy-writing.mdreading.mdresult-processing.md

image-processing.mddocs/

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

```