Exemple #1
0
jfloat Java_com_googlecode_leptonica_android_Skew_nativeFindSkew(JNIEnv *env, jclass clazz,
                                                                 jint nativePix, jfloat sweepRange,
                                                                 jfloat sweepDelta,
                                                                 jint sweepReduction,
                                                                 jint searchReduction,
                                                                 jfloat searchMinDelta) {
  LOGV(__FUNCTION__);
  // Corrects the rotation of each element in pixa to 0 degrees.

  PIX *pixs = (PIX *) nativePix;

  l_float32 angle, conf;

  if (!pixFindSkewSweepAndSearch(pixs, &angle, &conf, (l_int32) sweepReduction,
                                 (l_int32) searchReduction, (l_float32) sweepRange,
                                 (l_int32) sweepDelta, (l_float32) searchMinDelta)) {
    if (conf <= 0) {
      return (jfloat) 0;
    }

    return (jfloat) angle;
  }

  return (jfloat) 0;
}
main(int    argc,
     char **argv)
{
char        *filein, *fileout;
l_float32    deg2rad;
l_float32    angle, conf;
PIX         *pixs, *pixd;
static char  mainName[] = "skewtest";

    if (argc != 3)
	exit(ERROR_INT(" Syntax:  skewtest filein fileout", mainName, 1));

    filein = argv[1];
    fileout = argv[2];

    deg2rad = 3.1415926535 / 180.;

    if ((pixs = pixRead(filein)) == NULL)
	exit(ERROR_INT("pixs not made", mainName, 1));

#if 1
    pixd = pixDeskew(pixs, DESKEW_REDUCTION);
    pixWrite(fileout, pixd, IFF_PNG);
    pixDestroy(&pixd);
#endif

#if 0
    if (pixFindSkew(pixs, &angle, &conf)) {
	L_WARNING("skew angle not valid", mainName);
	exit(1);
    }
#endif

#if 0
    if (pixFindSkewSweep(pixs, &angle, SWEEP_REDUCTION,
                         SWEEP_RANGE, SWEEP_DELTA)) {
	L_WARNING("skew angle not valid", mainName);
	exit(1);
    }
#endif

#if 0
    if (pixFindSkewSweepAndSearch(pixs, &angle, &conf, SWEEP_REDUCTION2,
                         SEARCH_REDUCTION, SWEEP_RANGE2, SWEEP_DELTA2,
			 SEARCH_MIN_DELTA)) {
	L_WARNING("skew angle not valid", mainName);
	exit(1);
    }
#endif

    pixDestroy(&pixs);
    exit(0);
}
Exemple #3
0
/*!
 *  pixFindSkew()
 *
 *      Input:  pixs  (1 bpp)
 *              &angle   (<return> angle required to deskew, in degrees)
 *              &conf    (<return> confidence value is ratio max/min scores)
 *      Return: 0 if OK, 1 on error or if angle measurment not valid
 *
 *  Notes:
 *      (1) This is a simple high-level interface, that uses default
 *          values of the parameters for reasonable speed and accuracy.
 *      (2) The angle returned is the negative of the skew angle of
 *          the image.  It is the angle required for deskew.
 *          Clockwise rotations are positive angles.
 */
