/*! * pixaCreateFromBoxa() * * Input: pixs * boxa * &cropwarn (<optional return> TRUE if the boxa extent * is larger than pixs. * Return: pixad, or null on error * * Notes: * (1) This simply extracts from pixs the region corresponding to each * box in the boxa. * (2) The 3rd arg is optional. If the extent of the boxa exceeds the * size of the pixa, so that some boxes are either clipped * or entirely outside the pix, a warning is returned as TRUE. * (3) pixad will have only the properly clipped elements, and * the internal boxa will be correct. */ PIXA * pixaCreateFromBoxa(PIX *pixs, BOXA *boxa, l_int32 *pcropwarn) { l_int32 i, n, w, h, wbox, hbox, cropwarn; BOX *box, *boxc; PIX *pixd; PIXA *pixad; PROCNAME("pixaCreateFromBoxa"); if (!pixs) return (PIXA *)ERROR_PTR("pixs not defined", procName, NULL); if (!boxa) return (PIXA *)ERROR_PTR("boxa not defined", procName, NULL); n = boxaGetCount(boxa); if ((pixad = pixaCreate(n)) == NULL) return (PIXA *)ERROR_PTR("pixad not made", procName, NULL); boxaGetExtent(boxa, &wbox, &hbox, NULL); pixGetDimensions(pixs, &w, &h, NULL); cropwarn = FALSE; if (wbox > w || hbox > h) cropwarn = TRUE; if (pcropwarn) *pcropwarn = cropwarn; for (i = 0; i < n; i++) { box = boxaGetBox(boxa, i, L_COPY); if (cropwarn) { /* if box is outside pixs, pixd is NULL */ pixd = pixClipRectangle(pixs, box, &boxc); /* may be NULL */ if (pixd) { pixaAddPix(pixad, pixd, L_INSERT); pixaAddBox(pixad, boxc, L_INSERT); } boxDestroy(&box); } else { pixd = pixClipRectangle(pixs, box, NULL); pixaAddPix(pixad, pixd, L_INSERT); pixaAddBox(pixad, box, L_INSERT); } } return pixad; }
int ignore_alpha_at_edge(png_byte *alpha, unsigned char* indata, int w, int h, PIX *in, PIX **out) { int i, j, index, start_y, end_y; int find_end_x = CCX_FALSE; BOX* cropWindow; for (j = 1; j < w-1; j++) { for (i = 0; i < h; i++) { index = indata[i * w + (j)]; if(alpha[index] != 0) { if(find_end_x == CCX_FALSE) { start_y = j; find_end_x = CCX_TRUE; } else { end_y = j; } } } } cropWindow = boxCreate(start_y, 0, (w - (start_y + ( w - end_y) )), h - 1); *out = pixClipRectangle(in, cropWindow, NULL); boxDestroy(&cropWindow); return 0; }
/** * Returns an image of the current object at the given level in greyscale * if available in the input. To guarantee a binary image use BinaryImage. * NOTE that in order to give the best possible image, the bounds are * expanded slightly over the binary connected component, by the supplied * padding, so the top-left position of the returned image is returned * in (left,top). These will most likely not match the coordinates * returned by BoundingBox. * Use pixDestroy to delete the image after use. */ Pix* PageIterator::GetImage(PageIteratorLevel level, int padding, int* left, int* top) const { int right, bottom; if (!BoundingBox(level, left, top, &right, &bottom)) return NULL; Pix* pix = tesseract_->pix_grey(); if (pix == NULL) return GetBinaryImage(level); // Expand the box. *left = MAX(*left - padding, 0); *top = MAX(*top - padding, 0); right = MIN(right + padding, rect_width_); bottom = MIN(bottom + padding, rect_height_); Box* box = boxCreate(*left, *top, right - *left, bottom - *top); Pix* grey_pix = pixClipRectangle(pix, box, NULL); boxDestroy(&box); if (level == RIL_BLOCK) { Pix* mask = it_->block()->block->render_mask(); Pix* expanded_mask = pixCreate(right - *left, bottom - *top, 1); pixRasterop(expanded_mask, padding, padding, pixGetWidth(mask), pixGetHeight(mask), PIX_SRC, mask, 0, 0); pixDestroy(&mask); pixDilateBrick(expanded_mask, expanded_mask, 2*padding + 1, 2*padding + 1); pixInvert(expanded_mask, expanded_mask); pixSetMasked(grey_pix, expanded_mask, 255); pixDestroy(&expanded_mask); } return grey_pix; }
/*! * pixaClipToPix() * * Input: pixas * pixs * Return: pixad, or null on error * * Notes: * (1) This is intended for use in situations where pixas * was originally generated from the input pixs. * (2) Returns a pixad where each pix in pixas is ANDed * with its associated region of the input pixs. This * region is specified by the the box that is associated * with the pix. * (3) In a typical application of this function, pixas has * a set of region masks, so this generates a pixa of * the parts of pixs that correspond to each region * mask component, along with the bounding box for * the region. */ PIXA * pixaClipToPix(PIXA *pixas, PIX *pixs) { l_int32 i, n; BOX *box; PIX *pix, *pixc; PIXA *pixad; PROCNAME("pixaClipToPix"); if (!pixas) return (PIXA *)ERROR_PTR("pixas not defined", procName, NULL); if (!pixs) return (PIXA *)ERROR_PTR("pixs not defined", procName, NULL); n = pixaGetCount(pixas); if ((pixad = pixaCreate(n)) == NULL) return (PIXA *)ERROR_PTR("pixad not made", procName, NULL); for (i = 0; i < n; i++) { pix = pixaGetPix(pixas, i, L_CLONE); box = pixaGetBox(pixas, i, L_COPY); pixc = pixClipRectangle(pixs, box, NULL); pixAnd(pixc, pixc, pix); pixaAddPix(pixad, pixc, L_INSERT); pixaAddBox(pixad, box, L_INSERT); pixDestroy(&pix); } return pixad; }
jint Java_com_googlecode_leptonica_android_Clip_nativeClipRectangle(JNIEnv *env, jclass clazz, jint nativePix, jint nativeBox) { LOGV("%s",__FUNCTION__); PIX *pixs = (PIX *) nativePix; BOX *box = (BOX *) nativeBox; PIX *pixd; pixd = pixClipRectangle(pixs,box,NULL); return (jint) pixd; }
jlong Java_com_googlecode_leptonica_android_Clip_nativeClipRectangle(JNIEnv *env, jclass clazz, jlong nativePix, jlong nativeBox) { PIX *pixs = (PIX *) nativePix; BOX *box = (BOX *) nativeBox; PIX *pixd; pixd = pixClipRectangle(pixs,box,NULL); return (jlong) pixd; }
// Returns the number of components in the intersection_pix touched by line_box. static int NumTouchingIntersections(Box* line_box, Pix* intersection_pix) { if (intersection_pix == NULL) return 0; Pix* rect_pix = pixClipRectangle(intersection_pix, line_box, NULL); Boxa* boxa = pixConnComp(rect_pix, NULL, 8); pixDestroy(&rect_pix); if (boxa == NULL) return false; int result = boxaGetCount(boxa); boxaDestroy(&boxa); return result; }
// 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); }
/*! * \brief recogRescoreDidResult() * * \param[in] recog with LUT's pre-computed * \param[out] ppixdb [optional] debug result; can be null * \return 0 if OK, 1 on error * * <pre> * Notes: * (1) This does correlation matching with all templates using the * viterbi path segmentation. * </pre> */ static l_int32 recogRescoreDidResult(L_RECOG *recog, PIX **ppixdb) { l_int32 i, n, w2, h1, templ, x, xloc, dely, index; char *text; l_float32 score; BOX *box1; PIX *pixs, *pix1; L_RDID *did; PROCNAME("recogRescoreDidResult"); if (ppixdb) *ppixdb = NULL; if (!recog) return ERROR_INT("recog not defined", procName, 1); if ((did = recogGetDid(recog)) == NULL) return ERROR_INT("did not defined", procName, 1); if (did->fullarrays == 0) return ERROR_INT("did full arrays not made", procName, 1); if ((n = numaGetCount(did->naxloc)) == 0) return ERROR_INT("no elements in path", procName, 1); pixs = did->pixs; h1 = pixGetHeight(pixs); for (i = 0; i < n; i++) { numaGetIValue(did->natempl, i, &templ); numaGetIValue(did->naxloc, i, &xloc); numaGetIValue(did->nadely, i, &dely); pixaGetPixDimensions(recog->pixa_u, templ, &w2, NULL, NULL); /* TODO: try to fix xloc - 4, etc. */ x = L_MAX(xloc, 0); box1 = boxCreate(x, dely, w2, h1); pix1 = pixClipRectangle(pixs, box1, NULL); recogIdentifyPix(recog, pix1, NULL); recogTransferRchToDid(recog, x, dely); if (ppixdb) { rchExtract(recog->rch, &index, &score, &text, NULL, NULL, NULL, NULL); fprintf(stderr, "text = %s, index = %d, score = %5.3f\n", text, index, score); } pixDestroy(&pix1); boxDestroy(&box1); LEPT_FREE(text); } /* numaWriteStream(stderr, recog->did->nadely_r); */ if (ppixdb) *ppixdb = recogShowPath(recog, 1); return 0; }
void M_Utils::dispBlobOCRRes(BLOBNBOX* blob, PIX* im, Tesseract* ocrengine) { BOX* box_ = getBlobBoxImCoords(blob, im); PIX* bboxim = pixClipRectangle(im, box_, NULL); pixDisplay(bboxim, 100, 100); BLOB_CHOICE* ocr_res = runBlobOCR(blob, ocrengine); const char* const unicode_res = getBlobChoiceUnicode(ocr_res, ocrengine); cout << "OCR result: " << unicode_res << endl; cout << "certainty: " << ocr_res->certainty() << endl; waitForInput(); }
/** * Returns a binary image of the current object at the given level. * The position and size match the return from BoundingBoxInternal, and so this * could be upscaled with respect to the original input image. * Use pixDestroy to delete the image after use. * The following methods are used to generate the images: * RIL_BLOCK: mask the page image with the block polygon. * RIL_TEXTLINE: Clip the rectangle of the line box from the page image. * TODO(rays) fix this to generate and use a line polygon. * RIL_WORD: Clip the rectangle of the word box from the page image. * RIL_SYMBOL: Render the symbol outline to an image for cblobs (prior * to recognition) or the bounding box otherwise. * A reconstruction of the original image (using xor to check for double * representation) should be reasonably accurate, * apart from removed noise, at the block level. Below the block level, the * reconstruction will be missing images and line separators. * At the symbol level, kerned characters will be invade the bounding box * if rendered after recognition, making an xor reconstruction inaccurate, but * an or construction better. Before recognition, symbol-level reconstruction * should be good, even with xor, since the images come from the connected * components. */ Pix* PageIterator::GetBinaryImage(PageIteratorLevel level) const { int left, top, right, bottom; if (!BoundingBoxInternal(level, &left, &top, &right, &bottom)) return NULL; Pix* pix = NULL; switch (level) { case RIL_BLOCK: case RIL_PARA: int bleft, btop, bright, bbottom; BoundingBoxInternal(RIL_BLOCK, &bleft, &btop, &bright, &bbottom); pix = it_->block()->block->render_mask(); // AND the mask and the image. pixRasterop(pix, 0, 0, pixGetWidth(pix), pixGetHeight(pix), PIX_SRC & PIX_DST, tesseract_->pix_binary(), bleft, btop); if (level == RIL_PARA) { // RIL_PARA needs further attention: // clip the paragraph from the block mask. Box* box = boxCreate(left - bleft, top - btop, right - left, bottom - top); Pix* pix2 = pixClipRectangle(pix, box, NULL); boxDestroy(&box); pixDestroy(&pix); pix = pix2; } break; case RIL_TEXTLINE: case RIL_WORD: case RIL_SYMBOL: if (level == RIL_SYMBOL && cblob_it_ != NULL && cblob_it_->data()->area() != 0) return cblob_it_->data()->render(); // Just clip from the bounding box. Box* box = boxCreate(left, top, right - left, bottom - top); pix = pixClipRectangle(tesseract_->pix_binary(), box, NULL); boxDestroy(&box); break; } return pix; }
int main(int argc, char **argv) { char *dirin, *dirout, *infile, *outfile, *tail; l_int32 i, nfiles, border, x, y, w, h, xb, yb, wb, hb; BOX *box1, *box2; BOXA *boxa1, *boxa2; PIX *pixs, *pixt1, *pixd; SARRAY *safiles; static char mainName[] = "croptext"; if (argc != 4) return ERROR_INT("Syntax: croptext dirin border dirout", mainName, 1); dirin = argv[1]; border = atoi(argv[2]); dirout = argv[3]; setLeptDebugOK(1); safiles = getSortedPathnamesInDirectory(dirin, NULL, 0, 0); nfiles = sarrayGetCount(safiles); for (i = 0; i < nfiles; i++) { infile = sarrayGetString(safiles, i, L_NOCOPY); splitPathAtDirectory(infile, NULL, &tail); outfile = genPathname(dirout, tail); pixs = pixRead(infile); pixt1 = pixMorphSequence(pixs, "r11 + c10.40 + o5.5 + x4", 0); boxa1 = pixConnComp(pixt1, NULL, 8); if (boxaGetCount(boxa1) == 0) { fprintf(stderr, "Warning: no components on page %s\n", tail); continue; } boxa2 = boxaSort(boxa1, L_SORT_BY_AREA, L_SORT_DECREASING, NULL); box1 = boxaGetBox(boxa2, 0, L_CLONE); boxGetGeometry(box1, &x, &y, &w, &h); xb = L_MAX(0, x - border); yb = L_MAX(0, y - border); wb = w + 2 * border; hb = h + 2 * border; box2 = boxCreate(xb, yb, wb, hb); pixd = pixClipRectangle(pixs, box2, NULL); pixWrite(outfile, pixd, IFF_TIFF_G4); pixDestroy(&pixs); pixDestroy(&pixt1); pixDestroy(&pixd); boxaDestroy(&boxa1); boxaDestroy(&boxa2); } return 0; }
unsigned long long getImagePhash_px( PIX *pix_orig, char *tmpFilename ) { int free_8 = 0; // Convert colour images down to grey PIX *pix8; if( pixGetDepth(pix_orig) > 8 ) { pix8 = pixScaleRGBToGrayFast( pix_orig, 1, COLOR_GREEN ); if( pix8 == NULL ) { printf("Covertion to 8bit, did not go well."); return 0; } free_8 = 1; } else { // already gray free_8 = 0; pix8 = pix_orig; } int width = pixGetWidth( pix8 ); int height = pixGetHeight( pix8 ); BOX* box = boxCreate(1, 1, width-2, height-2); PIX* pixc = pixClipRectangle(pix8, box, NULL); if(free_8 == 1) { pixDestroy( &pix8 ); } PIX *pix8s = pixScale(pixc, 0.2, 0.2); pixDestroy( &pixc ); // Convert image down to binary (no gray) /* PIX *pix1 = pixThresholdToBinary( pix8s, 200 ); if( pix1 == NULL ) { printf( "Covertion to 1bit, did not go well."); pixDestroy( &pix8s ); return 0; } pixDestroy( &pix8s ); */ // Save the file for pHash processnig pixWrite( tmpFilename, pix8s, IFF_JFIF_JPEG); pixDestroy( &pix8s ); unsigned long long ret = calculateImagePhash( tmpFilename ); //unlink(tmpFilename); return ret; }
int main(int argc, char **argv) { BOX *box; PIX *pixt1, *pixt2, *pix1, *pix2, *pix3; L_REGPARAMS *rp; if (regTestSetup(argc, argv, &rp)) return 1; pixt1 = pixRead("feyn.tif"); /* 300 ppi */ box = boxCreate(19, 774, 2247, 2025); pix1 = pixClipRectangle(pixt1, box, NULL); pixDestroy(&pixt1); pixt1 = pixRead("lucasta.150.jpg"); pixt2 = pixConvertTo1(pixt1, 128); /* 150 ppi */ pix2 = pixScale(pixt2, 2.2, 2.2); /* 300 ppi */ pixDestroy(&pixt1); pixDestroy(&pixt2); pixt1 = pixRead("zanotti-78.jpg"); pixt2 = pixConvertTo1(pixt1, 128); /* 150 ppi */ pix3 = pixScale(pixt2, 2.0, 2.0); /* 300 ppi */ pixDestroy(&pixt1); pixDestroy(&pixt2); boxDestroy(&box); /* Make word boxes using pixWordMaskByDilation() */ MakeWordBoxes1(pix1, 20, rp); /* 0 */ MakeWordBoxes1(pix2, 20, rp); /* 1 */ MakeWordBoxes1(pix3, 20, rp); /* 2 */ /* Make word boxes using the higher-level functions * pixGetWordsInTextlines() and pixGetWordBoxesInTextlines() */ MakeWordBoxes2(pix1, 1, rp); /* 3, 4 */ MakeWordBoxes2(pix2, 1, rp); /* 5, 6 */ MakeWordBoxes2(pix3, 1, rp); /* 7, 8 */ /* Make word boxes using the higher-level functions * pixGetWordsInTextlines() and pixGetWordBoxesInTextlines() */ MakeWordBoxes2(pix1, 2, rp); /* 9, 10 */ MakeWordBoxes2(pix2, 2, rp); /* 11, 12 */ MakeWordBoxes2(pix3, 2, rp); /* 13, 14 */ pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); return regTestCleanup(rp); }
// Returns a pix of the original sample image. The pix is padded all round // by padding wherever possible. // The returned Pix must be pixDestroyed after use. // If the input page_pix is nullptr, nullptr is returned. Pix* TrainingSample::GetSamplePix(int padding, Pix* page_pix) const { if (page_pix == nullptr) return nullptr; int page_width = pixGetWidth(page_pix); int page_height = pixGetHeight(page_pix); TBOX padded_box = bounding_box(); padded_box.pad(padding, padding); // Clip the padded_box to the limits of the page TBOX page_box(0, 0, page_width, page_height); padded_box &= page_box; Box* box = boxCreate(page_box.left(), page_height - page_box.top(), page_box.width(), page_box.height()); Pix* sample_pix = pixClipRectangle(page_pix, box, nullptr); boxDestroy(&box); return sample_pix; }
main(int argc, char **argv) { char buf[256]; l_int32 i, j, k, index, conn, depth, bc; BOX *box; PIX *pix, *pixs, *pixd; PIXA *pixa; L_REGPARAMS *rp; if (regTestSetup(argc, argv, &rp)) return 1; pix = pixRead("feyn.tif"); box = boxCreate(383, 338, 1480, 1050); pixs = pixClipRectangle(pix, box, NULL); regTestWritePixAndCheck(rp, pixs, IFF_PNG); /* 0 */ for (i = 0; i < 2; i++) { conn = 4 + 4 * i; for (j = 0; j < 2; j++) { depth = 8 + 8 * j; for (k = 0; k < 2; k++) { bc = k + 1; index = 4 * i + 2 * j + k; fprintf(stderr, "Set %d\n", index); if (DEBUG) { fprintf(stderr, "%d: conn = %d, depth = %d, bc = %d\n", rp->index + 1, conn, depth, bc); } pixa = pixaCreate(0); pixSaveTiled(pixs, pixa, 1, 1, 20, 8); TestDistance(pixa, pixs, conn, depth, bc, rp); pixd = pixaDisplay(pixa, 0, 0); pixDisplayWithTitle(pixd, 0, 0, NULL, rp->display); pixaDestroy(&pixa); pixDestroy(&pixd); } } } boxDestroy(&box); pixDestroy(&pix); pixDestroy(&pixs); regTestCleanup(rp); return 0; }
// Get a clone/copy of the source image rectangle. // The returned Pix must be pixDestroyed. // This function will be used in the future by the page layout analysis, and // the layout analysis that uses it will only be available with Leptonica, // so there is no raw equivalent. Pix* ImageThresholder::GetPixRect() { if (pix_ != NULL) { if (IsFullImage()) { // Just clone the whole thing. return pixClone(pix_); } else { // Crop to the given rectangle. Box* box = boxCreate(rect_left_, rect_top_, rect_width_, rect_height_); Pix* cropped = pixClipRectangle(pix_, box, NULL); boxDestroy(&box); return cropped; } } // The input is raw, so we have to make a copy of it. Pix* raw_pix; RawRectToPix(&raw_pix); return raw_pix; }
/*! * pixFindMinRunsOrthogonal() * * Input: pixs (1 bpp) * angle (in radians) * depth (of pixd: 8 or 16 bpp) * Return: pixd (8 or 16 bpp), or null on error * * Notes: * (1) This computes, for each fg pixel in pixs, the minimum of * the runlengths going through that pixel in two orthogonal * directions: at @angle and at (90 + @angle). * (2) We use rotation by shear because the forward and backward * rotations by the same angle are exact inverse operations. * As a result, the nonzero pixels in pixd correspond exactly * to the fg pixels in pixs. This is not the case with * sampled rotation, due to spatial quantization. Nevertheless, * the result suffers from lack of exact correspondence * between original and rotated pixels, also due to spatial * quantization, causing some boundary pixels to be * shifted from bg to fg or v.v. */ static PIX * pixFindMinRunsOrthogonal(PIX *pixs, l_float32 angle, l_int32 depth) { l_int32 w, h, diag, xoff, yoff; PIX *pixb, *pixr, *pixh, *pixv, *pixg1, *pixg2, *pixd; BOX *box; PROCNAME("pixFindMinRunsOrthogonal"); if (!pixs || pixGetDepth(pixs) != 1) return (PIX *)ERROR_PTR("pixs undefined or not 1 bpp", procName, NULL); /* Rasterop into the center of a sufficiently large image * so we don't lose pixels for any rotation angle. */ pixGetDimensions(pixs, &w, &h, NULL); diag = (l_int32)(sqrt((l_float64)(w * w + h * h)) + 2.5); xoff = (diag - w) / 2; yoff = (diag - h) / 2; pixb = pixCreate(diag, diag, 1); pixRasterop(pixb, xoff, yoff, w, h, PIX_SRC, pixs, 0, 0); /* Rotate about the 'center', get the min of orthogonal transforms, * rotate back, and crop the part corresponding to pixs. */ pixr = pixRotateShear(pixb, diag / 2, diag / 2, angle, L_BRING_IN_WHITE); pixh = pixRunlengthTransform(pixr, 1, L_HORIZONTAL_RUNS, depth); pixv = pixRunlengthTransform(pixr, 1, L_VERTICAL_RUNS, depth); pixg1 = pixMinOrMax(NULL, pixh, pixv, L_CHOOSE_MIN); pixg2 = pixRotateShear(pixg1, diag / 2, diag / 2, -angle, L_BRING_IN_WHITE); box = boxCreate(xoff, yoff, w, h); pixd = pixClipRectangle(pixg2, box, NULL); pixDestroy(&pixb); pixDestroy(&pixr); pixDestroy(&pixh); pixDestroy(&pixv); pixDestroy(&pixg1); pixDestroy(&pixg2); boxDestroy(&box); return pixd; }
// Returns the number of black pixels found in the box made by adding the line // width to both sides of the line bounding box. (Increasing the smallest // dimension of the bounding box.) static int CountPixelsAdjacentToLine(int line_width, Box* line_box, Pix* nonline_pix) { l_int32 x, y, box_width, box_height; boxGetGeometry(line_box, &x, &y, &box_width, &box_height); if (box_width > box_height) { // horizontal line. int bottom = MIN(pixGetHeight(nonline_pix), y + box_height + line_width); y = MAX(0, y - line_width); box_height = bottom - y; } else { // Vertical line. int right = MIN(pixGetWidth(nonline_pix), x + box_width + line_width); x = MAX(0, x - line_width); box_width = right - x; } Box* box = boxCreate(x, y, box_width, box_height); Pix* rect_pix = pixClipRectangle(nonline_pix, box, NULL); boxDestroy(&box); l_int32 result; pixCountPixels(rect_pix, &result, NULL); pixDestroy(&rect_pix); return result; }
//------------------------------------------------------------------------------ //Ортогональный поворот исходного изображения и обрезка его до //крайней правой нижней части с размером (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; }
PIXA * GenerateSetOfMargePix(void) { l_float32 factor; BOX *box; PIX *pixs, *pixt1, *pixt2, *pixt3, *pixt4; PIXA *pixa; pixs = pixRead("marge.jpg"); box = boxCreate(130, 93, 263, 253); factor = sqrt(2.0); pixt1 = pixClipRectangle(pixs, box, NULL); /* 266 KB */ pixt2 = pixScale(pixt1, factor, factor); /* 532 KB */ pixt3 = pixScale(pixt2, factor, factor); /* 1064 KB */ pixt4 = pixScale(pixt3, factor, factor); /* 2128 KB */ pixa = pixaCreate(4); pixaAddPix(pixa, pixt1, L_INSERT); pixaAddPix(pixa, pixt2, L_INSERT); pixaAddPix(pixa, pixt3, L_INSERT); pixaAddPix(pixa, pixt4, L_INSERT); boxDestroy(&box); pixDestroy(&pixs); return pixa; }
/*! * \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; }
/*! * \brief pixConnCompPixa() * * \param[in] pixs 1 bpp * \param[out] ppixa pixa of each c.c. * \param[in] connectivity 4 or 8 * \return boxa, or NULL on error * * <pre> * Notes: * (1) This finds bounding boxes of 4- or 8-connected components * in a binary image, and saves images of each c.c * in a pixa array. * (2) It sets up 2 temporary pix, and for each c.c. that is * located in raster order, it erases the c.c. from one pix, * then uses the b.b. to extract the c.c. from the two pix using * an XOR, and finally erases the c.c. from the second pix. * (3) A clone of the returned boxa (where all boxes in the array * are clones) is inserted into the pixa. * (4) If the input is valid, this always returns a boxa and a pixa. * If pixs is empty, the boxa and pixa will be empty. * </pre> */ BOXA * pixConnCompPixa(PIX *pixs, PIXA **ppixa, l_int32 connectivity) { l_int32 h, iszero; l_int32 x, y, xstart, ystart; PIX *pix1, *pix2, *pix3, *pix4; PIXA *pixa; BOX *box; BOXA *boxa; L_STACK *stack, *auxstack; PROCNAME("pixConnCompPixa"); if (!ppixa) return (BOXA *)ERROR_PTR("&pixa not defined", procName, NULL); *ppixa = NULL; if (!pixs || pixGetDepth(pixs) != 1) return (BOXA *)ERROR_PTR("pixs undefined or not 1 bpp", procName, NULL); if (connectivity != 4 && connectivity != 8) return (BOXA *)ERROR_PTR("connectivity not 4 or 8", procName, NULL); boxa = NULL; pix1 = pix2 = pix3 = pix4 = NULL; stack = NULL; pixZero(pixs, &iszero); if (iszero) return boxaCreate(1); /* return empty boxa */ pix1 = pixCopy(NULL, pixs); pix2 = pixCopy(NULL, pixs); if (!pix1 || !pix2) { L_ERROR("pix1 or pix2 not made\n", procName); goto cleanup; } h = pixGetHeight(pixs); if ((stack = lstackCreate(h)) == NULL) { L_ERROR("stack not made\n", procName); goto cleanup; } auxstack = lstackCreate(0); stack->auxstack = auxstack; pixa = pixaCreate(0); boxa = boxaCreate(0); xstart = 0; ystart = 0; while (1) { if (!nextOnPixelInRaster(pix1, xstart, ystart, &x, &y)) break; if ((box = pixSeedfillBB(pix1, stack, x, y, connectivity)) == NULL) { L_ERROR("box not made\n", procName); pixaDestroy(&pixa); boxaDestroy(&boxa); goto cleanup; } boxaAddBox(boxa, box, L_INSERT); /* Save the c.c. and remove from pix2 as well */ pix3 = pixClipRectangle(pix1, box, NULL); pix4 = pixClipRectangle(pix2, box, NULL); pixXor(pix3, pix3, pix4); pixRasterop(pix2, box->x, box->y, box->w, box->h, PIX_SRC ^ PIX_DST, pix3, 0, 0); pixaAddPix(pixa, pix3, L_INSERT); pixDestroy(&pix4); xstart = x; ystart = y; } #if DEBUG pixCountPixels(pix1, &iszero, NULL); fprintf(stderr, "Number of remaining pixels = %d\n", iszero); pixWrite("junkremain", pix1, IFF_PNG); #endif /* DEBUG */ /* Remove old boxa of pixa and replace with a clone copy */ boxaDestroy(&pixa->boxa); pixa->boxa = boxaCopy(boxa, L_CLONE); *ppixa = pixa; /* Cleanup, freeing the fillsegs on each stack */ cleanup: lstackDestroy(&stack, TRUE); pixDestroy(&pix1); pixDestroy(&pix2); return boxa; }
main(int argc, char **argv) { l_int32 i, j, w1, h1, w2, h2, w, h, same; BOX *box1, *box2; PIX *pixs, *pixs1, *pixs2, *pix1, *pix2; PIX *pixg, *pixg1, *pixg2, *pixc2, *pixbl, *pixd; PIXA *pixa; static char mainName[] = "blend2_reg"; /* --- Set up the 8 bpp blending image --- */ pixg = pixCreate(660, 500, 8); for (i = 0; i < 500; i++) for (j = 0; j < 660; j++) pixSetPixel(pixg, j, i, (l_int32)(0.775 * j) % 256); /* --- Set up the initial color images to be blended together --- */ pixs1 = pixRead("wyom.jpg"); pixs2 = pixRead("fish24.jpg"); pixGetDimensions(pixs1, &w1, &h1, NULL); pixGetDimensions(pixs2, &w2, &h2, NULL); h = L_MIN(h1, h2); w = L_MIN(w1, w2); box1 = boxCreate(0, 0, w1, h1); box2 = boxCreate(0, 300, 660, 500); pix1 = pixClipRectangle(pixs1, box1, NULL); pix2 = pixClipRectangle(pixs2, box2, NULL); pixDestroy(&pixs1); pixDestroy(&pixs2); boxDestroy(&box1); boxDestroy(&box2); /* --- Blend 2 rgb images --- */ pixa = pixaCreate(0); pixSaveTiled(pixg, pixa, 1, 1, 40, 32); pixd = pixBlendWithGrayMask(pix1, pix2, pixg, 50, 50); pixSaveTiled(pix1, pixa, 1, 1, 40, 32); pixSaveTiled(pix2, pixa, 1, 0, 40, 32); pixSaveTiled(pixd, pixa, 1, 0, 40, 32); pixDestroy(&pixd); /* --- Blend 2 grayscale images --- */ pixg1 = pixConvertRGBToLuminance(pix1); pixg2 = pixConvertRGBToLuminance(pix2); pixd = pixBlendWithGrayMask(pixg1, pixg2, pixg, 50, 50); pixSaveTiled(pixg1, pixa, 1, 1, 40, 32); pixSaveTiled(pixg2, pixa, 1, 0, 40, 32); pixSaveTiled(pixd, pixa, 1, 0, 40, 32); pixDestroy(&pixg1); pixDestroy(&pixg2); pixDestroy(&pixd); /* --- Blend a colormap image and an rgb image --- */ pixc2 = pixFixedOctcubeQuantGenRGB(pix2, 2); pixd = pixBlendWithGrayMask(pix1, pixc2, pixg, 50, 50); pixSaveTiled(pix1, pixa, 1, 1, 40, 32); pixSaveTiled(pixc2, pixa, 1, 0, 40, 32); pixSaveTiled(pixd, pixa, 1, 0, 40, 32); pixDestroy(&pixc2); pixDestroy(&pixd); /* --- Blend a colormap image and a grayscale image --- */ pixg1 = pixConvertRGBToLuminance(pix1); pixc2 = pixFixedOctcubeQuantGenRGB(pix2, 2); pixd = pixBlendWithGrayMask(pixg1, pixc2, pixg, 50, 50); pixSaveTiled(pixg1, pixa, 1, 1, 40, 32); pixSaveTiled(pixc2, pixa, 1, 0, 40, 32); pixSaveTiled(pixd, pixa, 1, 0, 40, 32); pixDestroy(&pixd); pixd = pixBlendWithGrayMask(pixg1, pixc2, pixg, -100, -100); pixSaveTiled(pixg1, pixa, 1, 1, 40, 32); pixSaveTiled(pixc2, pixa, 1, 0, 40, 32); pixSaveTiled(pixd, pixa, 1, 0, 40, 32); pixDestroy(&pixd); pixDestroy(&pixg1); pixDestroy(&pixc2); /* --- Test png read/write with alpha channel --- */ /* First make pixs1, using pixg as the alpha channel */ pixs = pixRead("fish24.jpg"); box1 = boxCreate(0, 300, 660, 500); pixs1 = pixClipRectangle(pixs, box1, NULL); pixSaveTiled(pixs1, pixa, 1, 1, 40, 32); pixSetRGBComponent(pixs1, pixg, L_ALPHA_CHANNEL); /* To see the alpha channel, blend with a black image */ pixbl = pixCreate(660, 500, 32); pixd = pixBlendWithGrayMask(pixbl, pixs1, NULL, 0, 0); pixSaveTiled(pixd, pixa, 1, 0, 40, 32); pixDestroy(&pixd); /* Write out the RGBA image and read it back */ l_pngSetWriteAlpha(1); pixWrite("/tmp/junkpixs1.png", pixs1, IFF_PNG); l_pngSetStripAlpha(0); pixs2 = pixRead("/tmp/junkpixs1.png"); /* Make sure that the alpha channel image hasn't changed */ pixg2 = pixGetRGBComponent(pixs2, L_ALPHA_CHANNEL); pixEqual(pixg, pixg2, &same); if (same) fprintf(stderr, "PNG with alpha read/write OK\n"); else fprintf(stderr, "PNG with alpha read/write failed\n"); /* Blend again with a black image */ pixd = pixBlendWithGrayMask(pixbl, pixs2, NULL, 0, 0); pixSaveTiled(pixd, pixa, 1, 0, 40, 32); pixDestroy(&pixd); /* Blend with a white image */ pixSetAll(pixbl); pixd = pixBlendWithGrayMask(pixbl, pixs2, NULL, 0, 0); pixSaveTiled(pixd, pixa, 1, 0, 40, 32); pixDestroy(&pixd); l_pngSetWriteAlpha(0); /* reset to default */ l_pngSetStripAlpha(1); /* reset to default */ pixDestroy(&pixbl); pixDestroy(&pixs); pixDestroy(&pixs1); pixDestroy(&pixs2); pixDestroy(&pixg2); boxDestroy(&box1); /* --- Display results --- */ pixd = pixaDisplay(pixa, 0, 0); pixDisplay(pixd, 100, 100); pixWrite("/tmp/junkblend2.jpg", pixd, IFF_JFIF_JPEG); pixDestroy(&pixd); pixaDestroy(&pixa); pixDestroy(&pixg); pixDestroy(&pix1); pixDestroy(&pix2); return 0; }
int main(int argc, char **argv) { l_uint8 *data1, *data2; l_int32 i, n; size_t size1, size2; BOX *box; PIX *pix, *pix1, *pix2, *pix3; PIXA *pixa, *pixa1; PIXC *pixc, *pixc1, *pixc2; PIXAC *pixac, *pixac1, *pixac2; L_REGPARAMS *rp; SARRAY *sa; if (regTestSetup(argc, argv, &rp)) return 1; lept_mkdir("lept/comp"); pixac = pixacompCreate(1); pixa = pixaCreate(0); /* --- Read in the images --- */ pix1 = pixRead("marge.jpg"); pixc1 = pixcompCreateFromPix(pix1, IFF_JFIF_JPEG); pix2 = pixCreateFromPixcomp(pixc1); pixc2 = pixcompCreateFromPix(pix2, IFF_JFIF_JPEG); pix3 = pixCreateFromPixcomp(pixc2); regTestWritePixAndCheck(rp, pix3, IFF_JFIF_JPEG); /* 0 */ pixSaveTiledOutline(pix3, pixa, 1.0, 1, 30, 2, 32); pixacompAddPix(pixac, pix1, IFF_DEFAULT); pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); pixcompDestroy(&pixc1); pixcompDestroy(&pixc2); pix = pixRead("feyn.tif"); pix1 = pixScaleToGray6(pix); pixc1 = pixcompCreateFromPix(pix1, IFF_JFIF_JPEG); pix2 = pixCreateFromPixcomp(pixc1); pixc2 = pixcompCreateFromPix(pix2, IFF_JFIF_JPEG); pix3 = pixCreateFromPixcomp(pixc2); regTestWritePixAndCheck(rp, pix3, IFF_JFIF_JPEG); /* 1 */ pixSaveTiledOutline(pix3, pixa, 1.0, 1, 30, 2, 32); pixacompAddPix(pixac, pix1, IFF_DEFAULT); pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); pixcompDestroy(&pixc1); pixcompDestroy(&pixc2); box = boxCreate(1144, 611, 690, 180); pix1 = pixClipRectangle(pix, box, NULL); pixc1 = pixcompCreateFromPix(pix1, IFF_TIFF_G4); pix2 = pixCreateFromPixcomp(pixc1); pixc2 = pixcompCreateFromPix(pix2, IFF_TIFF_G4); pix3 = pixCreateFromPixcomp(pixc2); regTestWritePixAndCheck(rp, pix3, IFF_TIFF_G4); /* 2 */ pixSaveTiledOutline(pix3, pixa, 1.0, 0, 30, 2, 32); pixacompAddPix(pixac, pix1, IFF_DEFAULT); boxDestroy(&box); pixDestroy(&pix); pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); pixcompDestroy(&pixc1); pixcompDestroy(&pixc2); pix1 = pixRead("weasel4.11c.png"); pixc1 = pixcompCreateFromPix(pix1, IFF_PNG); pix2 = pixCreateFromPixcomp(pixc1); pixc2 = pixcompCreateFromPix(pix2, IFF_PNG); pix3 = pixCreateFromPixcomp(pixc2); regTestWritePixAndCheck(rp, pix3, IFF_PNG); /* 3 */ pixSaveTiledOutline(pix3, pixa, 1.0, 0, 30, 2, 32); pixacompAddPix(pixac, pix1, IFF_DEFAULT); pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); pixcompDestroy(&pixc1); pixcompDestroy(&pixc2); /* --- Extract formatting info from compressed strings --- */ for (i = 0; i < 4; i++) { pixc = pixacompGetPixcomp(pixac, i, L_NOCOPY); get_format_data(i, pixc->data, pixc->size); } /* Save a tiled composite from the pixa */ pix1 = pixaDisplayTiledAndScaled(pixa, 32, 400, 4, 0, 20, 2); regTestWritePixAndCheck(rp, pix1, IFF_JFIF_JPEG); /* 4 */ pixDestroy(&pix1); /* Convert the pixac --> pixa and save a tiled composite */ pixa1 = pixaCreateFromPixacomp(pixac, L_COPY); pix1 = pixaDisplayTiledAndScaled(pixa1, 32, 400, 4, 0, 20, 2); regTestWritePixAndCheck(rp, pix1, IFF_JFIF_JPEG); /* 5 */ pixaDestroy(&pixa1); pixDestroy(&pix1); /* Make a pixacomp from files, and join */ sa = sarrayCreate(0); for (i = 0; i < 6; i++) sarrayAddString(sa, (char *)fnames[i], L_COPY); pixac1 = pixacompCreateFromSA(sa, IFF_DEFAULT); pixacompJoin(pixac1, pixac, 0, -1); pixa1 = pixaCreateFromPixacomp(pixac1, L_COPY); pix1 = pixaDisplayTiledAndScaled(pixa1, 32, 250, 10, 0, 20, 2); regTestWritePixAndCheck(rp, pix1, IFF_JFIF_JPEG); /* 6 */ pixacompDestroy(&pixac1); pixaDestroy(&pixa1); pixDestroy(&pix1); sarrayDestroy(&sa); /* Test serialized I/O */ pixacompWrite("/tmp/lept/comp/file1.pac", pixac); regTestCheckFile(rp, "/tmp/lept/comp/file1.pac"); /* 7 */ pixac1 = pixacompRead("/tmp/lept/comp/file1.pac"); pixacompWrite("/tmp/lept/comp/file2.pac", pixac1); regTestCheckFile(rp, "/tmp/lept/comp/file2.pac"); /* 8 */ regTestCompareFiles(rp, 7, 8); /* 9 */ pixac2 = pixacompRead("/tmp/lept/comp/file2.pac"); pixa1 = pixaCreateFromPixacomp(pixac2, L_COPY); pix1 = pixaDisplayTiledAndScaled(pixa1, 32, 250, 4, 0, 20, 2); regTestWritePixAndCheck(rp, pix1, IFF_JFIF_JPEG); /* 10 */ pixacompDestroy(&pixac1); pixacompDestroy(&pixac2); pixaDestroy(&pixa1); pixDestroy(&pix1); /* Test serialized pixacomp I/O to and from memory */ pixacompWriteMem(&data1, &size1, pixac); pixac1 = pixacompReadMem(data1, size1); pixacompWriteMem(&data2, &size2, pixac1); pixac2 = pixacompReadMem(data2, size2); pixacompWrite("/tmp/lept/comp/file3.pac", pixac1); regTestCheckFile(rp, "/tmp/lept/comp/file3.pac"); /* 11 */ pixacompWrite("/tmp/lept/comp/file4.pac", pixac2); regTestCheckFile(rp, "/tmp/lept/comp/file4.pac"); /* 12 */ regTestCompareFiles(rp, 11, 12); /* 13 */ pixacompDestroy(&pixac1); pixacompDestroy(&pixac2); lept_free(data1); lept_free(data2); pixaDestroy(&pixa); pixacompDestroy(&pixac); return regTestCleanup(rp); }
//--------------------------------------------------------------------------- //Поиск основной надписи в указанном файле //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); }
int main(int argc, char **argv) { l_int32 index; l_uint32 val32; BOX *box, *box1, *box2, *box3, *box4, *box5; BOXA *boxa; L_KERNEL *kel; PIX *pixs, *pixg, *pixb, *pixd, *pixt, *pix1, *pix2, *pix3, *pix4; PIXA *pixa; PIXCMAP *cmap; L_REGPARAMS *rp; if (regTestSetup(argc, argv, &rp)) return 1; pixa = pixaCreate(0); /* Color non-white pixels on RGB */ pixs = pixRead("lucasta-frag.jpg"); pixt = pixConvert8To32(pixs); box = boxCreate(120, 30, 200, 200); pixColorGray(pixt, box, L_PAINT_DARK, 220, 0, 0, 255); regTestWritePixAndCheck(rp, pixt, IFF_JFIF_JPEG); /* 0 */ pixaAddPix(pixa, pixt, L_COPY); pixColorGray(pixt, NULL, L_PAINT_DARK, 220, 255, 100, 100); regTestWritePixAndCheck(rp, pixt, IFF_JFIF_JPEG); /* 1 */ pixaAddPix(pixa, pixt, L_INSERT); boxDestroy(&box); /* Color non-white pixels on colormap */ pixt = pixThresholdTo4bpp(pixs, 6, 1); box = boxCreate(120, 30, 200, 200); pixColorGray(pixt, box, L_PAINT_DARK, 220, 0, 0, 255); regTestWritePixAndCheck(rp, pixt, IFF_PNG); /* 2 */ pixaAddPix(pixa, pixt, L_COPY); pixColorGray(pixt, NULL, L_PAINT_DARK, 220, 255, 100, 100); regTestWritePixAndCheck(rp, pixt, IFF_PNG); /* 3 */ pixaAddPix(pixa, pixt, L_INSERT); boxDestroy(&box); /* Color non-black pixels on RGB */ pixt = pixConvert8To32(pixs); box = boxCreate(120, 30, 200, 200); pixColorGray(pixt, box, L_PAINT_LIGHT, 20, 0, 0, 255); regTestWritePixAndCheck(rp, pixt, IFF_PNG); /* 4 */ pixaAddPix(pixa, pixt, L_COPY); pixColorGray(pixt, NULL, L_PAINT_LIGHT, 80, 255, 100, 100); regTestWritePixAndCheck(rp, pixt, IFF_PNG); /* 5 */ pixaAddPix(pixa, pixt, L_INSERT); boxDestroy(&box); /* Color non-black pixels on colormap */ pixt = pixThresholdTo4bpp(pixs, 6, 1); box = boxCreate(120, 30, 200, 200); pixColorGray(pixt, box, L_PAINT_LIGHT, 20, 0, 0, 255); regTestWritePixAndCheck(rp, pixt, IFF_PNG); /* 6 */ pixaAddPix(pixa, pixt, L_COPY); pixColorGray(pixt, NULL, L_PAINT_LIGHT, 20, 255, 100, 100); regTestWritePixAndCheck(rp, pixt, IFF_PNG); /* 7 */ pixaAddPix(pixa, pixt, L_INSERT); boxDestroy(&box); /* Add highlight color to RGB */ pixt = pixConvert8To32(pixs); box = boxCreate(507, 5, 385, 45); pixg = pixClipRectangle(pixs, box, NULL); pixb = pixThresholdToBinary(pixg, 180); pixInvert(pixb, pixb); pixDisplayWrite(pixb, 1); composeRGBPixel(50, 0, 250, &val32); pixPaintThroughMask(pixt, pixb, box->x, box->y, val32); boxDestroy(&box); pixDestroy(&pixg); pixDestroy(&pixb); box = boxCreate(236, 107, 262, 40); pixg = pixClipRectangle(pixs, box, NULL); pixb = pixThresholdToBinary(pixg, 180); pixInvert(pixb, pixb); composeRGBPixel(250, 0, 50, &val32); pixPaintThroughMask(pixt, pixb, box->x, box->y, val32); boxDestroy(&box); pixDestroy(&pixg); pixDestroy(&pixb); box = boxCreate(222, 208, 247, 43); pixg = pixClipRectangle(pixs, box, NULL); pixb = pixThresholdToBinary(pixg, 180); pixInvert(pixb, pixb); composeRGBPixel(60, 250, 60, &val32); pixPaintThroughMask(pixt, pixb, box->x, box->y, val32); regTestWritePixAndCheck(rp, pixt, IFF_PNG); /* 8 */ pixaAddPix(pixa, pixt, L_INSERT); boxDestroy(&box); pixDestroy(&pixg); pixDestroy(&pixb); /* Add highlight color to colormap */ pixt = pixThresholdTo4bpp(pixs, 5, 1); cmap = pixGetColormap(pixt); pixcmapGetIndex(cmap, 255, 255, 255, &index); box = boxCreate(507, 5, 385, 45); pixSetSelectCmap(pixt, box, index, 50, 0, 250); boxDestroy(&box); box = boxCreate(236, 107, 262, 40); pixSetSelectCmap(pixt, box, index, 250, 0, 50); boxDestroy(&box); box = boxCreate(222, 208, 247, 43); pixSetSelectCmap(pixt, box, index, 60, 250, 60); regTestWritePixAndCheck(rp, pixt, IFF_PNG); /* 9 */ pixaAddPix(pixa, pixt, L_INSERT); boxDestroy(&box); /* Paint lines on RGB */ pixt = pixConvert8To32(pixs); pixRenderLineArb(pixt, 450, 20, 850, 320, 5, 200, 50, 125); pixRenderLineArb(pixt, 30, 40, 440, 40, 5, 100, 200, 25); box = boxCreate(70, 80, 300, 245); pixRenderBoxArb(pixt, box, 3, 200, 200, 25); regTestWritePixAndCheck(rp, pixt, IFF_JFIF_JPEG); /* 10 */ pixaAddPix(pixa, pixt, L_INSERT); boxDestroy(&box); /* Paint lines on colormap */ pixt = pixThresholdTo4bpp(pixs, 5, 1); pixRenderLineArb(pixt, 450, 20, 850, 320, 5, 200, 50, 125); pixRenderLineArb(pixt, 30, 40, 440, 40, 5, 100, 200, 25); box = boxCreate(70, 80, 300, 245); pixRenderBoxArb(pixt, box, 3, 200, 200, 25); regTestWritePixAndCheck(rp, pixt, IFF_PNG); /* 11 */ pixaAddPix(pixa, pixt, L_INSERT); boxDestroy(&box); /* Blend lines on RGB */ pixt = pixConvert8To32(pixs); pixRenderLineBlend(pixt, 450, 20, 850, 320, 5, 200, 50, 125, 0.35); pixRenderLineBlend(pixt, 30, 40, 440, 40, 5, 100, 200, 25, 0.35); box = boxCreate(70, 80, 300, 245); pixRenderBoxBlend(pixt, box, 3, 200, 200, 25, 0.6); regTestWritePixAndCheck(rp, pixt, IFF_JFIF_JPEG); /* 12 */ pixaAddPix(pixa, pixt, L_INSERT); boxDestroy(&box); /* Colorize gray on cmapped image. */ pix1 = pixRead("lucasta.150.jpg"); pix2 = pixThresholdTo4bpp(pix1, 7, 1); box1 = boxCreate(73, 206, 140, 27); pixColorGrayCmap(pix2, box1, L_PAINT_LIGHT, 130, 207, 43); regTestWritePixAndCheck(rp, pix2, IFF_PNG); /* 13 */ pixaAddPix(pixa, pix2, L_COPY); if (rp->display) pixPrintStreamInfo(stderr, pix2, "One box added"); box2 = boxCreate(255, 404, 197, 25); pixColorGrayCmap(pix2, box2, L_PAINT_LIGHT, 230, 67, 119); regTestWritePixAndCheck(rp, pix2, IFF_PNG); /* 14 */ pixaAddPix(pixa, pix2, L_COPY); if (rp->display) pixPrintStreamInfo(stderr, pix2, "Two boxes added"); box3 = boxCreate(122, 756, 224, 22); pixColorGrayCmap(pix2, box3, L_PAINT_DARK, 230, 67, 119); regTestWritePixAndCheck(rp, pix2, IFF_PNG); /* 15 */ pixaAddPix(pixa, pix2, L_COPY); if (rp->display) pixPrintStreamInfo(stderr, pix2, "Three boxes added"); box4 = boxCreate(11, 780, 147, 22); pixColorGrayCmap(pix2, box4, L_PAINT_LIGHT, 70, 137, 229); regTestWritePixAndCheck(rp, pix2, IFF_PNG); /* 16 */ pixaAddPix(pixa, pix2, L_COPY); if (rp->display) pixPrintStreamInfo(stderr, pix2, "Four boxes added"); box5 = boxCreate(163, 605, 78, 22); pixColorGrayCmap(pix2, box5, L_PAINT_LIGHT, 70, 137, 229); regTestWritePixAndCheck(rp, pix2, IFF_PNG); /* 17 */ pixaAddPix(pixa, pix2, L_INSERT); if (rp->display) pixPrintStreamInfo(stderr, pix2, "Five boxes added"); pixDestroy(&pix1); boxDestroy(&box1); boxDestroy(&box2); boxDestroy(&box3); boxDestroy(&box4); boxDestroy(&box5); pixDestroy(&pixs); /* Make a gray image and identify the fg pixels (val > 230) */ pixs = pixRead("feyn-fract.tif"); pix1 = pixConvertTo8(pixs, 0); kel = makeGaussianKernel(2, 2, 1.5, 1.0); pix2 = pixConvolve(pix1, kel, 8, 1); pix3 = pixThresholdToBinary(pix2, 230); boxa = pixConnComp(pix3, NULL, 8); pixDestroy(&pixs); pixDestroy(&pix1); pixDestroy(&pix3); kernelDestroy(&kel); /* Color the individual components in the gray image */ pix4 = pixColorGrayRegions(pix2, boxa, L_PAINT_DARK, 230, 255, 0, 0); regTestWritePixAndCheck(rp, pix4, IFF_PNG); /* 18 */ pixaAddPix(pixa, pix4, L_INSERT); pixDisplayWithTitle(pix4, 0, 0, NULL, rp->display); /* Threshold to 10 levels of gray */ pix3 = pixThresholdOn8bpp(pix2, 10, 1); regTestWritePixAndCheck(rp, pix3, IFF_PNG); /* 19 */ pixaAddPix(pixa, pix3, L_COPY); /* Color the individual components in the cmapped image */ pix4 = pixColorGrayRegions(pix3, boxa, L_PAINT_DARK, 230, 255, 0, 0); regTestWritePixAndCheck(rp, pix4, IFF_PNG); /* 20 */ pixaAddPix(pixa, pix4, L_INSERT); pixDisplayWithTitle(pix4, 0, 100, NULL, rp->display); boxaDestroy(&boxa); /* Color the entire gray image (not component-wise) */ pixColorGray(pix2, NULL, L_PAINT_DARK, 230, 255, 0, 0); regTestWritePixAndCheck(rp, pix2, IFF_PNG); /* 21 */ pixaAddPix(pixa, pix2, L_INSERT); /* Color the entire cmapped image (not component-wise) */ pixColorGray(pix3, NULL, L_PAINT_DARK, 230, 255, 0, 0); regTestWritePixAndCheck(rp, pix3, IFF_PNG); /* 22 */ pixaAddPix(pixa, pix3, L_INSERT); /* Reconstruct cmapped images */ pixd = ReconstructByValue(rp, "weasel2.4c.png"); regTestWritePixAndCheck(rp, pixd, IFF_PNG); /* 23 */ pixaAddPix(pixa, pixd, L_INSERT); pixd = ReconstructByValue(rp, "weasel4.11c.png"); regTestWritePixAndCheck(rp, pixd, IFF_PNG); /* 24 */ pixaAddPix(pixa, pixd, L_INSERT); pixd = ReconstructByValue(rp, "weasel8.240c.png"); regTestWritePixAndCheck(rp, pixd, IFF_PNG); /* 25 */ pixaAddPix(pixa, pixd, L_INSERT); /* Fake reconstruct cmapped images, with one color into a band */ pixd = FakeReconstructByBand(rp, "weasel2.4c.png"); regTestWritePixAndCheck(rp, pixd, IFF_PNG); /* 26 */ pixaAddPix(pixa, pixd, L_INSERT); pixd = FakeReconstructByBand(rp, "weasel4.11c.png"); regTestWritePixAndCheck(rp, pixd, IFF_PNG); /* 27 */ pixaAddPix(pixa, pixd, L_INSERT); pixd = FakeReconstructByBand(rp, "weasel8.240c.png"); regTestWritePixAndCheck(rp, pixd, IFF_PNG); /* 28 */ pixaAddPix(pixa, pixd, L_INSERT); /* If in testing mode, make a pdf */ if (rp->display) { pixaConvertToPdf(pixa, 100, 1.0, L_FLATE_ENCODE, 0, "Colorize and paint", "/tmp/lept/regout/paint.pdf"); L_INFO("Output pdf: /tmp/lept/regout/paint.pdf\n", rp->testname); } pixaDestroy(&pixa); return regTestCleanup(rp); }
int main(int argc, char **argv) { char buf[256]; l_int32 w, h, i, j, k, index, op, dir, stretch; l_float32 del, angle, angledeg; BOX *box; L_BMF *bmf; PIX *pixs, *pix1, *pix2, *pixd; PIXA *pixa; static char mainName[] = "warpertest"; if (argc != 1) return ERROR_INT("syntax: warpertest", mainName, 1); bmf = bmfCreate(NULL, 6); /* -------- Stereoscopic warping --------------*/ #if RUN_WARP pixs = pixRead("german.png"); pixGetDimensions(pixs, &w, &h, NULL); pixa = pixaCreate(50); for (i = 0; i < 50; i++) { /* need to test > 2 widths ! */ j = 7 * i; box = boxCreate(0, 0, w - j, h - j); pix1 = pixClipRectangle(pixs, box, NULL); pixd = pixWarpStereoscopic(pix1, 15, 22, 8, 30, -20, 1); pixSetChromaSampling(pixd, 0); pixaAddPix(pixa, pixd, L_INSERT); pixDestroy(&pix1); boxDestroy(&box); } pixDestroy(&pixs); pixaConvertToPdf(pixa, 100, 1.0, L_JPEG_ENCODE, 0, "warp.pdf", "/tmp/warp.pdf"); pixd = pixaDisplayTiledInRows(pixa, 32, 2000, 1.0, 0, 20, 2); pixWrite("/tmp/warp.jpg", pixd, IFF_JFIF_JPEG); pixaDestroy(&pixa); pixDestroy(&pixd); #endif /* -------- Quadratic Vertical Shear --------------*/ #if RUN_QUAD_VERT_SHEAR pixs = pixCreate(501, 501, 32); pixGetDimensions(pixs, &w, &h, NULL); pixSetAll(pixs); pixRenderLineArb(pixs, 0, 30, 500, 30, 5, 0, 0, 255); pixRenderLineArb(pixs, 0, 110, 500, 110, 5, 0, 255, 0); pixRenderLineArb(pixs, 0, 190, 500, 190, 5, 0, 255, 255); pixRenderLineArb(pixs, 0, 270, 500, 270, 5, 255, 0, 0); pixRenderLineArb(pixs, 0, 360, 500, 360, 5, 255, 0, 255); pixRenderLineArb(pixs, 0, 450, 500, 450, 5, 255, 255, 0); pixa = pixaCreate(50); for (i = 0; i < 50; i++) { j = 3 * i; dir = ((i / 2) & 1) ? L_WARP_TO_RIGHT : L_WARP_TO_LEFT; op = (i & 1) ? L_INTERPOLATED : L_SAMPLED; box = boxCreate(0, 0, w - j, h - j); pix1 = pixClipRectangle(pixs, box, NULL); pix2 = pixQuadraticVShear(pix1, dir, 60, -20, op, L_BRING_IN_WHITE); snprintf(buf, sizeof(buf), "%s, %s", dirstr[dir], opstr[op]); pixd = pixAddSingleTextblock(pix2, bmf, buf, 0xff000000, L_ADD_BELOW, 0); pixaAddPix(pixa, pixd, L_INSERT); pixDestroy(&pix1); pixDestroy(&pix2); boxDestroy(&box); } pixDestroy(&pixs); pixaConvertToPdf(pixa, 100, 1.0, L_FLATE_ENCODE, 0, "quad_vshear.pdf", "/tmp/quad_vshear.pdf"); pixd = pixaDisplayTiledInRows(pixa, 32, 2000, 1.0, 0, 20, 2); pixWrite("/tmp/quad_vshear.jpg", pixd, IFF_PNG); pixaDestroy(&pixa); pixDestroy(&pixd); #endif /* -------- Linear Horizontal stretching --------------*/ #if RUN_LIN_HORIZ_STRETCH pixs = pixRead("german.png"); pixa = pixaCreate(50); for (k = 0; k < 2; k++) { for (i = 0; i < 25; i++) { index = 25 * k + i; stretch = 10 + 4 * i; if (k == 0) stretch = -stretch; dir = (k == 1) ? L_WARP_TO_RIGHT : L_WARP_TO_LEFT; op = (i & 1) ? L_INTERPOLATED : L_SAMPLED; pix1 = pixStretchHorizontal(pixs, dir, L_LINEAR_WARP, stretch, op, L_BRING_IN_WHITE); snprintf(buf, sizeof(buf), "%s, %s", dirstr[dir], opstr[op]); pixd = pixAddSingleTextblock(pix1, bmf, buf, 0xff000000, L_ADD_BELOW, 0); pixaAddPix(pixa, pixd, L_INSERT); pixDestroy(&pix1); } } pixDestroy(&pixs); pixaConvertToPdf(pixa, 100, 1.0, L_JPEG_ENCODE, 0, "linear_hstretch.pdf", "/tmp/linear_hstretch.pdf"); pixd = pixaDisplayTiledInRows(pixa, 32, 2500, 1.0, 0, 20, 2); pixWrite("/tmp/linear_hstretch.jpg", pixd, IFF_JFIF_JPEG); pixaDestroy(&pixa); pixDestroy(&pixd); #endif /* -------- Quadratic Horizontal stretching --------------*/ #if RUN_QUAD_HORIZ_STRETCH pixs = pixRead("german.png"); pixa = pixaCreate(50); for (k = 0; k < 2; k++) { for (i = 0; i < 25; i++) { index = 25 * k + i; stretch = 10 + 4 * i; if (k == 0) stretch = -stretch; dir = (k == 1) ? L_WARP_TO_RIGHT : L_WARP_TO_LEFT; op = (i & 1) ? L_INTERPOLATED : L_SAMPLED; pix1 = pixStretchHorizontal(pixs, dir, L_QUADRATIC_WARP, stretch, op, L_BRING_IN_WHITE); snprintf(buf, sizeof(buf), "%s, %s", dirstr[dir], opstr[op]); pixd = pixAddSingleTextblock(pix1, bmf, buf, 0xff000000, L_ADD_BELOW, 0); pixaAddPix(pixa, pixd, L_INSERT); pixDestroy(&pix1); } } pixDestroy(&pixs); pixaConvertToPdf(pixa, 100, 1.0, L_JPEG_ENCODE, 0, "quad_hstretch.pdf", "/tmp/quad_hstretch.pdf"); pixd = pixaDisplayTiledInRows(pixa, 32, 2500, 1.0, 0, 20, 2); pixWrite("/tmp/quad_hstretch.jpg", pixd, IFF_JFIF_JPEG); pixaDestroy(&pixa); pixDestroy(&pixd); #endif /* -------- Horizontal Shear --------------*/ #if RUN_HORIZ_SHEAR pixs = pixRead("german.png"); pixGetDimensions(pixs, &w, &h, NULL); pixa = pixaCreate(50); for (i = 0; i < 25; i++) { del = 0.2 / 12.; angle = -0.2 + (i - (i & 1)) * del; angledeg = 180. * angle / 3.14159265; op = (i & 1) ? L_INTERPOLATED : L_SAMPLED; if (op == L_SAMPLED) pix1 = pixHShear(NULL, pixs, h / 2, angle, L_BRING_IN_WHITE); else pix1 = pixHShearLI(pixs, h / 2, angle, L_BRING_IN_WHITE); snprintf(buf, sizeof(buf), "%6.2f degree, %s", angledeg, opstr[op]); pixd = pixAddSingleTextblock(pix1, bmf, buf, 0xff000000, L_ADD_BELOW, 0); pixaAddPix(pixa, pixd, L_INSERT); pixDestroy(&pix1); } pixDestroy(&pixs); pixaConvertToPdf(pixa, 100, 1.0, L_JPEG_ENCODE, 0, "hshear.pdf", "/tmp/hshear.pdf"); pixd = pixaDisplayTiledInRows(pixa, 32, 2500, 1.0, 0, 20, 2); pixWrite("/tmp/hshear.jpg", pixd, IFF_JFIF_JPEG); pixaDestroy(&pixa); pixDestroy(&pixd); #endif /* -------- Vertical Shear --------------*/ #if RUN_VERT_SHEAR pixs = pixRead("german.png"); pixGetDimensions(pixs, &w, &h, NULL); pixa = pixaCreate(50); for (i = 0; i < 25; i++) { del = 0.2 / 12.; angle = -0.2 + (i - (i & 1)) * del; angledeg = 180. * angle / 3.14159265; op = (i & 1) ? L_INTERPOLATED : L_SAMPLED; if (op == L_SAMPLED) pix1 = pixVShear(NULL, pixs, w / 2, angle, L_BRING_IN_WHITE); else pix1 = pixVShearLI(pixs, w / 2, angle, L_BRING_IN_WHITE); snprintf(buf, sizeof(buf), "%6.2f degree, %s", angledeg, opstr[op]); pixd = pixAddSingleTextblock(pix1, bmf, buf, 0xff000000, L_ADD_BELOW, 0); pixaAddPix(pixa, pixd, L_INSERT); pixDestroy(&pix1); } pixDestroy(&pixs); pixaConvertToPdf(pixa, 100, 1.0, L_JPEG_ENCODE, 0, "vshear.pdf", "/tmp/vshear.pdf"); pixd = pixaDisplayTiledInRows(pixa, 32, 2500, 1.0, 0, 20, 2); pixWrite("/tmp/vshear.jpg", pixd, IFF_JFIF_JPEG); pixaDestroy(&pixa); pixDestroy(&pixd); #endif bmfDestroy(&bmf); return 0; }
std::vector<Figure> extractFigures(PIX *original, PageRegions &pageRegions, DocumentStatistics &docStats, bool verbose, bool showSteps, std::vector<Figure> &errors) { BOXA *bodytext = pageRegions.bodytext; BOXA *graphics = pageRegions.graphics; BOXA *captions = pageRegions.getCaptionsBoxa(); std::vector<Caption> unassigned_captions = pageRegions.captions; int total_captions = captions->n; PIXA *steps = showSteps ? pixaCreate(4) : NULL; // Add bodyText boxes to fill up the margin BOX *margin; BOX *foreground; pixClipToForeground(original, NULL, &foreground); BOX *extent; boxaGetExtent(graphics, NULL, NULL, &extent); margin = boxBoundingRegion(extent, foreground); boxDestroy(&extent); boxaGetExtent(bodytext, NULL, NULL, &extent); margin = boxBoundingRegion(margin, extent); boxDestroy(&extent); boxaGetExtent(pageRegions.other, NULL, NULL, &extent); margin = boxBoundingRegion(margin, extent); int x = margin->x - 2, y = margin->y - 2, h = margin->h + 4, w = margin->w + 4; x = std::max(x, 0); y = std::max(y, 0); h = std::min((int)original->h, h); w = std::min((int)original->w, w); boxDestroy(&margin); boxaAddBox(bodytext, boxCreate(0, 0, original->w, y), L_CLONE); boxaAddBox(bodytext, boxCreate(0, y + h, original->w, original->h - y - h), L_CLONE); boxaAddBox(bodytext, boxCreate(0, 0, x, original->h), L_CLONE); boxaAddBox(bodytext, boxCreate(x + w, 0, original->w - x - w, original->h), L_CLONE); // Add captions to body text boxaJoin(bodytext, captions, 0, captions->n); if (showSteps) pixaAddPix(steps, original, L_CLONE); // Generate proposed regions for each caption box double center = original->w / 2.0; BOXAA *allProposals = boxaaCreate(captions->n); BOXA *claimedImages = boxaCreate(captions->n); for (int i = 0; i < captions->n; i++) { BOX *captBox = boxaGetBox(captions, i, L_CLONE); BOXA *proposals = boxaCreate(4); for (int j = 0; j < bodytext->n; j++) { BOX *txtBox = boxaGetBox(bodytext, j, L_CLONE); BOX *proposal = NULL; int tolerance = 2; int horizontal = 0; int vertical = 0; boxAlignment(captBox, txtBox, tolerance, &horizontal, &vertical); if (vertical * horizontal != 0 or (vertical == 0 and horizontal == 0)) { continue; } if (vertical == 0) { if (horizontal == 1) { proposal = boxRelocateOneSide(NULL, captBox, txtBox->x + txtBox->w + 2, L_FROM_LEFT); } else if (horizontal == -1) { proposal = boxRelocateOneSide(NULL, captBox, txtBox->x - 2, L_FROM_RIGHT); } boxExpandUD(proposal, bodytext); if (horizontal == -1) { proposal->w -= captBox->w + 1; proposal->x = captBox->x + captBox->w + 1; } else if (horizontal == 1) { proposal->w -= captBox->w + 1; } } else { if (vertical == 1) { proposal = boxRelocateOneSide(NULL, captBox, txtBox->y + txtBox->h + 3, L_FROM_TOP); } else if (vertical == -1) { proposal = boxRelocateOneSide(NULL, captBox, txtBox->y - 3, L_FROM_BOT); } boxExpandLR(proposal, bodytext); if (vertical == -1) { proposal->h -= captBox->h + 1; proposal->y = captBox->y + captBox->h + 1; } else if (vertical == 1) { proposal->h -= captBox->h + 1; } } // For two columns document, captions that do not // cross the center should not have regions pass the center if (docStats.documentIsTwoColumn()) { if (captBox->x + captBox->w <= center and proposal->x + proposal->w > center) { boxRelocateOneSide(proposal, proposal, center - 1, L_FROM_RIGHT); } else if (captBox->x >= center and proposal->x < center) { boxRelocateOneSide(proposal, proposal, center + 1, L_FROM_LEFT); } } BOX *clippedProposal; pixClipBoxToForeground(original, proposal, NULL, &clippedProposal); if (clippedProposal != NULL and scoreBox(clippedProposal, pageRegions.captions.at(i).type, bodytext, graphics, claimedImages, original) > 0) { boxaAddBox(proposals, clippedProposal, L_CLONE); } } if (proposals->n > 0) { boxaaAddBoxa(allProposals, proposals, L_CLONE); } else { // Give up on this caption int on_caption = i - (total_captions - unassigned_captions.size()); errors.push_back(Figure(unassigned_captions.at(on_caption), NULL)); unassigned_captions.erase(unassigned_captions.begin() + on_caption); } } std::vector<Figure> figures = std::vector<Figure>(); if (unassigned_captions.size() == 0) { return figures; } // Now go through every possible assignment of captions // to proposals pick the highest scorign one int numConfigurations = 1; for (int i = 0; i < allProposals->n; ++i) { numConfigurations *= allProposals->boxa[i]->n; } if (verbose) printf("Found %d possible configurations\n", numConfigurations); BOXA *bestProposals = NULL; std::vector<bool> bestKeep; int bestFound = -1; double bestScore = -1; for (int onConfig = 0; onConfig < numConfigurations; ++onConfig) { // Gather the proposed regions based on the configuration number int configNum = onConfig; BOXA *proposals = boxaCreate(allProposals->n); std::vector<bool> keep; for (int i = 0; i < allProposals->n; ++i) { int numProposals = allProposals->boxa[i]->n; int selected = configNum % numProposals; configNum = configNum / numProposals; boxaAddBox(proposals, allProposals->boxa[i]->box[selected], L_COPY); } // Attempt to split any overlapping regions for (int i = 0; i < proposals->n; ++i) { for (int j = i; j < proposals->n; ++j) { BOX *p1 = proposals->box[i]; BOX *p2 = proposals->box[j]; int eq; boxEqual(p1, p2, &eq); if (not eq) continue; int vertical, horizontal; boxAlignment(unassigned_captions.at(i).boundingBox, unassigned_captions.at(j).boundingBox, 2, &horizontal, &vertical); if (vertical == 0 or horizontal != 0) continue; double split = splitBoxVertical(original, p1); if (split > 0) { BOX *topClipped; BOX *botClipped; BOX *top = boxRelocateOneSide(NULL, p1, split - 1, L_FROM_BOT); pixClipBoxToForeground(original, top, NULL, &topClipped); BOX *bot = boxRelocateOneSide(NULL, p1, split + 1, L_FROM_TOP); pixClipBoxToForeground(original, bot, NULL, &botClipped); if (vertical == -1) { proposals->box[i] = topClipped; proposals->box[j] = botClipped; } else { proposals->box[i] = botClipped; proposals->box[j] = topClipped; } if (verbose) printf("Split a region vertically\n"); } } } if (showSteps) { pixaAddPix(steps, pixDrawBoxa(original, proposals, 4, 0xff000000), L_CLONE); } // Score the proposals int numFound = 0; double totalScore = 0; for (int i = 0; i < proposals->n; ++i) { double score = scoreBox(proposals->box[i], pageRegions.captions.at(i).type, bodytext, graphics, proposals, original); totalScore += score; if (score > 0) { numFound += 1; keep.push_back(true); } else { keep.push_back(false); } } // Switch in for the current best needed if (numFound > bestFound or (numFound == bestFound and totalScore > bestScore)) { bestFound = numFound; bestScore = totalScore; bestProposals = proposals; bestKeep = keep; } } if (showSteps) { BOX *clip; PIXA *show = pixaCreate(4); pixClipBoxToForeground(original, NULL, NULL, &clip); int pad = 10; clip->x -= 10; clip->y -= 10; clip->w += pad * 2; clip->h += pad * 2; for (int i = 0; i < steps->n; ++i) { pixaAddPix(show, pixClipRectangle(steps->pix[i], clip, NULL), L_CLONE); } pixDisplay(pixaDisplayTiled(pixaConvertTo32(show), 4000, 1, 30), 0, 0); } for (int i = 0; i < bestProposals->n; ++i) { if (bestKeep.at(i)) { BOX *imageBox = bestProposals->box[i]; int pad = 2; imageBox->x -= pad; imageBox->y -= pad; imageBox->w += pad * 2; imageBox->h += pad * 2; figures.push_back(Figure(unassigned_captions.at(i), imageBox)); } else { errors.push_back(Figure(unassigned_captions.at(i), NULL)); } } return figures; }
/*! * dewarpShowResults() * * Input: dewa * sarray (of indexed input images) * boxa (crop boxes for input images; can be null) * firstpage, lastpage * fontdir (for text bitmap fonts) * pdfout (filename) * Return: 0 if OK, 1 on error * * Notes: * (1) This generates a pdf of image pairs (before, after) for * the designated set of input pages. * (2) If the boxa exists, its elements are aligned with numbers * in the filenames in @sa. It is used to crop the input images. * It is assumed that the dewa was generated from the cropped * images. No undercropping is applied before rendering. */ l_int32 dewarpShowResults(L_DEWARPA *dewa, SARRAY *sa, BOXA *boxa, l_int32 firstpage, l_int32 lastpage, const char *fontdir, const char *pdfout) { char bufstr[256]; char *outpath; l_int32 i, modelpage; L_BMF *bmf; BOX *box; L_DEWARP *dew; PIX *pixs, *pixc, *pixd, *pixt1, *pixt2; PIXA *pixa; PROCNAME("dewarpShowResults"); if (!dewa) return ERROR_INT("dewa not defined", procName, 1); if (!sa) return ERROR_INT("sa not defined", procName, 1); if (!pdfout) return ERROR_INT("pdfout not defined", procName, 1); if (firstpage > lastpage) return ERROR_INT("invalid first/last page numbers", procName, 1); lept_rmdir("dewarp_pdfout"); lept_mkdir("dewarp_pdfout"); if ((bmf = bmfCreate(fontdir, 6)) == NULL) L_ERROR("bmf not made; page info not displayed", procName); fprintf(stderr, "Dewarping and generating s/by/s view\n"); for (i = firstpage; i <= lastpage; i++) { if (i && (i % 10 == 0)) fprintf(stderr, ".. %d ", i); pixs = pixReadIndexed(sa, i); if (boxa) { box = boxaGetBox(boxa, i, L_CLONE); pixc = pixClipRectangle(pixs, box, NULL); boxDestroy(&box); } else pixc = pixClone(pixs); dew = dewarpaGetDewarp(dewa, i); pixd = NULL; if (dew) { dewarpaApplyDisparity(dewa, dew->pageno, pixc, GRAYIN_VALUE, 0, 0, &pixd, NULL); dewarpMinimize(dew); } pixa = pixaCreate(2); pixaAddPix(pixa, pixc, L_INSERT); if (pixd) pixaAddPix(pixa, pixd, L_INSERT); pixt1 = pixaDisplayTiledAndScaled(pixa, 32, 500, 2, 0, 35, 2); if (dew) { modelpage = (dew->hasref) ? dew->refpage : dew->pageno; snprintf(bufstr, sizeof(bufstr), "Page %d; using %d\n", i, modelpage); } else snprintf(bufstr, sizeof(bufstr), "Page %d; no dewarp\n", i); pixt2 = pixAddSingleTextblock(pixt1, bmf, bufstr, 0x0000ff00, L_ADD_BELOW, 0); snprintf(bufstr, sizeof(bufstr), "/tmp/dewarp_pdfout/%05d", i); pixWrite(bufstr, pixt2, IFF_JFIF_JPEG); pixaDestroy(&pixa); pixDestroy(&pixs); pixDestroy(&pixt1); pixDestroy(&pixt2); } fprintf(stderr, "\n"); fprintf(stderr, "Generating pdf of result\n"); convertFilesToPdf("/tmp/dewarp_pdfout", NULL, 100, 1.0, L_JPEG_ENCODE, 0, "Dewarp sequence", pdfout); outpath = genPathname(pdfout, NULL); fprintf(stderr, "Output written to: %s\n", outpath); FREE(outpath); bmfDestroy(&bmf); return 0; }