@@ -32,6 +32,9 @@ BinaryImage binarizeSauvola(const QImage& src, const QSize windowSize, const dou
32
32
}
33
33
34
34
const QImage gray (toGrayscale (src));
35
+ if (gray.isNull ()) {
36
+ return BinaryImage ();
37
+ }
35
38
const int w = gray.width ();
36
39
const int h = gray.height ();
37
40
@@ -114,6 +117,9 @@ BinaryImage binarizeWolf(const QImage& src,
114
117
}
115
118
116
119
const QImage gray (toGrayscale (src));
120
+ if (gray.isNull ()) {
121
+ return BinaryImage ();
122
+ }
117
123
const int w = gray.width ();
118
124
const int h = gray.height ();
119
125
@@ -211,6 +217,9 @@ BinaryImage binarizeBradley(const QImage& src, const QSize windowSize, const dou
211
217
}
212
218
213
219
QImage gray (toGrayscale (src));
220
+ if (gray.isNull ()) {
221
+ return BinaryImage ();
222
+ }
214
223
const int w = gray.width ();
215
224
const int h = gray.height ();
216
225
@@ -268,6 +277,120 @@ BinaryImage binarizeBradley(const QImage& src, const QSize windowSize, const dou
268
277
return bwImg;
269
278
} // binarizeBradley
270
279
280
+ BinaryImage binarizeGrad (const QImage& src, const QSize windowSize, const double k, const double delta) {
281
+ if (windowSize.isEmpty ()) {
282
+ throw std::invalid_argument (" binarizeGrad: invalid windowSize" );
283
+ }
284
+
285
+ if (src.isNull ()) {
286
+ return BinaryImage ();
287
+ }
288
+
289
+ QImage gray (toGrayscale (src));
290
+ if (gray.isNull ()) {
291
+ return BinaryImage ();
292
+ }
293
+ QImage gmean (toGrayscale (src));
294
+ if (gmean.isNull ()) {
295
+ return BinaryImage ();
296
+ }
297
+ const int w = gray.width ();
298
+ const int h = gray.height ();
299
+
300
+ const uint8_t * grayLine = gray.bits ();
301
+ const int grayBpl = gray.bytesPerLine ();
302
+
303
+ uint8_t * gmeanLine = gmean.bits ();
304
+ const int gmeanBpl = gmean.bytesPerLine ();
305
+
306
+ IntegralImage<uint32_t > integralImage (w, h);
307
+
308
+ for (int y = 0 ; y < h; ++y) {
309
+ integralImage.beginRow ();
310
+ for (int x = 0 ; x < w; ++x) {
311
+ const uint32_t pixel = grayLine[x];
312
+ integralImage.push (pixel);
313
+ }
314
+ grayLine += grayBpl;
315
+ }
316
+
317
+ const int windowLowerHalf = windowSize.height () >> 1 ;
318
+ const int windowUpperHalf = windowSize.height () - windowLowerHalf;
319
+ const int windowLeftHalf = windowSize.width () >> 1 ;
320
+ const int windowRightHalf = windowSize.width () - windowLeftHalf;
321
+
322
+ for (int y = 0 ; y < h; ++y) {
323
+ const int top = std::max (0 , y - windowLowerHalf);
324
+ const int bottom = std::min (h, y + windowUpperHalf); // exclusive
325
+ for (int x = 0 ; x < w; ++x) {
326
+ const int left = std::max (0 , x - windowLeftHalf);
327
+ const int right = std::min (w, x + windowRightHalf); // exclusive
328
+ const int area = (bottom - top) * (right - left);
329
+ assert (area > 0 ); // because windowSize > 0 and w > 0 and h > 0
330
+ const QRect rect (left, top, right - left, bottom - top);
331
+ const double windowSum = integralImage.sum (rect);
332
+
333
+ const double rArea = 1.0 / area;
334
+ const double mean = windowSum * rArea + 0.5 ;
335
+ const int imean = (int )((mean < 0.0 ) ? 0.0 : (mean < 255.0 ) ? mean : 255.0 );
336
+ gmeanLine[x] = imean;
337
+ }
338
+ gmeanLine += gmeanBpl;
339
+ }
340
+
341
+ double gvalue = 127.5 ;
342
+ double sum_g = 0.0 , sum_gi = 0.0 ;
343
+ grayLine = gray.bits ();
344
+ gmeanLine = gmean.bits ();
345
+ for (int y = 0 ; y < h; y++){
346
+ double sum_gl = 0.0 ;
347
+ double sum_gil = 0.0 ;
348
+ for (int x = 0 ; x < w; x++){
349
+ double gi = grayLine[x];
350
+ double g = gmeanLine[x];
351
+ g -= gi;
352
+ g = (g < 0.0 ) ? -g : g;
353
+ gi *= g;
354
+ sum_gl += g;
355
+ sum_gil += gi;
356
+ }
357
+ sum_g += sum_gl;
358
+ sum_gi += sum_gil;
359
+ grayLine += grayBpl;
360
+ gmeanLine += gmeanBpl;
361
+ }
362
+ gvalue = (sum_g > 0.0 ) ? (sum_gi / sum_g) : gvalue;
363
+
364
+ double const meanGrad = gvalue * (1.0 - k);
365
+
366
+ BinaryImage bwImg (w, h);
367
+ uint32_t * bwLine = bwImg.data ();
368
+ const int bwWpl = bwImg.wordsPerLine ();
369
+
370
+ grayLine = gray.bits ();
371
+ gmeanLine = gmean.bits ();
372
+ for (int y = 0 ; y < h; ++y) {
373
+ for (int x = 0 ; x < w; ++x) {
374
+ const double origin = grayLine[x];
375
+ const double mean = gmeanLine[x];
376
+ const double threshold = meanGrad + mean * k;
377
+ const uint32_t msb = uint32_t (1 ) << 31 ;
378
+ const uint32_t mask = msb >> (x & 31 );
379
+ if (origin < (threshold + delta)) {
380
+ // black
381
+ bwLine[x >> 5 ] |= mask;
382
+ } else {
383
+ // white
384
+ bwLine[x >> 5 ] &= ~mask;
385
+ }
386
+ }
387
+ grayLine += grayBpl;
388
+ gmeanLine += gmeanBpl;
389
+ bwLine += bwWpl;
390
+ }
391
+ return bwImg;
392
+ } // binarizeGrad
393
+
271
394
BinaryImage binarizeEdgeDiv (const QImage& src,
272
395
const QSize windowSize,
273
396
const double kep,
@@ -282,6 +405,9 @@ BinaryImage binarizeEdgeDiv(const QImage& src,
282
405
}
283
406
284
407
QImage gray (toGrayscale (src));
408
+ if (gray.isNull ()) {
409
+ return BinaryImage ();
410
+ }
285
411
const int w = gray.width ();
286
412
const int h = gray.height ();
287
413
0 commit comments