diff --git a/prog/flipselgen.c.notused b/prog/flipselgen.c.notused index f8a76774a..a4e314c05 100644 --- a/prog/flipselgen.c.notused +++ b/prog/flipselgen.c.notused @@ -25,7 +25,7 @@ *====================================================================*/ /* - * flipselgen.c + * flipselgen.c.notused * * NOTE * ================================================================ diff --git a/src/flipdetect.c b/src/flipdetect.c index b974ba46d..fffc6443d 100644 --- a/src/flipdetect.c +++ b/src/flipdetect.c @@ -157,12 +157,26 @@ * A high-level interface, pixOrientCorrect() combines the detection * of the orientation with the rotation decision and the rotation itself. * + * The structuring elements used for text orientation detection require text + * with ascenders and descenders. They have been designed to work best + * with normal sized text (about 10 pt font), scanned with a resolution + * between 150 and 300 ppi. + * * For pedagogical reasons, we have included a dwa implementation of * this functionality, in flipdetectdwa.c.notused. It shows by example * how to make a dwa implementation of an application that uses binary * morphological operations. It is faster than the rasterop implementation, * but not by a large amount. * + * The generation of flipdetectdwa.c.notused was achieved as follows: + * (1) The program flipselgen.c.notused generates the DWA code, in two C files + * (2) The low-level DWA code in those two files was put into a single + * file, fliphmtgen.c.notused, for clarity. We didn't want the two + * files (fmorphgen.3.c and fmorphgenlow.3.c) sitting around and + * possibly causing confusion. + * (3) This low-level code was directly incorporated into flipdetectdwa.c, + * where it substitutes for the basic rasterop code in flipdetect.c. + * * Finally, use can be made of programs such as exiftool and convert to * read exif camera orientation data in jpeg files and conditionally rotate. * Here is an example shell script, made by Dan9er: @@ -250,7 +264,7 @@ static void pixDebugFlipDetect(const char *filename, PIX *pixs, /*! * \brief pixOrientCorrect() * - * \param[in] pixs 1 bpp, deskewed, English text, 150 - 300 ppi + * \param[in] pixs 1 bpp, deskewed, Roman text, 150 - 300 ppi * \param[in] minupconf minimum value for which a decision can be made * \param[in] minratio minimum conf ratio required for a decision * \param[out] pupconf [optional] ; use NULL to skip @@ -268,6 +282,7 @@ static void pixDebugFlipDetect(const char *filename, PIX *pixs, * Use 0.0 for default values for %minupconf and %minratio * (4) Optional output of intermediate confidence results and * the rotation performed on pixs. + * (5) Use on text images with a resolution between 150 and 300 ppi. * */ PIX * @@ -338,7 +353,7 @@ PIX *pix1; /*! * \brief pixOrientDetect() * - * \param[in] pixs 1 bpp, deskewed, English text, 150 - 300 ppi + * \param[in] pixs 1 bpp, deskewed, Roman text, 150 - 300 ppi * \param[out] pupconf [optional] ; may be NULL * \param[out] pleftconf [optional] ; may be NULL * \param[in] mincount min number of up + down; use 0 for default @@ -390,13 +405,14 @@ PIX *pix1; * (6) One should probably not interpret the direction unless * there are a sufficient number of counts for both orientations, * in which case neither upconf nor leftconf will be 0.0. - * (7) This algorithm will fail on some images, such as tables, + * (7) Use on text images with a resolution between 150 and 300 ppi. + * (8) This algorithm will fail on some images, such as tables, * where most of the characters are numbers and appear as * uppercase, but there are some repeated words that give a * biased signal. It may be advisable to run a table detector * first (e.g., pixDecideIfTable()), and not run the orientation * detector if it is a table. - * (8) Uses rasterop implementation of HMT. + * (9) Uses rasterop implementation of HMT. * */ l_ok @@ -513,7 +529,7 @@ l_float32 absupconf, absleftconf; /*! * \brief pixUpDownDetect() * - * \param[in] pixs 1 bpp, deskewed, English text, 150 - 300 ppi + * \param[in] pixs 1 bpp, deskewed, Roman text, 150 - 300 ppi * \param[out] pconf confidence that text is rightside-up * \param[in] mincount min number of up + down; use 0 for default * \param[in] npixels number of pixels removed from each side of word box @@ -546,6 +562,7 @@ l_float32 absupconf, absleftconf; * this function is designed to work for input pix between * 150 and 300 ppi, and an 8x reduction on a 150 ppi image * is going too far -- components will get merged. + * (5) Use on text images with a resolution between 150 and 300 ppi. * */ l_ok @@ -670,7 +687,7 @@ SEL *sel1, *sel2, *sel3, *sel4; /*! * \brief pixMirrorDetect() * - * \param[in] pixs 1 bpp, deskewed, English text + * \param[in] pixs 1 bpp, deskewed, Roman text, 150 - 300 ppi * \param[out] pconf confidence that text is not LR mirror reversed * \param[in] mincount min number of left + right; use 0 for default * \param[in] debug 1 for debug output; 0 otherwise @@ -704,6 +721,7 @@ SEL *sel1, *sel2, *sel3, *sel4; * parts of the characters are purposely weakened sufficiently * to allow these characters to remain open. The wonders * of morphology! + * (5) Use on text images with a resolution between 150 and 300 ppi. * */ l_ok diff --git a/src/fliphmtgen.c.notused b/src/fliphmtgen.c.notused new file mode 100644 index 000000000..bd5511fb2 --- /dev/null +++ b/src/fliphmtgen.c.notused @@ -0,0 +1,367 @@ +/*====================================================================* + - Copyright (C) 2001 Leptonica. All rights reserved. + - + - Redistribution and use in source and binary forms, with or without + - modification, are permitted provided that the following conditions + - are met: + - 1. Redistributions of source code must retain the above copyright + - notice, this list of conditions and the following disclaimer. + - 2. Redistributions in binary form must reproduce the above + - copyright notice, this list of conditions and the following + - disclaimer in the documentation and/or other materials + - provided with the distribution. + - + - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY + - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *====================================================================*/ + +/* + * fliphmtgen.c.notused + * + * NOTE + * ================================================================ + * This code has been retired from the library, along with the code + * in flipdetectdwa.c which uses it. It is no longer compiled. + * ================================================================ + * + * DWA implementation of hit-miss transforms with auto-generated sels + * for pixOrientDetectDwa() and pixUpDownDetectDwa() in + * flipdetectdwa.c + * + * PIX *pixFlipFHMTGen() + * static l_int32 flipfhmtgen_low() -- dispatcher + * static void fhmt_1_0() + * static void fhmt_1_1() + * static void fhmt_1_2() + * static void fhmt_1_3() + * + * The code (slightly rearranged) was generated by prog/flipselgen.c + */ + +#ifdef HAVE_CONFIG_H +#include +#endif /* HAVE_CONFIG_H */ + +#include +#include "allheaders.h" + +static l_int32 NUM_SELS_GENERATED = 4; +static char SEL_NAMES[][10] = {"flipsel1", + "flipsel2", + "flipsel3", + "flipsel4"}; + +static l_int32 flipfhmtgen_low(l_uint32 *, l_int32, l_int32, l_int32, + l_uint32 *, l_int32, l_int32); + +static void fhmt_1_0(l_uint32 *, l_int32, l_int32, l_int32, l_uint32 *, + l_int32); +static void fhmt_1_1(l_uint32 *, l_int32, l_int32, l_int32, l_uint32 *, + l_int32); +static void fhmt_1_2(l_uint32 *, l_int32, l_int32, l_int32, l_uint32 *, + l_int32); +static void fhmt_1_3(l_uint32 *, l_int32, l_int32, l_int32, l_uint32 *, + l_int32); + +/*---------------------------------------------------------------------* + * Top-level hmt functions * + *---------------------------------------------------------------------*/ +/* + * pixFlipFHMTGen() + * + * Input: pixd (usual 3 choices: null, == pixs, != pixs) + * pixs + * sel name (one of four defined in SEL_NAMES[]) + * Return: pixd + * + * Notes: + * Action: hit-miss transform on pixs by the sel + * N.B.: the sel must have at least one hit, and it + * can have any number of misses. + */ +PIX * +pixFlipFHMTGen(PIX *pixd, + PIX *pixs, + const char *selname) +{ +l_int32 i, index, found, w, h, wpls, wpld; +l_uint32 *datad, *datas, *datat; +PIX *pixt; + + PROCNAME("pixFlipFHMTGen"); + + if (!pixs) + return (PIX *)ERROR_PTR("pixs not defined", procName, pixd); + if (pixGetDepth(pixs) != 1) + return (PIX *)ERROR_PTR("pixs must be 1 bpp", procName, pixd); + + found = FALSE; + for (i = 0; i < NUM_SELS_GENERATED; i++) { + if (strcmp(selname, SEL_NAMES[i]) == 0) { + found = TRUE; + index = i; + break; + } + } + if (found == FALSE) + return (PIX *)ERROR_PTR("sel index not found", procName, pixd); + + if (pixd) { + if (!pixSizesEqual(pixs, pixd)) + return (PIX *)ERROR_PTR("sizes not equal", procName, pixd); + } else { + if ((pixd = pixCreateTemplate(pixs)) == NULL) + return (PIX *)ERROR_PTR("pixd not made", procName, NULL); + } + + wpls = pixGetWpl(pixs); + wpld = pixGetWpl(pixd); + + /* The images must be surrounded with ADDED_BORDER white pixels, + * that we'll read from. We fabricate a "proper" + * image as the subimage within the border, having the + * following parameters: */ + w = pixGetWidth(pixs) - 2 * ADDED_BORDER; + h = pixGetHeight(pixs) - 2 * ADDED_BORDER; + datas = pixGetData(pixs) + ADDED_BORDER * wpls + ADDED_BORDER / 32; + datad = pixGetData(pixd) + ADDED_BORDER * wpld + ADDED_BORDER / 32; + + if (pixd == pixs) { /* need temp image if in-place */ + if ((pixt = pixCopy(NULL, pixs)) == NULL) + return (PIX *)ERROR_PTR("pixt not made", procName, pixd); + datat = pixGetData(pixt) + ADDED_BORDER * wpls + ADDED_BORDER / 32; + flipfhmtgen_low(datad, w, h, wpld, datat, wpls, index); + pixDestroy(&pixt); + } else { /* simple and not in-place */ + flipfhmtgen_low(datad, w, h, wpld, datas, wpls, index); + } + + return pixd; +} + + +/*---------------------------------------------------------------------* + * Fast hmt dispatcher * + *---------------------------------------------------------------------*/ +/* + * flipfhmtgen_low() + * + * A dispatcher to appropriate low-level code for flip hmt ops + */ +static l_int32 +flipfhmtgen_low(l_uint32 *datad, + l_int32 w, + l_int32 h, + l_int32 wpld, + l_uint32 *datas, + l_int32 wpls, + l_int32 index) +{ + + switch (index) + { + case 0: + fhmt_1_0(datad, w, h, wpld, datas, wpls); + break; + case 1: + fhmt_1_1(datad, w, h, wpld, datas, wpls); + break; + case 2: + fhmt_1_2(datad, w, h, wpld, datas, wpls); + break; + case 3: + fhmt_1_3(datad, w, h, wpld, datas, wpls); + break; + } + + return 0; +} + + +/*--------------------------------------------------------------------------* + * Low-level auto-generated hmt routines * + *--------------------------------------------------------------------------*/ +/* + * N.B. in all the low-level routines, the part of the image + * that is accessed has been clipped by ADDED_BORDER pixels + * on all four sides. This is done in the higher level + * code by redefining w and h smaller and by moving the + * start-of-image pointers up to the beginning of this + * interior rectangle. + */ + +static void +fhmt_1_0(l_uint32 *datad, + l_int32 w, + l_int32 h, + l_int32 wpld, + l_uint32 *datas, + l_int32 wpls) +{ +l_int32 i; +l_int32 j, pwpls; +l_uint32 *sptr, *dptr; +l_int32 wpls2, wpls3; + + wpls2 = 2 * wpls; + wpls3 = 3 * wpls; + pwpls = (l_uint32)(w + 31) / 32; /* proper wpl of src */ + + for (i = 0; i < h; i++) { + sptr = datas + i * wpls; + dptr = datad + i * wpld; + for (j = 0; j < pwpls; j++, sptr++, dptr++) { + *dptr = ((*(sptr - wpls) >> 3) | (*(sptr - wpls - 1) << 29)) & + (~*(sptr - wpls)) & + ((~*(sptr - wpls) << 1) | (~*(sptr - wpls + 1) >> 31)) & + ((*(sptr) >> 3) | (*(sptr - 1) << 29)) & + ((~*(sptr) >> 1) | (~*(sptr - 1) << 31)) & + (~*sptr) & + ((~*(sptr) << 1) | (~*(sptr + 1) >> 31)) & + ((*(sptr + wpls) >> 3) | (*(sptr + wpls - 1) << 29)) & + (~*(sptr + wpls)) & + ((*(sptr + wpls2) >> 3) | (*(sptr + wpls2 - 1) << 29)) & + ((*(sptr + wpls3) >> 3) | (*(sptr + wpls3 - 1) << 29)) & + ((*(sptr + wpls3) >> 2) | (*(sptr + wpls3 - 1) << 30)) & + ((*(sptr + wpls3) >> 1) | (*(sptr + wpls3 - 1) << 31)) & + (*(sptr + wpls3)) & + ((*(sptr + wpls3) << 1) | (*(sptr + wpls3 + 1) >> 31)) & + ((*(sptr + wpls3) << 2) | (*(sptr + wpls3 + 1) >> 30)); + } + } +} + + +static void +fhmt_1_1(l_uint32 *datad, + l_int32 w, + l_int32 h, + l_int32 wpld, + l_uint32 *datas, + l_int32 wpls) +{ +l_int32 i; +l_int32 j, pwpls; +l_uint32 *sptr, *dptr; +l_int32 wpls2, wpls3; + + wpls2 = 2 * wpls; + wpls3 = 3 * wpls; + pwpls = (l_uint32)(w + 31) / 32; /* proper wpl of src */ + + for (i = 0; i < h; i++) { + sptr = datas + i * wpls; + dptr = datad + i * wpld; + for (j = 0; j < pwpls; j++, sptr++, dptr++) { + *dptr = ((~*(sptr - wpls) >> 1) | (~*(sptr - wpls - 1) << 31)) & + (~*(sptr - wpls)) & + ((*(sptr - wpls) << 3) | (*(sptr - wpls + 1) >> 29)) & + ((~*(sptr) >> 1) | (~*(sptr - 1) << 31)) & + (~*sptr) & + ((~*(sptr) << 1) | (~*(sptr + 1) >> 31)) & + ((*(sptr) << 3) | (*(sptr + 1) >> 29)) & + (~*(sptr + wpls)) & + ((*(sptr + wpls) << 3) | (*(sptr + wpls + 1) >> 29)) & + ((*(sptr + wpls2) << 3) | (*(sptr + wpls2 + 1) >> 29)) & + ((*(sptr + wpls3) >> 2) | (*(sptr + wpls3 - 1) << 30)) & + ((*(sptr + wpls3) >> 1) | (*(sptr + wpls3 - 1) << 31)) & + (*(sptr + wpls3)) & + ((*(sptr + wpls3) << 1) | (*(sptr + wpls3 + 1) >> 31)) & + ((*(sptr + wpls3) << 2) | (*(sptr + wpls3 + 1) >> 30)) & + ((*(sptr + wpls3) << 3) | (*(sptr + wpls3 + 1) >> 29)); + } + } +} + + +static void +fhmt_1_2(l_uint32 *datad, + l_int32 w, + l_int32 h, + l_int32 wpld, + l_uint32 *datas, + l_int32 wpls) +{ +l_int32 i; +l_int32 j, pwpls; +l_uint32 *sptr, *dptr; +l_int32 wpls2, wpls3; + + wpls2 = 2 * wpls; + wpls3 = 3 * wpls; + pwpls = (l_uint32)(w + 31) / 32; /* proper wpl of src */ + + for (i = 0; i < h; i++) { + sptr = datas + i * wpls; + dptr = datad + i * wpld; + for (j = 0; j < pwpls; j++, sptr++, dptr++) { + *dptr = ((*(sptr - wpls3) >> 3) | (*(sptr - wpls3 - 1) << 29)) & + ((*(sptr - wpls3) >> 2) | (*(sptr - wpls3 - 1) << 30)) & + ((*(sptr - wpls3) >> 1) | (*(sptr - wpls3 - 1) << 31)) & + (*(sptr - wpls3)) & + ((*(sptr - wpls3) << 1) | (*(sptr - wpls3 + 1) >> 31)) & + ((*(sptr - wpls3) << 2) | (*(sptr - wpls3 + 1) >> 30)) & + ((*(sptr - wpls2) >> 3) | (*(sptr - wpls2 - 1) << 29)) & + ((*(sptr - wpls) >> 3) | (*(sptr - wpls - 1) << 29)) & + (~*(sptr - wpls)) & + ((*(sptr) >> 3) | (*(sptr - 1) << 29)) & + ((~*(sptr) >> 1) | (~*(sptr - 1) << 31)) & + (~*sptr) & + ((~*(sptr) << 1) | (~*(sptr + 1) >> 31)) & + ((*(sptr + wpls) >> 3) | (*(sptr + wpls - 1) << 29)) & + (~*(sptr + wpls)) & + ((~*(sptr + wpls) << 1) | (~*(sptr + wpls + 1) >> 31)); + } + } +} + + +static void +fhmt_1_3(l_uint32 *datad, + l_int32 w, + l_int32 h, + l_int32 wpld, + l_uint32 *datas, + l_int32 wpls) +{ +l_int32 i; +l_int32 j, pwpls; +l_uint32 *sptr, *dptr; +l_int32 wpls2, wpls3; + + wpls2 = 2 * wpls; + wpls3 = 3 * wpls; + pwpls = (l_uint32)(w + 31) / 32; /* proper wpl of src */ + + for (i = 0; i < h; i++) { + sptr = datas + i * wpls; + dptr = datad + i * wpld; + for (j = 0; j < pwpls; j++, sptr++, dptr++) { + *dptr = ((*(sptr - wpls3) >> 2) | (*(sptr - wpls3 - 1) << 30)) & + ((*(sptr - wpls3) >> 1) | (*(sptr - wpls3 - 1) << 31)) & + (*(sptr - wpls3)) & + ((*(sptr - wpls3) << 1) | (*(sptr - wpls3 + 1) >> 31)) & + ((*(sptr - wpls3) << 2) | (*(sptr - wpls3 + 1) >> 30)) & + ((*(sptr - wpls3) << 3) | (*(sptr - wpls3 + 1) >> 29)) & + ((*(sptr - wpls2) << 3) | (*(sptr - wpls2 + 1) >> 29)) & + (~*(sptr - wpls)) & + ((*(sptr - wpls) << 3) | (*(sptr - wpls + 1) >> 29)) & + ((~*(sptr) >> 1) | (~*(sptr - 1) << 31)) & + (~*sptr) & + ((~*(sptr) << 1) | (~*(sptr + 1) >> 31)) & + ((*(sptr) << 3) | (*(sptr + 1) >> 29)) & + ((~*(sptr + wpls) >> 1) | (~*(sptr + wpls - 1) << 31)) & + (~*(sptr + wpls)) & + ((*(sptr + wpls) << 3) | (*(sptr + wpls + 1) >> 29)); + } + } +}