1 /************************************************************************/
2 /*                                                                      */
3 /*                 Copyright 2004 by Ullrich Koethe                     */
4 /*                                                                      */
5 /*    This file is part of the VIGRA computer vision library.           */
6 /*    The VIGRA Website is                                              */
7 /*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
8 /*    Please direct questions, bug reports, and contributions to        */
9 /*        ullrich.koethe@iwr.uni-heidelberg.de    or                    */
10 /*        vigra@informatik.uni-hamburg.de                               */
11 /*                                                                      */
12 /*    Permission is hereby granted, free of charge, to any person       */
13 /*    obtaining a copy of this software and associated documentation    */
14 /*    files (the "Software"), to deal in the Software without           */
15 /*    restriction, including without limitation the rights to use,      */
16 /*    copy, modify, merge, publish, distribute, sublicense, and/or      */
17 /*    sell copies of the Software, and to permit persons to whom the    */
18 /*    Software is furnished to do so, subject to the following          */
19 /*    conditions:                                                       */
20 /*                                                                      */
21 /*    The above copyright notice and this permission notice shall be    */
22 /*    included in all copies or substantial portions of the             */
23 /*    Software.                                                         */
24 /*                                                                      */
25 /*    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND    */
26 /*    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES   */
27 /*    OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND          */
28 /*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
29 /*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
30 /*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
31 /*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
32 /*    OTHER DEALINGS IN THE SOFTWARE.                                   */
33 /*                                                                      */
34 /************************************************************************/
35 
36 #include <iostream>
37 #include "vigra/unittest.hxx"
38 #include "vigra/stdimage.hxx"
39 #include "vigra/multi_morphology.hxx"
40 #include "vigra/linear_algebra.hxx"
41 #include "vigra/matrix.hxx"
42 
43 using namespace vigra;
44 
45 struct MultiMorphologyTest
46 {
47     typedef vigra::MultiArray<3,int> IntVolume;
48     typedef vigra::MultiArray<2,int> IntImage;
49 
MultiMorphologyTestMultiMorphologyTest50     MultiMorphologyTest() :
51         img(IntImage::difference_type(7,7)),
52         img2(IntImage::difference_type(7,7)),
53         lin(IntImage::difference_type(7,1)),
54         vol(IntVolume::difference_type(5,5,5))
55     {
56         static const unsigned char in[] = {
57             0, 1, 1, 1, 1, 1, 0,
58             0, 1, 1, 1, 1, 1, 0,
59             0, 1, 1, 1, 1, 1, 0,
60             0, 1, 1, 1, 1, 1, 0,
61             0, 1, 1, 1, 1, 1, 0,
62             0, 1, 1, 1, 1, 1, 0,
63             0, 1, 1, 1, 1, 1, 0};
64 
65         const unsigned char *i=in;
66         for(IntImage::iterator iter=img.begin(); iter!=img.end(); ++iter, ++i){
67             *iter=*i;
68         }
69         static const unsigned char in1d[] = {0, 1, 1, 1, 1, 1, 0};
70         i=in1d;
71         for(IntImage::iterator iter=lin.begin(); iter!=lin.end(); ++iter, ++i){
72             *iter=*i;
73         }
74 
75         static const unsigned char in1[] = {
76             0, 1, 2, 3, 4, 5, 6,
77             0, 1, 2, 3, 4, 5, 6,
78             0, 1, 2, 3, 4, 5, 6,
79             0, 1, 2, 3, 4, 5, 6,
80             0, 1, 2, 3, 4, 5, 6,
81             0, 1, 2, 3, 4, 5, 6,
82             0, 1, 2, 3, 4, 5, 6};
83 
84         i=in1;
85         for(IntImage::iterator iter=img2.begin(); iter!=img2.end(); ++iter, ++i){
86             *iter=*i;
87         }
88 
89         static const unsigned char in2[] = { 0, 0, 0, 0, 0,
90                                              0, 0, 0, 0, 0,
91                                              0, 0, 0, 0, 0,
92                                              0, 0, 0, 0, 0,
93                                              0, 0, 0, 0, 0,
94 
95                                              0, 0, 0, 0, 0,
96                                              0, 1, 1, 1, 0,
97                                              0, 1, 1, 1, 0,
98                                              0, 1, 1, 1, 0,
99                                              0, 0, 0, 0, 0,
100 
101                                              0, 0, 0, 0, 0,
102                                              0, 1, 1, 1, 0,
103                                              0, 1, 1, 1, 0,
104                                              0, 1, 1, 1, 0,
105                                              0, 0, 0, 0, 0,
106 
107                                              0, 0, 0, 0, 0,
108                                              0, 1, 1, 1, 0,
109                                              0, 1, 1, 1, 0,
110                                              0, 1, 1, 1, 0,
111                                              0, 0, 0, 0, 0,
112 
113                                              0, 0, 0, 0, 0,
114                                              0, 0, 0, 0, 0,
115                                              0, 0, 0, 0, 0,
116                                              0, 0, 0, 0, 0,
117                                              0, 0, 0, 0, 0};
118 
119         i=in2;
120         for(IntVolume::iterator iter=vol.begin(); iter!=vol.end(); ++iter, ++i){
121             *iter=*i;
122         }
123     }
124 
binaryErosionTestMultiMorphologyTest125     void binaryErosionTest()
126     {
127         IntImage res(img);
128         int foreground = NumericTraits<int>::one();
129 
130         static const int desired[] = {
131                    0, 0, 0, foreground, 0, 0, 0,
132                    0, 0, 0, foreground, 0, 0, 0,
133                    0, 0, 0, foreground, 0, 0, 0,
134                    0, 0, 0, foreground, 0, 0, 0,
135                    0, 0, 0, foreground, 0, 0, 0,
136                    0, 0, 0, foreground, 0, 0, 0,
137                    0, 0, 0, foreground, 0, 0, 0};
138 
139         multiBinaryErosion(srcMultiArrayRange(img), destMultiArray(res), 2);
140         shouldEqualSequence(res.begin(), res.end(), desired);
141 
142         res = 0;
143         multiBinaryErosion(img, res, 2);
144         shouldEqualSequence(res.begin(), res.end(), desired);
145     }
146 
binaryErosionTest2MultiMorphologyTest147     void binaryErosionTest2()
148     {
149         IntImage res(img2);
150         int foreground = NumericTraits<int>::one();
151 
152         static const int desired[] = {
153                    0, 0, 0, foreground, foreground, foreground, foreground,
154                    0, 0, 0, foreground, foreground, foreground, foreground,
155                    0, 0, 0, foreground, foreground, foreground, foreground,
156                    0, 0, 0, foreground, foreground, foreground, foreground,
157                    0, 0, 0, foreground, foreground, foreground, foreground,
158                    0, 0, 0, foreground, foreground, foreground, foreground,
159                    0, 0, 0, foreground, foreground, foreground, foreground};
160 
161         multiBinaryErosion(img2, res, 2);
162         shouldEqualSequence(res.begin(), res.end(), desired);
163     }
164 
binaryErosionTest1DMultiMorphologyTest165     void binaryErosionTest1D()
166     {
167         IntImage res(lin);
168         int foreground = NumericTraits<int>::one();
169 
170         static const int desired[] = {0, 0, 0, foreground, 0, 0, 0};
171         multiBinaryErosion(lin, res, 2);
172         shouldEqualSequence(res.begin(), res.end(), desired);
173     }
174 
binaryErosionAndDilationTest3DMultiMorphologyTest175     void binaryErosionAndDilationTest3D()
176     {
177         IntVolume res(vol.shape()), res2(vol.shape());
178         int f = NumericTraits<int>::one();
179 
180         static const int desiredErosion[] = {  0, 0, 0, 0, 0,
181                                                0, 0, 0, 0, 0,
182                                                0, 0, 0, 0, 0,
183                                                0, 0, 0, 0, 0,
184                                                0, 0, 0, 0, 0,
185 
186                                                0, 0, 0, 0, 0,
187                                                0, 0, 0, 0, 0,
188                                                0, 0, 0, 0, 0,
189                                                0, 0, 0, 0, 0,
190                                                0, 0, 0, 0, 0,
191 
192                                                0, 0, 0, 0, 0,
193                                                0, 0, 0, 0, 0,
194                                                0, 0, f, 0, 0,
195                                                0, 0, 0, 0, 0,
196                                                0, 0, 0, 0, 0,
197 
198                                                0, 0, 0, 0, 0,
199                                                0, 0, 0, 0, 0,
200                                                0, 0, 0, 0, 0,
201                                                0, 0, 0, 0, 0,
202                                                0, 0, 0, 0, 0,
203 
204                                                0, 0, 0, 0, 0,
205                                                0, 0, 0, 0, 0,
206                                                0, 0, 0, 0, 0,
207                                                0, 0, 0, 0, 0,
208                                                0, 0, 0, 0, 0};
209 
210         multiBinaryErosion(vol, res, 1);
211         shouldEqualSequence(res.begin(), res.end(), desiredErosion);
212 
213         static const int desiredDilation[] = {  0, 0, 0, 0, 0,
214                                                 0, 0, 0, 0, 0,
215                                                 0, 0, 0, 0, 0,
216                                                 0, 0, 0, 0, 0,
217                                                 0, 0, 0, 0, 0,
218 
219                                                 0, 0, 0, 0, 0,
220                                                 0, 0, 0, 0, 0,
221                                                 0, 0, f, 0, 0,
222                                                 0, 0, 0, 0, 0,
223                                                 0, 0, 0, 0, 0,
224 
225                                                 0, 0, 0, 0, 0,
226                                                 0, 0, f, 0, 0,
227                                                 0, f, f, f, 0,
228                                                 0, 0, f, 0, 0,
229                                                 0, 0, 0, 0, 0,
230 
231                                                 0, 0, 0, 0, 0,
232                                                 0, 0, 0, 0, 0,
233                                                 0, 0, f, 0, 0,
234                                                 0, 0, 0, 0, 0,
235                                                 0, 0, 0, 0, 0,
236 
237                                                 0, 0, 0, 0, 0,
238                                                 0, 0, 0, 0, 0,
239                                                 0, 0, 0, 0, 0,
240                                                 0, 0, 0, 0, 0,
241                                                 0, 0, 0, 0, 0};
242 
243         IntVolume v2(res);
244 
245         multiBinaryDilation(v2, res, 1);
246         shouldEqualSequence(res.begin(), res.end(), desiredDilation);
247 
248         multiBinaryDilation(v2, res2, 1.8);
249         shouldEqualSequence(res2.begin(), res2.end(), vol.begin());
250     }
251 
grayErosionTest2DMultiMorphologyTest252     void grayErosionTest2D()
253     {
254         typedef vigra::MultiArray<2,float> FloatImage;
255         FloatImage in(img), res(img), res_cmp(img);
256 
257         //erosion on original image
258         multiGrayscaleErosion(srcMultiArrayRange(in), destMultiArray(res), 1);
259 
260         //create comparable result = result+2 for every pixel
261         for(FloatImage::iterator iter=res.begin(); iter!=res.end(); ++iter){
262             *iter+=2.9f;
263         }
264 
265         //create compare image = img+2 for every pixel
266         for(FloatImage::iterator iter=in.begin(); iter!=in.end(); ++iter){
267             *iter+=2.9f;
268         }
269         //erosion on compare image (image+2)
270         multiGrayscaleErosion(in, res_cmp, 1);
271 
272         shouldEqualSequence(res.begin(), res.end(), res_cmp.begin());
273     }
274 
grayDilationTest2DMultiMorphologyTest275     void grayDilationTest2D()
276     {
277         typedef vigra::MultiArray<2,float> FloatImage;
278         FloatImage in(img), res(img), res_cmp(img);
279 
280         //dilation on original image
281         multiGrayscaleDilation(srcMultiArrayRange(in), destMultiArray(res), 1);
282 
283         //create comparable result = result+2 for every pixel
284         for(FloatImage::iterator iter=res.begin(); iter!=res.end(); ++iter){
285             *iter+=2.9f;
286         }
287 
288         //create compare image = img+2 for every pixel
289         for(FloatImage::iterator iter=in.begin(); iter!=in.end(); ++iter){
290             *iter+=2.9f;
291         }
292         //dilation on compare image (image+2)
293         multiGrayscaleDilation(in, res_cmp, 1);
294 
295         shouldEqualSequence(res.begin(), res.end(), res_cmp.begin());
296     }
297 
grayErosionAndDilationTest2DMultiMorphologyTest298     void grayErosionAndDilationTest2D()
299     {
300         typedef vigra::MultiArray<2, float> FloatImage;
301         FloatImage in(img), di_res(img), er_res(img);
302 
303         //erosion on original image
304         multiGrayscaleErosion(in, er_res, 1);
305         //dilation on original inverted image
306         for(FloatImage::iterator iter=in.begin(); iter!=in.end(); ++iter){
307             *iter*=-1.0f;
308         }
309         multiGrayscaleDilation(in, di_res, 1);
310         //Invert dilation res
311         for(FloatImage::iterator iter=di_res.begin(); iter!=di_res.end(); ++iter){
312             *iter*=-1.0f;
313         }
314 
315         shouldEqualSequence(di_res.begin(),di_res.end(), er_res.begin());
316     }
317 
grayClosingTest2DMultiMorphologyTest318     void grayClosingTest2D()
319     {
320         typedef vigra::MultiArray<2,UInt8> UInt8Image;
321         UInt8Image in(img), tmp(img), res(img);
322 
323         //erosion on original image
324         multiGrayscaleErosion(srcMultiArrayRange(in), destMultiArray(tmp),2);
325         multiGrayscaleDilation(srcMultiArrayRange(tmp), destMultiArray(res),2);
326     }
327 
328     IntImage img, img2, lin;
329     IntVolume vol;
330 };
331 
332 
333 struct MorphologyTestSuite
334 : public vigra::test_suite
335 {
MorphologyTestSuiteMorphologyTestSuite336     MorphologyTestSuite()
337     : vigra::test_suite("MorphologyTestSuite")
338     {
339         add( testCase( &MultiMorphologyTest::binaryErosionTest));
340         add( testCase( &MultiMorphologyTest::binaryErosionTest2));
341         add( testCase( &MultiMorphologyTest::binaryErosionTest1D));
342         add( testCase( &MultiMorphologyTest::binaryErosionAndDilationTest3D));
343         add( testCase( &MultiMorphologyTest::grayErosionTest2D));
344         add( testCase( &MultiMorphologyTest::grayDilationTest2D));
345         add( testCase( &MultiMorphologyTest::grayErosionAndDilationTest2D));
346         add( testCase( &MultiMorphologyTest::grayClosingTest2D));
347     }
348 };
349 
main(int argc,char ** argv)350 int main(int argc, char ** argv)
351 {
352     MorphologyTestSuite test;
353 
354     int failed = test.run(vigra::testsToBeExecuted(argc, argv));
355 
356     std::cout << test.report() << std::endl;
357     return (failed != 0);
358 }
359 
360