l_int32
pixFindSkew(PIX        *pixs,
            l_float32  *pangle,
            l_float32  *pconf)
{
    PROCNAME("pixFindSkew");

    if (!pixs)
        return ERROR_INT("pixs not defined", procName, 1);
    if (pixGetDepth(pixs) != 1)
        return ERROR_INT("pixs not 1 bpp", procName, 1);
    if (!pangle)
        return ERROR_INT("&angle not defined", procName, 1);
    if (!pconf)
        return ERROR_INT("&conf not defined", procName, 1);

    return pixFindSkewSweepAndSearch(pixs, pangle, pconf,
                                     DEFAULT_SWEEP_REDUCTION,
                                     DEFAULT_BS_REDUCTION,
                                     DEFAULT_SWEEP_RANGE,
                                     DEFAULT_SWEEP_DELTA,
                                     DEFAULT_MINBS_DELTA);
}
Exemple #4
0
/*!
 * \brief   pixGetLocalSkewAngles()
 *
 * \param[in]    pixs         1 bpp
 * \param[in]    nslices      the number of horizontal overlapping slices; must
 *                            be larger than 1 and not exceed 20; 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
 * \param[out]   pa [optional] slope of skew as fctn of y
 * \param[out]   pb [optional] intercept at y=0 of skew as fctn of y
 * \param[in]    debug   1 for generating plot of skew angle vs. y; 0 otherwise
 * \return  naskew, or NULL on error
 *
 * <pre>
 * Notes:
 *      (1) The local skew is measured in a set of overlapping strips.
 *          We then do a least square linear fit parameters to get
 *          the slope and intercept parameters a and b in
 *              skew-angle = a * y + b  (degrees)
 *          for the local skew as a function of raster line y.
 *          This is then used to make naskew, which can be interpreted
 *          as the computed skew angle (in degrees) at the left edge
 *          of each raster line.
 *      (2) naskew can then be used to find the baselines of text, because
 *          each text line has a baseline that should intersect
 *          the left edge of the image with the angle given by this
 *          array, evaluated at the raster line of intersection.
 * </pre>
 */
