1 /*====================================================================*
2 - Copyright (C) 2001 Leptonica. All rights reserved.
3 -
4 - Redistribution and use in source and binary forms, with or without
5 - modification, are permitted provided that the following conditions
6 - are met:
7 - 1. Redistributions of source code must retain the above copyright
8 - notice, this list of conditions and the following disclaimer.
9 - 2. Redistributions in binary form must reproduce the above
10 - copyright notice, this list of conditions and the following
11 - disclaimer in the documentation and/or other materials
12 - provided with the distribution.
13 -
14 - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15 - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16 - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17 - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY
18 - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23 - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *====================================================================*/
26
27 /*
28 * affine_reg.c
29 *
30 * Tests affine transforms, including invertability and large distortions.
31 */
32
33 #include "allheaders.h"
34
35 static void MakePtas(l_int32 i, PTA **pptas, PTA **pptad);
36 static l_int32 RenderHashedBoxa(PIX *pixt, BOXA *boxa, l_int32 i);
37
38
39 /* Sample values.
40 * 1-3: invertability tests
41 * 4: comparison between sampling and sequential
42 * 5: test with large distortion
43 */
44 static const l_int32 x1[] = { 300, 300, 300, 95, 32};
45 static const l_int32 y1[] = {1200, 1200, 1250, 2821, 934};
46 static const l_int32 x2[] = {1200, 1200, 1125, 1432, 487};
47 static const l_int32 y2[] = {1100, 1100, 1100, 2682, 934};
48 static const l_int32 x3[] = { 200, 200, 200, 232, 32};
49 static const l_int32 y3[] = { 200, 200, 200, 657, 67};
50
51 static const l_int32 xp1[] = { 500, 300, 350, 117, 32};
52 static const l_int32 yp1[] = {1700, 1400, 1400, 2629, 934};
53 static const l_int32 xp2[] = {850, 1400, 1400, 1464, 487};
54 static const l_int32 yp2[] = {850, 1500, 1500, 2432, 804};
55 static const l_int32 xp3[] = { 450, 200, 400, 183, 61};
56 static const l_int32 yp3[] = { 300, 300, 400, 490, 83};
57
58 static const l_int32 SHIFTX = 44;
59 static const l_int32 SHIFTY = 39;
60 static const l_float32 SCALEX = 0.83;
61 static const l_float32 SCALEY = 0.78;
62 static const l_float32 ROTATION = 0.11; /* radian */
63
64 #define ADDED_BORDER_PIXELS 1000
65 #define ALL 1
66
67
main(int argc,char ** argv)68 int main(int argc,
69 char **argv)
70 {
71 char bufname[256];
72 l_int32 i, w, h;
73 l_float32 *mat1, *mat2, *mat3, *mat1i, *mat2i, *mat3i, *matdinv;
74 l_float32 matd[9], matdi[9];
75 BOXA *boxa, *boxa2;
76 PIX *pix, *pixs, *pixb, *pixg, *pixc, *pixcs;
77 PIX *pixd, *pix1, *pix2, *pix3;
78 PIXA *pixa;
79 PTA *ptas, *ptad;
80 L_REGPARAMS *rp;
81
82 if (regTestSetup(argc, argv, &rp))
83 return 1;
84
85 pix = pixRead("feyn.tif");
86 pixs = pixScale(pix, 0.22, 0.22);
87 pixDestroy(&pix);
88
89 #if ALL
90 /* Test invertability of sequential. */
91 fprintf(stderr, "Test invertability of sequential\n");
92 pixa = pixaCreate(0);
93 for (i = 0; i < 3; i++) {
94 pixb = pixAddBorder(pixs, ADDED_BORDER_PIXELS, 0);
95 MakePtas(i, &ptas, &ptad);
96 pix1 = pixAffineSequential(pixb, ptad, ptas, 0, 0);
97 regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 0,3,6 */
98 pixaAddPix(pixa, pix1, L_INSERT);
99 pix2 = pixAffineSequential(pix1, ptas, ptad, 0, 0);
100 regTestWritePixAndCheck(rp, pix2, IFF_PNG); /* 1,4,7 */
101 pixaAddPix(pixa, pix2, L_INSERT);
102 pixd = pixRemoveBorder(pix2, ADDED_BORDER_PIXELS);
103 pixXor(pixd, pixd, pixs);
104 regTestWritePixAndCheck(rp, pixd, IFF_PNG); /* 2,5,8 */
105 pixaAddPix(pixa, pixd, L_INSERT);
106 pixDestroy(&pixb);
107 ptaDestroy(&ptas);
108 ptaDestroy(&ptad);
109 }
110
111 pix1 = pixaDisplayTiledInColumns(pixa, 3, 1.0, 20, 3);
112 pix2 = pixScaleToGray(pix1, 0.2);
113 regTestWritePixAndCheck(rp, pix2, IFF_PNG); /* 9 */
114 pixDisplayWithTitle(pix2, 0, 100, NULL, rp->display);
115 pixDestroy(&pix1);
116 pixDestroy(&pix2);
117 pixaDestroy(&pixa);
118 #endif
119
120 #if ALL
121 /* Test invertability of sampling */
122 fprintf(stderr, "Test invertability of sampling\n");
123 pixa = pixaCreate(0);
124 for (i = 0; i < 3; i++) {
125 pixb = pixAddBorder(pixs, ADDED_BORDER_PIXELS, 0);
126 MakePtas(i, &ptas, &ptad);
127 pix1 = pixAffineSampledPta(pixb, ptad, ptas, L_BRING_IN_WHITE);
128 regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 10,13,16 */
129 pixaAddPix(pixa, pix1, L_INSERT);
130 pix2 = pixAffineSampledPta(pix1, ptas, ptad, L_BRING_IN_WHITE);
131 regTestWritePixAndCheck(rp, pix2, IFF_PNG); /* 11,14,17 */
132 pixaAddPix(pixa, pix2, L_INSERT);
133 pixd = pixRemoveBorder(pix2, ADDED_BORDER_PIXELS);
134 pixXor(pixd, pixd, pixs);
135 regTestWritePixAndCheck(rp, pixd, IFF_PNG); /* 12,15,18 */
136 pixaAddPix(pixa, pixd, L_INSERT);
137 pixDestroy(&pixb);
138 ptaDestroy(&ptas);
139 ptaDestroy(&ptad);
140 }
141
142 pix1 = pixaDisplayTiledInColumns(pixa, 3, 1.0, 20, 3);
143 pix2 = pixScaleToGray(pix1, 0.2);
144 regTestWritePixAndCheck(rp, pix2, IFF_PNG); /* 19 */
145 pixDisplayWithTitle(pix2, 200, 100, NULL, rp->display);
146 pixDestroy(&pix1);
147 pixDestroy(&pix2);
148 pixDestroy(&pixs);
149 pixaDestroy(&pixa);
150 #endif
151
152 #if ALL
153 /* Test invertability of interpolation on grayscale */
154 fprintf(stderr, "Test invertability of grayscale interpolation\n");
155 pix = pixRead("feyn.tif");
156 pixg = pixScaleToGray3(pix);
157 pixDestroy(&pix);
158 pixa = pixaCreate(0);
159 for (i = 0; i < 3; i++) {
160 pixb = pixAddBorder(pixg, ADDED_BORDER_PIXELS / 3, 255);
161 MakePtas(i, &ptas, &ptad);
162 pix1 = pixAffinePta(pixb, ptad, ptas, L_BRING_IN_WHITE);
163 regTestWritePixAndCheck(rp, pix1, IFF_JFIF_JPEG); /* 20,23,26 */
164 pixaAddPix(pixa, pix1, L_INSERT);
165 pix2 = pixAffinePta(pix1, ptas, ptad, L_BRING_IN_WHITE);
166 regTestWritePixAndCheck(rp, pix2, IFF_JFIF_JPEG); /* 21,24,27 */
167 pixaAddPix(pixa, pix2, L_INSERT);
168 pixd = pixRemoveBorder(pix2, ADDED_BORDER_PIXELS / 3);
169 pixXor(pixd, pixd, pixg);
170 pixInvert(pixd, pixd);
171 regTestWritePixAndCheck(rp, pixd, IFF_JFIF_JPEG); /* 22,25,28 */
172 pixaAddPix(pixa, pixd, L_INSERT);
173 pixDestroy(&pixb);
174 ptaDestroy(&ptas);
175 ptaDestroy(&ptad);
176 }
177
178 pix1 = pixaDisplayTiledInColumns(pixa, 3, 1.0, 20, 3);
179 pix2 = pixScale(pix1, 0.2, 0.2);
180 regTestWritePixAndCheck(rp, pix2, IFF_JFIF_JPEG); /* 29 */
181 pixDisplayWithTitle(pix2, 400, 100, NULL, rp->display);
182 pixDestroy(&pix1);
183 pixDestroy(&pix2);
184 pixDestroy(&pixg);
185 pixaDestroy(&pixa);
186 #endif
187
188 #if ALL
189 /* Test invertability of interpolation on color */
190 fprintf(stderr, "Test invertability of color interpolation\n");
191 pixa = pixaCreate(0);
192 pixc = pixRead("test24.jpg");
193 pixcs = pixScale(pixc, 0.3, 0.3);
194 for (i = 0; i < 3; i++) {
195 pixb = pixAddBorder(pixcs, ADDED_BORDER_PIXELS / 4, 0xffffff00);
196 MakePtas(i, &ptas, &ptad);
197 pix1 = pixAffinePta(pixb, ptad, ptas, L_BRING_IN_WHITE);
198 regTestWritePixAndCheck(rp, pix1, IFF_JFIF_JPEG); /* 30,33,36 */
199 pixaAddPix(pixa, pix1, L_INSERT);
200 pix2 = pixAffinePta(pix1, ptas, ptad, L_BRING_IN_WHITE);
201 regTestWritePixAndCheck(rp, pix2, IFF_JFIF_JPEG); /* 31,34,37 */
202 pixaAddPix(pixa, pix2, L_INSERT);
203 pixd = pixRemoveBorder(pix2, ADDED_BORDER_PIXELS / 4);
204 pixXor(pixd, pixd, pixcs);
205 pixInvert(pixd, pixd);
206 regTestWritePixAndCheck(rp, pixd, IFF_JFIF_JPEG); /* 32,35,38 */
207 pixaAddPix(pixa, pixd, L_INSERT);
208 pixDestroy(&pixb);
209 ptaDestroy(&ptas);
210 ptaDestroy(&ptad);
211 }
212
213 pix1 = pixaDisplayTiledInColumns(pixa, 3, 1.0, 20, 3);
214 pix2 = pixScale(pix1, 0.25, 0.25);
215 regTestWritePixAndCheck(rp, pix2, IFF_JFIF_JPEG); /* 39 */
216 pixDisplayWithTitle(pix2, 600, 100, NULL, rp->display);
217 pixDestroy(&pix1);
218 pixDestroy(&pix2);
219 pixDestroy(&pixc);
220 pixaDestroy(&pixa);
221 #endif
222
223 #if ALL
224 /* Comparison between sequential and sampling */
225 fprintf(stderr, "Compare sequential with sampling\n");
226 pix = pixRead("feyn.tif");
227 pixs = pixScale(pix, 0.22, 0.22);
228 pixDestroy(&pix);
229
230 MakePtas(3, &ptas, &ptad);
231 pixa = pixaCreate(0);
232
233 /* Use sequential transforms */
234 pix1 = pixAffineSequential(pixs, ptas, ptad,
235 ADDED_BORDER_PIXELS, ADDED_BORDER_PIXELS);
236 regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 40 */
237 pixaAddPix(pixa, pix1, L_INSERT);
238
239 /* Use sampled transform */
240 pix2 = pixAffineSampledPta(pixs, ptas, ptad, L_BRING_IN_WHITE);
241 regTestWritePixAndCheck(rp, pix2, IFF_PNG); /* 41 */
242 pixaAddPix(pixa, pix2, L_COPY);
243
244 /* Compare the results */
245 pixXor(pix2, pix2, pix1);
246 regTestWritePixAndCheck(rp, pix2, IFF_PNG); /* 42 */
247 pixaAddPix(pixa, pix2, L_INSERT);
248
249 pix1 = pixaDisplayTiledInColumns(pixa, 3, 1.0, 20, 3);
250 pix2 = pixScale(pix1, 0.5, 0.5);
251 regTestWritePixAndCheck(rp, pix2, IFF_PNG); /* 43 */
252 pixDisplayWithTitle(pix2, 800, 100, NULL, rp->display);
253 pixDestroy(&pix1);
254 pixDestroy(&pix2);
255 pixDestroy(&pixs);
256 pixaDestroy(&pixa);
257 ptaDestroy(&ptas);
258 ptaDestroy(&ptad);
259 #endif
260
261
262 #if ALL
263 /* Test with large distortion */
264 fprintf(stderr, "Test with large distortion\n");
265 MakePtas(4, &ptas, &ptad);
266 pixa = pixaCreate(0);
267 pix = pixRead("feyn.tif");
268 pixg = pixScaleToGray6(pix);
269 pixDestroy(&pix);
270
271 pix1 = pixAffineSequential(pixg, ptas, ptad, 0, 0);
272 regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 44 */
273 pixaAddPix(pixa, pix1, L_COPY);
274
275 pix2 = pixAffineSampledPta(pixg, ptas, ptad, L_BRING_IN_WHITE);
276 regTestWritePixAndCheck(rp, pix2, IFF_PNG); /* 45 */
277 pixaAddPix(pixa, pix2, L_COPY);
278
279 pix3 = pixAffinePta(pixg, ptas, ptad, L_BRING_IN_WHITE);
280 regTestWritePixAndCheck(rp, pix3, IFF_PNG); /* 46 */
281 pixaAddPix(pixa, pix3, L_INSERT);
282
283 pixXor(pix1, pix1, pix2);
284 pixInvert(pix1, pix1);
285 regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 47 */
286 pixaAddPix(pixa, pix1, L_INSERT);
287 pixXor(pix2, pix2, pix3);
288 pixInvert(pix2, pix2);
289 regTestWritePixAndCheck(rp, pix2, IFF_PNG); /* 48 */
290 pixaAddPix(pixa, pix2, L_INSERT);
291
292 pix1 = pixaDisplayTiledInColumns(pixa, 5, 1.0, 20, 3);
293 pix2 = pixScale(pix1, 0.8, 0.8);
294 regTestWritePixAndCheck(rp, pix2, IFF_PNG); /* 49 */
295 pixDisplayWithTitle(pix2, 1000, 100, NULL, rp->display);
296 pixDestroy(&pix1);
297 pixDestroy(&pix2);
298 pixDestroy(&pixg);
299 pixaDestroy(&pixa);
300 ptaDestroy(&ptas);
301 ptaDestroy(&ptad);
302 #endif
303
304 #if ALL
305 /* Set up pix and boxa */
306 fprintf(stderr, "Test affine transforms and inverses on pix and boxa\n");
307 pixa = pixaCreate(0);
308 pix = pixRead("lucasta.1.300.tif");
309 pixTranslate(pix, pix, 70, 0, L_BRING_IN_WHITE);
310 pix1 = pixCloseBrick(NULL, pix, 14, 5);
311 pixOpenBrick(pix1, pix1, 1, 2);
312 boxa = pixConnComp(pix1, NULL, 8);
313 pixs = pixConvertTo32(pix);
314 pixGetDimensions(pixs, &w, &h, NULL);
315 pixc = pixCopy(NULL, pixs);
316 RenderHashedBoxa(pixc, boxa, 113);
317 regTestWritePixAndCheck(rp, pixc, IFF_PNG); /* 50 */
318 pixaAddPix(pixa, pixc, L_INSERT);
319 pixDestroy(&pix);
320 pixDestroy(&pix1);
321
322 /* Set up an affine transform in matd, and apply it to boxa */
323 mat1 = createMatrix2dTranslate(SHIFTX, SHIFTY);
324 mat2 = createMatrix2dScale(SCALEX, SCALEY);
325 mat3 = createMatrix2dRotate(w / 2, h / 2, ROTATION);
326 l_productMat3(mat3, mat2, mat1, matd, 3);
327 boxa2 = boxaAffineTransform(boxa, matd);
328
329 /* Set up the inverse transform --> matdi */
330 mat1i = createMatrix2dTranslate(-SHIFTX, -SHIFTY);
331 mat2i = createMatrix2dScale(1.0/ SCALEX, 1.0 / SCALEY);
332 mat3i = createMatrix2dRotate(w / 2, h / 2, -ROTATION);
333 l_productMat3(mat1i, mat2i, mat3i, matdi, 3);
334
335 /* Invert the original affine transform --> matdinv */
336 affineInvertXform(matd, &matdinv);
337 if (rp->display) {
338 fprintf(stderr, " Affine transform, applied to boxa\n");
339 for (i = 0; i < 9; i++) {
340 if (i && (i % 3 == 0)) fprintf(stderr, "\n");
341 fprintf(stderr, " %7.3f ", matd[i]);
342 }
343 fprintf(stderr, "\n Inverse transform, by composing inverse parts");
344 for (i = 0; i < 9; i++) {
345 if (i % 3 == 0) fprintf(stderr, "\n");
346 fprintf(stderr, " %7.3f ", matdi[i]);
347 }
348 fprintf(stderr, "\n Inverse transform, by inverting affine xform");
349 for (i = 0; i < 6; i++) {
350 if (i % 3 == 0) fprintf(stderr, "\n");
351 fprintf(stderr, " %7.3f ", matdinv[i]);
352 }
353 fprintf(stderr, "\n");
354 }
355
356 /* Apply the inverted affine transform --> pixs */
357 pixd = pixAffine(pixs, matdinv, L_BRING_IN_WHITE);
358 RenderHashedBoxa(pixd, boxa2, 513);
359 regTestWritePixAndCheck(rp, pixd, IFF_PNG); /* 51 */
360 pixaAddPix(pixa, pixd, L_INSERT);
361
362 pix1 = pixaDisplayTiledInColumns(pixa, 2, 1.0, 30, 2);
363 regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 52 */
364 pixDisplayWithTitle(pix1, 1200, 100, NULL, rp->display);
365 pixDestroy(&pix1);
366 pixaDestroy(&pixa);
367
368 pixDestroy(&pixs);
369 boxaDestroy(&boxa);
370 boxaDestroy(&boxa2);
371 lept_free(mat1);
372 lept_free(mat2);
373 lept_free(mat3);
374 lept_free(mat1i);
375 lept_free(mat2i);
376 lept_free(mat3i);
377 lept_free(matdinv);
378 #endif
379
380 return regTestCleanup(rp);
381 }
382
383 static void
MakePtas(l_int32 i,PTA ** pptas,PTA ** pptad)384 MakePtas(l_int32 i,
385 PTA **pptas,
386 PTA **pptad)
387 {
388
389 *pptas = ptaCreate(3);
390 ptaAddPt(*pptas, x1[i], y1[i]);
391 ptaAddPt(*pptas, x2[i], y2[i]);
392 ptaAddPt(*pptas, x3[i], y3[i]);
393 *pptad = ptaCreate(3);
394 ptaAddPt(*pptad, xp1[i], yp1[i]);
395 ptaAddPt(*pptad, xp2[i], yp2[i]);
396 ptaAddPt(*pptad, xp3[i], yp3[i]);
397 return;
398 }
399
400
401 static l_int32
RenderHashedBoxa(PIX * pixt,BOXA * boxa,l_int32 i)402 RenderHashedBoxa(PIX *pixt,
403 BOXA *boxa,
404 l_int32 i)
405 {
406 l_int32 j, n, rval, gval, bval;
407 BOX *box;
408
409 n = boxaGetCount(boxa);
410 rval = (1413 * i) % 256;
411 gval = (4917 * i) % 256;
412 bval = (7341 * i) % 256;
413 for (j = 0; j < n; j++) {
414 box = boxaGetBox(boxa, j, L_CLONE);
415 pixRenderHashBoxArb(pixt, box, 10, 3, i % 4, 1, rval, gval, bval);
416 boxDestroy(&box);
417 }
418 return 0;
419 }
420
421
422