qrtools 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. data/History.txt +6 -0
  2. data/Manifest.txt +65 -0
  3. data/README.txt +75 -0
  4. data/Rakefile +49 -0
  5. data/bin/qrdecode +14 -0
  6. data/ext/qrtools/Makefile.in +65 -0
  7. data/ext/qrtools/bitstream.cpp +147 -0
  8. data/ext/qrtools/bitstream.h +48 -0
  9. data/ext/qrtools/codedata.cpp +506 -0
  10. data/ext/qrtools/codedata.h +95 -0
  11. data/ext/qrtools/container.cpp +288 -0
  12. data/ext/qrtools/container.h +175 -0
  13. data/ext/qrtools/decodeqr.h +286 -0
  14. data/ext/qrtools/ecidecoder.cpp +341 -0
  15. data/ext/qrtools/ecidecoder.h +110 -0
  16. data/ext/qrtools/extconf.rb +24 -0
  17. data/ext/qrtools/formatinfo.cpp +195 -0
  18. data/ext/qrtools/formatinfo.h +113 -0
  19. data/ext/qrtools/galois.cpp +593 -0
  20. data/ext/qrtools/galois.h +134 -0
  21. data/ext/qrtools/imagereader.cpp +1099 -0
  22. data/ext/qrtools/imagereader.h +127 -0
  23. data/ext/qrtools/libdecodeqr.cpp +195 -0
  24. data/ext/qrtools/libdecodeqr.dep +80 -0
  25. data/ext/qrtools/libdecodeqr.dsp +160 -0
  26. data/ext/qrtools/libdecodeqr.dsw +29 -0
  27. data/ext/qrtools/libdecodeqr.mak +245 -0
  28. data/ext/qrtools/qrerror.h +40 -0
  29. data/ext/qrtools/qrtools.c +17 -0
  30. data/ext/qrtools/qrtools.h +21 -0
  31. data/ext/qrtools/qrtools_decoder.c +123 -0
  32. data/ext/qrtools/qrtools_decoder.h +10 -0
  33. data/ext/qrtools/qrtools_encoder.c +63 -0
  34. data/ext/qrtools/qrtools_encoder.h +10 -0
  35. data/ext/qrtools/qrtools_header.c +51 -0
  36. data/ext/qrtools/qrtools_header.h +10 -0
  37. data/ext/qrtools/qrtools_image.c +80 -0
  38. data/ext/qrtools/qrtools_image.h +11 -0
  39. data/ext/qrtools/qrtools_qrcode.c +36 -0
  40. data/ext/qrtools/qrtools_qrcode.h +10 -0
  41. data/ext/qrtools/qrtools_ui_camera.c +58 -0
  42. data/ext/qrtools/qrtools_ui_camera.h +10 -0
  43. data/ext/qrtools/qrtools_ui_window.c +40 -0
  44. data/ext/qrtools/qrtools_ui_window.h +10 -0
  45. data/ext/qrtools/qrtypes.h +42 -0
  46. data/ext/qrtools/version.h +42 -0
  47. data/lib/qrtools.rb +11 -0
  48. data/lib/qrtools/decoder.rb +17 -0
  49. data/lib/qrtools/encoder.rb +14 -0
  50. data/lib/qrtools/image.rb +43 -0
  51. data/lib/qrtools/qrcode.rb +54 -0
  52. data/lib/qrtools/ui/camera.rb +28 -0
  53. data/lib/qrtools/ui/window.rb +16 -0
  54. data/lib/qrtools/version.rb +3 -0
  55. data/qrtools.gemspec +38 -0
  56. data/test/assets/01-1.jpg +0 -0
  57. data/test/helper.rb +17 -0
  58. data/test/test_decoder.rb +67 -0
  59. data/test/test_encoder.rb +35 -0
  60. data/test/test_header.rb +14 -0
  61. data/test/test_image.rb +19 -0
  62. data/test/test_qrcode.rb +78 -0
  63. data/test/test_qrdecode.rb +0 -0
  64. data/test/ui/test_camera.rb +43 -0
  65. data/test/ui/test_window.rb +34 -0
  66. metadata +138 -0