NUMA *
pixGetLocalSkewAngles(PIX        *pixs,
                      l_int32     nslices,
                      l_int32     redsweep,
                      l_int32     redsearch,
                      l_float32   sweeprange,
                      l_float32   sweepdelta,
                      l_float32   minbsdelta,
                      l_float32  *pa,
                      l_float32  *pb,
                      l_int32     debug)
{
l_int32    w, h, hs, i, ystart, yend, ovlap, npts;
l_float32  angle, conf, ycenter, a, b;
BOX       *box;
GPLOT     *gplot;
NUMA      *naskew, *nax, *nay;
PIX       *pix;
PTA       *pta;

    PROCNAME("pixGetLocalSkewAngles");

    if (!pixs || pixGetDepth(pixs) != 1)
        return (NUMA *)ERROR_PTR("pixs undefined or not 1 bpp", procName, NULL);
    if (nslices < 2 || nslices > 20)
        nslices = DEFAULT_SLICES;
    if (redsweep < 1 || redsweep > 8)
        redsweep = DEFAULT_SWEEP_REDUCTION;
    if (redsearch < 1 || redsearch > redsweep)
        redsearch = DEFAULT_BS_REDUCTION;
    if (sweeprange == 0.0)
        sweeprange = DEFAULT_SWEEP_RANGE;
    if (sweepdelta == 0.0)
        sweepdelta = DEFAULT_SWEEP_DELTA;
    if (minbsdelta == 0.0)
        minbsdelta = DEFAULT_MINBS_DELTA;

    pixGetDimensions(pixs, &w, &h, NULL);
    hs = h / nslices;
    ovlap = (l_int32)(OVERLAP_FRACTION * hs);
    pta = ptaCreate(nslices);
    for (i = 0; i < nslices; i++) {
        ystart = L_MAX(0, hs * i - ovlap);
        yend = L_MIN(h - 1, hs * (i + 1) + ovlap);
        ycenter = (ystart + yend) / 2;
        box = boxCreate(0, ystart, w, yend - ystart + 1);
        pix = pixClipRectangle(pixs, box, NULL);
        pixFindSkewSweepAndSearch(pix, &angle, &conf, redsweep, redsearch,
                                  sweeprange, sweepdelta, minbsdelta);
        if (conf > MIN_ALLOWED_CONFIDENCE)
            ptaAddPt(pta, ycenter, angle);
        pixDestroy(&pix);
        boxDestroy(&box);
    }

        /* Do linear least squares fit */
    if ((npts = ptaGetCount(pta)) < 2) {
        ptaDestroy(&pta);
        return (NUMA *)ERROR_PTR("can't fit skew", procName, NULL);
    }
    ptaGetLinearLSF(pta, &a, &b, NULL);
    if (pa) *pa = a;
    if (pb) *pb = b;

        /* Make skew angle array as function of raster line */
    naskew = numaCreate(h);
    for (i = 0; i < h; i++) {
        angle = a * i + b;
        numaAddNumber(naskew, angle);
    }

    if (debug) {
        lept_mkdir("lept/baseline");
        ptaGetArrays(pta, &nax, &nay);
        gplot = gplotCreate("/tmp/lept/baseline/skew", GPLOT_PNG,
                            "skew as fctn of y", "y (in raster lines from top)",
                            "angle (in degrees)");
        gplotAddPlot(gplot, NULL, naskew, GPLOT_POINTS, "linear lsf");
        gplotAddPlot(gplot, nax, nay, GPLOT_POINTS, "actual data pts");
        gplotMakeOutput(gplot);
        gplotDestroy(&gplot);
        numaDestroy(&nax);
        numaDestroy(&nay);
    }

    ptaDestroy(&pta);
    return naskew;
}
Exemple #5
0
int main(int    argc,
         char **argv)
{
char        *filein, *fileout;
l_int32      ret;
l_float32    deg2rad;
l_float32    angle, conf, score;
PIX         *pix, *pixs, *pixd;
static char  mainName[] = "skewtest";

    if (argc != 3)
        return ERROR_INT(" Syntax:  skewtest filein fileout", mainName, 1);
    filein = argv[1];
    fileout = argv[2];

    setLeptDebugOK(1);
    pixd = NULL;
    deg2rad = 3.1415926535 / 180.;

    if ((pixs = pixRead(filein)) == NULL)
        return ERROR_INT("pixs not made", mainName, 1);

        /* Find the skew angle various ways */
    pix = pixConvertTo1(pixs, 130);
    pixWrite("/tmp/binarized.tif", pix, IFF_TIFF_G4);
    pixFindSkew(pix, &angle, &conf);
    fprintf(stderr, "pixFindSkew():\n"
                    "  conf = %5.3f, angle = %7.3f degrees\n", conf, angle);

    pixFindSkewSweepAndSearchScorePivot(pix, &angle, &conf, &score,
                                        SWEEP_REDUCTION2, SEARCH_REDUCTION,
                                        0.0, SWEEP_RANGE2, SWEEP_DELTA2,
                                        SEARCH_MIN_DELTA,
                                        L_SHEAR_ABOUT_CORNER);
    fprintf(stderr, "pixFind...Pivot(about corner):\n"
                    "  conf = %5.3f, angle = %7.3f degrees, score = %f\n",
            conf, angle, score);

    pixFindSkewSweepAndSearchScorePivot(pix, &angle, &conf, &score,
                                        SWEEP_REDUCTION2, SEARCH_REDUCTION,
                                        0.0, SWEEP_RANGE2, SWEEP_DELTA2,
                                        SEARCH_MIN_DELTA,
                                        L_SHEAR_ABOUT_CENTER);
    fprintf(stderr, "pixFind...Pivot(about center):\n"
                    "  conf = %5.3f, angle = %7.3f degrees, score = %f\n",
            conf, angle, score);

        /* Use top-level */
    pixd = pixDeskew(pixs, 0);
    pixWriteImpliedFormat(fileout, pixd, 0, 0);


#if 0
        /* Do it piecemeal; fails if outside the range */
    if (pixGetDepth(pixs) == 1) {
        pixd = pixDeskew(pix, DESKEW_REDUCTION);
        pixWrite(fileout, pixd, IFF_PNG);
    }
    else {
        ret = pixFindSkewSweepAndSearch(pix, &angle, &conf, SWEEP_REDUCTION2,
                                        SEARCH_REDUCTION, SWEEP_RANGE2,
                                        SWEEP_DELTA2, SEARCH_MIN_DELTA);
        if (ret)
            L_WARNING("skew angle not valid\n", mainName);
        else {
            fprintf(stderr, "conf = %5.3f, angle = %7.3f degrees\n",
                    conf, angle);
            if (conf > 2.5)
                pixd = pixRotate(pixs, angle * deg2rad, L_ROTATE_AREA_MAP,
                                 L_BRING_IN_WHITE, 0, 0);
            else
                pixd = pixClone(pixs);
            pixWrite(fileout, pixd, IFF_PNG);
            pixDestroy(&pixd);
        }
    }
#endif

    pixDestroy(&pixs);
    pixDestroy(&pix);
    pixDestroy(&pixd);
    return 0;
}
Exemple #6
0
/*!
 *  deskew()
 *
 *      Input:  pixs
 *              redsearch  (for binary search: reduction factor = 1, 2 or 4)
 *      Return: deskewed pix, or NULL on error
 */
