Exemple #1
0
/*!
 * \brief   pixDeskewLocal()
 *
 * \param[in]    pixs        1 bpp
 * \param[in]    nslices     the number of horizontal overlapping slices;
 *                           must be larger than 1 and not exceed 20;
 *                           use 0 for default
 * \param[in]    redsweep    sweep reduction factor: 1, 2, 4 or 8;
 *                           use 0 for default value
 * \param[in]    redsearch   search reduction factor: 1, 2, 4 or 8, and
 *                           not larger than redsweep; use 0 for default value
 * \param[in]    sweeprange  half the full range, assumed about 0; in degrees;
 *                           use 0.0 for default value
 * \param[in]    sweepdelta  angle increment of sweep; in degrees;
 *                           use 0.0 for default value
 * \param[in]    minbsdelta  min binary search increment angle; in degrees;
 *                           use 0.0 for default value
 * \return  pixd, or NULL on error
 *
 * <pre>
 * Notes:
 *      (1) This function allows deskew of a page whose skew changes
 *          approximately linearly with vertical position.  It uses
 *          a projective transform that in effect does a differential
 *          shear about the LHS of the page, and makes all text lines
 *          horizontal.
 *      (2) The origin of the keystoning can be either a cheap document
 *          feeder that rotates the page as it is passed through, or a
 *          camera image taken from either the left or right side
 *          of the vertical.
 *      (3) The image transformation is a projective warping,
 *          not a rotation.  Apart from this function, the text lines
 *          must be properly aligned vertically with respect to each
 *          other.  This can be done by pre-processing the page; e.g.,
 *          by rotating or horizontally shearing it.
 *          Typically, this can be achieved by vertically aligning
 *          the page edge.
 * </pre>
 */
