main(int argc, char **argv) { l_int32 w; PIX *pixs, *pixt, *pixd; PIXA *pixa; static char mainName[] = "smoothedge_reg"; pixs = pixRead("raggededge.png"); w = pixGetWidth(pixs); pixa = pixaCreate(0); PixAddEdgeData(pixa, pixs, L_FROM_RIGHT, MIN_JUMP, MIN_REVERSAL); PixAddEdgeData(pixa, pixs, L_FROM_LEFT, MIN_JUMP, MIN_REVERSAL); pixt = pixRotateOrth(pixs, 1); PixAddEdgeData(pixa, pixt, L_FROM_BOTTOM, MIN_JUMP, MIN_REVERSAL); PixAddEdgeData(pixa, pixt, L_FROM_TOP, MIN_JUMP, MIN_REVERSAL); pixDestroy(&pixt); pixt = pixRotateOrth(pixs, 2); PixAddEdgeData(pixa, pixt, L_FROM_LEFT, MIN_JUMP, MIN_REVERSAL); PixAddEdgeData(pixa, pixt, L_FROM_RIGHT, MIN_JUMP, MIN_REVERSAL); pixDestroy(&pixt); pixt = pixRotateOrth(pixs, 3); PixAddEdgeData(pixa, pixt, L_FROM_TOP, MIN_JUMP, MIN_REVERSAL); PixAddEdgeData(pixa, pixt, L_FROM_BOTTOM, MIN_JUMP, MIN_REVERSAL); pixDestroy(&pixt); pixDestroy(&pixs); /* Display at 2x scaling */ pixd = pixaDisplayTiledAndScaled(pixa, 32, 2 * (w + 10), 2, 0, 25, 2); pixWrite("/tmp/junkpixd.png", pixd, IFF_PNG); pixDestroy(&pixd); pixaDestroy(&pixa); return 0; }
Pix* pixCorrectOrientation(Pix* pix){ FUNCNAME("pixCorrectOrientation"); l_float32 upConf,leftConf; l_int32 orientDetectResult = pixOrientDetectDwa(pix, &upConf, &leftConf, 0, 0); if(!orientDetectResult){ l_int32 orient; orientDetectResult = makeOrientDecision(upConf, leftConf, 0, 0, &orient, 0); if(!orientDetectResult){ L_INFO("upConf = %.2f, leftConf = %.2f, orientation = %i\n", procName, upConf, leftConf, orient); } switch (orient) { case L_TEXT_ORIENT_UNKNOWN: case L_TEXT_ORIENT_UP: return pixClone(pix); break; case L_TEXT_ORIENT_LEFT: return pixRotateOrth(pix, 1); case L_TEXT_ORIENT_DOWN: return pixRotateOrth(pix, 2); case L_TEXT_ORIENT_RIGHT: return pixRotateOrth(pix, 3); } } return pixClone(pix); }
jlong Java_com_googlecode_leptonica_android_Rotate_nativeRotateOrth(JNIEnv *env, jclass clazz, jlong nativePix, jint quads) { PIX *pixs = (PIX *) nativePix; PIX *pixd; pixd = pixRotateOrth(pixs,(int)quads); return (jlong) pixd; }
/* * Rotate pixs by number of 90 degree cw rotations */ void MainWindow::rotate(int quads) { PIX *pixd; pixd = pixRotateOrth(pixs, quads); pixs = pixCopy(NULL, pixd); setPixToScene(); pixDestroy(&pixd); modified = true; updateTitle(); }
jint Java_com_googlecode_leptonica_android_Rotate_nativeRotateOrth(JNIEnv *env, jclass clazz, jint nativePix, jint quads) { LOGV("%s",__FUNCTION__); PIX *pixs = (PIX *) nativePix; PIX *pixd; pixd = pixRotateOrth(pixs,(int)quads); return (jint) pixd; }
// Helper gets the image of a rectangle, using the block.re_rotation() if // needed to get to the image, and rotating the result back to horizontal // layout. (CJK characters will be on their left sides) The vertical text flag // is set in the returned ImageData if the text was originally vertical, which // can be used to invoke a different CJK recognition engine. The revised_box // is also returned to enable calculation of output bounding boxes. ImageData* Tesseract::GetRectImage(const TBOX& box, const BLOCK& block, int padding, TBOX* revised_box) const { TBOX wbox = box; wbox.pad(padding, padding); *revised_box = wbox; // Number of clockwise 90 degree rotations needed to get back to tesseract // coords from the clipped image. int num_rotations = 0; if (block.re_rotation().y() > 0.0f) num_rotations = 1; else if (block.re_rotation().x() < 0.0f) num_rotations = 2; else if (block.re_rotation().y() < 0.0f) num_rotations = 3; // Handle two cases automatically: 1 the box came from the block, 2 the box // came from a box file, and refers to the image, which the block may not. if (block.bounding_box().major_overlap(*revised_box)) revised_box->rotate(block.re_rotation()); // Now revised_box always refers to the image. // BestPix is never colormapped, but may be of any depth. Pix* pix = BestPix(); int width = pixGetWidth(pix); int height = pixGetHeight(pix); TBOX image_box(0, 0, width, height); // Clip to image bounds; *revised_box &= image_box; if (revised_box->null_box()) return NULL; Box* clip_box = boxCreate(revised_box->left(), height - revised_box->top(), revised_box->width(), revised_box->height()); Pix* box_pix = pixClipRectangle(pix, clip_box, NULL); if (box_pix == NULL) return NULL; boxDestroy(&clip_box); if (num_rotations > 0) { Pix* rot_pix = pixRotateOrth(box_pix, num_rotations); pixDestroy(&box_pix); box_pix = rot_pix; } // Convert sub-8-bit images to 8 bit. int depth = pixGetDepth(box_pix); if (depth < 8) { Pix* grey; grey = pixConvertTo8(box_pix, false); pixDestroy(&box_pix); box_pix = grey; } bool vertical_text = false; if (num_rotations > 0) { // Rotated the clipped revised box back to internal coordinates. FCOORD rotation(block.re_rotation().x(), -block.re_rotation().y()); revised_box->rotate(rotation); if (num_rotations != 2) vertical_text = true; } return new ImageData(vertical_text, box_pix); }
/* * pixFindSkewOrthogonalRange() * * Input: pixs (1 bpp) * &angle (<return> angle required to deskew; in degrees cw) * &conf (<return> confidence given by ratio of max/min score) * redsweep (sweep reduction factor = 1, 2, 4 or 8) * redsearch (binary search reduction factor = 1, 2, 4 or 8; * and must not exceed redsweep) * sweeprange (half the full range in each orthogonal * direction, taken about 0, in degrees) * sweepdelta (angle increment of sweep; in degrees) * minbsdelta (min binary search increment angle; in degrees) * confprior (amount by which confidence of 90 degree rotated * result is reduced when comparing with unrotated * confidence value) * Return: 0 if OK, 1 on error or if angle measurment not valid * * Notes: * (1) This searches for the skew angle, first in the range * [-sweeprange, sweeprange], and then in * [90 - sweeprange, 90 + sweeprange], with angles measured * clockwise. For exploring the full range of possibilities, * suggest using sweeprange = 47.0 degrees, giving some overlap * at 45 and 135 degrees. From these results, and discounting * the the second confidence by %confprior, it selects the * angle for maximal differential variance. If the angle * is larger than pi/4, the angle found after 90 degree rotation * is selected. * (2) The larger the confidence value, the greater the probability * that the proper alignment is given by the angle that maximizes * variance. It should be compared to a threshold, which depends * on the application. Values between 3.0 and 6.0 are common. * (3) Allowing for both portrait and landscape searches is more * difficult, because if the signal from the text lines is weak, * a signal from vertical rules can be larger! * The most difficult documents to deskew have some or all of: * (a) Multiple columns, not aligned * (b) Black lines along the vertical edges * (c) Text from two pages, and at different angles * Rule of thumb for resolution: * (a) If the margins are clean, you can work at 75 ppi, * although 100 ppi is safer. * (b) If there are vertical lines in the margins, do not * work below 150 ppi. The signal from the text lines must * exceed that from the margin lines. * (4) Choosing the %confprior parameter depends on knowing something * about the source of image. However, we're not using * real probabilities here, so its use is qualitative. * If landscape and portrait are equally likely, use * %confprior = 0.0. If the likelihood of portrait (non-rotated) * is 100 times higher than that of landscape, we want to reduce * the chance that we rotate to landscape in a situation where * the landscape signal is accidentally larger than the * portrait signal. To do this use a positive value of * %confprior; say 1.5. */ l_int32 pixFindSkewOrthogonalRange(PIX *pixs, l_float32 *pangle, l_float32 *pconf, l_int32 redsweep, l_int32 redsearch, l_float32 sweeprange, l_float32 sweepdelta, l_float32 minbsdelta, l_float32 confprior) { l_float32 angle1, conf1, score1, angle2, conf2, score2; PIX *pixr; PROCNAME("pixFindSkewOrthogonalRange"); if (pangle) *pangle = 0.0; if (pconf) *pconf = 0.0; if (!pangle || !pconf) return ERROR_INT("&angle and/or &conf not defined", procName, 1); if (!pixs || pixGetDepth(pixs) != 1) return ERROR_INT("pixs not defined or not 1 bpp", procName, 1); pixFindSkewSweepAndSearchScorePivot(pixs, &angle1, &conf1, &score1, redsweep, redsearch, 0.0, sweeprange, sweepdelta, minbsdelta, L_SHEAR_ABOUT_CORNER); pixr = pixRotateOrth(pixs, 1); pixFindSkewSweepAndSearchScorePivot(pixr, &angle2, &conf2, &score2, redsweep, redsearch, 0.0, sweeprange, sweepdelta, minbsdelta, L_SHEAR_ABOUT_CORNER); pixDestroy(&pixr); if (conf1 > conf2 - confprior) { *pangle = angle1; *pconf = conf1; } else { *pangle = -90.0 + angle2; *pconf = conf2; } #if DEBUG_PRINT_ORTH fprintf(stderr, " About 0: angle1 = %7.3f, conf1 = %7.3f, score1 = %f\n", angle1, conf1, score1); fprintf(stderr, " About 90: angle2 = %7.3f, conf2 = %7.3f, score2 = %f\n", angle2, conf2, score2); fprintf(stderr, " Final: angle = %7.3f, conf = %7.3f\n", *pangle, *pconf); #endif /* DEBUG_PRINT_ORTH */ return 0; }
//------------------------------------------------------------------------------ //Ортогональный поворот исходного изображения и обрезка его до //крайней правой нижней части с размером (dX x dY) //------------------------------------------------------------------------------ PIX* LeptPrepareFile::getCroppingRotatePix(PIX *pix, l_int32 degree, l_int32 dX, l_int32 dY) { PIX *pixRotated, *pixCrop; BOX *boxCrop; l_int32 quads; LEP_LOG("enter"); SetNULL(3, (void **)&pixRotated, &pixCrop, &boxCrop); try { LEP_STR_THROW(!pix, "Изображение не найдено"); quads = degree / 90; pixRotated = pixRotateOrth(pix, quads); LEP_STR_THROW(!pixRotated, "Ошибка поворота"); boxCrop = boxCreate(pixRotated->w - dX, pixRotated->h - dY, dX, dY); LEP_STR_THROW(!boxCrop, "Ошибка создания box"); pixCrop = pixClipRectangle(pixRotated, boxCrop, NULL); LEP_STR_THROW(!pixCrop, "Ошибка обрезки"); }catch (string error) { LEP_ERROR(error); }; if (pixRotated) pixDestroy(&pixRotated); if (boxCrop) boxDestroy(&boxCrop); LEP_LOG("exit"); return pixCrop; }
l_int32 main(int argc, char **argv) { l_int32 ret, i, n, similar, x1, y1, val1, val2, val3, val4; l_float32 minave, minave2, maxave, fract; NUMA *na1, *na2, *na3, *na4, *na5, *na6; NUMAA *naa; PIX *pixs, *pix1, *pix2, *pix3, *pix4; L_REGPARAMS *rp; if (regTestSetup(argc, argv, &rp)) return 1; pixs = pixRead("feyn.tif"); pix1 = pixScaleToGray6(pixs); pixDisplayWithTitle(pix1, 100, 600, NULL, rp->display); /* Find averages of min and max along about 120 horizontal lines */ fprintf(stderr, "Ignore the following 12 error messages:\n"); na1 = numaCreate(0); na3 = numaCreate(0); for (y1 = 40; y1 < 575; y1 += 5) { ret = pixMinMaxNearLine(pix1, 20, y1, 400, y1, 5, L_SCAN_BOTH, NULL, NULL, &minave, &maxave); if (!ret) { numaAddNumber(na1, (l_int32)minave); numaAddNumber(na3, (l_int32)maxave); if (rp->display) fprintf(stderr, "y = %d: minave = %d, maxave = %d\n", y1, (l_int32)minave, (l_int32)maxave); } } /* Find averages along about 120 vertical lines. We've rotated * the image by 90 degrees, so the results should be nearly * identical to the first set. Also generate a single-sided * scan (L_SCAN_NEGATIVE) for comparison with the double-sided scans. */ pix2 = pixRotateOrth(pix1, 3); pixDisplayWithTitle(pix2, 600, 600, NULL, rp->display); na2 = numaCreate(0); na4 = numaCreate(0); na5 = numaCreate(0); for (x1 = 40; x1 < 575; x1 += 5) { ret = pixMinMaxNearLine(pix2, x1, 20, x1, 400, 5, L_SCAN_BOTH, NULL, NULL, &minave, &maxave); pixMinMaxNearLine(pix2, x1, 20, x1, 400, 5, L_SCAN_NEGATIVE, NULL, NULL, &minave2, NULL); if (!ret) { numaAddNumber(na2, (l_int32)minave); numaAddNumber(na4, (l_int32)maxave); numaAddNumber(na5, (l_int32)minave2); if (rp->display) fprintf(stderr, "x = %d: minave = %d, minave2 = %d, maxave = %d\n", x1, (l_int32)minave, (l_int32)minave2, (l_int32)maxave); } } numaSimilar(na1, na2, 3.0, &similar); /* should be TRUE */ regTestCompareValues(rp, similar, 1, 0); /* 0 */ numaSimilar(na3, na4, 1.0, &similar); /* should be TRUE */ regTestCompareValues(rp, similar, 1, 0); /* 1 */ numaWrite("/tmp/lept/regout/na1.na", na1); numaWrite("/tmp/lept/regout/na2.na", na2); numaWrite("/tmp/lept/regout/na3.na", na3); numaWrite("/tmp/lept/regout/na4.na", na4); numaWrite("/tmp/lept/regout/na5.na", na5); regTestCheckFile(rp, "/tmp/lept/regout/na1.na"); /* 2 */ regTestCheckFile(rp, "/tmp/lept/regout/na2.na"); /* 3 */ regTestCheckFile(rp, "/tmp/lept/regout/na3.na"); /* 4 */ regTestCheckFile(rp, "/tmp/lept/regout/na4.na"); /* 5 */ regTestCheckFile(rp, "/tmp/lept/regout/na5.na"); /* 6 */ /* Plot the average minimums for the 3 cases */ naa = numaaCreate(3); numaaAddNuma(naa, na1, L_INSERT); /* portrait, double-sided */ numaaAddNuma(naa, na2, L_INSERT); /* landscape, double-sided */ numaaAddNuma(naa, na5, L_INSERT); /* landscape, single-sided */ gplotSimpleN(naa, GPLOT_PNG, "/tmp/lept/regout/nearline", "Average minimums along lines"); #if 0 #ifndef _WIN32 sleep(1); #else Sleep(1000); #endif /* _WIN32 */ #endif pix3 = pixRead("/tmp/lept/regout/nearline.png"); regTestWritePixAndCheck(rp, pix3, IFF_PNG); /* 7 */ pixDisplayWithTitle(pix3, 100, 100, NULL, rp->display); if (rp->display) { n = numaGetCount(na3); for (i = 0; i < n; i++) { numaGetIValue(na1, i, &val1); numaGetIValue(na2, i, &val2); numaGetIValue(na3, i, &val3); numaGetIValue(na4, i, &val4); fprintf(stderr, "val1 = %d, val2 = %d, diff = %d; " "val3 = %d, val4 = %d, diff = %d\n", val1, val2, L_ABS(val1 - val2), val3, val4, L_ABS(val3 - val4)); } } numaaDestroy(&naa); numaDestroy(&na3); numaDestroy(&na4); /* Plot minima along a single line, with different distances */ pixMinMaxNearLine(pix1, 20, 200, 400, 200, 2, L_SCAN_BOTH, &na1, NULL, NULL, NULL); pixMinMaxNearLine(pix1, 20, 200, 400, 200, 5, L_SCAN_BOTH, &na2, NULL, NULL, NULL); pixMinMaxNearLine(pix1, 20, 200, 400, 200, 15, L_SCAN_BOTH, &na3, NULL, NULL, NULL); numaWrite("/tmp/lept/regout/na6.na", na1); regTestCheckFile(rp, "/tmp/lept/regout/na6.na"); /* 8 */ n = numaGetCount(na1); fract = 100.0 / n; na4 = numaTransform(na1, 0.0, fract); na5 = numaTransform(na2, 0.0, fract); na6 = numaTransform(na3, 0.0, fract); numaDestroy(&na1); numaDestroy(&na2); numaDestroy(&na3); na1 = numaUniformSampling(na4, 100); na2 = numaUniformSampling(na5, 100); na3 = numaUniformSampling(na6, 100); naa = numaaCreate(3); numaaAddNuma(naa, na1, L_INSERT); numaaAddNuma(naa, na2, L_INSERT); numaaAddNuma(naa, na3, L_INSERT); gplotSimpleN(naa, GPLOT_PNG, "/tmp/lept/regout/nearline2", "Min along line"); pix4 = pixRead("/tmp/lept/regout/nearline2.png"); regTestWritePixAndCheck(rp, pix4, IFF_PNG); /* 9 */ pixDisplayWithTitle(pix4, 800, 100, NULL, rp->display); numaaDestroy(&naa); numaDestroy(&na4); numaDestroy(&na5); numaDestroy(&na6); pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); pixDestroy(&pix4); pixDestroy(&pixs); return regTestCleanup(rp); }
/* * Test both vertical and horizontal projections on this image. * We rotate the image by 90 degrees for the horizontal projection, * so that the two results should be identical. */ void TestProjection(L_REGPARAMS *rp, PIX *pixs) { l_int32 outline; NUMA *na1, *na2, *na3, *na4, *na5, *na6; NUMA *na7, *na8, *na9, *na10, *na11, *na12; PIX *pixd, *pixt; PIXA *pixa; outline = 2; pixColumnStats(pixs, &na1, &na3, &na5, &na7, &na9, &na11); pixd = pixRotateOrth(pixs, 1); pixRowStats(pixd, &na2, &na4, &na6, &na8, &na10, &na12); /* The png plot files are written to "/tmp/proj.0.png", etc. * These temp files are overwritten each time this * function is called. */ gplotSimple1(na1, GPLOT_PNG, "/tmp/proj.0", "Mean value"); gplotSimple1(na2, GPLOT_PNG, "/tmp/proj.1", "Mean value"); gplotSimple1(na3, GPLOT_PNG, "/tmp/proj.2", "Median value"); gplotSimple1(na4, GPLOT_PNG, "/tmp/proj.3", "Median value"); gplotSimple1(na5, GPLOT_PNG, "/tmp/proj.4", "Mode value"); gplotSimple1(na6, GPLOT_PNG, "/tmp/proj.5", "Mode value"); gplotSimple1(na7, GPLOT_PNG, "/tmp/proj.6", "Mode count"); gplotSimple1(na8, GPLOT_PNG, "/tmp/proj.7", "Mode count"); gplotSimple1(na9, GPLOT_PNG, "/tmp/proj.8", "Variance"); gplotSimple1(na10, GPLOT_PNG, "/tmp/proj.9", "Variance"); gplotSimple1(na11, GPLOT_PNG, "/tmp/proj.10", "Square Root Variance"); gplotSimple1(na12, GPLOT_PNG, "/tmp/proj.11", "Square Root Variance"); #ifndef _WIN32 sleep(1); #else Sleep(1000); #endif /* _WIN32 */ /* Each of the 12 plot files is read into a pix and then: * (1) saved into a pixa for display * (2) saved as a golden file (generate stage) or compared * to the existing golden file (testing stage) */ pixa = pixaCreate(13); pixSaveTiledOutline(pixs, pixa, 1, 1, 30, outline, 32); pixt = pixRead("/tmp/proj.0.png"); regTestWritePixAndCheck(rp, pixt, IFF_PNG); /* 0 */ pixSaveTiledOutline(pixt, pixa, 1, 1, 30, outline, 32); pixDestroy(&pixt); pixt = pixRead("/tmp/proj.1.png"); regTestWritePixAndCheck(rp, pixt, IFF_PNG); /* 1 */ pixSaveTiledOutline(pixt, pixa, 1, 0, 30, outline, 32); pixDestroy(&pixt); pixt = pixRead("/tmp/proj.2.png"); regTestWritePixAndCheck(rp, pixt, IFF_PNG); /* 2 */ pixSaveTiledOutline(pixt, pixa, 1, 1, 30, outline, 32); pixDestroy(&pixt); pixt = pixRead("/tmp/proj.3.png"); regTestWritePixAndCheck(rp, pixt, IFF_PNG); /* 3 */ pixSaveTiledOutline(pixt, pixa, 1, 0, 30, outline, 32); pixDestroy(&pixt); pixt = pixRead("/tmp/proj.4.png"); regTestWritePixAndCheck(rp, pixt, IFF_PNG); /* 4 */ pixSaveTiledOutline(pixt, pixa, 1, 1, 30, outline, 32); pixDestroy(&pixt); pixt = pixRead("/tmp/proj.5.png"); regTestWritePixAndCheck(rp, pixt, IFF_PNG); /* 5 */ pixSaveTiledOutline(pixt, pixa, 1, 0, 30, outline, 32); pixDestroy(&pixt); pixt = pixRead("/tmp/proj.6.png"); regTestWritePixAndCheck(rp, pixt, IFF_PNG); /* 6 */ pixSaveTiledOutline(pixt, pixa, 1, 1, 30, outline, 32); pixDestroy(&pixt); pixt = pixRead("/tmp/proj.7.png"); regTestWritePixAndCheck(rp, pixt, IFF_PNG); /* 7 */ pixSaveTiledOutline(pixt, pixa, 1, 0, 30, outline, 32); pixDestroy(&pixt); pixt = pixRead("/tmp/proj.8.png"); regTestWritePixAndCheck(rp, pixt, IFF_PNG); /* 8 */ pixSaveTiledOutline(pixt, pixa, 1, 1, 30, outline, 32); pixDestroy(&pixt); pixt = pixRead("/tmp/proj.9.png"); regTestWritePixAndCheck(rp, pixt, IFF_PNG); /* 9 */ pixSaveTiledOutline(pixt, pixa, 1, 0, 30, outline, 32); pixDestroy(&pixt); pixt = pixRead("/tmp/proj.10.png"); regTestWritePixAndCheck(rp, pixt, IFF_PNG); /* 10 */ pixSaveTiledOutline(pixt, pixa, 1, 1, 30, outline, 32); pixDestroy(&pixt); pixt = pixRead("/tmp/proj.11.png"); regTestWritePixAndCheck(rp, pixt, IFF_PNG); /* 11 */ pixSaveTiledOutline(pixt, pixa, 1, 0, 30, outline, 32); pixDestroy(&pixt); /* The pixa is composited into a pix and 'goldened'/tested */ pixt = pixaDisplay(pixa, 0, 0); regTestWritePixAndCheck(rp, pixt, IFF_PNG); /* 12 */ pixDisplayWithTitle(pixt, 100, 0, NULL, rp->display); pixDestroy(&pixt); pixaDestroy(&pixa); /* The 12 plot files are tested in pairs for identity */ regTestCompareFiles(rp, 0, 1); regTestCompareFiles(rp, 2, 3); regTestCompareFiles(rp, 4, 5); regTestCompareFiles(rp, 6, 7); regTestCompareFiles(rp, 8, 9); regTestCompareFiles(rp, 10, 11); pixDestroy(&pixd); numaDestroy(&na1); numaDestroy(&na2); numaDestroy(&na3); numaDestroy(&na4); numaDestroy(&na5); numaDestroy(&na6); numaDestroy(&na7); numaDestroy(&na8); numaDestroy(&na9); numaDestroy(&na10); numaDestroy(&na11); numaDestroy(&na12); return; }
int main(int argc, char **argv) { FPIX *fpix1, *fpix2, *fpix3, *fpix4; PIX *pix1, *pix2, *pix3, *pix4, *pix5, *pix6, *pix7, *pix8; L_REGPARAMS *rp; if (regTestSetup(argc, argv, &rp)) return 1; /* Test orthogonal rotations */ pix1 = pixRead("marge.jpg"); pix2 = pixConvertTo8(pix1, 0); fpix1 = pixConvertToFPix(pix2, 1); fpix2 = fpixRotateOrth(fpix1, 1); pix3 = fpixConvertToPix(fpix2, 8, L_CLIP_TO_ZERO, 0); pix4 = pixRotateOrth(pix2, 1); regTestComparePix(rp, pix3, pix4); /* 0 */ pixDisplayWithTitle(pix3, 100, 100, NULL, rp->display); fpix3 = fpixRotateOrth(fpix1, 2); pix5 = fpixConvertToPix(fpix3, 8, L_CLIP_TO_ZERO, 0); pix6 = pixRotateOrth(pix2, 2); regTestComparePix(rp, pix5, pix6); /* 1 */ pixDisplayWithTitle(pix5, 560, 100, NULL, rp->display); fpix4 = fpixRotateOrth(fpix1, 3); pix7 = fpixConvertToPix(fpix4, 8, L_CLIP_TO_ZERO, 0); pix8 = pixRotateOrth(pix2, 3); regTestComparePix(rp, pix7, pix8); /* 2 */ pixDisplayWithTitle(pix7, 1170, 100, NULL, rp->display); pixDisplayWithTitle(pix2, 560, 580, NULL, rp->display); pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); pixDestroy(&pix4); pixDestroy(&pix5); pixDestroy(&pix6); pixDestroy(&pix7); pixDestroy(&pix8); fpixDestroy(&fpix1); fpixDestroy(&fpix2); fpixDestroy(&fpix3); fpixDestroy(&fpix4); /* Test adding various borders */ pix1 = pixRead("marge.jpg"); pix2 = pixConvertTo8(pix1, 0); fpix1 = pixConvertToFPix(pix2, 1); fpix2 = fpixAddMirroredBorder(fpix1, 21, 21, 25, 25); pix3 = fpixConvertToPix(fpix2, 8, L_CLIP_TO_ZERO, 0); pix4 = pixAddMirroredBorder(pix2, 21, 21, 25, 25); regTestComparePix(rp, pix3, pix4); /* 3 */ pixDisplayWithTitle(pix3, 100, 1000, NULL, rp->display); fpix3 = fpixAddContinuedBorder(fpix1, 21, 21, 25, 25); pix5 = fpixConvertToPix(fpix3, 8, L_CLIP_TO_ZERO, 0); pix6 = pixAddContinuedBorder(pix2, 21, 21, 25, 25); regTestComparePix(rp, pix5, pix6); /* 4 */ pixDisplayWithTitle(pix5, 750, 1000, NULL, rp->display); pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); pixDestroy(&pix4); pixDestroy(&pix5); pixDestroy(&pix6); fpixDestroy(&fpix1); fpixDestroy(&fpix2); fpixDestroy(&fpix3); return regTestCleanup(rp); }
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; }
/*! * \brief pixOrientCorrect() * * \param[in] pixs 1 bpp, deskewed, English 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 * \param[out] pleftconf [optional] ; use NULL to skip * \param[out] protation [optional] ; use NULL to skip * \param[in] debug 1 for debug output; 0 otherwise * \return pixd may be rotated by 90, 180 or 270; null on error * * <pre> * Notes: * (1) Simple top-level function to detect if Roman text is in * reading orientation, and to rotate the image accordingly if not. * (2) Returns a copy if no rotation is needed. * (3) See notes for pixOrientDetect() and pixOrientDecision(). * Use 0.0 for default values for %minupconf and %minratio * (4) Optional output of intermediate confidence results and * the rotation performed on pixs. * </pre> */ PIX * pixOrientCorrect(PIX *pixs, l_float32 minupconf, l_float32 minratio, l_float32 *pupconf, l_float32 *pleftconf, l_int32 *protation, l_int32 debug) { l_int32 orient; l_float32 upconf, leftconf; PIX *pix1; PROCNAME("pixOrientCorrect"); if (!pixs || pixGetDepth(pixs) != 1) return (PIX *)ERROR_PTR("pixs undefined or not 1 bpp", procName, NULL); lept_mkdir("lept/orient"); /* Get confidences for orientation */ pixUpDownDetectDwa(pixs, &upconf, 0, debug); pix1 = pixRotate90(pixs, 1); pixUpDownDetectDwa(pix1, &leftconf, 0, debug); pixDestroy(&pix1); if (pupconf) *pupconf = upconf; if (pleftconf) *pleftconf = leftconf; /* Decide what to do */ makeOrientDecision(upconf,leftconf, minupconf, minratio, &orient, debug); /* Do it */ switch (orient) { case L_TEXT_ORIENT_UNKNOWN: L_INFO("text orientation not determined; no rotation\n", procName); if (protation) *protation = 0; return pixCopy(NULL, pixs); break; case L_TEXT_ORIENT_UP: L_INFO("text is oriented up; no rotation\n", procName); if (protation) *protation = 0; return pixCopy(NULL, pixs); break; case L_TEXT_ORIENT_LEFT: L_INFO("landscape; text oriented left; 90 cw rotation\n", procName); if (protation) *protation = 90; return pixRotateOrth(pixs, 1); break; case L_TEXT_ORIENT_DOWN: L_INFO("text oriented down; 180 cw rotation\n", procName); if (protation) *protation = 180; return pixRotateOrth(pixs, 2); break; case L_TEXT_ORIENT_RIGHT: L_INFO("landscape; text oriented right; 270 cw rotation\n", procName); if (protation) *protation = 270; return pixRotateOrth(pixs, 3); break; default: L_ERROR("invalid orient flag!\n", procName); return pixCopy(NULL, pixs); } }
/*! * pixFindNormalizedSquareSum() * * Input: pixs * &hratio (<optional return> ratio of normalized horiz square sum * to result if the pixel distribution were uniform) * &vratio (<optional return> ratio of normalized vert square sum * to result if the pixel distribution were uniform) * &fract (<optional return> ratio of fg pixels to total pixels) * Return: 0 if OK, 1 on error or if there are no fg pixels * * Notes: * (1) Let the image have h scanlines and N fg pixels. * If the pixels were uniformly distributed on scanlines, * the sum of squares of fg pixels on each scanline would be * h * (N / h)^2. However, if the pixels are not uniformly * distributed (e.g., for text), the sum of squares of fg * pixels will be larger. We return in hratio and vratio the * ratio of these two values. * (2) If there are no fg pixels, hratio and vratio are returned as 0.0. */ l_int32 pixFindNormalizedSquareSum(PIX *pixs, l_float32 *phratio, l_float32 *pvratio, l_float32 *pfract) { l_int32 i, w, h, empty; l_float32 sum, sumsq, uniform, val; NUMA *na; PIX *pixt; PROCNAME("pixFindNormalizedSquareSum"); if (!pixs || pixGetDepth(pixs) != 1) return ERROR_INT("pixs not defined or not 1 bpp", procName, 1); pixGetDimensions(pixs, &w, &h, NULL); if (!phratio && !pvratio) return ERROR_INT("nothing to do", procName, 1); if (phratio) *phratio = 0.0; if (pvratio) *pvratio = 0.0; empty = 0; if (phratio) { na = pixCountPixelsByRow(pixs, NULL); numaGetSum(na, &sum); /* fg pixels */ if (pfract) *pfract = sum / (l_float32)(w * h); if (sum != 0.0) { uniform = sum * sum / h; /* h*(sum / h)^2 */ sumsq = 0.0; for (i = 0; i < h; i++) { numaGetFValue(na, i, &val); sumsq += val * val; } *phratio = sumsq / uniform; } else { empty = 1; } numaDestroy(&na); } if (pvratio) { if (empty == 1) return 1; pixt = pixRotateOrth(pixs, 1); na = pixCountPixelsByRow(pixt, NULL); numaGetSum(na, &sum); if (pfract) *pfract = sum / (l_float32)(w * h); if (sum != 0.0) { uniform = sum * sum / w; sumsq = 0.0; for (i = 0; i < w; i++) { numaGetFValue(na, i, &val); sumsq += val * val; } *pvratio = sumsq / uniform; } else { empty = 1; } pixDestroy(&pixt); numaDestroy(&na); } return empty; }
main(int argc, char **argv) { l_int32 i, j, w, h; l_int32 minsum[5] = { 2, 40, 50, 50, 70}; l_int32 skipdist[5] = { 5, 5, 10, 10, 30}; l_int32 delta[5] = { 2, 10, 10, 25, 40}; l_int32 maxbg[5] = {10, 15, 10, 20, 40}; BOX *box1, *box2, *box3, *box4; BOXA *boxa; PIX *pixs, *pixc, *pixt, *pixd, *pix32; PIXA *pixas, *pixad; L_REGPARAMS *rp; if (regTestSetup(argc, argv, &rp)) return 1; /* Generate and save 1 bpp masks */ pixas = pixaCreate(0); pixs = pixCreate(300, 250, 1); pixSetAll(pixs); box1 = boxCreate(50, 0, 140, 25); box2 = boxCreate(120, 100, 100, 25); box3 = boxCreate(75, 170, 80, 20); box4 = boxCreate(150, 80, 25, 70); pixClearInRect(pixs, box1); pixaAddPix(pixas, pixs, L_COPY); pixt = pixRotateOrth(pixs, 1); pixaAddPix(pixas, pixt, L_INSERT); pixClearInRect(pixs, box2); pixaAddPix(pixas, pixs, L_COPY); pixt = pixRotateOrth(pixs, 1); pixaAddPix(pixas, pixt, L_INSERT); pixClearInRect(pixs, box3); pixaAddPix(pixas, pixs, L_COPY); pixt = pixRotateOrth(pixs, 1); pixaAddPix(pixas, pixt, L_INSERT); pixClearInRect(pixs, box4); pixaAddPix(pixas, pixs, L_COPY); pixt = pixRotateOrth(pixs, 1); pixaAddPix(pixas, pixt, L_INSERT); boxDestroy(&box1); boxDestroy(&box2); boxDestroy(&box3); boxDestroy(&box4); pixDestroy(&pixs); /* Do 5 splittings on each of the 8 masks */ pixad = pixaCreate(0); for (j = 0; j < 8; j++) { pixt = pixaGetPix(pixas, j, L_CLONE); pixGetDimensions(pixt, &w, &h, NULL); pix32 = pixCreate(w, h, 32); pixSetAll(pix32); pixPaintThroughMask(pix32, pixt, 0, 0, 0xc0c0c000); pixSaveTiled(pix32, pixad, 1, 1, 30, 32); for (i = 0; i < 5; i++) { pixc = pixCopy(NULL, pix32); boxa = pixSplitComponentIntoBoxa(pixt, NULL, minsum[i], skipdist[i], delta[i], maxbg[i], 0, 1); /* boxaWriteStream(stderr, boxa); */ pixd = pixBlendBoxaRandom(pixc, boxa, 0.4); pixRenderBoxaArb(pixd, boxa, 2, 255, 0, 0); pixSaveTiled(pixd, pixad, 1, 0, 30, 32); pixDestroy(&pixd); pixDestroy(&pixc); boxaDestroy(&boxa); } pixDestroy(&pixt); pixDestroy(&pix32); } /* Display results */ pixd = pixaDisplay(pixad, 0, 0); regTestWritePixAndCheck(rp, pixd, IFF_PNG); /* 0 */ pixDisplayWithTitle(pixd, 100, 100, NULL, rp->display); pixDestroy(&pixd); pixaDestroy(&pixad); /* Put the 8 masks all together, and split 5 ways */ pixad = pixaCreate(0); pixs = pixaDisplayOnLattice(pixas, 325, 325); pixGetDimensions(pixs, &w, &h, NULL); pix32 = pixCreate(w, h, 32); pixSetAll(pix32); pixPaintThroughMask(pix32, pixs, 0, 0, 0xc0c0c000); pixSaveTiled(pix32, pixad, 1, 1, 30, 32); for (i = 0; i < 5; i++) { pixc = pixCopy(NULL, pix32); boxa = pixSplitIntoBoxa(pixs, minsum[i], skipdist[i], delta[i], maxbg[i], 0, 1); /* boxaWriteStream(stderr, boxa); */ pixd = pixBlendBoxaRandom(pixc, boxa, 0.4); pixRenderBoxaArb(pixd, boxa, 2, 255, 0, 0); pixSaveTiled(pixd, pixad, 1, 0, 30, 32); pixDestroy(&pixd); pixDestroy(&pixc); boxaDestroy(&boxa); } pixDestroy(&pix32); pixDestroy(&pixs); /* Display results */ pixd = pixaDisplay(pixad, 0, 0); regTestWritePixAndCheck(rp, pixd, IFF_PNG); /* 1 */ pixDisplayWithTitle(pixd, 600, 100, NULL, rp->display); pixDestroy(&pixd); pixaDestroy(&pixad); pixaDestroy(&pixas); regTestCleanup(rp); return 0; }
//--------------------------------------------------------------------------- //Поиск основной надписи в указанном файле //findstr - поля для поиска //border - Толщина краёв которая будет очищена в найденных PIX //trustratio - коэф.надёжности //tolerance - предельное отклонение //outTrustRatio - полученное значение с чем сравнивался trustratio //расширеное описание параметров см.boxaGetLinkedBox //--------------------------------------------------------------------------- l_int32 LeptonicaProccesingDrawing::findFrameInFile(string findstr, l_int32 border, l_float32 trustratio, l_int32 tolerance, l_float32 &outTrustRatio) { BOXA *frame; BOX *box; PIX *pixC, *pixR, *pixRbig, *pixTemp; l_int32 result; l_int32 fRes; l_int32 angOtho; l_int32 scale; LEP_LOG("enter"); SetNULL(1, (void**)&frame); result = 1; findFrame.setTolerance(tolerance); findFrame.setTrustRatio(trustratio); try { LEP_STR_THROW(!prepareFile.isLastProcessingOK(), "Файл изображения не инициализирован"); //Разбор строки с описанием полей ParseFieldsStr(findstr, Fields); LEP_STR_THROW(Fields.size() == 0, "Поля не найдены"); //Поиск рамки для каждого изображения pixC = prepareFile.pixRotate000; frame = findFrame.findFrame(pixC, Fields); angOtho = 0; if (!frame) { pixC = prepareFile.pixRotate090; frame = findFrame.findFrame(pixC, Fields); angOtho = 90; } if (!frame) { pixC = prepareFile.pixRotate180; frame = findFrame.findFrame(pixC, Fields); angOtho = 180;} if (!frame) { pixC = prepareFile.pixRotate270; frame = findFrame.findFrame(pixC, Fields); angOtho = 270;} if (frame) { for (int i = 0; i < frame->n; i++) { //пересчёт координат из точки отсчёта обрезанных скоректированных изображений //в точку отсчёта уменьшенного и повернутого изначального изображения //иногда реальная ширина изображения может быть меньше ширины эталона wSmallPix (hSmallPix) //(wSmallPix < pixC->w) ? wSmallPix : pixC->w, удалить //(hSmallPix < pixC->h) ? hSmallPix : pixC->h, удалить box = prepareFile.boxReCalcPosition( frame->box[i], pixC->w, pixC->h, angOtho); if ((prepareFile.pix->xres == 600) && (prepareFile.pix->yres == 600)) scale = 2; else scale = 1; pixTemp = pixGetFromBoxAndAngle(prepareFile.pix, box, -prepareFile.angle, scale); pixRbig = pixRotateOrth(pixTemp, angOtho / 90); boxDestroy(&box); pixDestroy(&pixTemp); pixR = pixClipRectangle(pixC, frame->box[i], NULL); //pixDisplay(pixRbig, 800,800); if (pixRbig) { Fields[i].FieldPIXbig = pixRemoveBorder(pixRbig, border); pixDestroy(&pixRbig); } else LEP_LOG("Ошибка получения поля (big)"); if (pixR) { Fields[i].FieldPIX = pixRemoveBorder(pixR, border); pixDestroy(&pixR); } else LEP_LOG("Ошибка получения поля"); } result = 0; } }catch (string error) { LEP_ERROR(error); }; boxaDestroy(&frame); outTrustRatio = findFrame.getLastOutTrustRatio(); LEP_LOG("exit"); return result; /*PIXA *pixa2 = pixClipRectangles(clearPix, ramka); PIX *pix2 = pixaDisplay(pixa2, 11500, 8600); pix2 = pixMorphSequence(pix2, "d5.5", 0); pixWrite("c:\\pix2.tif", pix2, IFF_TIFF_ZIP); pixDestroy(&pix2); */ //pixDisplay(GetPixFromSTR("Наименование"), 800,800); //pixDisplay(GetPixFromSTR("Обозначение"), 800,800); //pixDisplay(GetPixFromSTR("None4"), 800,800); //pixWrite("c:\\2.tif", pix, IFF_TIFF_ZIP); }
l_int32 main(int argc, char **argv) { l_float32 dist, distr, distg, distb; NUMA *na1, *na2; PIX *pix1, *pix2, *pix3, *pix4, *pix5, *pix6; L_REGPARAMS *rp; if (regTestSetup(argc, argv, &rp)) return 1; /* Test earthmover distance: extreme DC */ fprintf(stderr, "Test earthmover distance\n"); na1 = numaMakeConstant(0, 201); na2 = numaMakeConstant(0, 201); numaSetValue(na1, 0, 100); numaSetValue(na2, 200, 100); numaEarthMoverDistance(na1, na2, &dist); regTestCompareValues(rp, 200.0, dist, 0.0001); /* 0 */ numaDestroy(&na1); numaDestroy(&na2); /* Test connected component labelling */ fprintf(stderr, "Test c.c. labelling\n"); pix1 = pixRead("feyn-fract.tif"); pix2 = pixConnCompTransform(pix1, 8, 8); regTestWritePixAndCheck(rp, pix2, IFF_PNG); /* 1 */ pixDisplayWithTitle(pix2, 0, 0, NULL, rp->display); pix3 = pixConnCompTransform(pix1, 8, 16); pix4 = pixConvert16To8(pix3, L_LS_BYTE); regTestCompareSimilarPix(rp, pix2, pix4, 3, 0.001, 0); /* 2 */ pixDestroy(&pix2); pixDestroy(&pix3); pixDestroy(&pix4); /* Test connected component area labelling */ fprintf(stderr, "Test c.c. area labelling\n"); pix2 = pixConnCompAreaTransform(pix1, 8); pix3 = pixConvert16To8(pix2, L_CLIP_TO_255); regTestWritePixAndCheck(rp, pix3, IFF_PNG); /* 3 */ pixDisplayWithTitle(pix3, 0, 350, NULL, rp->display); pixMultConstantGray(pix2, 0.3); pix4 = pixConvert16To8(pix2, L_LS_BYTE); regTestWritePixAndCheck(rp, pix4, IFF_PNG); /* 4 */ pixDisplayWithTitle(pix4, 0, 700, NULL, rp->display); pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); pixDestroy(&pix4); /* Test color transform: 4-fold symmetry */ fprintf(stderr, "Test color transform: 4-fold symmetry\n"); pix1 = pixRead("form1.tif"); pix2 = pixRotateOrth(pix1, 1); pix3 = pixRotateOrth(pix1, 2); pix4 = pixRotateOrth(pix1, 3); pix5 = pixLocToColorTransform(pix1); regTestWritePixAndCheck(rp, pix5, IFF_PNG); /* 5 */ pix6 = pixLocToColorTransform(pix2); regTestWritePixAndCheck(rp, pix6, IFF_PNG); /* 6 */ FindEMD(pix5, pix6, &distr, &distg, &distb); regTestCompareValues(rp, 0.12, distr, 0.01); /* 7 */ regTestCompareValues(rp, 0.00, distg, 0.01); /* 8 */ regTestCompareValues(rp, 0.00, distb, 0.01); /* 9 */ fprintf(stderr, "90 deg rotation: dist (r,g,b) = (%5.2f, %5.2f, %5.2f)\n", distr, distg, distb); pixDestroy(&pix6); pix6 = pixLocToColorTransform(pix3); regTestWritePixAndCheck(rp, pix6, IFF_PNG); /* 10 */ FindEMD(pix5, pix6, &distr, &distg, &distb); regTestCompareValues(rp, 0.12, distr, 0.01); /* 11 */ regTestCompareValues(rp, 0.09, distg, 0.01); /* 12 */ regTestCompareValues(rp, 0.00, distb, 0.01); /* 13 */ fprintf(stderr, "180 deg rotation: dist (r,g,b) = (%5.2f, %5.2f, %5.2f)\n", distr, distg, distb); pixDestroy(&pix6); pix6 = pixLocToColorTransform(pix4); regTestWritePixAndCheck(rp, pix6, IFF_PNG); /* 14 */ FindEMD(pix5, pix6, &distr, &distg, &distb); regTestCompareValues(rp, 0.00, distr, 0.01); /* 15 */ regTestCompareValues(rp, 0.09, distg, 0.01); /* 16 */ regTestCompareValues(rp, 0.00, distb, 0.01); /* 17 */ fprintf(stderr, "270 deg rotation: dist (r,g,b) = (%5.2f, %5.2f, %5.2f)\n", distr, distg, distb); pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); pixDestroy(&pix4); pixDestroy(&pix5); pixDestroy(&pix6); /* Test color transform: same form with translation */ fprintf(stderr, "Test color transform with translation\n"); pix1 = pixRead("form1.tif"); pix2 = pixLocToColorTransform(pix1); pixDisplayWithTitle(pix2, 0, 0, NULL, rp->display); pixTranslate(pix1, pix1, 10, 10, L_BRING_IN_WHITE); pix3 = pixLocToColorTransform(pix1); regTestWritePixAndCheck(rp, pix3, IFF_PNG); /* 18 */ pixDisplayWithTitle(pix3, 470, 0, NULL, rp->display); FindEMD(pix2, pix3, &distr, &distg, &distb); regTestCompareValues(rp, 1.76, distr, 0.01); /* 19 */ regTestCompareValues(rp, 2.65, distg, 0.01); /* 20 */ regTestCompareValues(rp, 2.03, distb, 0.01); /* 21 */ fprintf(stderr, "Translation dist (r,g,b) = (%5.2f, %5.2f, %5.2f)\n", distr, distg, distb); pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); /* Test color transform: same form with small rotation */ fprintf(stderr, "Test color transform with small rotation\n"); pix1 = pixRead("form1.tif"); pix2 = pixLocToColorTransform(pix1); pixRotateShearCenterIP(pix1, 0.1, L_BRING_IN_WHITE); pix3 = pixLocToColorTransform(pix1); regTestWritePixAndCheck(rp, pix3, IFF_PNG); /* 22 */ pixDisplayWithTitle(pix3, 880, 0, NULL, rp->display); FindEMD(pix2, pix3, &distr, &distg, &distb); regTestCompareValues(rp, 1.50, distr, 0.01); /* 23 */ regTestCompareValues(rp, 1.71, distg, 0.01); /* 24 */ regTestCompareValues(rp, 1.42, distb, 0.01); /* 25 */ fprintf(stderr, "Rotation dist (r,g,b) = (%5.2f, %5.2f, %5.2f)\n", distr, distg, distb); pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); /* Test color transform: 2 different forms */ fprintf(stderr, "Test color transform (2 forms)\n"); pix1 = pixRead("form1.tif"); pix2 = pixLocToColorTransform(pix1); pixDisplayWithTitle(pix2, 0, 600, NULL, rp->display); pix3 = pixRead("form2.tif"); pix4 = pixLocToColorTransform(pix3); regTestWritePixAndCheck(rp, pix4, IFF_PNG); /* 25 */ pixDisplayWithTitle(pix4, 470, 600, NULL, rp->display); FindEMD(pix2, pix4, &distr, &distg, &distb); regTestCompareValues(rp, 6.10, distr, 0.02); /* 27 */ regTestCompareValues(rp, 11.13, distg, 0.01); /* 28 */ regTestCompareValues(rp, 10.53, distb, 0.01); /* 29 */ fprintf(stderr, "Different forms: dist (r,g,b) = (%5.2f, %5.2f, %5.2f)\n", distr, distg, distb); pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); pixDestroy(&pix4); return regTestCleanup(rp); }
int main(int argc, char **argv) { l_int32 i, n, ws, hs, w, h, rval, gval, bval, order; l_float32 *mat1, *mat2, *mat3; l_float32 matd[9]; BOX *box, *boxt; BOXA *boxa, *boxat, *boxa1, *boxa2, *boxa3, *boxa4, *boxa5; PIX *pix, *pixs, *pixc, *pixt, *pix1, *pix2, *pix3; PIXA *pixa; L_REGPARAMS *rp; if (regTestSetup(argc, argv, &rp)) return 1; /* ----------------------------------------------------------- * * Test hash rendering in 3 modes * * ----------------------------------------------------------- */ pixs = pixRead("feyn.tif"); box = boxCreate(461, 429, 1393, 342); pix1 = pixClipRectangle(pixs, box, NULL); boxa = pixConnComp(pix1, NULL, 8); n = boxaGetCount(boxa); pix2 = pixConvertTo8(pix1, 1); pix3 = pixConvertTo32(pix1); for (i = 0; i < n; i++) { boxt = boxaGetBox(boxa, i, L_CLONE); rval = (1413 * (i + 1)) % 256; gval = (4917 * (i + 1)) % 256; bval = (7341 * (i + 1)) % 256; pixRenderHashBox(pix1, boxt, 8, 2, i % 4, 1, L_SET_PIXELS); pixRenderHashBoxArb(pix2, boxt, 7, 2, i % 4, 1, rval, gval, bval); pixRenderHashBoxBlend(pix3, boxt, 7, 2, i % 4, 1, rval, gval, bval, 0.5); boxDestroy(&boxt); } regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 0 */ regTestWritePixAndCheck(rp, pix2, IFF_PNG); /* 1 */ regTestWritePixAndCheck(rp, pix3, IFF_PNG); /* 2 */ pixDisplayWithTitle(pix1, 0, 0, NULL, rp->display); pixDisplayWithTitle(pix2, 0, 300, NULL, rp->display); pixDisplayWithTitle(pix3, 0, 570, NULL, rp->display); boxaDestroy(&boxa); boxDestroy(&box); pixDestroy(&pixs); pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); /* ----------------------------------------------------------- * * Test orthogonal box rotation and hash rendering * * ----------------------------------------------------------- */ pixs = pixRead("feyn.tif"); box = boxCreate(461, 429, 1393, 342); pix1 = pixClipRectangle(pixs, box, NULL); pixc = pixConvertTo32(pix1); pixGetDimensions(pix1, &w, &h, NULL); boxa1 = pixConnComp(pix1, NULL, 8); pixa = pixaCreate(4); for (i = 0; i < 4; i++) { pix2 = pixRotateOrth(pixc, i); boxa2 = boxaRotateOrth(boxa1, w, h, i); rval = (1413 * (i + 4)) % 256; gval = (4917 * (i + 4)) % 256; bval = (7341 * (i + 4)) % 256; pixRenderHashBoxaArb(pix2, boxa2, 10, 3, i, 1, rval, gval, bval); pixaAddPix(pixa, pix2, L_INSERT); boxaDestroy(&boxa2); } pix3 = pixaDisplayTiledInRows(pixa, 32, 1200, 0.7, 0, 30, 3); regTestWritePixAndCheck(rp, pix3, IFF_PNG); /* 3 */ pixDisplayWithTitle(pix3, 0, 800, NULL, rp->display); boxDestroy(&box); pixDestroy(&pixs); pixDestroy(&pix1); pixDestroy(&pix3); pixDestroy(&pixc); boxaDestroy(&boxa1); pixaDestroy(&pixa); /* ----------------------------------------------------------- * * Test box transforms with either translation or scaling * * combined with rotation, using the simple 'ordered' * * function. Show that the order of the operations does * * not matter; different hashing schemes end up in the * * identical boxes. * * ----------------------------------------------------------- */ pix = pixRead("feyn.tif"); box = boxCreate(420, 360, 1500, 465); pixt = pixClipRectangle(pix, box, NULL); pixs = pixAddBorderGeneral(pixt, 0, 200, 0, 0, 0); boxDestroy(&box); pixDestroy(&pix); pixDestroy(&pixt); boxa = pixConnComp(pixs, NULL, 8); n = boxaGetCount(boxa); pixa = pixaCreate(0); pixt = pixConvertTo32(pixs); for (i = 0; i < 3; i++) { if (i == 0) order = L_TR_SC_RO; else if (i == 1) order = L_TR_RO_SC; else order = L_SC_TR_RO; boxat = boxaTransformOrdered(boxa, SHIFTX_2, SHIFTY_2, 1.0, 1.0, 450, 250, ROTATION_2, order); RenderTransformedBoxa(pixt, boxat, i); boxaDestroy(&boxat); } pixSaveTiled(pixt, pixa, 1.0, 1, 30, 32); pixDestroy(&pixt); pixt = pixConvertTo32(pixs); for (i = 0; i < 3; i++) { if (i == 0) order = L_RO_TR_SC; else if (i == 1) order = L_RO_SC_TR; else order = L_SC_RO_TR; boxat = boxaTransformOrdered(boxa, SHIFTX_2, SHIFTY_2, 1.0, 1.0, 450, 250, ROTATION_2, order); RenderTransformedBoxa(pixt, boxat, i + 4); boxaDestroy(&boxat); } pixSaveTiled(pixt, pixa, 1.0, 1, 30, 0); pixDestroy(&pixt); pixt = pixConvertTo32(pixs); for (i = 0; i < 3; i++) { if (i == 0) order = L_TR_SC_RO; else if (i == 1) order = L_SC_RO_TR; else order = L_SC_TR_RO; boxat = boxaTransformOrdered(boxa, 0, 0, SCALEX_2, SCALEY_2, 450, 250, ROTATION_2, order); RenderTransformedBoxa(pixt, boxat, i + 8); boxaDestroy(&boxat); } pixSaveTiled(pixt, pixa, 1.0, 1, 30, 0); pixDestroy(&pixt); pixt = pixConvertTo32(pixs); for (i = 0; i < 3; i++) { if (i == 0) order = L_RO_TR_SC; else if (i == 1) order = L_RO_SC_TR; else order = L_TR_RO_SC; boxat = boxaTransformOrdered(boxa, 0, 0, SCALEX_2, SCALEY_2, 450, 250, ROTATION_2, order); RenderTransformedBoxa(pixt, boxat, i + 12); boxaDestroy(&boxat); } pixSaveTiled(pixt, pixa, 1.0, 1, 30, 0); pixDestroy(&pixt); pixt = pixaDisplay(pixa, 0, 0); regTestWritePixAndCheck(rp, pixt, IFF_PNG); /* 4 */ pixDisplayWithTitle(pixt, 1000, 0, NULL, rp->display); pixDestroy(&pixt); pixDestroy(&pixs); boxaDestroy(&boxa); pixaDestroy(&pixa); /* ----------------------------------------------------------- * * Do more testing of box and pta transforms. Show that * * resulting boxes are identical by three methods. * * ----------------------------------------------------------- */ /* Set up pix and boxa */ pixa = pixaCreate(0); pix = pixRead("lucasta.1.300.tif"); pixTranslate(pix, pix, 70, 0, L_BRING_IN_WHITE); pixt = pixCloseBrick(NULL, pix, 14, 5); pixOpenBrick(pixt, pixt, 1, 2); boxa = pixConnComp(pixt, NULL, 8); pixs = pixConvertTo32(pix); pixc = pixCopy(NULL, pixs); RenderTransformedBoxa(pixc, boxa, 113); pixSaveTiled(pixc, pixa, 0.5, 1, 30, 32); pixDestroy(&pix); pixDestroy(&pixc); pixDestroy(&pixt); /* (a) Do successive discrete operations: shift, scale, rotate */ pix1 = pixTranslate(NULL, pixs, SHIFTX_3, SHIFTY_3, L_BRING_IN_WHITE); boxa1 = boxaTranslate(boxa, SHIFTX_3, SHIFTY_3); pixc = pixCopy(NULL, pix1); RenderTransformedBoxa(pixc, boxa1, 213); pixSaveTiled(pixc, pixa, 0.5, 0, 30, 32); pixDestroy(&pixc); pix2 = pixScale(pix1, SCALEX_3, SCALEY_3); boxa2 = boxaScale(boxa1, SCALEX_3, SCALEY_3); pixc = pixCopy(NULL, pix2); RenderTransformedBoxa(pixc, boxa2, 313); pixSaveTiled(pixc, pixa, 0.5, 1, 30, 32); pixDestroy(&pixc); pixGetDimensions(pix2, &w, &h, NULL); pix3 = pixRotateAM(pix2, ROTATION_3, L_BRING_IN_WHITE); boxa3 = boxaRotate(boxa2, w / 2, h / 2, ROTATION_3); pixc = pixCopy(NULL, pix3); RenderTransformedBoxa(pixc, boxa3, 413); pixSaveTiled(pixc, pixa, 0.5, 0, 30, 32); pixDestroy(&pixc); /* (b) Set up and use the composite transform */ mat1 = createMatrix2dTranslate(SHIFTX_3, SHIFTY_3); mat2 = createMatrix2dScale(SCALEX_3, SCALEY_3); mat3 = createMatrix2dRotate(w / 2, h / 2, ROTATION_3); l_productMat3(mat3, mat2, mat1, matd, 3); boxa4 = boxaAffineTransform(boxa, matd); pixc = pixCopy(NULL, pix3); RenderTransformedBoxa(pixc, boxa4, 513); pixSaveTiled(pixc, pixa, 0.5, 1, 30, 32); pixDestroy(&pixc); /* (c) Use the special 'ordered' function */ pixGetDimensions(pixs, &ws, &hs, NULL); boxa5 = boxaTransformOrdered(boxa, SHIFTX_3, SHIFTY_3, SCALEX_3, SCALEY_3, ws / 2, hs / 2, ROTATION_3, L_TR_SC_RO); pixc = pixCopy(NULL, pix3); RenderTransformedBoxa(pixc, boxa5, 613); pixSaveTiled(pixc, pixa, 0.5, 0, 30, 32); pixDestroy(&pixc); pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); boxaDestroy(&boxa1); boxaDestroy(&boxa2); boxaDestroy(&boxa3); boxaDestroy(&boxa4); boxaDestroy(&boxa5); lept_free(mat1); lept_free(mat2); lept_free(mat3); pixt = pixaDisplay(pixa, 0, 0); regTestWritePixAndCheck(rp, pixt, IFF_PNG); /* 5 */ pixDisplayWithTitle(pixt, 1000, 300, NULL, rp->display); pixDestroy(&pixt); pixDestroy(&pixs); boxaDestroy(&boxa); pixaDestroy(&pixa); return regTestCleanup(rp); }