202#include <config_auto.h>
206#include "allheaders.h"
209static const char *textsel1 =
"x oo "
215static const char *textsel2 =
" oo x"
221static const char *textsel3 =
"xxxxxx"
227static const char *textsel4 =
"xxxxxx"
234static const l_int32 DefaultMinUpDownCount = 70;
235static const l_float32 DefaultMinUpDownConf = 8.0;
236static const l_float32 DefaultMinUpDownRatio = 2.5;
239static const l_int32 DefaultMinMirrorFlipCount = 100;
240static const l_float32 DefaultMinMirrorFlipConf = 5.0;
243static void pixDebugFlipDetect(
const char *filename,
PIX *pixs,
244 PIX *pixhm, l_int32 enable);
278 l_float32 *pleftconf,
283l_float32 upconf, leftconf;
286 if (!pixs || pixGetDepth(pixs) != 1)
287 return (
PIX *)ERROR_PTR(
"pixs undefined or not 1 bpp", __func__, NULL);
291 pix1 = pixRotate90(pixs, 1);
294 if (pupconf) *pupconf = upconf;
295 if (pleftconf) *pleftconf = leftconf;
304 L_INFO(
"text orientation not determined; no rotation\n", __func__);
305 if (protation) *protation = 0;
306 return pixCopy(NULL, pixs);
309 L_INFO(
"text is oriented up; no rotation\n", __func__);
310 if (protation) *protation = 0;
311 return pixCopy(NULL, pixs);
314 L_INFO(
"landscape; text oriented left; 90 cw rotation\n", __func__);
315 if (protation) *protation = 90;
316 return pixRotateOrth(pixs, 1);
319 L_INFO(
"text oriented down; 180 cw rotation\n", __func__);
320 if (protation) *protation = 180;
321 return pixRotateOrth(pixs, 2);
324 L_INFO(
"landscape; text oriented right; 270 cw rotation\n", __func__);
325 if (protation) *protation = 270;
326 return pixRotateOrth(pixs, 3);
329 L_ERROR(
"invalid orient flag!\n", __func__);
330 return pixCopy(NULL, pixs);
405 l_float32 *pleftconf,
411 if (!pixs || pixGetDepth(pixs) != 1)
412 return ERROR_INT(
"pixs not defined or not 1 bpp", __func__, 1);
413 if (!pupconf && !pleftconf)
414 return ERROR_INT(
"nothing to do", __func__, 1);
416 mincount = DefaultMinUpDownCount;
421 pix1 = pixRotate90(pixs, 1);
467l_float32 absupconf, absleftconf;
470 return ERROR_INT(
"&orient not defined", __func__, 1);
472 if (upconf == 0.0 || leftconf == 0.0) {
473 L_INFO(
"not enough confidence to get orientation\n", __func__);
477 if (minupconf == 0.0)
478 minupconf = DefaultMinUpDownConf;
480 minratio = DefaultMinUpDownRatio;
481 absupconf = L_ABS(upconf);
482 absleftconf = L_ABS(leftconf);
486 if (upconf > minupconf && absupconf > minratio * absleftconf)
488 else if (leftconf > minupconf && absleftconf > minratio * absupconf)
490 else if (upconf < -minupconf && absupconf > minratio * absleftconf)
492 else if (leftconf < -minupconf && absleftconf > minratio * absupconf)
496 lept_stderr(
"upconf = %7.3f, leftconf = %7.3f\n", upconf, leftconf);
498 lept_stderr(
"Confidence is low; no determination is made\n");
500 lept_stderr(
"Text is rightside-up\n");
502 lept_stderr(
"Text is rotated 90 deg ccw\n");
504 lept_stderr(
"Text is upside-down\n");
506 lept_stderr(
"Text is rotated 90 deg cw\n");
558l_int32 countup, countdown, nmax;
560PIX *pix0, *pix1, *pix2, *pix3, *pixm;
561SEL *sel1, *sel2, *sel3, *sel4;
564 return ERROR_INT(
"&conf not defined", __func__, 1);
566 if (!pixs || pixGetDepth(pixs) != 1)
567 return ERROR_INT(
"pixs not defined or not 1 bpp", __func__, 1);
569 mincount = DefaultMinUpDownCount;
574 lept_mkdir(
"lept/orient");
577 sel1 = selCreateFromString(textsel1, 5, 6, NULL);
578 sel2 = selCreateFromString(textsel2, 5, 6, NULL);
579 sel3 = selCreateFromString(textsel3, 5, 6, NULL);
580 sel4 = selCreateFromString(textsel4, 5, 6, NULL);
586 pix0 = pixMorphCompSequence(pixs,
"c1.8 + c30.1", 0);
592 l_int32 i, nbox, x, y, w, h;
595 pix1 = pixMorphSequence(pix0,
"o10.1", 0);
596 boxa = pixConnComp(pix1, NULL, 8);
597 pixm = pixCreateTemplate(pix1);
599 nbox = boxaGetCount(boxa);
600 for (i = 0; i < nbox; i++) {
601 box = boxaGetBox(boxa, i,
L_CLONE);
602 boxGetGeometry(box, &x, &y, &w, &h);
604 pixRasterop(pixm, x + npixels, y - 6, w - 2 * npixels, h + 13,
614 pix1 = pixHMT(NULL, pix0, sel1);
615 pix2 = pixHMT(NULL, pix0, sel2);
616 pixOr(pix1, pix1, pix2);
618 pixAnd(pix1, pix1, pixm);
619 pix3 = pixReduceRankBinaryCascade(pix1, 1, 1, 0, 0);
620 pixCountPixels(pix3, &countup, NULL);
621 pixDebugFlipDetect(
"/tmp/lept/orient/up.png", pixs, pix1, debug);
627 pix1 = pixHMT(NULL, pix0, sel3);
628 pix2 = pixHMT(NULL, pix0, sel4);
629 pixOr(pix1, pix1, pix2);
631 pixAnd(pix1, pix1, pixm);
632 pix3 = pixReduceRankBinaryCascade(pix1, 1, 1, 0, 0);
633 pixCountPixels(pix3, &countdown, NULL);
634 pixDebugFlipDetect(
"/tmp/lept/orient/down.png", pixs, pix1, debug);
641 nup = (l_float32)(countup);
642 ndown = (l_float32)(countdown);
643 nmax = L_MAX(countup, countdown);
645 *pconf = 2. * ((nup - ndown) / sqrt(nup + ndown));
648 if (pixm) pixWriteDebug(
"/tmp/lept/orient/pixm1.png", pixm, IFF_PNG);
649 lept_stderr(
"nup = %7.3f, ndown = %7.3f, conf = %7.3f\n",
651 if (*pconf > DefaultMinUpDownConf)
652 lept_stderr(
"Text is rightside-up\n");
653 if (*pconf < -DefaultMinUpDownConf)
654 lept_stderr(
"Text is upside-down\n");
715l_int32 count1, count2, nmax;
716l_float32 nleft, nright;
717PIX *pix0, *pix1, *pix2, *pix3;
721 return ERROR_INT(
"&conf not defined", __func__, 1);
723 if (!pixs || pixGetDepth(pixs) != 1)
724 return ERROR_INT(
"pixs not defined or not 1 bpp", __func__, 1);
726 mincount = DefaultMinMirrorFlipCount;
729 lept_mkdir(
"lept/orient");
732 sel1 = selCreateFromString(textsel1, 5, 6, NULL);
733 sel2 = selCreateFromString(textsel2, 5, 6, NULL);
736 pix3 = pixMorphCompSequence(pixs,
"d1.30", 0);
737 pixXor(pix3, pix3, pixs);
738 pix0 = pixMorphCompSequence(pixs,
"c15.1", 0);
739 pixXor(pix0, pix0, pixs);
740 pixAnd(pix0, pix0, pix3);
741 pixOr(pix0, pix0, pixs);
745 pix1 = pixHMT(NULL, pix0, sel1);
746 pix3 = pixReduceRankBinaryCascade(pix1, 1, 1, 0, 0);
747 pixCountPixels(pix3, &count1, NULL);
748 pixDebugFlipDetect(
"/tmp/lept/orient/right.png", pixs, pix1, debug);
753 pix2 = pixHMT(NULL, pix0, sel2);
754 pix3 = pixReduceRankBinaryCascade(pix2, 1, 1, 0, 0);
755 pixCountPixels(pix3, &count2, NULL);
756 pixDebugFlipDetect(
"/tmp/lept/orient/left.png", pixs, pix2, debug);
760 nright = (l_float32)count1;
761 nleft = (l_float32)count2;
762 nmax = L_MAX(count1, count2);
768 *pconf = 2. * ((nright - nleft) / sqrt(nright + nleft));
771 lept_stderr(
"nright = %f, nleft = %f\n", nright, nleft);
772 if (*pconf > DefaultMinMirrorFlipConf)
773 lept_stderr(
"Text is not mirror reversed\n");
774 if (*pconf < -DefaultMinMirrorFlipConf)
775 lept_stderr(
"Text is mirror reversed\n");
795pixDebugFlipDetect(
const char *filename,
805 pixt = pixConvert1To4Cmap(pixs);
806 pixthm = pixMorphSequence(pixhm,
"d5.5", 0);
807 pixSetMaskedCmap(pixt, pixthm, 0, 0, 255, 0, 0);
809 pixWriteDebug(filename, pixt, IFF_PNG);
l_ok makeOrientDecision(l_float32 upconf, l_float32 leftconf, l_float32 minupconf, l_float32 minratio, l_int32 *porient, l_int32 debug)
makeOrientDecision()
l_ok pixMirrorDetect(PIX *pixs, l_float32 *pconf, l_int32 mincount, l_int32 debug)
pixMirrorDetect()
l_ok pixUpDownDetect(PIX *pixs, l_float32 *pconf, l_int32 mincount, l_int32 npixels, l_int32 debug)
pixUpDownDetect()
l_ok pixOrientDetect(PIX *pixs, l_float32 *pupconf, l_float32 *pleftconf, l_int32 mincount, l_int32 debug)
pixOrientDetect()
PIX * pixOrientCorrect(PIX *pixs, l_float32 minupconf, l_float32 minratio, l_float32 *pupconf, l_float32 *pleftconf, l_int32 *protation, l_int32 debug)
pixOrientCorrect()