@@ -0,0 +1,134 @@
1
+ /////////////////////////////////////////////////////////////////////////
2
+ //
3
+ // galois.h --a part of libdecodeqr
4
+ //
5
+ // Copyright(C) 2007 NISHI Takao <zophos@koka-in.org>
6
+ // JMA (Japan Medical Association)
7
+ // NaCl (Network Applied Communication Laboratory Ltd.)
8
+ //
9
+ // This is free software with ABSOLUTELY NO WARRANTY.
10
+ // You can redistribute and/or modify it under the terms of LGPL.
11
+ //
12
+ // $Id: galois.h 36 2007-02-21 23:22:03Z zophos $
13
+ //
14
+ #ifndef __GALOIS__
15
+ #define __GALOIS__
16
+
17
+ #include <memory.h>
18
+
19
+ #ifndef NULL
20
+ #define NULL 0
21
+ #endif
22
+
23
+ namespace Galois{
24
+ class Nomial{
25
+ public:
26
+ unsigned int val;
27
+
28
+ private:
29
+ void *_gf;
30
+
31
+ public:
32
+ static Nomial *instance(void * gf,unsigned int x);
33
+ Nomial *dup();
34
+
35
+ unsigned int to_exp();
36
+ unsigned int to_vect();
37
+
38
+ inline int m();
39
+ inline int n();
40
+ inline unsigned int exp2vect(unsigned int x);
41
+ inline unsigned int vect2exp(unsigned int x);
42
+
43
+ bool is_zero();
44
+ bool operator==(Nomial x);
45
+ bool operator!=(Nomial x);
46
+ Nomial operator+(Nomial x);
47
+ Nomial operator-(Nomial x);
48
+ Nomial operator*(Nomial x);
49
+ Nomial operator/(Nomial x);
50
+
51
+ protected:
52
+ Nomial(void * gf,unsigned int x);
53
+ };
54
+
55
+ class Field{
56
+ public:
57
+ int m;
58
+ int n;
59
+ unsigned int *exp2vect;
60
+ unsigned int *vect2exp;
61
+ Nomial **pool;
62
+ private:
63
+ int _pool_size;
64
+ bool _need_delete;
65
+
66
+ public:
67
+ Field(int m);
68
+ ~Field();
69
+
70
+ int pool_size();
71
+
72
+ Nomial *exp2nomial(unsigned int x);
73
+ Nomial *vect2nomial(unsigned int x);
74
+ Nomial *zero();
75
+ };
76
+
77
+
78
+ class Polynomial{
79
+ public:
80
+ int cols;
81
+ int rows;
82
+ Nomial **nomial;
83
+
84
+ Polynomial();
85
+ Polynomial(int rows);
86
+ Polynomial(int cols,int rows);
87
+ ~Polynomial();
88
+
89
+ Polynomial *dup();
90
+ Polynomial *dup(int count);
91
+ Polynomial *dup(int start_col,int start_row,int count);
92
+ Polynomial *dup(int start_col,int start_row,
93
+ int col_count,int row_count);
94
+
95
+ Nomial *set(int row,Nomial *val);
96
+ Nomial *set(int col,int row,Nomial *val);
97
+
98
+ Nomial *get(int row);
99
+ Nomial *get(int col,int row);
100
+
101
+ Polynomial *lu();
102
+ Polynomial *lu(int count);
103
+ Polynomial *lu(int start_col,int start_row,int count);
104
+ Polynomial *_lu(Polynomial *buf);
105
+
106
+ Polynomial *solve();
107
+ Polynomial *solve(Polynomial *lu);
108
+
109
+ void swap_col(int i,int j);
110
+ };
111
+
112
+ class BCH :public Polynomial{
113
+ public:
114
+ int error_size;
115
+ int *error_pos;
116
+ int syndrome_size;
117
+ Galois::Nomial **syndromes;
118
+
119
+ private:
120
+ Field *_gf;
121
+ int _capability;
122
+
123
+ public:
124
+ BCH(Field *gf,int size,int capability);
125
+ ~BCH();
126
+
127
+ int decode(int syndorome_base=0);
128
+
129
+ private:
130
+ Galois::Nomial *_error_syndrome(int d);
131
+ };
132
+ }
133
+
134
+ #endif
@@ -0,0 +1,1099 @@
1
+ /////////////////////////////////////////////////////////////////////////
2
+ //
3
+ // imagereader.cpp --a part of libdecodeqr
4
+ //
5
+ // Copyright(C) 2007 NISHI Takao <zophos@koka-in.org>
6
+ // JMA (Japan Medical Association)
7
+ // NaCl (Network Applied Communication Laboratory Ltd.)
8
+ //
9
+ // This is free software with ABSOLUTELY NO WARRANTY.
10
+ // You can redistribute and/or modify it under the terms of LGPL.
11
+ //
12
+ // $Id: imagereader.cpp 36 2007-02-21 23:22:03Z zophos $
13
+ //
14
+ #include "imagereader.h"
15
+
16
+ namespace Qr{
17
+
18
+ //
19
+ // avoid cvBoundingRect() fxxcin' bug.
20
+ //
21
+ typedef struct{
22
+ CvRect feret;
23
+ CvSeq *contour;
24
+ } ImageReaderCandidate;
25
+
26
+
27
+ /////////////////////////////////////////////////////////////////////
28
+ //
29
+ //
30
+ //
31
+ ImageReader::ImageReader()
32
+ {
33
+ this->_init();
34
+ }
35
+ ImageReader::ImageReader(int width,int height,int depth,int channel)
36
+ {
37
+ this->_init();
38
+ this->_alloc_image(width,height,depth,channel);
39
+ }
40
+ ImageReader::~ImageReader()
41
+ {
42
+ if(this->qr)
43
+ delete this->qr;
44
+
45
+ if(this->_seq_code_area_contour)
46
+ cvRelease((void **)&this->_seq_code_area_contour);
47
+
48
+ cvRelease((void **)&this->_seq_finder_pattern);
49
+ cvReleaseMemStorage(&this->_stor_tmp);
50
+ cvReleaseMemStorage(&this->_stor);
51
+
52
+ this->release_image();
53
+ }
54
+
55
+ void ImageReader::_init()
56
+ {
57
+ memset(this->_coderegion_vertexes,0,sizeof(CvPoint)*4);
58
+ memset(this->_finderpattern_boxes,0,sizeof(CvBox2D)*3);
59
+
60
+ this->_img_src_internal=NULL;
61
+ this->_img_src=NULL;
62
+ this->_img_transformed=NULL;
63
+ this->_img_binarized=NULL;
64
+ this->_img_tmp_1c=NULL;
65
+
66
+ this->_stor=cvCreateMemStorage(0);
67
+ this->_stor_tmp=cvCreateMemStorage(0);
68
+
69
+ this->_seq_finder_pattern=cvCreateSeq(CV_SEQ_ELTYPE_GENERIC,
70
+ sizeof(CvSeq),
71
+ sizeof(CvBox2D),
72
+ this->_stor);
73
+ this->_seq_code_area_contour=NULL;
74
+
75
+ this->status=0;
76
+ this->qr=NULL;
77
+ }
78
+ void ImageReader::_alloc_image(int width,int height,int depth,int channel)
79
+ {
80
+ this->_img_src_internal=cvCreateImage(cvSize(width,height),
81
+ depth,channel);
82
+ cvZero(this->_img_src_internal);
83
+ this->_img_src=this->_img_src_internal;
84
+
85
+ this->_img_transformed=cvCloneImage(this->_img_src);
86
+ this->_img_binarized=cvCreateImage(cvSize(this->_img_src->width,
87
+ this->_img_src->height),
88
+ IPL_DEPTH_8U,1);
89
+ cvZero(this->_img_binarized);
90
+ this->_img_tmp_1c=cvCloneImage(this->_img_binarized);
91
+ }
92
+
93
+ IplImage *ImageReader::set_image(IplImage *src)
94
+ {
95
+ this->release_image();
96
+
97
+ this->_img_src=src;
98
+ this->_img_transformed=cvCloneImage(this->_img_src);
99
+ this->_img_binarized=cvCreateImage(cvSize(this->_img_src->width,
100
+ this->_img_src->height),
101
+ IPL_DEPTH_8U,1);
102
+ cvZero(this->_img_binarized);
103
+ this->_img_tmp_1c=cvCloneImage(this->_img_binarized);
104
+
105
+ return(this->_img_src);
106
+ }
107
+
108
+ IplImage *ImageReader::set_image(int width,int height,
109
+ int depth,int channel)
110
+ {
111
+ this->release_image();
112
+ this->_alloc_image(width,height,depth,channel);
113
+
114
+ return(this->_img_src);
115
+ }
116
+
117
+ void ImageReader::release_image()
118
+ {
119
+ if(this->_img_tmp_1c)
120
+ cvReleaseImage(&this->_img_tmp_1c);
121
+ if(this->_img_binarized)
122
+ cvReleaseImage(&this->_img_binarized);
123
+ if(this->_img_transformed)
124
+ cvReleaseImage(&this->_img_transformed);
125
+ if(this->_img_src_internal)
126
+ cvReleaseImage(&this->_img_src_internal);
127
+
128
+ this->_img_tmp_1c=NULL;
129
+ this->_img_binarized=NULL;
130
+ this->_img_transformed=NULL;
131
+ this->_img_src_internal=NULL;
132
+ this->_img_src=NULL;
133
+ }
134
+
135
+
136
+ IplImage *ImageReader::src_buffer()
137
+ {
138
+ return(this->_img_src);
139
+ }
140
+ IplImage *ImageReader::transformed_buffer()
141
+ {
142
+ return(this->_img_transformed);
143
+ }
144
+ IplImage *ImageReader::binarized_buffer()
145
+ {
146
+ return(this->_img_binarized);
147
+ }
148
+ IplImage *ImageReader::tmp_buffer()
149
+ {
150
+ return(this->_img_tmp_1c);
151
+ }
152
+ CvPoint *ImageReader::coderegion_vertexes()
153
+ {
154
+ return(this->_coderegion_vertexes);
155
+ }
156
+ CvBox2D *ImageReader::finderpattern_boxes()
157
+ {
158
+ return(this->_finderpattern_boxes);
159
+ }
160
+
161
+
162
+ Qr *ImageReader::decode(int adaptive_th_size,
163
+ int adaptive_th_delta)
164
+ {
165
+ if(this->status&QR_IMAGEREADER_WORKING)
166
+ return(NULL);
167
+
168
+ if(!this->_img_src){
169
+ this->status=(QR_IMAGEREADER_ERROR|
170
+ QR_IMAGEREADER_NOT_INVALID_SRC_IMAGE);
171
+ return(NULL);
172
+ }
173
+
174
+ this->status=QR_IMAGEREADER_WORKING;
175
+
176
+ cvResetImageROI(this->_img_transformed);
177
+ cvResetImageROI(this->_img_binarized);
178
+ cvResetImageROI(this->_img_tmp_1c);
179
+
180
+ Qr *ret=this->_decode(adaptive_th_size,adaptive_th_delta);
181
+
182
+ this->status^=QR_IMAGEREADER_WORKING;
183
+ return(ret);
184
+ }
185
+
186
+ Qr *ImageReader::decode(IplImage *src,
187
+ int adaptive_th_size,
188
+ int adaptive_th_delta)
189
+ {
190
+ if(this->status&QR_IMAGEREADER_WORKING)
191
+ return(NULL);
192
+
193
+ this->status=QR_IMAGEREADER_WORKING;
194
+
195
+ this->set_image(src);
196
+ Qr *ret=this->_decode(adaptive_th_size,adaptive_th_delta);
197
+
198
+ this->_img_src=NULL;
199
+
200
+ this->status^=QR_IMAGEREADER_WORKING;
201
+ return(ret);
202
+ }
203
+
204
+
205
+ Qr *ImageReader::_decode(int adaptive_th_size,int adaptive_th_delta)
206
+ {
207
+ if(this->qr){
208
+ delete this->qr;
209
+ this->qr=NULL;
210
+ }
211
+
212
+ memset(this->_coderegion_vertexes,0,sizeof(CvPoint)*4);
213
+ memset(this->_finderpattern_boxes,0,sizeof(CvBox2D)*3);
214
+
215
+ //
216
+ // binarize
217
+ //
218
+ if(this->_img_src->nChannels>1)
219
+ cvCvtColor(this->_img_src,this->_img_tmp_1c,CV_BGR2GRAY);
220
+ else
221
+ cvCopy(this->_img_src,this->_img_tmp_1c);
222
+
223
+ cvSmooth(this->_img_tmp_1c,this->_img_binarized,CV_MEDIAN,3);
224
+ cvCopy(this->_img_binarized,this->_img_tmp_1c);
225
+ if(adaptive_th_size>0)
226
+ cvAdaptiveThreshold(this->_img_tmp_1c,
227
+ this->_img_binarized,
228
+ 128,CV_ADAPTIVE_THRESH_MEAN_C,
229
+ CV_THRESH_BINARY_INV,
230
+ adaptive_th_size,
231
+ adaptive_th_delta);
232
+ else
233
+ cvThreshold(this->_img_tmp_1c,
234
+ this->_img_binarized,
235
+ adaptive_th_delta,
236
+ 255,CV_THRESH_BINARY_INV);
237
+
238
+ //
239
+ // find finder patterns from binarized image
240
+ //
241
+ this->_find_finder_pattern();
242
+ if(this->_seq_finder_pattern->total!=3){
243
+ this->status|=(QR_IMAGEREADER_ERROR|
244
+ QR_IMAGEREADER_NOT_FOUND_FINDER_PATTERN);
245
+ return(NULL);
246
+ }
247
+
248
+ //
249
+ // find code area from binarized image using finder patterns
250
+ //
251
+ this->_find_code_area_contour(FIND_CODE_AREA_POLY_APPROX_TH);
252
+
253
+ if(!this->_seq_code_area_contour||
254
+ this->_seq_code_area_contour->total!=4){
255
+ this->status|=(QR_IMAGEREADER_ERROR|
256
+ QR_IMAGEREADER_NOT_FOUND_CODE_AREA);
257
+ return(NULL);
258
+ }
259
+
260
+ //
261
+ // perspective transform from source image
262
+ //
263
+ this->_transform_image();
264
+ IplImage *code_matrix=NULL;
265
+ for(int th=POSTERIZED_TH_LOW;th<=POSTERIZED_TH_HI&&(!code_matrix);
266
+ th+=POSTERIZED_TH_STEP){
267
+
268
+ this->_create_posterized_image(adaptive_th_size,
269
+ adaptive_th_delta*3,
270
+ th,
271
+ POSTERIZED_TH_HI);
272
+ code_matrix=this->_get_code_matrix();
273
+ }
274
+
275
+ if(!code_matrix){
276
+ this->status|=(QR_IMAGEREADER_ERROR|
277
+ QR_IMAGEREADER_NOT_DETERMINABLE_CODE_AREA);
278
+ return(NULL);
279
+ }
280
+
281
+ this->qr=new Qr();
282
+ this->qr->set_version((code_matrix->width-17)/4);
283
+ if(this->qr->version>=7){
284
+ //FIXME this->_verify_code_version();
285
+ }
286
+
287
+ if(this->_get_format_info(code_matrix,0)<0){
288
+ if((this->_get_format_info(code_matrix,1)<0)&&
289
+ (this->qr->formatinfo->status&QR_FORMATINFO_INVALID_LEVEL)){
290
+ this->_get_format_info(code_matrix,0);
291
+ if(this->qr->formatinfo->status&QR_FORMATINFO_INVALID_LEVEL){
292
+ cvReleaseImage(&code_matrix);
293
+ this->status|=(QR_IMAGEREADER_ERROR|
294
+ this->qr->formatinfo->status);
295
+ return(NULL);
296
+ }
297
+ }
298
+ }
299
+
300
+ IplImage *function_patterns=this->_get_function_patterns();
301
+
302
+ this->_unmask_code_matrix(code_matrix,function_patterns);
303
+ this->_read_code_word(code_matrix,function_patterns);
304
+
305
+ cvReleaseImage(&function_patterns);
306
+ cvReleaseImage(&code_matrix);
307
+
308
+ int errors=this->qr->decode_codedata();
309
+
310
+ #ifdef _DEBUG
311
+ fprintf(stderr,"errors=%d\n",errors);
312
+ #endif
313
+ this->status|=(QR_IMAGEREADER_DECODED|this->qr->status);
314
+
315
+ return(this->qr);
316
+ }
317
+
318
+ CvSeq *ImageReader::_find_finder_pattern()
319
+ {
320
+ IplImage *src=this->_img_binarized;
321
+ cvClearSeq(this->_seq_finder_pattern);
322
+
323
+ // for contour list
324
+ cvClearMemStorage(this->_stor_tmp);
325
+ CvSeq *cont=cvCreateSeq(CV_SEQ_ELTYPE_POINT,
326
+ sizeof(CvSeq),sizeof(CvPoint),
327
+ this->_stor_tmp);
328
+
329
+ //
330
+ // Find all contours.
331
+ //
332
+ // cvFindContours() spoil source image.
333
+ //
334
+ CvRect roi=cvGetImageROI(src);
335
+ cvSetImageROI(this->_img_tmp_1c,roi);
336
+ cvCopy(src,this->_img_tmp_1c);
337
+
338
+ cvFindContours(this->_img_tmp_1c,
339
+ this->_stor_tmp,&cont,sizeof(CvContour),
340
+ CV_RETR_LIST,CV_CHAIN_APPROX_NONE,cvPoint(0,0));
341
+
342
+ cvResetImageROI(this->_img_tmp_1c);
343
+
344
+ // for marker candidates list
345
+ CvSeq *candidates=cvCreateSeq(CV_SEQ_ELTYPE_GENERIC,
346
+ sizeof(CvSeq),sizeof(ImageReaderCandidate),
347
+ this->_stor_tmp);
348
+ //
349
+ // check each block
350
+ //
351
+ CvSeq *cont_head=cont;
352
+ for(;cont;cont=cont->h_next){
353
+ CvRect feret=cvBoundingRect(cont);
354
+ double area=fabs(cvContourArea(cont));
355
+ double area_ratio=area/(double)(feret.width*feret.height);
356
+ double feret_ratio=((feret.width<feret.height)?
357
+ (double)feret.width/(double)feret.height:
358
+ (double)feret.height/(double)feret.width);
359
+
360
+ //
361
+ // search square
362
+ //
363
+ if(area>=MIN_AREA &&
364
+ area_ratio>=MIN_AREA_RATIO &&
365
+ feret_ratio>=MIN_FERET_RATIO){
366
+ ImageReaderCandidate c;
367
+ c.feret.x=feret.x;
368
+ c.feret.y=feret.y;
369
+ c.feret.width=feret.width;
370
+ c.feret.height=feret.height;
371
+ c.contour=cont;
372
+ cvSeqPush(candidates,&c);
373
+ }
374
+ else{
375
+ cvClearSeq(cont);
376
+ }
377
+ }
378
+ cvRelease((void **)&cont_head);
379
+
380
+ //
381
+ // check each sqare has inner squire
382
+ //
383
+ int i;
384
+ for(i=0;i<candidates->total;i++){
385
+ ImageReaderCandidate *cand1=
386
+ (ImageReaderCandidate *)cvGetSeqElem(candidates,i);
387
+
388
+ int inner_contour=0;
389
+ int j;
390
+ for(j=0;j<candidates->total;j++){
391
+ if(i==j)
392
+ continue;
393
+
394
+ ImageReaderCandidate *cand2=
395
+ (ImageReaderCandidate *)cvGetSeqElem(candidates,j);
396
+ CvRect max_rect=cvMaxRect(&(cand1->feret),&(cand2->feret));
397
+ if(cand1->feret.x==max_rect.x&&
398
+ cand1->feret.y==max_rect.y&&
399
+ cand1->feret.width==max_rect.width&&
400
+ cand1->feret.height==max_rect.height)
401
+ inner_contour++;
402
+ }
403
+
404
+ //
405
+ // There were 2 squires (white and black) inside a squire,
406
+ // the most outer squire assumed as position marker.
407
+ //
408
+ if(inner_contour==2){
409
+ CvBox2D box=cvMinAreaRect2(cand1->contour);
410
+ cvSeqPush(this->_seq_finder_pattern,&box);
411
+ }
412
+ }
413
+
414
+ //
415
+ // clear buffers
416
+ //
417
+ for(i=0;i<candidates->total;i++){
418
+ ImageReaderCandidate *cand1=
419
+ (ImageReaderCandidate *)cvGetSeqElem(candidates,i);
420
+ cvClearSeq(cand1->contour);
421
+ }
422
+ //cvClearSeq(candidates);
423
+ cvRelease((void **)&candidates);
424
+
425
+ cvClearMemStorage(this->_stor_tmp);
426
+
427
+ return(this->_seq_finder_pattern);
428
+ }
429
+
430
+ /////////////////////////////////////////////////////////////////////////
431
+ //
432
+ //
433
+ //
434
+ CvSeq *ImageReader::_find_code_area_contour(double th)
435
+ {
436
+ IplImage *src=this->_img_binarized;
437
+ IplImage *mask=this->_img_tmp_1c;
438
+ cvZero(mask);
439
+
440
+ cvClearMemStorage(this->_stor_tmp);
441
+
442
+ //
443
+ // create position maker mask
444
+ //
445
+ CvBox2D box;
446
+ CvPoint2D32f pt_32f[4];
447
+ CvSeq *markers_vertex=cvCreateSeq(CV_SEQ_ELTYPE_POINT,
448
+ sizeof(CvSeq),
449
+ sizeof(CvPoint),
450
+ this->_stor_tmp);
451
+
452
+
453
+ int c=this->_seq_finder_pattern->total,i;
454
+ for(i=0;i<c;i++){
455
+ box=*(CvBox2D *)cvGetSeqElem(this->_seq_finder_pattern,i);
456
+ this->_finderpattern_boxes[i]=box;
457
+
458
+ //
459
+ // set 2-cells margin for fale-safe
460
+ //
461
+ box.size.width+=box.size.width/7.0F*4.0F;
462
+ box.size.height+=box.size.height/7.0F*4.0F;
463
+
464
+ //
465
+ // get each position maker's vertex
466
+ //
467
+ cvBoxPoints(box,pt_32f);
468
+ for(int j=0;j<4;j++){
469
+ CvPoint p=cvPointFrom32f(pt_32f[j]);
470
+ cvSeqPush(markers_vertex,&p);
471
+ }
472
+ }
473
+
474
+ //
475
+ // create Minimal-area bounding rectangle which condist
476
+ // every position makers
477
+ //
478
+ box=cvMinAreaRect2(markers_vertex);
479
+ cvRelease((void **)&markers_vertex);
480
+
481
+ //
482
+ // create code area mask
483
+ //
484
+ cvBoxPoints(box,pt_32f);
485
+ CvPoint *points=new CvPoint[4];
486
+ for(i=0;i<4;i++){
487
+ points[i]=cvPointFrom32f(pt_32f[i]);
488
+ }
489
+ i=4;
490
+ cvFillPoly(mask,&points,&i,1,cvScalarAll(255));
491
+ delete points;
492
+
493
+ //
494
+ // apply mask to src image and reduce noise using opening
495
+ //
496
+ cvAnd(src,mask,mask);
497
+ cvErode(mask,mask,NULL,1);
498
+ cvDilate(mask,mask,NULL,1);
499
+
500
+ //
501
+ // get contours of masked image
502
+ //
503
+ CvSeq *cont=cvCreateSeq(CV_SEQ_ELTYPE_POINT,
504
+ sizeof(CvSeq),sizeof(CvPoint),
505
+ this->_stor_tmp);
506
+ cvFindContours(mask,cont->storage,&cont,sizeof(CvContour),
507
+ CV_RETR_EXTERNAL,CV_CHAIN_APPROX_NONE,cvPoint(0,0));
508
+
509
+ //
510
+ // calcurate convex hull that assumed as code area
511
+ //
512
+ CvSeq *pts=cvCreateSeq(CV_SEQ_ELTYPE_POINT,
513
+ sizeof(CvSeq),sizeof(CvPoint),
514
+ this->_stor_tmp);
515
+ CvSeq *cont_head=cont;
516
+ for(;cont;cont=cont->h_next){
517
+ int c=cont->total;
518
+ for(i=0;i<c;i++){
519
+ CvPoint pt=*((CvPoint *)cvGetSeqElem(cont,i));
520
+ cvSeqPush(pts,&pt);
521
+ }
522
+ cvClearSeq(cont);
523
+ }
524
+ cvRelease((void **)&cont_head);
525
+
526
+ CvSeq *hull=cvConvexHull2(pts);
527
+
528
+ //
529
+ // polygonal approximation to reduce noise
530
+ //
531
+ if(this->_seq_code_area_contour){
532
+ cvClearSeq(this->_seq_code_area_contour);
533
+ cvRelease((void **)&this->_seq_code_area_contour);
534
+ this->_seq_code_area_contour=NULL;
535
+ }
536
+ if(hull){
537
+ int hullcount=hull->total;
538
+ CvMat* vector=cvCreateMat(1,hullcount,CV_32SC2);
539
+ for(i=0;i<hullcount;i++ ){
540
+ CV_MAT_ELEM(*vector,CvPoint,0,i)=
541
+ **CV_GET_SEQ_ELEM(CvPoint*,hull,i);
542
+ }
543
+ CvContour header;
544
+ CvSeqBlock block;
545
+ this->_seq_code_area_contour=cvApproxPoly(
546
+ cvPointSeqFromMat(CV_SEQ_KIND_CURVE+CV_SEQ_FLAG_CLOSED,
547
+ vector, &header, &block),
548
+ sizeof(CvContour),
549
+ this->_stor,
550
+ CV_POLY_APPROX_DP,th,0);
551
+
552
+ cvRelease((void **)&hull);
553
+ }
554
+
555
+ return(this->_seq_code_area_contour);
556
+ }
557
+
558
+
559
+ CvRect ImageReader::_transform_image()
560
+ {
561
+ IplImage *src=this->_img_src;
562
+ IplImage *dst=this->_img_transformed;
563
+ cvResetImageROI(dst);
564
+
565
+ //
566
+ // get code area's Centor of Gravity
567
+ //
568
+ int i;
569
+ int c=this->_seq_code_area_contour->total;
570
+ CvPoint2D32f cog;
571
+ cog.x=0.0F;
572
+ cog.y=0.0F;
573
+ for(i=0;i<c;i++){
574
+ CvPoint2D32f p=cvPointTo32f(
575
+ *(CvPoint *)cvGetSeqElem(this->_seq_code_area_contour,i));
576
+ cog.x+=p.x;
577
+ cog.y+=p.y;
578
+ }
579
+ cog.x/=(float)c;
580
+ cog.y/=(float)c;
581
+
582
+ //
583
+ // sort code_area_contour by clock-wise
584
+ //
585
+ cvSeqSort(this->_seq_code_area_contour,seq_cmp_by_clockwise,&cog);
586
+
587
+
588
+ //
589
+ // calculates matrix of perspective transform
590
+ //
591
+ // The src rectangle transform to a square which left-top vertex
592
+ // is same as src rectangle and each side length is same as top side
593
+ // length of src.
594
+ //
595
+ CvPoint2D32f spts[4];
596
+ CvPoint2D32f dpts[4];
597
+ float max_d=0.0F;
598
+ int offset=0;
599
+
600
+ #ifdef _DEBUG
601
+ fprintf(stderr,"target region: ");
602
+ #endif
603
+ for(i=0;i<c;i++){
604
+ this->_coderegion_vertexes[i]=*(CvPoint *)cvGetSeqElem(
605
+ this->_seq_code_area_contour,i);
606
+ spts[i]=cvPointTo32f(this->_coderegion_vertexes[i]);
607
+
608
+ //
609
+ // find nearest finder pattern
610
+ //
611
+ int j=0;
612
+ float tmp_d=0.0F;
613
+ float min_d=(this->_finderpattern_boxes[j].center.x-spts[i].x)*
614
+ (this->_finderpattern_boxes[j].center.x-spts[i].x)+
615
+ (this->_finderpattern_boxes[j].center.y-spts[i].y)*
616
+ (this->_finderpattern_boxes[j].center.y-spts[i].y);
617
+
618
+ for(j=1;j<3;j++){
619
+ tmp_d=(this->_finderpattern_boxes[j].center.x-spts[i].x)*
620
+ (this->_finderpattern_boxes[j].center.x-spts[i].x)+
621
+ (this->_finderpattern_boxes[j].center.y-spts[i].y)*
622
+ (this->_finderpattern_boxes[j].center.y-spts[i].y);
623
+
624
+ if(min_d>tmp_d)
625
+ min_d=tmp_d;
626
+ }
627
+ if(max_d<min_d){
628
+ max_d=min_d;
629
+ offset=i;
630
+ }
631
+
632
+ #ifdef _DEBUG
633
+ fprintf(stderr,"(%.0lf,%.0lf) ",spts[i].x,spts[i].y);
634
+ #endif
635
+ }
636
+
637
+ offset=(offset+2)%4;
638
+
639
+ #ifdef _DEBUG
640
+ fprintf(stderr,", rotation offset=%d\n",offset);
641
+ #endif
642
+
643
+ float side_len=cvSqrt((spts[0].x-spts[1].x)*(spts[0].x-spts[1].x)+
644
+ (spts[0].y-spts[1].y)*(spts[0].y-spts[1].y));
645
+ for(i=0;i<4;i++)
646
+ dpts[i]=cvPoint2D32f(0.0,0.0);
647
+
648
+ dpts[(offset+1)%4].x+=side_len;
649
+ dpts[(offset+2)%4].x+=side_len;
650
+ dpts[(offset+2)%4].y+=side_len;
651
+ dpts[(offset+3)%4].y+=side_len;
652
+
653
+ CvMat *map=cvCreateMat(3,3,CV_64FC1);
654
+
655
+ cvWarpPerspectiveQMatrix(spts,dpts,map);
656
+
657
+ //
658
+ // perspective transform
659
+ //
660
+ cvWarpPerspective(src,dst,map);
661
+ cvReleaseMat(&map);
662
+
663
+ //
664
+ // set ROI as code area
665
+ //
666
+ CvRect roi=cvRect((int)dpts[offset].x,(int)dpts[offset].y,
667
+ (int)side_len+1,(int)side_len+1);
668
+ cvSetImageROI(dst,roi);
669
+
670
+ return(roi);
671
+ }
672
+
673
+
674
+ void ImageReader::_create_posterized_image(int block_size,
675
+ double delta,
676
+ int low_th,
677
+ int hi_th)
678
+ {
679
+ IplImage *src=this->_img_transformed;
680
+ IplImage *dst=this->_img_binarized;
681
+ IplImage *buf=this->_img_tmp_1c;
682
+
683
+ CvRect roi=cvGetImageROI(src);
684
+ cvSetImageROI(buf,roi);
685
+ cvSetImageROI(dst,roi);
686
+
687
+ if(this->_img_src->nChannels>1)
688
+ cvCvtColor(src,buf,CV_BGR2GRAY);
689
+ else
690
+ cvCopy(src,buf);
691
+
692
+ if(block_size>0)
693
+ apaptive_white_leveling(buf,dst,128,
694
+ CV_ADAPTIVE_THRESH_MEAN_C,
695
+ CV_THRESH_BINARY_INV,
696
+ block_size,delta);
697
+ else
698
+ cvThreshold(buf,dst,delta,
699
+ 255,CV_THRESH_BINARY_INV);
700
+
701
+ int a=0;
702
+ int b=0;
703
+ if(hi_th>low_th){
704
+ a=128/(hi_th-low_th);
705
+ b=-a*low_th;
706
+ }
707
+ else{
708
+ hi_th=low_th;
709
+ }
710
+
711
+ uchar lut_data[256];
712
+ int i;
713
+ for(i=0;i<low_th;i++)
714
+ lut_data[i]=0;
715
+ for(i=low_th;i<hi_th;i++)
716
+ lut_data[i]=a*i+b;
717
+ for(i=hi_th;i<256;i++)
718
+ lut_data[i]=255;
719
+ CvMat lut=cvMat(1,256,CV_8UC1,lut_data);
720
+ cvLUT(dst,buf,&lut);
721
+ cvCopy(buf,dst);
722
+
723
+ CvRect roi_mask=roi;
724
+ cvDilate(buf,buf,NULL,1);
725
+ cvErode(buf,buf,NULL,1);
726
+
727
+ roi_mask.x+=1;
728
+ roi_mask.y+=1;
729
+ roi_mask.width-=2;
730
+ roi_mask.height-=2;
731
+ cvSetImageROI(buf,roi_mask);
732
+ cvSet(buf,cvScalarAll(0));
733
+ cvSetImageROI(buf,roi);
734
+ cvOr(dst,buf,dst);
735
+
736
+ cvResetImageROI(buf);
737
+ }
738
+
739
+
740
+ IplImage *ImageReader::_get_code_matrix()
741
+ {
742
+ IplImage *src=this->_img_binarized;
743
+
744
+ double cell_size=this->_get_cell_size();
745
+ if(cell_size<=0.0)
746
+ return(NULL);
747
+
748
+ CvRect roi=cvGetImageROI(src);
749
+ int version=(int)(((double)roi.width/cell_size-17.0)/4.0);
750
+ int w=4*version+17;
751
+
752
+ IplImage *dst=cvCreateImage(cvSize(w,w),IPL_DEPTH_8U,1);
753
+ cvResize(src,dst);
754
+
755
+
756
+ #ifdef _DEBUG
757
+ fprintf(stderr,"version=%d (%dx%d); %lfpixel/module\n",
758
+ version,w,w,cell_size*cell_size);
759
+ #endif
760
+ return(dst);
761
+ }
762
+
763
+ int ImageReader::_get_format_info(IplImage *src,int pos)
764
+ {
765
+ unsigned int raw_data=0;
766
+ this->qr->init_each_formatinfo_pattern_pixel();
767
+ int x,y;
768
+ while(this->qr->each_formatinfo_pattern_pixel(pos,&x,&y)){
769
+ raw_data<<=1;
770
+ if(CV_IMAGE_ELEM(src,uchar,y,x)==255)
771
+ raw_data|=0x01;
772
+ }
773
+
774
+ #ifdef _DEBUG
775
+ fprintf(stderr,"format Info=%04x, ",raw_data);
776
+ #endif
777
+
778
+ int ret=this->qr->decode_formatinfo(raw_data);
779
+
780
+ #ifdef _DEBUG
781
+ fprintf(stderr,"corrected %d errors ",ret);
782
+
783
+ char l[2]={0,0};
784
+ switch(this->qr->formatinfo->level){
785
+ case 0:
786
+ l[0]='M';
787
+ break;
788
+ case 1:
789
+ l[0]='L';
790
+ break;
791
+ case 2:
792
+ l[0]='H';
793
+ break;
794
+ case 3:
795
+ l[0]='Q';
796
+ }
797
+ int m=0;
798
+ if(this->qr->formatinfo->mask_pattern&0x4)
799
+ m|=0x100;
800
+ if(this->qr->formatinfo->mask_pattern&0x2)
801
+ m|=0x10;
802
+ if(this->qr->formatinfo->mask_pattern&0x1)
803
+ m|=0x1;
804
+
805
+ fprintf(stderr," =>level %s, mask %03x\n",l,m);
806
+ #endif
807
+
808
+ return(ret);
809
+ }
810
+
811
+ IplImage *ImageReader::_get_function_patterns()
812
+ {
813
+ IplImage *buf=cvCreateImage(cvSize(this->qr->cells_par_side,
814
+ this->qr->cells_par_side),
815
+ IPL_DEPTH_8U,1);
816
+ cvZero(buf);
817
+
818
+ int x,y;
819
+ this->qr->init_each_function_pattern_pixel();
820
+ while(this->qr->each_function_pattern_pixel(&x,&y)){
821
+ CV_IMAGE_ELEM(buf,uchar,y,x)=255;
822
+ }
823
+
824
+ cvNot(buf,buf);
825
+
826
+ return(buf);
827
+ }
828
+
829
+ void ImageReader::_unmask_code_matrix(IplImage *src,
830
+ IplImage *function_patterns)
831
+ {
832
+ IplImage *mask=this->_get_mask_pattern();
833
+ IplImage *unproc=cvCloneImage(mask);
834
+
835
+ cvAnd(function_patterns,unproc,unproc);
836
+ cvXor(src,mask,src,unproc);
837
+
838
+ cvReleaseImage(&unproc);
839
+ cvReleaseImage(&mask);
840
+ }
841
+
842
+ int ImageReader::_read_code_word(IplImage *src,IplImage *mask)
843
+ {
844
+ //
845
+ // erace timing pattern
846
+ //
847
+ IplImage *codes=cvCreateImage(cvSize(src->width-1,src->height-1),
848
+ IPL_DEPTH_8U,1);
849
+ cvZero(codes);
850
+ IplImage *funcs=cvCloneImage(codes);
851
+
852
+ CvRect roi=cvGetImageROI(src);
853
+
854
+ CvRect r=cvRect(7,0,roi.width-7,6);
855
+ cvSetImageROI(src,r);
856
+ cvSetImageROI(mask,r);
857
+ r.x-=1;
858
+ cvSetImageROI(codes,r);
859
+ cvSetImageROI(funcs,r);
860
+ cvCopy(src,codes);
861
+ cvCopy(mask,funcs);
862
+
863
+ r=cvRect(0,7,6,roi.height-6);
864
+ cvSetImageROI(src,r);
865
+ cvSetImageROI(mask,r);
866
+ r.y-=1;
867
+ cvSetImageROI(codes,r);
868
+ cvSetImageROI(funcs,r);
869
+ cvCopy(src,codes);
870
+ cvCopy(mask,funcs);
871
+
872
+ r=cvRect(7,7,roi.width-7,roi.height-7);
873
+ cvSetImageROI(src,r);
874
+ cvSetImageROI(mask,r);
875
+ r.x-=1;
876
+ r.y-=1;
877
+ cvSetImageROI(codes,r);
878
+ cvSetImageROI(funcs,r);
879
+ cvCopy(src,codes);
880
+ cvCopy(mask,funcs);
881
+
882
+ cvSetImageROI(src,roi);
883
+ cvSetImageROI(mask,roi);
884
+
885
+ cvResetImageROI(codes);
886
+ cvResetImageROI(funcs);
887
+
888
+ //
889
+ // read code from matrix
890
+ //
891
+ uchar data=0;
892
+ int bit_count=0,word_count=0;
893
+ int dir=-1;
894
+ int x=codes->width-1;
895
+ int y=codes->height-1;
896
+
897
+ do{
898
+ data<<=1;
899
+ bit_count++;
900
+ if(CV_IMAGE_ELEM(codes,uchar,y,x)>=128)
901
+ data|=1;
902
+ if(!(bit_count%8)){
903
+ if(this->qr->push_codedata(data))
904
+ word_count++;
905
+ data=0;
906
+ }
907
+
908
+ if(x&0x1){
909
+ if(CV_IMAGE_ELEM(funcs,uchar,y,x-1))
910
+ x--;
911
+ else{
912
+ do{
913
+ y+=dir;
914
+ if(y<0||y>=codes->height){
915
+ x-=2;
916
+ dir*=-1;
917
+ y+=dir;
918
+ if(x<0)
919
+ break;
920
+ }
921
+ }while(!CV_IMAGE_ELEM(funcs,uchar,y,x));
922
+ }
923
+ }
924
+ else{
925
+ x++;
926
+ do{
927
+ y+=dir;
928
+ if(y>=0&&y<codes->height){
929
+ if(CV_IMAGE_ELEM(funcs,uchar,y,x)){
930
+ break;
931
+ }
932
+ else if(CV_IMAGE_ELEM(funcs,uchar,y,x-1)){
933
+ x--;
934
+ break;
935
+ }
936
+ else{
937
+ y+=dir;
938
+ }
939
+ }
940
+ else{
941
+ x-=2;
942
+ dir*=-1;
943
+ y+=dir;
944
+ if(x<0)
945
+ break;
946
+ }
947
+ }while(!CV_IMAGE_ELEM(funcs,uchar,y,x));
948
+ }
949
+ }while(x>=0);
950
+
951
+ if(data){
952
+ if(this->qr->push_codedata(data))
953
+ word_count++;
954
+ }
955
+
956
+ cvReleaseImage(&funcs);
957
+ cvReleaseImage(&codes);
958
+
959
+ #ifdef _DEBUG
960
+ fprintf(stderr,"%d words in %d blocks <= %d bits, %d words were read.\n",
961
+ this->qr->codedata->total_words,
962
+ this->qr->codedata->data_blocks,
963
+ bit_count,word_count);
964
+ #endif
965
+
966
+ return(bit_count);
967
+ }
968
+
969
+
970
+ /////////////////////////////////////////////////////////////////////////
971
+ //
972
+ //
973
+ //
974
+ double ImageReader::_get_cell_size()
975
+ {
976
+ IplImage *src=this->_img_binarized;
977
+ this->_find_finder_pattern();
978
+
979
+ int c=this->_seq_finder_pattern->total;
980
+ if(c!=3)
981
+ return(-1.0);
982
+
983
+ double cell_size=0.0;
984
+ for(int i=0;i<c;i++){
985
+ CvBox2D box=*(CvBox2D *)cvGetSeqElem(this->_seq_finder_pattern,
986
+ i);
987
+ cell_size+=box.size.width+box.size.height;
988
+ }
989
+
990
+ cell_size/=42.0;
991
+
992
+ return(cell_size);
993
+ }
994
+
995
+ /////////////////////////////////////////////////////////////////////////
996
+ //
997
+ //
998
+ //
999
+ IplImage *ImageReader::_get_mask_pattern()
1000
+ {
1001
+ IplImage *mask=cvCreateImage(cvSize(this->qr->cells_par_side,
1002
+ this->qr->cells_par_side),
1003
+ IPL_DEPTH_8U,1);
1004
+ cvZero(mask);
1005
+
1006
+ CvRect roi=cvGetImageROI(mask);
1007
+ roi.width+=roi.x;
1008
+ roi.height+=roi.y;
1009
+
1010
+ for(int y=roi.y;y<roi.height;y++){
1011
+ for(int x=roi.x;x<roi.width;x++){
1012
+ CV_IMAGE_ELEM(mask,uchar,y,x)=this->qr->
1013
+ formatinfo->mask_pixel(y,x);
1014
+ }
1015
+ }
1016
+
1017
+ return(mask);
1018
+ }
1019
+
1020
+
1021
+ /////////////////////////////////////////////////////////////////////////
1022
+ //
1023
+ // sort by clock-wise
1024
+ //
1025
+ static int seq_cmp_by_clockwise(const void *_a,const void *_b,void *_cog)
1026
+ {
1027
+ CvPoint* a = (CvPoint*)_a;
1028
+ CvPoint* b = (CvPoint*)_b;
1029
+ CvPoint2D32f *cog=(CvPoint2D32f *)_cog;
1030
+
1031
+ float aa=cvFastArctan((float)(a->y)-cog->y,cog->x-(float)(a->x));
1032
+ float ba=cvFastArctan((float)(b->y)-cog->y,cog->x-(float)(b->x));
1033
+
1034
+ return(aa < ba ? 1 : aa > ba ? -1 : 0);
1035
+ }
1036
+
1037
+ /////////////////////////////////////////////////////////////////////////
1038
+ //
1039
+ // following code originates in OpenCV/cv/src/cvadapthresh.cpp
1040
+ //
1041
+ void apaptive_white_leveling(const CvArr* src,
1042
+ CvArr* dst,
1043
+ double middle_value,
1044
+ int adaptive_method,
1045
+ int threshold_type,
1046
+ int block_size,
1047
+ double param1)
1048
+ {
1049
+ CV_FUNCNAME( "apaptive_white_leveling" );
1050
+ CvMat src_stub, dst_stub;
1051
+ CvMat *srcMat,*dstMat,*mean,*mask;
1052
+
1053
+ __BEGIN__
1054
+ if( adaptive_method != CV_ADAPTIVE_THRESH_MEAN_C &&
1055
+ adaptive_method != CV_ADAPTIVE_THRESH_GAUSSIAN_C )
1056
+ CV_ERROR( CV_StsBadArg,
1057
+ "Only CV_ADAPTIVE_THRESH_MEAN_C and CV_ADAPTIVE_THRESH_GAUSSIAN_C "
1058
+ "adaptive method are acceptable" );
1059
+
1060
+ if( threshold_type != CV_THRESH_BINARY &&
1061
+ threshold_type != CV_THRESH_BINARY_INV )
1062
+ CV_ERROR( CV_StsBadArg, "Only CV_TRESH_BINARY and CV_THRESH_BINARY_INV "
1063
+ "threshold types are acceptable" );
1064
+
1065
+ srcMat=cvGetMat(src, &src_stub );
1066
+ dstMat=cvGetMat(dst, &dst_stub );
1067
+
1068
+ if( !CV_ARE_CNS_EQ( srcMat, dstMat ))
1069
+ CV_ERROR( CV_StsUnmatchedFormats, "" );
1070
+
1071
+ if( CV_MAT_TYPE(dstMat->type) != CV_8UC1 )
1072
+ CV_ERROR( CV_StsUnsupportedFormat, "" );
1073
+
1074
+ if( !CV_ARE_SIZES_EQ( srcMat, dstMat ) )
1075
+ CV_ERROR( CV_StsUnmatchedSizes, "" );
1076
+
1077
+ mean=cvCreateMat(srcMat->rows,srcMat->cols,CV_8UC1);
1078
+ mask=cvCreateMat(srcMat->rows,srcMat->cols,CV_8UC1);
1079
+
1080
+ cvSmooth( srcMat, mean, adaptive_method == CV_ADAPTIVE_THRESH_MEAN_C ?
1081
+ CV_BLUR : CV_GAUSSIAN, block_size, block_size );
1082
+ cvSubS(mean,cvRealScalar(param1),mean);
1083
+ cvAbsDiff(srcMat,mean,dstMat);
1084
+ cvCmp(srcMat,mean,mask,CV_CMP_GT);
1085
+ cvAddS(dstMat,cvRealScalar(middle_value),dstMat,mask);
1086
+ cvNot(mask,mask);
1087
+ cvSubRS(dstMat,cvRealScalar(middle_value),dstMat,mask);
1088
+
1089
+ if(threshold_type!=CV_THRESH_BINARY)
1090
+ cvNot(dstMat,dstMat);
1091
+
1092
+ cvReleaseMat( &mask );
1093
+ cvReleaseMat( &mean );
1094
+
1095
+ __END__
1096
+
1097
+ }
1098
+
1099
+ }