PIX *
pixDeskewLocal(PIX       *pixs,
               l_int32    nslices,
               l_int32    redsweep,
               l_int32    redsearch,
               l_float32  sweeprange,
               l_float32  sweepdelta,
               l_float32  minbsdelta)
{
l_int32    ret;
PIX       *pixd;
PTA       *ptas, *ptad;

    PROCNAME("pixDeskewLocal");

    if (!pixs || pixGetDepth(pixs) != 1)
        return (PIX *)ERROR_PTR("pixs undefined or not 1 bpp", procName, NULL);

        /* Skew array gives skew angle (deg) as fctn of raster line
         * where it intersects the LHS of the image */
    ret = pixGetLocalSkewTransform(pixs, nslices, redsweep, redsearch,
                                   sweeprange, sweepdelta, minbsdelta,
                                   &ptas, &ptad);
    if (ret != 0)
        return (PIX *)ERROR_PTR("transform pts not found", procName, NULL);

        /* Use a projective transform */
    pixd = pixProjectiveSampledPta(pixs, ptad, ptas, L_BRING_IN_WHITE);

    ptaDestroy(&ptas);
    ptaDestroy(&ptad);
    return pixd;
}
Exemple #2
0
int main(int argc, char* argv[])
{
    PIX *pixs, *pixb, *pixt;
    int minb;

    if (argc < 2) {
USAGE:	fprintf(stderr, "Usage:  %s </path/to/text-image>\n"
		"\t\t[binarize-threshold] [minw:minh:maxw:maxh]\n",
		strrchr(argv[0], '/') + 1);
	return EINVAL;
    }

    if (2 < argc) {	errno = 0;
	minb = strtol(argv[2], NULL, 10);

	if (errno < 0) {
	    fprintf(stderr, "strtol: %s\n", strerror(errno));
	    goto USAGE;
	}
    } else minb = 180;

    if (!(pixs = pixRead(argv[1]))) ;

    if (1 && (pixt = pixBackgroundNormMorph(pixs, NULL, 4, 5, 248))) {
	pixDestroy(&pixs);	pixs = pixt;
    } else
    if (0 && (pixt = pixBackgroundNorm(pixs, NULL, NULL,
	    10, 15, 60, 40, 248, 2, 1))) {
	pixDestroy(&pixs);	pixs = pixt;
    }

    if (1 && (pixt = pixFindSkewAndDeskew(pixs, 1, NULL, NULL))) {
	pixDestroy(&pixs);	pixs = pixt;
    }	if (0 && pixDisplay(pixs, 0, 0)) ;

    if (1) {	PTA *ptas, *ptad;
	if (!(pixb = pixConvertTo1(pixs, minb))) ;

	// pixt = pixDeskewLocal(pixs, 10, 0, 0, 0.0, 0.0, 0.0))
	if (!pixGetLocalSkewTransform(pixb,
		10, 0, 0, 0.0, 0.0, 0.0, &ptas, &ptad)) {
	    if ((pixt = pixProjectiveSampledPta(pixs,
		ptad, ptas, L_BRING_IN_WHITE))) {
		pixDestroy(&pixs);	pixs = pixt;
	    }	ptaDestroy(&ptas);	ptaDestroy(&ptad);
	}	pixDestroy(&pixb);
    }

    if (0 && (pixt = pixGammaTRC(NULL, pixs, 1.0, 30, 180))) {
	pixDestroy(&pixs);	pixs = pixt;
    }

    if (!(pixb = pixConvertTo1(pixs, minb))) ;

    if (0) { pixDestroy(&pixs); pixs = pixCopy(pixs, pixb); }	// XXX:

    if (1) {
	BOX* box;
	int i, n, j, m;
	PIX *pixi, *pixl;
	BOXA *boxi, *boxl;
	int x, y, w, h, wid;
	int X = INT_MAX, Y = INT_MAX, W = 0, H;

	// XXX: do smaller(or no) pixOpenBrick
	if (pixGetRegionsBinary(pixb, &pixi, &pixl, NULL, 0)) ;

	boxl = pixConnComp(pixl, NULL, 4);
	n = boxaGetCount(boxl);

	for (i = 0; i < n; ++i) {   BOXA* boxa;
	    box = boxaGetBox(boxl, i, L_CLONE);
	    boxGetGeometry(box, &x, &y, &w, &h);

	    if (w < 30 || h < 30 || w < h || h < (w / 40)) {
		boxDestroy(&box);	continue;
		boxaRemoveBox(boxl, i);
	    }

	    if (x < X) X = x;	if (y < Y) Y = y; if (W < w) W = w;

	    pixt = pixClipRectangle(pixb, box, NULL);
	    boxDestroy(&box);

	    // XXX: for English
	    if (0) pixt = pixDilateBrick(pixt, pixt, h >> 1, h >> 1); else

	    pixt = pixDilateBrick(pixt, pixt, 16 < h ? h >> 4 : 1, h << 1);
	    if (0 && pixDisplay(pixt, 0, 0)) ;

	    boxa = pixConnComp(pixt, NULL, 8);
	    pixDestroy(&pixt);

	    wid = (h * 3) >> 2;
	    //boxaShift(boxa, x, y);
	    m = boxaGetCount(boxa);

	    for (j = 0; j < m; ++j) {
		int x0, y0, w0;

		box = boxaGetBox(boxa, j, L_CLONE);
		boxGetGeometry(box, &x0, &y0, &w0, NULL);

		// merge adjacent 2 or 3 small boxes
		if (1 && w0 < wid && (j + 1) < m) {
		    BOX* boxn;	int xn, wn;

		    boxn = boxaGetBox(boxa, j + 1, L_CLONE);
		    boxGetGeometry(boxn, &xn, NULL, &wn, NULL);

		    if ((w0 = xn + wn - x0) < h) {
			boxaSparseClearBox(boxa, ++j);

			if (w0 < wid && (j + 1) < m) {
			    boxDestroy(&boxn);
			    boxn = boxaGetBox(boxa, j + 1, L_CLONE);
			    boxGetGeometry(boxn, &xn, NULL, &wn, NULL);

			    if ((wn = xn + wn - x0) < h) {
				boxaSparseClearBox(boxa, ++j);
				w0 = wn;
			    }
			}

			boxSetGeometry(box, -1, -1, w0, -1);
		    }	boxDestroy(&boxn);
		}

		boxSetGeometry(box, x + x0, y + y0, -1, -1);
		boxDestroy(&box);
	    }	boxaSparseCompact(boxa);

	    if (1 && (pixt = pixDrawBoxa(pixs, boxa, 1, 0xff000000))) {
		pixDestroy(&pixs);	pixs = pixt;
	    }	boxaDestroy(&boxa);
	}   H = y + h;