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