C++: binarizer updates
[zxing.git] / cpp / magick / src / main.cpp
1 /*
2  *  main.cpp
3  *  zxing
4  *
5  *  Copyright 2010 ZXing authors All rights reserved.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19
20 #include <iostream>
21 #include <fstream>
22 #include <string>
23 #include <Magick++.h>
24 #include "MagickBitmapSource.h"
25 #include <zxing/common/Counted.h>
26 //#include <zxing/qrcode/QRCodeReader.h>
27 #include <zxing/Binarizer.h>
28 #include <zxing/MultiFormatReader.h>
29 #include <zxing/Result.h>
30 #include <zxing/ReaderException.h>
31 #include <zxing/common/GlobalHistogramBinarizer.h>
32 #include <zxing/common/HybridBinarizer.h>
33 #include <exception>
34 #include <zxing/Exception.h>
35 #include <zxing/common/IllegalArgumentException.h>
36 #include <zxing/BinaryBitmap.h>
37
38 //#include <zxing/qrcode/detector/Detector.h>
39 //#include <zxing/qrcode/detector/QREdgeDetector.h>
40 //#include <zxing/qrcode/decoder/Decoder.h>
41
42 using namespace Magick;
43 using namespace std;
44 using namespace zxing;
45 //using namespace zxing::qrcode;
46
47 static bool raw_dump = false;
48
49 static const int MAX_EXPECTED = 1024;
50
51 Ref<Result> decode(Ref<BinaryBitmap> image) {
52   Ref<Reader> reader(new MultiFormatReader);
53   return Ref<Result> (new Result(*reader->decode(image)));
54 }
55
56
57 int test_image(Image& image, bool hybrid, string expected = "") {
58
59   string cell_result;
60   int res = -1;
61
62   Ref<BitMatrix> matrix(NULL);
63   Ref<Binarizer> binarizer(NULL);
64
65
66   try {
67     Ref<MagickBitmapSource> source(new MagickBitmapSource(image));
68
69     if (hybrid) {
70       binarizer = new HybridBinarizer(source);
71     } else {
72       binarizer = new GlobalHistogramBinarizer(source);
73     }
74
75     Ref<BinaryBitmap> binary(new BinaryBitmap(binarizer));
76     Ref<Result> result(decode(binary));
77     cell_result = result->getText()->getText();
78     res = 0;
79   } catch (ReaderException e) {
80     cell_result = "zxing::ReaderException: " + string(e.what());
81     res = -2;
82   } catch (zxing::IllegalArgumentException& e) {
83     cell_result = "zxing::IllegalArgumentException: " + string(e.what());
84     res = -3;
85   } catch (zxing::Exception& e) {
86     cell_result = "zxing::Exception: " + string(e.what());
87     res = -4;
88   } catch (std::exception& e) {
89     cell_result = "std::exception: " + string(e.what());
90     res = -5;
91   }
92
93   if (cell_result.compare(expected)) {
94     res = -6;
95     if (!raw_dump) {
96         cout << (hybrid ? "Hybrid" : "Global") << " binarizer failed:\n";
97         if (expected.length() >= 0) {
98           cout << "  Expected: " << expected << "\n";
99         }
100         cout << "  Detected: " << cell_result << endl;
101     }
102   }
103
104
105   if (raw_dump && !hybrid) /* don't print twice, and global is a bit better */
106     cout << cell_result << endl;
107
108   return res;
109 }
110
111 int test_image_hybrid(Image& image, string expected = "") {
112   return test_image(image, true, expected);
113 }
114
115 int test_image_global(Image& image, string expected = "") {
116   return test_image(image, false, expected);
117 }
118
119 string get_expected(string imagefilename) {
120   string textfilename = imagefilename;
121   int dotpos = textfilename.rfind(".");
122   textfilename.replace(dotpos+1, textfilename.length() - dotpos - 1, "txt");
123   char data[MAX_EXPECTED];
124   FILE *fp = fopen(textfilename.data(), "rb");
125     
126   // get file size
127   fseek(fp, 0, SEEK_END);
128   int toread = ftell(fp);
129   rewind(fp);
130   
131   if (toread > MAX_EXPECTED) {
132         cerr << "MAX_EXPECTED = " << MAX_EXPECTED << " but file '" << textfilename << "' has " << toread
133              << " bytes! Skipping..." << endl;
134     fclose(fp);
135     return "";
136   }
137   
138   int nread = fread(data, sizeof(char), toread, fp);
139   if (nread != toread) {
140     cerr << "Could not read entire contents of file '" << textfilename << "'! Skipping..." << endl;
141     fclose(fp);
142     return "";
143   }
144   fclose(fp);
145   data[nread] = '\0';
146   string expected(data);
147   return expected;
148 }
149
150 int main(int argc, char** argv) {
151   if (argc <= 1) {
152     cout << "Usage: " << argv[0] << " [--dump-raw] <filename1> [<filename2> ...]" << endl;
153     return 1;
154   }
155
156   int total = 0;
157   int gonly = 0;
158   int honly = 0;
159   int both = 0;
160   int neither = 0;
161
162   if (argc == 2) raw_dump = true;
163
164   for (int i = 1; i < argc; i++) {
165     string infilename = argv[i];
166     if (infilename.substr(infilename.length()-3,3).compare("txt") == 0) {
167       continue;
168     }
169     if (infilename.compare("--dump-raw") == 0) {
170       raw_dump = true;
171       continue;
172     }
173     if (!raw_dump)
174       cerr << "Processing: " << infilename << endl;
175     Image image;
176     try {
177       image.read(infilename);
178     } catch (...) {
179       cerr << "Unable to open image, ignoring" << endl;
180       continue;
181     }
182
183     string expected;
184     expected = get_expected(infilename);
185
186     int gresult = 1;
187     int hresult = 1;
188
189     hresult = test_image_hybrid(image, expected);
190     gresult = test_image_global(image, expected);
191
192     gresult = gresult == 0;
193     hresult = hresult == 0;
194
195     gonly += gresult && !hresult;
196     honly += hresult && !gresult;
197     both += gresult && hresult;
198     neither += !gresult && !hresult;
199     total = total + 1;
200   }
201
202   if (!raw_dump)
203     cout << (honly+both)  << " passed hybrid, " << (gonly+both) << " passed global, "
204       << both << " pass both, " << neither << " pass neither, " << honly
205       << " passed only hybrid, " << gonly << " passed only global, of " << total
206       << " total." << endl;
207
208   return 0;
209 }
210
211