PIX *
deskew(PIX     *pixs,
       l_int32  redsearch)
{
l_float32  angle, conf, deg2rad;
PIX       *pixg;  /* gray version */
PIX       *pixb; /* binary version */
PIX       *pixd;  /* destination image */

    PROCNAME("deskew");

    if (!pixs)
	return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);

    /* Calculate a skew angle.  We may need to make a binary version of the
     * image for this calculation.
     */
    if (pixGetDepth(pixs) != 1) {
	/* FIX ME:  We should probably pick a threshold value with more care.  */
	/* Create a grayscale image if we need one.  */
	if (pixGetDepth(pixs) >= 24) {
	    pixg = pixConvertRGBToGray(pixs, 0.0, 0.0, 0.0);
	} else {
	    pixg = pixs;
	}
	    
	pixb = pixThresholdToBinary(pixg, 127);
	if (pixg != pixs) {
	    pixDestroy(&pixg);
	}
	/* Assert:  We are done with any gray image.  */
    } else {
	pixb = pixs;
    }
    /* Assert: We have a valid binary image.  */
    if (redsearch != 1 && redsearch != 2 && redsearch != 4)
	return (PIX *)ERROR_PTR("redsearch not in {1,2,4}", procName, NULL);

    deg2rad = 3.1415926535 / 180.;
    if (pixFindSkewSweepAndSearch(pixb, &angle, &conf,
				  DEFAULT_SWEEP_REDUCTION, redsearch,
				  DEFAULT_SWEEP_RANGE, DEFAULT_SWEEP_DELTA,
				  DEFAULT_MINBS_DELTA)) {
	pixd = pixClone(pixs);
	goto finish;
    }
	
    if (L_ABS(angle) < MIN_DESKEW_ANGLE || conf < MIN_ALLOWED_CONFIDENCE) {
	pixd = pixClone(pixs);
	goto finish;
    }

    /* If the pixel depth of pixs is 1, we need to use a bit-depth
     * independent rotate instead of the more accurate area mapping rotate.
     */
    if (pixGetDepth(pixs) == 1) {
	if ((pixd = pixRotateShear(pixs, 0, 0, deg2rad * angle, 0xffffff00)) == NULL) {
	    pixd = pixClone(pixs);
	}
    } else {
#if defined(COLOR_ROTATE)
	if ((pixd = pixRotateAMColorFast(pixs, deg2rad * angle)) == NULL) {
	    pixd = pixClone(pixs);
	}
#else
	if ((pixd = pixRotateAM(pixs, deg2rad * angle, 0xffffff00)) == NULL) {
	    pixd = pixClone(pixs);
	}
#endif
    }

   finish:
    if (pixb != pixs) {
	pixDestroy(&pixb);
    }
    return pixd;
}
int main(int    argc,
         char **argv)
{
l_int32      w, h, ystart, yend, y, ymax, ymid, i, window, sum1, sum2, rankx;
l_uint32     uval;
l_float32    ave, rankval, maxvar, variance, norm, conf, angle, radangle;
NUMA        *na1;
PIX         *pix1, *pix2, *pix3, *pix4, *pix5, *pix6, *pix7;
PIXA        *pixa;
static char  mainName[] = "findbinding";

    if (argc != 1)
        return ERROR_INT(" Syntax:  findbinding", mainName, 1);

    lept_mkdir("lept/binding");
    pixa = pixaCreate(0);

    pix1 = pixRead("binding-example.45.jpg");
    pix2 = pixConvertTo8(pix1, 0);

        /* Find the skew angle */
    pix3 = pixConvertTo1(pix2, 150);
    pixFindSkewSweepAndSearch(pix3, &angle, &conf, 2, 2, 7.0, 1.0, 0.01);
    fprintf(stderr, "angle = %f, conf = %f\n", angle, conf);

        /* Deskew, bringing in black pixels at the edges */
    if (L_ABS(angle) < 0.1 || conf < 1.5) {
        pix4 = pixClone(pix2);
    } else {
        radangle = 3.1416 * angle / 180.0;
        pix4 = pixRotate(pix2, radangle, L_ROTATE_AREA_MAP,
                         L_BRING_IN_BLACK, 0, 0);
    }

        /* Rotate 90 degrees to make binding horizontal */
    pix5 = pixRotateOrth(pix4, 1);

        /* Sort pixels in each row by their gray value.
         * Dark pixels on the left, light ones on the right. */
    pix6 = pixRankRowTransform(pix5);
    pixDisplay(pix5, 0, 0);
    pixDisplay(pix6, 550, 0);
    pixaAddPix(pixa, pix4, L_COPY);
    pixaAddPix(pixa, pix5, L_COPY);
    pixaAddPix(pixa, pix6, L_COPY);

        /* Make an a priori estimate of the y-interval within which the
         * binding will be found.  The search will be done in this interval. */
    pixGetDimensions(pix6, &w, &h, NULL);
    ystart = 0.25 * h;
    yend = 0.75 * h;

        /* Choose a very light rank value; close to white, which
         * corresponds to a column in pix6 near the right side. */
    rankval = 0.98;
    rankx = (l_int32)(w * rankval);

        /* Investigate variance in a small window (vertical, size = 5)
         * of the pixels in that column.  These are the %rankval
         * pixels in each raster of pix6.  Find the y-location of
         * maximum variance. */
    window = 5;
    norm = 1.0 / window;
    maxvar = 0.0;
    na1 = numaCreate(0);
    numaSetParameters(na1, ystart, 1);
    for (y = ystart; y <= yend; y++) {
        sum1 = sum2 = 0;
        for (i = 0; i < window; i++) {
            pixGetPixel(pix6, rankx, y + i, &uval);
            sum1 += uval;
            sum2 += uval * uval;
        }
        ave = norm * sum1;
        variance = norm * sum2 - ave * ave;
        numaAddNumber(na1, variance);
        ymid = y + window / 2;
        if (variance > maxvar) {
            maxvar = variance;
            ymax = ymid;
        }
    }

        /* Plot the windowed variance as a function of the y-value
         * of the window location */
    fprintf(stderr, "maxvar = %f, ymax = %d\n", maxvar, ymax);
    gplotSimple1(na1, GPLOT_PNG, "/tmp/lept/binding/root", NULL);
    pix7 = pixRead("/tmp/lept/binding/root.png");
    pixDisplay(pix7, 0, 800);
    pixaAddPix(pixa, pix7, L_COPY);

        /* Superimpose the variance plot over the image.
         * The variance peak is at the binding. */
    pixRenderPlotFromNumaGen(&pix5, na1, L_VERTICAL_LINE, 3, w - 120, 100, 1,
                                                           0x0000ff00);
    pixDisplay(pix5, 1050, 0);
    pixaAddPix(pixa, pix5, L_COPY);

        /* Bundle the results up in a pdf */
    fprintf(stderr, "Writing pdf output file: /tmp/lept/binding/binding.pdf\n");
    pixaConvertToPdf(pixa, 45, 1.0, 0, 0, "Binding locator",
                     "/tmp/lept/binding/binding.pdf");

    pixDestroy(&pix1);
    pixDestroy(&pix2);
    pixDestroy(&pix3);
    pixDestroy(&pix4);
    pixDestroy(&pix5);
    pixDestroy(&pix6);
    pixDestroy(&pix7);
    pixaDestroy(&pixa);
    numaDestroy(&na1);
    return 0;
}
Exemple #8
0
/*!
 *  pixDeskewGeneral()
 *
 *      Input:  pixs  (any depth)
 *              redsweep  (for linear search: reduction factor = 1, 2 or 4;
 *                         use 0 for default)
 *              sweeprange (in degrees in each direction from 0;
 *                          use 0.0 for default)
 *              sweepdelta (in degrees; use 0.0 for default)
 *              redsearch  (for binary search: reduction factor = 1, 2 or 4;
 *                          use 0 for default;)
 *              thresh (for binarizing the image; use 0 for default)
 *              &angle   (<optional return> angle required to deskew,
 *                        in degrees; use NULL to skip)
 *              &conf    (<optional return> conf value is ratio
 *                        of max/min scores; use NULL to skip)
 *      Return: pixd (deskewed pix), or null on error
 *
 *  Notes:
 *      (1) This binarizes if necessary and finds the skew angle.  If the
 *          angle is large enough and there is sufficient confidence,
 *          it returns a deskewed image; otherwise, it returns a clone.
 */
