1 /*
2     Scan Tailor - Interactive post-processing tool for scanned pages.
3     Copyright (C) 2007-2008  Joseph Artsimovich <joseph_a@mail.ru>
4 
5     This program is free software: you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation, either version 3 of the License, or
8     (at your option) any later version.
9 
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14 
15     You should have received a copy of the GNU General Public License
16     along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include <QImage>
20 #include <algorithm>
21 #include <boost/test/auto_unit_test.hpp>
22 #include <list>
23 #include "BWColor.h"
24 #include "BinaryImage.h"
25 #include "ConnComp.h"
26 #include "ConnCompEraserExt.h"
27 #include "RasterOp.h"
28 #include "Utils.h"
29 
30 namespace imageproc {
31 namespace tests {
32 using namespace utils;
33 
34 BOOST_AUTO_TEST_SUITE(ConnCompEraserExtTestSuite);
35 
BOOST_AUTO_TEST_CASE(test_null_image)36 BOOST_AUTO_TEST_CASE(test_null_image) {
37   ConnCompEraser eraser(BinaryImage(), CONN4);
38   BOOST_CHECK(eraser.nextConnComp().isNull());
39 }
40 
checkAlignedImage(const ConnCompEraserExt & eraser,const BinaryImage & nonaligned)41 static bool checkAlignedImage(const ConnCompEraserExt& eraser, const BinaryImage& nonaligned) {
42   const BinaryImage aligned(eraser.computeConnCompImageAligned());
43   const int pad = aligned.width() - nonaligned.width();
44   if (pad < 0) {
45     return false;
46   }
47 
48   BinaryImage test1(nonaligned);
49   BinaryImage empty1(test1.size());
50   empty1.fill(WHITE);
51   rasterOp<RopXor<RopSrc, RopDst>>(test1, test1.rect(), aligned, QPoint(pad, 0));
52   if (test1 != empty1) {
53     return false;
54   }
55 
56   if (pad > 0) {
57     // Check that padding is white.
58     BinaryImage test2(pad, nonaligned.height());
59     BinaryImage empty2(test2.size());
60     empty2.fill(WHITE);
61     rasterOp<RopSrc>(test2, test2.rect(), aligned, QPoint(0, 0));
62     if (test2 != empty2) {
63       return false;
64     }
65   }
66 
67   return true;
68 }
69 
BOOST_AUTO_TEST_CASE(test_small_image)70 BOOST_AUTO_TEST_CASE(test_small_image) {
71   static const int inp[]
72       = {0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0,
73          0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0};
74 
75   std::list<BinaryImage> c4i;
76 
77   static const int out4_1[] = {1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0};
78   c4i.push_back(makeBinaryImage(out4_1, 3, 6));
79 
80   static const int out4_2[] = {1, 1};
81   c4i.push_back(makeBinaryImage(out4_2, 2, 1));
82 
83   static const int out4_3[] = {0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1};
84   c4i.push_back(makeBinaryImage(out4_3, 7, 2));
85 
86   static const int out4_4[] = {
87       1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0,
88   };
89   c4i.push_back(makeBinaryImage(out4_4, 4, 3));
90 
91   static const int out4_5[] = {1};
92   c4i.push_back(makeBinaryImage(out4_5, 1, 1));
93 
94   static const int out4_6[] = {1};
95   c4i.push_back(makeBinaryImage(out4_6, 1, 1));
96 
97   std::list<BinaryImage> c8i;
98 
99   static const int out8_1[] = {
100       0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1,
101       1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0,
102   };
103   c8i.push_back(makeBinaryImage(out8_1, 9, 6));
104 
105   static const int out8_2[] = {
106       0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0,
107   };
108   c8i.push_back(makeBinaryImage(out8_2, 8, 2));
109 
110   BinaryImage img(makeBinaryImage(inp, 9, 8));
111 
112   ConnComp cc;
113   ConnCompEraserExt eraser4(img, CONN4);
114   while (!(cc = eraser4.nextConnComp()).isNull()) {
115     const BinaryImage cc_img(eraser4.computeConnCompImage());
116     const auto it(std::find(c4i.begin(), c4i.end(), cc_img));
117     if (it != c4i.end()) {
118       BOOST_CHECK(checkAlignedImage(eraser4, cc_img));
119       c4i.erase(it);
120     } else {
121       BOOST_ERROR("Incorrect 4-connected block found.");
122     }
123   }
124   BOOST_CHECK_MESSAGE(c4i.empty(), "Not all 4-connected blocks were found.");
125 
126   ConnCompEraserExt eraser8(img, CONN8);
127   while (!(cc = eraser8.nextConnComp()).isNull()) {
128     const BinaryImage cc_img(eraser8.computeConnCompImage());
129     const auto it(std::find(c8i.begin(), c8i.end(), cc_img));
130     if (it != c8i.end()) {
131       BOOST_CHECK(checkAlignedImage(eraser8, cc_img));
132       c8i.erase(it);
133     } else {
134       BOOST_ERROR("Incorrect 8-connected block found.");
135     }
136   }
137   BOOST_CHECK_MESSAGE(c8i.empty(), "Not all 8-connected blocks were found.");
138 }
139 
140 BOOST_AUTO_TEST_SUITE_END();
141 }  // namespace tests
142 }  // namespace imageproc