Leptonica 1.85.0
Image processing and image analysis suite
Loading...
Searching...
No Matches
affine.c
Go to the documentation of this file.
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
234#ifdef HAVE_CONFIG_H
235#include <config_auto.h>
236#endif /* HAVE_CONFIG_H */
237
238#include <string.h>
239#include <math.h>
240#include "allheaders.h"
241
242extern l_float32 AlphaMaskBorderVals[2];
243
244#ifndef NO_CONSOLE_IO
245#define DEBUG 0
246#endif /* ~NO_CONSOLE_IO */
247
248/*-------------------------------------------------------------*
249 * Sampled affine image transformation *
250 *-------------------------------------------------------------*/
281PIX *
283 PTA *ptad,
284 PTA *ptas,
285 l_int32 incolor)
286{
287l_float32 *vc;
288PIX *pixd;
289
290 if (!pixs)
291 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
292 if (!ptas)
293 return (PIX *)ERROR_PTR("ptas not defined", __func__, NULL);
294 if (!ptad)
295 return (PIX *)ERROR_PTR("ptad not defined", __func__, NULL);
296 if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK)
297 return (PIX *)ERROR_PTR("invalid incolor", __func__, NULL);
298 if (ptaGetCount(ptas) != 3)
299 return (PIX *)ERROR_PTR("ptas count not 3", __func__, NULL);
300 if (ptaGetCount(ptad) != 3)
301 return (PIX *)ERROR_PTR("ptad count not 3", __func__, NULL);
302
303 /* Get backwards transform from dest to src, and apply it */
304 getAffineXformCoeffs(ptad, ptas, &vc);
305 pixd = pixAffineSampled(pixs, vc, incolor);
306 LEPT_FREE(vc);
307
308 return pixd;
309}
310
311
329PIX *
331 l_float32 *vc,
332 l_int32 incolor)
333{
334l_int32 i, j, w, h, d, x, y, wpls, wpld, color, cmapindex;
335l_uint32 val;
336l_uint32 *datas, *datad, *lines, *lined;
337PIX *pixd;
338PIXCMAP *cmap;
339
340 if (!pixs)
341 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
342 if (!vc)
343 return (PIX *)ERROR_PTR("vc not defined", __func__, NULL);
344 if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK)
345 return (PIX *)ERROR_PTR("invalid incolor", __func__, NULL);
346 pixGetDimensions(pixs, &w, &h, &d);
347 if (d != 1 && d != 2 && d != 4 && d != 8 && d != 32)
348 return (PIX *)ERROR_PTR("depth not 1, 2, 4, 8 or 16", __func__, NULL);
349
350 /* Init all dest pixels to color to be brought in from outside */
351 pixd = pixCreateTemplate(pixs);
352 if ((cmap = pixGetColormap(pixs)) != NULL) {
353 if (incolor == L_BRING_IN_WHITE)
354 color = 1;
355 else
356 color = 0;
357 pixcmapAddBlackOrWhite(cmap, color, &cmapindex);
358 pixSetAllArbitrary(pixd, cmapindex);
359 } else {
360 if ((d == 1 && incolor == L_BRING_IN_WHITE) ||
361 (d > 1 && incolor == L_BRING_IN_BLACK)) {
362 pixClearAll(pixd);
363 } else {
364 pixSetAll(pixd);
365 }
366 }
367
368 /* Scan over the dest pixels */
369 datas = pixGetData(pixs);
370 wpls = pixGetWpl(pixs);
371 datad = pixGetData(pixd);
372 wpld = pixGetWpl(pixd);
373 for (i = 0; i < h; i++) {
374 lined = datad + i * wpld;
375 for (j = 0; j < w; j++) {
376 affineXformSampledPt(vc, j, i, &x, &y);
377 if (x < 0 || y < 0 || x >=w || y >= h)
378 continue;
379 lines = datas + y * wpls;
380 if (d == 1) {
381 val = GET_DATA_BIT(lines, x);
382 SET_DATA_BIT_VAL(lined, j, val);
383 } else if (d == 8) {
384 val = GET_DATA_BYTE(lines, x);
385 SET_DATA_BYTE(lined, j, val);
386 } else if (d == 32) {
387 lined[j] = lines[x];
388 } else if (d == 2) {
389 val = GET_DATA_DIBIT(lines, x);
390 SET_DATA_DIBIT(lined, j, val);
391 } else if (d == 4) {
392 val = GET_DATA_QBIT(lines, x);
393 SET_DATA_QBIT(lined, j, val);
394 }
395 }
396 }
397
398 return pixd;
399}
400
401
402/*---------------------------------------------------------------------*
403 * Interpolated affine image transformation *
404 *---------------------------------------------------------------------*/
420PIX *
422 PTA *ptad,
423 PTA *ptas,
424 l_int32 incolor)
425{
426l_int32 d;
427l_uint32 colorval;
428PIX *pixt1, *pixt2, *pixd;
429
430 if (!pixs)
431 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
432 if (!ptas)
433 return (PIX *)ERROR_PTR("ptas not defined", __func__, NULL);
434 if (!ptad)
435 return (PIX *)ERROR_PTR("ptad not defined", __func__, NULL);
436 if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK)
437 return (PIX *)ERROR_PTR("invalid incolor", __func__, NULL);
438 if (ptaGetCount(ptas) != 3)
439 return (PIX *)ERROR_PTR("ptas count not 3", __func__, NULL);
440 if (ptaGetCount(ptad) != 3)
441 return (PIX *)ERROR_PTR("ptad count not 3", __func__, NULL);
442
443 if (pixGetDepth(pixs) == 1)
444 return pixAffineSampledPta(pixs, ptad, ptas, incolor);
445
446 /* Remove cmap if it exists, and unpack to 8 bpp if necessary */
447 pixt1 = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC);
448 d = pixGetDepth(pixt1);
449 if (d < 8)
450 pixt2 = pixConvertTo8(pixt1, FALSE);
451 else
452 pixt2 = pixClone(pixt1);
453 d = pixGetDepth(pixt2);
454
455 /* Compute actual color to bring in from edges */
456 colorval = 0;
457 if (incolor == L_BRING_IN_WHITE) {
458 if (d == 8)
459 colorval = 255;
460 else /* d == 32 */
461 colorval = 0xffffff00;
462 }
463
464 if (d == 8)
465 pixd = pixAffinePtaGray(pixt2, ptad, ptas, colorval);
466 else /* d == 32 */
467 pixd = pixAffinePtaColor(pixt2, ptad, ptas, colorval);
468 pixDestroy(&pixt1);
469 pixDestroy(&pixt2);
470 return pixd;
471}
472
473
488PIX *
490 l_float32 *vc,
491 l_int32 incolor)
492{
493l_int32 d;
494l_uint32 colorval;
495PIX *pixt1, *pixt2, *pixd;
496
497 if (!pixs)
498 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
499 if (!vc)
500 return (PIX *)ERROR_PTR("vc not defined", __func__, NULL);
501
502 if (pixGetDepth(pixs) == 1)
503 return pixAffineSampled(pixs, vc, incolor);
504
505 /* Remove cmap if it exists, and unpack to 8 bpp if necessary */
506 pixt1 = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC);
507 d = pixGetDepth(pixt1);
508 if (d < 8)
509 pixt2 = pixConvertTo8(pixt1, FALSE);
510 else
511 pixt2 = pixClone(pixt1);
512 d = pixGetDepth(pixt2);
513
514 /* Compute actual color to bring in from edges */
515 colorval = 0;
516 if (incolor == L_BRING_IN_WHITE) {
517 if (d == 8)
518 colorval = 255;
519 else /* d == 32 */
520 colorval = 0xffffff00;
521 }
522
523 if (d == 8)
524 pixd = pixAffineGray(pixt2, vc, colorval);
525 else /* d == 32 */
526 pixd = pixAffineColor(pixt2, vc, colorval);
527 pixDestroy(&pixt1);
528 pixDestroy(&pixt2);
529 return pixd;
530}
531
532
542PIX *
544 PTA *ptad,
545 PTA *ptas,
546 l_uint32 colorval)
547{
548l_float32 *vc;
549PIX *pixd;
550
551 if (!pixs)
552 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
553 if (!ptas)
554 return (PIX *)ERROR_PTR("ptas not defined", __func__, NULL);
555 if (!ptad)
556 return (PIX *)ERROR_PTR("ptad not defined", __func__, NULL);
557 if (pixGetDepth(pixs) != 32)
558 return (PIX *)ERROR_PTR("pixs must be 32 bpp", __func__, NULL);
559 if (ptaGetCount(ptas) != 3)
560 return (PIX *)ERROR_PTR("ptas count not 3", __func__, NULL);
561 if (ptaGetCount(ptad) != 3)
562 return (PIX *)ERROR_PTR("ptad count not 3", __func__, NULL);
563
564 /* Get backwards transform from dest to src, and apply it */
565 getAffineXformCoeffs(ptad, ptas, &vc);
566 pixd = pixAffineColor(pixs, vc, colorval);
567 LEPT_FREE(vc);
568
569 return pixd;
570}
571
572
581PIX *
583 l_float32 *vc,
584 l_uint32 colorval)
585{
586l_int32 i, j, w, h, d, wpls, wpld;
587l_uint32 val;
588l_uint32 *datas, *datad, *lined;
589l_float32 x, y;
590PIX *pix1, *pix2, *pixd;
591
592 if (!pixs)
593 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
594 pixGetDimensions(pixs, &w, &h, &d);
595 if (d != 32)
596 return (PIX *)ERROR_PTR("pixs must be 32 bpp", __func__, NULL);
597 if (!vc)
598 return (PIX *)ERROR_PTR("vc not defined", __func__, NULL);
599
600 datas = pixGetData(pixs);
601 wpls = pixGetWpl(pixs);
602 pixd = pixCreateTemplate(pixs);
603 pixSetAllArbitrary(pixd, colorval);
604 datad = pixGetData(pixd);
605 wpld = pixGetWpl(pixd);
606
607 /* Iterate over destination pixels */
608 for (i = 0; i < h; i++) {
609 lined = datad + i * wpld;
610 for (j = 0; j < w; j++) {
611 /* Compute float src pixel location corresponding to (i,j) */
612 affineXformPt(vc, j, i, &x, &y);
613 linearInterpolatePixelColor(datas, wpls, w, h, x, y, colorval,
614 &val);
615 *(lined + j) = val;
616 }
617 }
618
619 /* If rgba, transform the pixs alpha channel and insert in pixd */
620 if (pixGetSpp(pixs) == 4) {
621 pix1 = pixGetRGBComponent(pixs, L_ALPHA_CHANNEL);
622 pix2 = pixAffineGray(pix1, vc, 255); /* bring in opaque */
623 pixSetRGBComponent(pixd, pix2, L_ALPHA_CHANNEL);
624 pixDestroy(&pix1);
625 pixDestroy(&pix2);
626 }
627
628 return pixd;
629}
630
631
641PIX *
643 PTA *ptad,
644 PTA *ptas,
645 l_uint8 grayval)
646{
647l_float32 *vc;
648PIX *pixd;
649
650 if (!pixs)
651 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
652 if (!ptas)
653 return (PIX *)ERROR_PTR("ptas not defined", __func__, NULL);
654 if (!ptad)
655 return (PIX *)ERROR_PTR("ptad not defined", __func__, NULL);
656 if (pixGetDepth(pixs) != 8)
657 return (PIX *)ERROR_PTR("pixs must be 8 bpp", __func__, NULL);
658 if (ptaGetCount(ptas) != 3)
659 return (PIX *)ERROR_PTR("ptas count not 3", __func__, NULL);
660 if (ptaGetCount(ptad) != 3)
661 return (PIX *)ERROR_PTR("ptad count not 3", __func__, NULL);
662
663 /* Get backwards transform from dest to src, and apply it */
664 getAffineXformCoeffs(ptad, ptas, &vc);
665 pixd = pixAffineGray(pixs, vc, grayval);
666 LEPT_FREE(vc);
667
668 return pixd;
669}
670
671
672
681PIX *
683 l_float32 *vc,
684 l_uint8 grayval)
685{
686l_int32 i, j, w, h, wpls, wpld, val;
687l_uint32 *datas, *datad, *lined;
688l_float32 x, y;
689PIX *pixd;
690
691 if (!pixs)
692 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
693 pixGetDimensions(pixs, &w, &h, NULL);
694 if (pixGetDepth(pixs) != 8)
695 return (PIX *)ERROR_PTR("pixs must be 8 bpp", __func__, NULL);
696 if (!vc)
697 return (PIX *)ERROR_PTR("vc not defined", __func__, NULL);
698
699 datas = pixGetData(pixs);
700 wpls = pixGetWpl(pixs);
701 pixd = pixCreateTemplate(pixs);
702 pixSetAllArbitrary(pixd, grayval);
703 datad = pixGetData(pixd);
704 wpld = pixGetWpl(pixd);
705
706 /* Iterate over destination pixels */
707 for (i = 0; i < h; i++) {
708 lined = datad + i * wpld;
709 for (j = 0; j < w; j++) {
710 /* Compute float src pixel location corresponding to (i,j) */
711 affineXformPt(vc, j, i, &x, &y);
712 linearInterpolatePixelGray(datas, wpls, w, h, x, y, grayval, &val);
713 SET_DATA_BYTE(lined, j, val);
714 }
715 }
716
717 return pixd;
718}
719
720
721/*---------------------------------------------------------------------------*
722 * Affine transform including alpha (blend) component *
723 *---------------------------------------------------------------------------*/
767PIX *
769 PTA *ptad,
770 PTA *ptas,
771 PIX *pixg,
772 l_float32 fract,
773 l_int32 border)
774{
775l_int32 ws, hs, d;
776PIX *pixd, *pixb1, *pixb2, *pixg2, *pixga;
777PTA *ptad2, *ptas2;
778
779 if (!pixs)
780 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
781 pixGetDimensions(pixs, &ws, &hs, &d);
782 if (d != 32 && pixGetColormap(pixs) == NULL)
783 return (PIX *)ERROR_PTR("pixs not cmapped or 32 bpp", __func__, NULL);
784 if (pixg && pixGetDepth(pixg) != 8) {
785 L_WARNING("pixg not 8 bpp; using 'fract' transparent alpha\n",
786 __func__);
787 pixg = NULL;
788 }
789 if (!pixg && (fract < 0.0 || fract > 1.0)) {
790 L_WARNING("invalid fract; using 1.0 (fully transparent)\n", __func__);
791 fract = 1.0;
792 }
793 if (!pixg && fract == 0.0)
794 L_WARNING("fully opaque alpha; image will not be blended\n", __func__);
795 if (!ptad)
796 return (PIX *)ERROR_PTR("ptad not defined", __func__, NULL);
797 if (!ptas)
798 return (PIX *)ERROR_PTR("ptas not defined", __func__, NULL);
799
800 /* Add border; the color doesn't matter */
801 pixb1 = pixAddBorder(pixs, border, 0);
802
803 /* Transform the ptr arrays to work on the bordered image */
804 ptad2 = ptaTransform(ptad, border, border, 1.0, 1.0);
805 ptas2 = ptaTransform(ptas, border, border, 1.0, 1.0);
806
807 /* Do separate affine transform of rgb channels of pixs and of pixg */
808 pixd = pixAffinePtaColor(pixb1, ptad2, ptas2, 0);
809 if (!pixg) {
810 pixg2 = pixCreate(ws, hs, 8);
811 if (fract == 1.0)
812 pixSetAll(pixg2);
813 else
814 pixSetAllArbitrary(pixg2, (l_int32)(255.0 * fract));
815 } else {
816 pixg2 = pixResizeToMatch(pixg, NULL, ws, hs);
817 }
818 if (ws > 10 && hs > 10) { /* see note 7 */
819 pixSetBorderRingVal(pixg2, 1,
820 (l_int32)(255.0 * fract * AlphaMaskBorderVals[0]));
821 pixSetBorderRingVal(pixg2, 2,
822 (l_int32)(255.0 * fract * AlphaMaskBorderVals[1]));
823
824 }
825 pixb2 = pixAddBorder(pixg2, border, 0); /* must be black border */
826 pixga = pixAffinePtaGray(pixb2, ptad2, ptas2, 0);
827 pixSetRGBComponent(pixd, pixga, L_ALPHA_CHANNEL);
828 pixSetSpp(pixd, 4);
829
830 pixDestroy(&pixg2);
831 pixDestroy(&pixb1);
832 pixDestroy(&pixb2);
833 pixDestroy(&pixga);
834 ptaDestroy(&ptad2);
835 ptaDestroy(&ptas2);
836 return pixd;
837}
838
839
840/*-------------------------------------------------------------*
841 * Affine coordinate transformation *
842 *-------------------------------------------------------------*/
914l_ok
916 PTA *ptad,
917 l_float32 **pvc)
918{
919l_int32 i;
920l_float32 x1, y1, x2, y2, x3, y3;
921l_float32 *b; /* rhs vector of primed coords X'; coeffs returned in *pvc */
922l_float32 *a[6]; /* 6x6 matrix A */
923
924 if (!ptas)
925 return ERROR_INT("ptas not defined", __func__, 1);
926 if (!ptad)
927 return ERROR_INT("ptad not defined", __func__, 1);
928 if (!pvc)
929 return ERROR_INT("&vc not defined", __func__, 1);
930
931 b = (l_float32 *)LEPT_CALLOC(6, sizeof(l_float32));
932 *pvc = b;
933
934 ptaGetPt(ptas, 0, &x1, &y1);
935 ptaGetPt(ptas, 1, &x2, &y2);
936 ptaGetPt(ptas, 2, &x3, &y3);
937 ptaGetPt(ptad, 0, &b[0], &b[1]);
938 ptaGetPt(ptad, 1, &b[2], &b[3]);
939 ptaGetPt(ptad, 2, &b[4], &b[5]);
940
941 for (i = 0; i < 6; i++)
942 a[i] = (l_float32 *)LEPT_CALLOC(6, sizeof(l_float32));
943 a[0][0] = x1;
944 a[0][1] = y1;
945 a[0][2] = 1.;
946 a[1][3] = x1;
947 a[1][4] = y1;
948 a[1][5] = 1.;
949 a[2][0] = x2;
950 a[2][1] = y2;
951 a[2][2] = 1.;
952 a[3][3] = x2;
953 a[3][4] = y2;
954 a[3][5] = 1.;
955 a[4][0] = x3;
956 a[4][1] = y3;
957 a[4][2] = 1.;
958 a[5][3] = x3;
959 a[5][4] = y3;
960 a[5][5] = 1.;
961
962 gaussjordan(a, b, 6);
963
964 for (i = 0; i < 6; i++)
965 LEPT_FREE(a[i]);
966
967 return 0;
968}
969
970
1002l_ok
1003affineInvertXform(l_float32 *vc,
1004 l_float32 **pvci)
1005{
1006l_int32 i;
1007l_float32 *vci;
1008l_float32 *a[3];
1009l_float32 b[3] = {1.0, 1.0, 1.0}; /* anything; results ignored */
1010
1011 if (!pvci)
1012 return ERROR_INT("&vci not defined", __func__, 1);
1013 *pvci = NULL;
1014 if (!vc)
1015 return ERROR_INT("vc not defined", __func__, 1);
1016
1017#if 1
1018 for (i = 0; i < 3; i++)
1019 a[i] = (l_float32 *)LEPT_CALLOC(3, sizeof(l_float32));
1020 a[0][0] = vc[0];
1021 a[0][1] = vc[1];
1022 a[0][2] = vc[2];
1023 a[1][0] = vc[3];
1024 a[1][1] = vc[4];
1025 a[1][2] = vc[5];
1026 a[2][2] = 1.0;
1027 gaussjordan(a, b, 3); /* this inverts matrix a */
1028 vci = (l_float32 *)LEPT_CALLOC(6, sizeof(l_float32));
1029 *pvci = vci;
1030 vci[0] = a[0][0];
1031 vci[1] = a[0][1];
1032 vci[2] = a[0][2];
1033 vci[3] = a[1][0];
1034 vci[4] = a[1][1];
1035 vci[5] = a[1][2];
1036 for (i = 0; i < 3; i++)
1037 LEPT_FREE(a[i]);
1038
1039#else
1040
1041 /* Alternative version, inverting a 2x2 matrix */
1042 { l_float32 *a2[2];
1043 for (i = 0; i < 2; i++)
1044 a2[i] = (l_float32 *)LEPT_CALLOC(2, sizeof(l_float32));
1045 a2[0][0] = vc[0];
1046 a2[0][1] = vc[1];
1047 a2[1][0] = vc[3];
1048 a2[1][1] = vc[4];
1049 b[0] = vc[2];
1050 b[1] = vc[5];
1051 gaussjordan(a2, b, 2); /* this inverts matrix a2 */
1052 vci = (l_float32 *)LEPT_CALLOC(6, sizeof(l_float32));
1053 *pvci = vci;
1054 vci[0] = a2[0][0];
1055 vci[1] = a2[0][1];
1056 vci[2] = -b[0]; /* note sign */
1057 vci[3] = a2[1][0];
1058 vci[4] = a2[1][1];
1059 vci[5] = -b[1]; /* note sign */
1060 for (i = 0; i < 2; i++)
1061 LEPT_FREE(a2[i]);
1062 }
1063#endif
1064
1065 return 0;
1066}
1067
1068
1083l_ok
1085 l_int32 x,
1086 l_int32 y,
1087 l_int32 *pxp,
1088 l_int32 *pyp)
1089{
1090 if (!vc)
1091 return ERROR_INT("vc not defined", __func__, 1);
1092
1093 *pxp = (l_int32)(vc[0] * x + vc[1] * y + vc[2] + 0.5);
1094 *pyp = (l_int32)(vc[3] * x + vc[4] * y + vc[5] + 0.5);
1095 return 0;
1096}
1097
1098
1113l_ok
1114affineXformPt(l_float32 *vc,
1115 l_int32 x,
1116 l_int32 y,
1117 l_float32 *pxp,
1118 l_float32 *pyp)
1119{
1120 if (!vc)
1121 return ERROR_INT("vc not defined", __func__, 1);
1122
1123 *pxp = vc[0] * x + vc[1] * y + vc[2];
1124 *pyp = vc[3] * x + vc[4] * y + vc[5];
1125 return 0;
1126}
1127
1128
1129/*-------------------------------------------------------------*
1130 * Interpolation helper functions *
1131 *-------------------------------------------------------------*/
1152l_ok
1154 l_int32 wpls,
1155 l_int32 w,
1156 l_int32 h,
1157 l_float32 x,
1158 l_float32 y,
1159 l_uint32 colorval,
1160 l_uint32 *pval)
1161{
1162l_int32 valid, xpm, ypm, xp, xp2, yp, xf, yf;
1163l_int32 rval, gval, bval;
1164l_uint32 word00, word01, word10, word11;
1165l_uint32 *lines;
1166
1167 if (!pval)
1168 return ERROR_INT("&val not defined", __func__, 1);
1169 *pval = colorval;
1170 if (!datas)
1171 return ERROR_INT("datas not defined", __func__, 1);
1172
1173 /* Skip if x or y are invalid. (x,y) must be in the source image.
1174 * Failure to detect an invalid point will cause a mem address fault.
1175 * Occasionally, x or y will be a nan, and relational checks always
1176 * fail for nans. Therefore we check if the point is inside the pix */
1177 valid = (x >= 0.0 && y >= 0.0 && x < w && y < h);
1178 if (!valid) return 0;
1179
1180 xpm = (l_int32)(16.0 * x);
1181 ypm = (l_int32)(16.0 * y);
1182 xp = xpm >> 4;
1183 xp2 = xp + 1 < w ? xp + 1 : xp;
1184 yp = ypm >> 4;
1185 if (yp + 1 >= h) wpls = 0;
1186 xf = xpm & 0x0f;
1187 yf = ypm & 0x0f;
1188
1189#if DEBUG
1190 if (xf < 0 || yf < 0)
1191 lept_stderr("xp = %d, yp = %d, xf = %d, yf = %d\n", xp, yp, xf, yf);
1192#endif /* DEBUG */
1193
1194 /* Do area weighting (eqiv. to linear interpolation) */
1195 lines = datas + yp * wpls;
1196 word00 = *(lines + xp);
1197 word10 = *(lines + xp2);
1198 word01 = *(lines + wpls + xp);
1199 word11 = *(lines + wpls + xp2);
1200 rval = ((16 - xf) * (16 - yf) * ((word00 >> L_RED_SHIFT) & 0xff) +
1201 xf * (16 - yf) * ((word10 >> L_RED_SHIFT) & 0xff) +
1202 (16 - xf) * yf * ((word01 >> L_RED_SHIFT) & 0xff) +
1203 xf * yf * ((word11 >> L_RED_SHIFT) & 0xff)) / 256;
1204 gval = ((16 - xf) * (16 - yf) * ((word00 >> L_GREEN_SHIFT) & 0xff) +
1205 xf * (16 - yf) * ((word10 >> L_GREEN_SHIFT) & 0xff) +
1206 (16 - xf) * yf * ((word01 >> L_GREEN_SHIFT) & 0xff) +
1207 xf * yf * ((word11 >> L_GREEN_SHIFT) & 0xff)) / 256;
1208 bval = ((16 - xf) * (16 - yf) * ((word00 >> L_BLUE_SHIFT) & 0xff) +
1209 xf * (16 - yf) * ((word10 >> L_BLUE_SHIFT) & 0xff) +
1210 (16 - xf) * yf * ((word01 >> L_BLUE_SHIFT) & 0xff) +
1211 xf * yf * ((word11 >> L_BLUE_SHIFT) & 0xff)) / 256;
1212 composeRGBPixel(rval, gval, bval, pval);
1213 return 0;
1214}
1215
1216
1236l_ok
1238 l_int32 wpls,
1239 l_int32 w,
1240 l_int32 h,
1241 l_float32 x,
1242 l_float32 y,
1243 l_int32 grayval,
1244 l_int32 *pval)
1245{
1246l_int32 valid, xpm, ypm, xp, xp2, yp, xf, yf, v00, v10, v01, v11;
1247l_uint32 *lines;
1248
1249 if (!pval)
1250 return ERROR_INT("&val not defined", __func__, 1);
1251 *pval = grayval;
1252 if (!datas)
1253 return ERROR_INT("datas not defined", __func__, 1);
1254
1255 /* Skip if x or y is invalid. (x,y) must be in the source image.
1256 * Failure to detect an invalid point will cause a mem address fault.
1257 * Occasionally, x or y will be a nan, and relational checks always
1258 * fail for nans. Therefore we check if the point is inside the pix */
1259 valid = (x >= 0.0 && y >= 0.0 && x < w && y < h);
1260 if (!valid) return 0;
1261
1262 xpm = (l_int32)(16.0 * x);
1263 ypm = (l_int32)(16.0 * y);
1264 xp = xpm >> 4;
1265 xp2 = xp + 1 < w ? xp + 1 : xp;
1266 yp = ypm >> 4;
1267 if (yp + 1 >= h) wpls = 0;
1268 xf = xpm & 0x0f;
1269 yf = ypm & 0x0f;
1270
1271#if DEBUG
1272 if (xf < 0 || yf < 0)
1273 lept_stderr("xp = %d, yp = %d, xf = %d, yf = %d\n", xp, yp, xf, yf);
1274#endif /* DEBUG */
1275
1276 /* Interpolate by area weighting. */
1277 lines = datas + yp * wpls;
1278 v00 = (16 - xf) * (16 - yf) * GET_DATA_BYTE(lines, xp);
1279 v10 = xf * (16 - yf) * GET_DATA_BYTE(lines, xp2);
1280 v01 = (16 - xf) * yf * GET_DATA_BYTE(lines + wpls, xp);
1281 v11 = xf * yf * GET_DATA_BYTE(lines + wpls, xp2);
1282 *pval = (v00 + v01 + v10 + v11) / 256;
1283 return 0;
1284}
1285
1286
1287
1288/*-------------------------------------------------------------*
1289 * Gauss-jordan linear equation solver *
1290 *-------------------------------------------------------------*/
1291#define SWAP(a,b) {temp = (a); (a) = (b); (b) = temp;}
1292
1313l_int32
1314gaussjordan(l_float32 **a,
1315 l_float32 *b,
1316 l_int32 n)
1317{
1318l_int32 i, icol, irow, j, k, col, row, success;
1319l_int32 *indexc, *indexr, *ipiv;
1320l_float32 maxval, val, pivinv, temp;
1321
1322 if (!a)
1323 return ERROR_INT("a not defined", __func__, 1);
1324 if (!b)
1325 return ERROR_INT("b not defined", __func__, 1);
1326
1327 success = TRUE;
1328 indexc = (l_int32 *)LEPT_CALLOC(n, sizeof(l_int32));
1329 indexr = (l_int32 *)LEPT_CALLOC(n, sizeof(l_int32));
1330 ipiv = (l_int32 *)LEPT_CALLOC(n, sizeof(l_int32));
1331 if (!indexc || !indexr || !ipiv) {
1332 L_ERROR("array not made\n", __func__);
1333 success = FALSE;
1334 goto cleanup_arrays;
1335 }
1336
1337 icol = irow = 0; /* silence static checker */
1338 for (i = 0; i < n; i++) {
1339 maxval = 0.0;
1340 for (j = 0; j < n; j++) {
1341 if (ipiv[j] != 1) {
1342 for (k = 0; k < n; k++) {
1343 if (ipiv[k] == 0) {
1344 if (fabs(a[j][k]) >= maxval) {
1345 maxval = fabs(a[j][k]);
1346 irow = j;
1347 icol = k;
1348 }
1349 } else if (ipiv[k] > 1) {
1350 L_ERROR("singular matrix\n", __func__);
1351 success = FALSE;
1352 goto cleanup_arrays;
1353 }
1354 }
1355 }
1356 }
1357 ++(ipiv[icol]);
1358
1359 if (irow != icol) {
1360 for (col = 0; col < n; col++)
1361 SWAP(a[irow][col], a[icol][col]);
1362 SWAP(b[irow], b[icol]);
1363 }
1364
1365 indexr[i] = irow;
1366 indexc[i] = icol;
1367 if (a[icol][icol] == 0.0) {
1368 L_ERROR("singular matrix\n", __func__);
1369 success = FALSE;
1370 goto cleanup_arrays;
1371 }
1372 pivinv = 1.0 / a[icol][icol];
1373 a[icol][icol] = 1.0;
1374 for (col = 0; col < n; col++)
1375 a[icol][col] *= pivinv;
1376 b[icol] *= pivinv;
1377
1378 for (row = 0; row < n; row++) {
1379 if (row != icol) {
1380 val = a[row][icol];
1381 a[row][icol] = 0.0;
1382 for (col = 0; col < n; col++)
1383 a[row][col] -= a[icol][col] * val;
1384 b[row] -= b[icol] * val;
1385 }
1386 }
1387 }
1388
1389 for (col = n - 1; col >= 0; col--) {
1390 if (indexr[col] != indexc[col]) {
1391 for (k = 0; k < n; k++)
1392 SWAP(a[k][indexr[col]], a[k][indexc[col]]);
1393 }
1394 }
1395
1396cleanup_arrays:
1397 LEPT_FREE(indexr);
1398 LEPT_FREE(indexc);
1399 LEPT_FREE(ipiv);
1400 return (success) ? 0 : 1;
1401}
1402
1403
1404/*-------------------------------------------------------------*
1405 * Sequential affine image transformation *
1406 *-------------------------------------------------------------*/
1435PIX *
1437 PTA *ptad,
1438 PTA *ptas,
1439 l_int32 bw,
1440 l_int32 bh)
1441{
1442l_int32 x1, y1, x2, y2, x3, y3; /* ptas */
1443l_int32 x1p, y1p, x2p, y2p, x3p, y3p; /* ptad */
1444l_int32 x1sc, y1sc; /* scaled origin */
1445l_float32 x2s, x2sp, scalex, scaley;
1446l_float32 th3, th3p, ph2, ph2p;
1447#if DEBUG
1448l_float32 rad2deg;
1449#endif /* DEBUG */
1450PIX *pix1, *pix2, *pixd;
1451
1452 if (!pixs)
1453 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
1454 if (!ptas)
1455 return (PIX *)ERROR_PTR("ptas not defined", __func__, NULL);
1456 if (!ptad)
1457 return (PIX *)ERROR_PTR("ptad not defined", __func__, NULL);
1458
1459 if (ptaGetCount(ptas) != 3)
1460 return (PIX *)ERROR_PTR("ptas count not 3", __func__, NULL);
1461 if (ptaGetCount(ptad) != 3)
1462 return (PIX *)ERROR_PTR("ptad count not 3", __func__, NULL);
1463 ptaGetIPt(ptas, 0, &x1, &y1);
1464 ptaGetIPt(ptas, 1, &x2, &y2);
1465 ptaGetIPt(ptas, 2, &x3, &y3);
1466 ptaGetIPt(ptad, 0, &x1p, &y1p);
1467 ptaGetIPt(ptad, 1, &x2p, &y2p);
1468 ptaGetIPt(ptad, 2, &x3p, &y3p);
1469
1470 pix1 = pix2 = pixd = NULL;
1471
1472 if (y1 == y3)
1473 return (PIX *)ERROR_PTR("y1 == y3!", __func__, NULL);
1474 if (y1p == y3p)
1475 return (PIX *)ERROR_PTR("y1p == y3p!", __func__, NULL);
1476
1477 if (bw != 0 || bh != 0) {
1478 /* resize all points and add border to pixs */
1479 x1 = x1 + bw;
1480 y1 = y1 + bh;
1481 x2 = x2 + bw;
1482 y2 = y2 + bh;
1483 x3 = x3 + bw;
1484 y3 = y3 + bh;
1485 x1p = x1p + bw;
1486 y1p = y1p + bh;
1487 x2p = x2p + bw;
1488 y2p = y2p + bh;
1489 x3p = x3p + bw;
1490 y3p = y3p + bh;
1491
1492 if ((pix1 = pixAddBorderGeneral(pixs, bw, bw, bh, bh, 0)) == NULL)
1493 return (PIX *)ERROR_PTR("pix1 not made", __func__, NULL);
1494 } else {
1495 pix1 = pixCopy(NULL, pixs);
1496 }
1497
1498 /*-------------------------------------------------------------*
1499 The horizontal shear is done to move the 3rd point to the
1500 y axis. This moves the 2nd point either towards or away
1501 from the y axis, depending on whether it is above or below
1502 the x axis. That motion must be computed so that we know
1503 the angle of vertical shear to use to get the 2nd point
1504 on the x axis. We must also know the x coordinate of the
1505 2nd point in order to compute how much scaling is required
1506 to match points on the axis.
1507 *-------------------------------------------------------------*/
1508
1509 /* Shear angles required to put src points on x and y axes */
1510 th3 = atan2((l_float64)(x1 - x3), (l_float64)(y1 - y3));
1511 x2s = (l_float32)(x2 - ((l_float32)(y1 - y2) * (x3 - x1)) / (y1 - y3));
1512 if (x2s == (l_float32)x1) {
1513 L_ERROR("x2s == x1!\n", __func__);
1514 goto cleanup_pix;
1515 }
1516 ph2 = atan2((l_float64)(y1 - y2), (l_float64)(x2s - x1));
1517
1518 /* Shear angles required to put dest points on x and y axes.
1519 * Use the negative of these values to instead move the
1520 * src points from the axes to the actual dest position.
1521 * These values are also needed to scale the image. */
1522 th3p = atan2((l_float64)(x1p - x3p), (l_float64)(y1p - y3p));
1523 x2sp = (l_float32)(x2p -
1524 ((l_float32)(y1p - y2p) * (x3p - x1p)) / (y1p - y3p));
1525 if (x2sp == (l_float32)x1p) {
1526 L_ERROR("x2sp == x1p!\n", __func__);
1527 goto cleanup_pix;
1528 }
1529 ph2p = atan2((l_float64)(y1p - y2p), (l_float64)(x2sp - x1p));
1530
1531 /* Shear image to first put src point 3 on the y axis,
1532 * and then to put src point 2 on the x axis */
1533 pixHShearIP(pix1, y1, th3, L_BRING_IN_WHITE);
1534 pixVShearIP(pix1, x1, ph2, L_BRING_IN_WHITE);
1535
1536 /* Scale image to match dest scale. The dest scale
1537 * is calculated above from the angles th3p and ph2p
1538 * that would be required to move the dest points to
1539 * the x and y axes. */
1540 scalex = (l_float32)(x2sp - x1p) / (x2s - x1);
1541 scaley = (l_float32)(y3p - y1p) / (y3 - y1);
1542 if ((pix2 = pixScale(pix1, scalex, scaley)) == NULL) {
1543 L_ERROR("pix2 not made\n", __func__);
1544 goto cleanup_pix;
1545 }
1546
1547#if DEBUG
1548 rad2deg = 180. / 3.1415926535;
1549 lept_stderr("th3 = %5.1f deg, ph2 = %5.1f deg\n",
1550 rad2deg * th3, rad2deg * ph2);
1551 lept_stderr("th3' = %5.1f deg, ph2' = %5.1f deg\n",
1552 rad2deg * th3p, rad2deg * ph2p);
1553 lept_stderr("scalex = %6.3f, scaley = %6.3f\n", scalex, scaley);
1554#endif /* DEBUG */
1555
1556 /*-------------------------------------------------------------*
1557 Scaling moves the 1st src point, which is the origin.
1558 It must now be moved again to coincide with the origin
1559 (1st point) of the dest. After this is done, the 2nd
1560 and 3rd points must be sheared back to the original
1561 positions of the 2nd and 3rd dest points. We use the
1562 negative of the angles that were previously computed
1563 for shearing those points in the dest image to x and y
1564 axes, and take the shears in reverse order as well.
1565 *-------------------------------------------------------------*/
1566 /* Shift image to match dest origin. */
1567 x1sc = (l_int32)(scalex * x1 + 0.5); /* x comp of origin after scaling */
1568 y1sc = (l_int32)(scaley * y1 + 0.5); /* y comp of origin after scaling */
1569 pixRasteropIP(pix2, x1p - x1sc, y1p - y1sc, L_BRING_IN_WHITE);
1570
1571 /* Shear image to take points 2 and 3 off the axis and
1572 * put them in the original dest position */
1573 pixVShearIP(pix2, x1p, -ph2p, L_BRING_IN_WHITE);
1574 pixHShearIP(pix2, y1p, -th3p, L_BRING_IN_WHITE);
1575
1576 if (bw != 0 || bh != 0) {
1577 if ((pixd = pixRemoveBorderGeneral(pix2, bw, bw, bh, bh)) == NULL)
1578 L_ERROR("pixd not made\n", __func__);
1579 } else {
1580 pixd = pixClone(pix2);
1581 }
1582
1583cleanup_pix:
1584 pixDestroy(&pix1);
1585 pixDestroy(&pix2);
1586 return pixd;
1587}
l_ok affineInvertXform(l_float32 *vc, l_float32 **pvci)
affineInvertXform()
Definition affine.c:1003
PIX * pixAffinePtaColor(PIX *pixs, PTA *ptad, PTA *ptas, l_uint32 colorval)
pixAffinePtaColor()
Definition affine.c:543
l_ok affineXformSampledPt(l_float32 *vc, l_int32 x, l_int32 y, l_int32 *pxp, l_int32 *pyp)
affineXformSampledPt()
Definition affine.c:1084
l_ok linearInterpolatePixelColor(l_uint32 *datas, l_int32 wpls, l_int32 w, l_int32 h, l_float32 x, l_float32 y, l_uint32 colorval, l_uint32 *pval)
linearInterpolatePixelColor()
Definition affine.c:1153
l_int32 gaussjordan(l_float32 **a, l_float32 *b, l_int32 n)
gaussjordan()
Definition affine.c:1314
PIX * pixAffineSampled(PIX *pixs, l_float32 *vc, l_int32 incolor)
pixAffineSampled()
Definition affine.c:330
PIX * pixAffinePtaWithAlpha(PIX *pixs, PTA *ptad, PTA *ptas, PIX *pixg, l_float32 fract, l_int32 border)
pixAffinePtaWithAlpha()
Definition affine.c:768
PIX * pixAffine(PIX *pixs, l_float32 *vc, l_int32 incolor)
pixAffine()
Definition affine.c:489
PIX * pixAffineSampledPta(PIX *pixs, PTA *ptad, PTA *ptas, l_int32 incolor)
pixAffineSampledPta()
Definition affine.c:282
l_ok linearInterpolatePixelGray(l_uint32 *datas, l_int32 wpls, l_int32 w, l_int32 h, l_float32 x, l_float32 y, l_int32 grayval, l_int32 *pval)
linearInterpolatePixelGray()
Definition affine.c:1237
PIX * pixAffineSequential(PIX *pixs, PTA *ptad, PTA *ptas, l_int32 bw, l_int32 bh)
pixAffineSequential()
Definition affine.c:1436
PIX * pixAffineGray(PIX *pixs, l_float32 *vc, l_uint8 grayval)
pixAffineGray()
Definition affine.c:682
PIX * pixAffinePta(PIX *pixs, PTA *ptad, PTA *ptas, l_int32 incolor)
pixAffinePta()
Definition affine.c:421
PIX * pixAffinePtaGray(PIX *pixs, PTA *ptad, PTA *ptas, l_uint8 grayval)
pixAffinePtaGray()
Definition affine.c:642
l_ok affineXformPt(l_float32 *vc, l_int32 x, l_int32 y, l_float32 *pxp, l_float32 *pyp)
affineXformPt()
Definition affine.c:1114
l_ok getAffineXformCoeffs(PTA *ptas, PTA *ptad, l_float32 **pvc)
getAffineXformCoeffs()
Definition affine.c:915
PIX * pixAffineColor(PIX *pixs, l_float32 *vc, l_uint32 colorval)
pixAffineColor()
Definition affine.c:582
#define GET_DATA_QBIT(pdata, n)
#define SET_DATA_DIBIT(pdata, n, val)
#define SET_DATA_BIT_VAL(pdata, n, val)
#define GET_DATA_BYTE(pdata, n)
#define GET_DATA_DIBIT(pdata, n)
#define SET_DATA_BYTE(pdata, n, val)
#define GET_DATA_BIT(pdata, n)
#define SET_DATA_QBIT(pdata, n, val)
@ L_ALPHA_CHANNEL
Definition pix.h:331
@ REMOVE_CMAP_BASED_ON_SRC
Definition pix.h:384
@ L_BRING_IN_BLACK
Definition pix.h:663
@ L_BRING_IN_WHITE
Definition pix.h:662