PIX *
pixDeskewGeneral(PIX        *pixs,
                 l_int32     redsweep,
                 l_float32   sweeprange,
                 l_float32   sweepdelta,
                 l_int32     redsearch,
                 l_int32     thresh,
                 l_float32  *pangle,
                 l_float32  *pconf)
{
l_int32    ret, depth;
l_float32  angle, conf, deg2rad;
PIX       *pixb, *pixd;

    PROCNAME("pixDeskewGeneral");

    if (!pixs)
        return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
    if (redsweep == 0)
        redsweep = DEFAULT_SWEEP_REDUCTION;
    else if (redsweep != 1 && redsweep != 2 && redsweep != 4)
        return (PIX *)ERROR_PTR("redsweep not in {1,2,4}", procName, NULL);
    if (sweeprange == 0.0)
        sweeprange = DEFAULT_SWEEP_RANGE;
    if (sweepdelta == 0.0)
        sweepdelta = DEFAULT_SWEEP_DELTA;
    if (redsearch == 0)
        redsearch = DEFAULT_BS_REDUCTION;
    else if (redsearch != 1 && redsearch != 2 && redsearch != 4)
        return (PIX *)ERROR_PTR("redsearch not in {1,2,4}", procName, NULL);
    if (thresh == 0)
        thresh = DEFAULT_BINARY_THRESHOLD;

    deg2rad = 3.1415926535 / 180.;

        /* Binarize if necessary */
    depth = pixGetDepth(pixs);
    if (depth == 1)
        pixb = pixClone(pixs);
    else
        pixb = pixConvertTo1(pixs, thresh);

        /* Use the 1 bpp image to find the skew */
    ret = pixFindSkewSweepAndSearch(pixb, &angle, &conf, redsweep, redsearch,
                                    sweeprange, sweepdelta,
                                    DEFAULT_MINBS_DELTA);
    pixDestroy(&pixb);
    if (pangle)
        *pangle = angle;
    if (pconf)
        *pconf = conf;
    if (ret)
        return pixClone(pixs);

    if (L_ABS(angle) < MIN_DESKEW_ANGLE || conf < MIN_ALLOWED_CONFIDENCE)
        return pixClone(pixs);

    if ((pixd = pixRotate(pixs, deg2rad * angle, L_ROTATE_AREA_MAP,
                          L_BRING_IN_WHITE, 0, 0)) == NULL)
        return pixClone(pixs);
    else
        return pixd;
}
//---------------------------------------------------------------------------
//Уменьшение в 2 раза
//Поиск угла
//Предварительное выпрямление
//Эрозия для удаления тонких линий
//Поиск box для обрезки белых полей изображения
//Обрезка предварительно выпрямленного изображения
//Получение трёх изображений:
//------------------------------------------------------------------------------
PIX* LeptPrepareFile::getClearImage(PIX *pix, l_float32 *angle, l_float32 *conf)
{
	PIX        *pixReduce2, *pixDeskew, *pixCrop, *pixErode;
	PIXA       *pixa1, *pixa2;
	l_int32	   result;
	l_float32  _angle, _conf;
	l_int32    XC_crop, YC_crop, XC_old, YC_old, XC_new, YC_new;


		LEP_LOG("enter");
	SetNULL(7, (void **)&pixReduce2, &pixDeskew, &pixCrop, &pixErode, &pixa1, &pixa2, &boxFirstCrop);
	SetNULL(2, (void **)angle, conf);
	try
	{
		LEP_STR_THROW(!pix, "Изображение не найдено");
		//Уменьшение в 2 раза для ускорения (при DPI = 600)
	if ((pix->xres == 600) && (pix->yres == 600))                 //В дальнейшем переработать потому как в текущем варианте обрабатывает корректно только DPI300 и DPI600
		pixReduce2 = pixReduceBinary2(pix, NULL);
	else
	{
		pixReduce2 = pixCreateTemplateNoInit(pix);
		LEP_STR_THROW(!pixReduce2, "Ошибка в pixReduceBinary2");

		pixCopy(pixReduce2, pix);
	}

		LEP_STR_THROW(!pixReduce2, "Ошибка в pixReduceBinary2");
		//Поиск угла наклона
	result = pixFindSkewSweepAndSearch(pixReduce2, &_angle, &_conf,
						4,    //линеное уменьшение,  DEFAULT_SWEEP_REDUCTION = 4
						2,    //бинарное уменьшение, DEFAULT_BS_REDUCTION = 2
						10,   //максимальный угол поиска
				    		0.1,  //дельта угла поиска
						0.01);//конечная дельта угла поиска, DEFAULT_MINBS_DELTA = 0.01
		LEP_STR_THROW(result != 0, "Ошибка поиска угла");
	if (angle) *angle = _angle;
	if (conf) *conf = _conf;
		//Предварительное выпрямление
	pixDeskew = pixRotate(pixReduce2, 3.1415926535 / 180. * _angle, L_ROTATE_AREA_MAP, L_BRING_IN_WHITE, 0, 0);
		LEP_STR_THROW(!pixDeskew, "Ошибка при предварительном повороте изображения");
		//Эрозия для удаления тонких линий
	pixErode = pixCreateTemplateNoInit(pixDeskew);
		LEP_STR_THROW(!pixErode, "Ошибка в pixCreateTemplateNoInit");
	pixCopy(pixErode, pixDeskew);
	pixErodeBrick(pixErode, pixErode, 3, 3);
		//pixWrite("c:\\temp0_0.tif", pixErode, IFF_TIFF_ZIP);
		//Поиск box для обрезки белых полей изображения
	result = pixClipBoxToForeground(pixErode, NULL, NULL, &boxFirstCrop);
		LEP_STR_THROW(result != 0, "Ошибка при поиске обрезки изображения");
		//Получение точки вокруг которой происходило вращение, с учётом обрезки
		XC_old = pixErode->w / 2;      //точка вращения старого изображения на старом изображении
		YC_old = pixErode->h / 2;
		XC_new = boxFirstCrop->w / 2;       //точка вращения нового изображения на новом изображении
		YC_new = boxFirstCrop->h / 2;
		XC_crop = boxFirstCrop->x + XC_new; //точка вращения нового изображения на старом изображении
		YC_crop = boxFirstCrop->y + YC_new;
		centerXRotate = XC_new - (XC_crop - XC_old);   //точка вращения старого изображения на новом изображении
		centerYRotate = YC_new - (YC_crop - YC_old);
		//Обрезка предварительно выпрямленного изображения
	pixCrop = pixClipRectangle(pixDeskew, boxFirstCrop, NULL);
		LEP_STR_THROW(!pixCrop, "Ошибка при обрезке изображения");
		//pixWrite("c:\\pixCrop.tif", pixCrop, IFF_TIFF_ZIP);
	}catch (string error)
	{
		LEP_ERROR(error);
	};

	pixDestroy(&pixReduce2);
	pixDestroy(&pixDeskew);
	pixDestroy(&pixErode);
		LEP_LOG("exit");
	return pixCrop;

}