int TessDllAPI::BeginPage(uinT32 xsize,uinT32 ysize,unsigned char *buf,uinT8 bpp) { inT16 c; EndPage(); if (page_image.create (xsize+800, ysize+800, 1)==-1) return 0L; //make the image bigger to enclose in whitespace //copy the passed buffer into the center of the image IMAGE tmp; tmp.create(xsize, ysize, bpp); for (c=0;c<ysize;c++) CopyMemory(tmp.get_buffer ()+(c)*((xsize*bpp + 7)/8), buf+((ysize-1)-c)*((xsize*bpp + 7)/8),((xsize*bpp + 7)/8)); copy_sub_image(&tmp, 0, 0, 0, 0, &page_image, 400, 400, false); return ProcessPagePass1(); }
void scale_image_cop_out( //scale an image IMAGE &image, //source image IMAGE &target_image, //target image float factor, //scale factor int *hires, int *lores, int *oldhires, int *oldlores) { inT32 xsize, ysize, new_xsize, new_ysize; xsize = image.get_xsize (); ysize = image.get_ysize (); new_xsize = target_image.get_xsize (); new_ysize = target_image.get_ysize (); if (factor <= 0.5) reduce_sub_image (&image, 0, 0, xsize, ysize, &target_image, 0, 0, (inT32) (1.0 / factor), FALSE); else if (factor >= 2) enlarge_sub_image (&image, 0, 0, &target_image, 0, 0, new_xsize, new_ysize, (inT32) factor, FALSE); else copy_sub_image (&image, 0, 0, xsize, ysize, &target_image, 0, 0, FALSE); free(hires); free(lores); free(oldhires); free(oldlores); }
void sv_show_sub_image(IMAGE* source, // Image to show. inT32 xstart, // Start image coords. inT32 ystart, inT32 xext, // Size of rectangle to show. inT32 yext, ScrollView* window, // Window to draw in. inT32 xpos, // Place to show bottom-left. inT32 ypos) { // Y position. #ifdef HAVE_LIBLEPT Pix* pix; if (xstart != 0 || ystart != 0 || xext != source->get_xsize() || yext != source->get_ysize()) { IMAGE sub_im; sub_im.create(xext, yext, source->get_bpp()); copy_sub_image(source, xstart, ystart, xext, yext, &sub_im, 0, 0, false); pix = sub_im.ToPix(); } else { pix = source->ToPix(); } #ifndef GRAPHICS_DISABLED window->Image(pix, xpos, window->TranslateYCoordinate(yext) + ypos); #endif pixDestroy(&pix); #endif }
// Cut out the requested rectangle of the binary image to the // tesseract global image ready for recognition. void TessBaseAPI::CopyBinaryRect(const unsigned char* imagedata, int bytes_per_line, int left, int top, int width, int height) { // Copy binary image, cutting out the required rectangle. IMAGE image; image.capture(const_cast<unsigned char*>(imagedata), bytes_per_line*8, top + height, 1); page_image.create(width, height, 1); copy_sub_image(&image, left, 0, width, height, &page_image, 0, 0, false); }
int TessDllAPI::BeginPageUpright(uinT32 xsize,uinT32 ysize,unsigned char *buf, uinT8 bpp) { EndPage(); //It looks like Adaptive thresholding is disabled so this must be a 1 bpp image if (page_image.create (xsize+800, ysize+800, 1)==-1) return 0L; //make the image bigger to enclose in whitespace //copy the passed buffer into the center of the image IMAGE tmp; tmp.capture(buf, xsize, ysize, bpp); copy_sub_image(&tmp, 0, 0, 0, 0, &page_image, 400, 400, true); return ProcessPagePass1(); }
// Copy the raw image rectangle, taking all data from the class, to the Pix. void ImageThresholder::RawRectToPix(Pix** pix) const { if (image_bytespp_ < 4) { // Go via a tesseract image structure (doesn't copy the data) // and use ToPix. IMAGE image; int bits_per_pixel = image_bytespp_ * 8; if (image_bytespp_ == 0) bits_per_pixel = 1; image.capture(const_cast<uinT8*>(image_data_), image_width_, rect_top_ + rect_height_, bits_per_pixel); if (IsFullImage()) { *pix = image.ToPix(); } else { IMAGE rect; rect.create(rect_width_, rect_height_, bits_per_pixel); // The capture chopped the image off at top+height, so copy // the rectangle with y = 0 to get a rectangle of height // starting at the bottom, since copy_sub_image uses bottom-up coords. copy_sub_image(&image, rect_left_, 0, rect_width_, rect_height_, &rect, 0, 0, true); *pix = rect.ToPix(); } } else { *pix = pixCreate(rect_width_, rect_height_, 32); uinT32* data = pixGetData(*pix); int wpl = pixGetWpl(*pix); const uinT8* imagedata = image_data_ + rect_top_ * image_bytespl_ + rect_left_ * image_bytespp_; for (int y = 0; y < rect_height_; ++y) { const uinT8* linedata = imagedata; uinT32* line = data + y * wpl; for (int x = 0; x < rect_width_; ++x) { line[x] = (linedata[0] << 24) | (linedata[1] << 16) | (linedata[2] << 8) | linedata[3]; linedata += 4; } imagedata += image_bytespl_; } } }
/********************************************************************** * SetBlobStrokeWidth * * Set the horizontal and vertical stroke widths in the blob. **********************************************************************/ void SetBlobStrokeWidth(bool debug, BLOBNBOX* blob) { #ifdef HAVE_LIBLEPT // Cut the blob rectangle into a Pix. // TODO(rays) make the page_image a Pix so this is more direct. const TBOX& box = blob->bounding_box(); IMAGE blob_im; int width = box.width(); int height = box.height(); blob_im.create(width, height, 1); copy_sub_image(&page_image, box.left(), box.bottom(), width, height, &blob_im, 0, 0, false); Pix* pix = blob_im.ToPix(); Pix* dist_pix = pixDistanceFunction(pix, 4, 8, L_BOUNDARY_BG); if (debug) { pixWrite("cutpix.png", pix, IFF_PNG); pixWrite("distpix.png", dist_pix, IFF_PNG); } pixDestroy(&pix); // Compute the stroke widths. uinT32* data = pixGetData(dist_pix); int wpl = pixGetWpl(dist_pix); // Horizontal width of stroke. STATS h_stats(0, width + 1); for (int y = 0; y < height; ++y) { uinT32* pixels = data + y*wpl; int prev_pixel = 0; int pixel = GET_DATA_BYTE(pixels, 0); for (int x = 1; x < width; ++x) { int next_pixel = GET_DATA_BYTE(pixels, x); // We are looking for a pixel that is equal to its vertical neighbours, // yet greater than its left neighbour. if (prev_pixel < pixel && (y == 0 || pixel == GET_DATA_BYTE(pixels - wpl, x - 1)) && (y == height - 1 || pixel == GET_DATA_BYTE(pixels + wpl, x - 1))) { if (pixel > next_pixel) { // Single local max, so an odd width. h_stats.add(pixel * 2 - 1, 1); } else if (pixel == next_pixel && x + 1 < width && pixel > GET_DATA_BYTE(pixels, x + 1)) { // Double local max, so an even width. h_stats.add(pixel * 2, 1); } } prev_pixel = pixel; pixel = next_pixel; } } if (debug) { h_stats.print(stderr, true); } // Vertical width of stroke. STATS v_stats(0, height + 1); for (int x = 0; x < width; ++x) { int prev_pixel = 0; int pixel = GET_DATA_BYTE(data, x); for (int y = 1; y < height; ++y) { uinT32* pixels = data + y*wpl; int next_pixel = GET_DATA_BYTE(pixels, x); // We are looking for a pixel that is equal to its horizontal neighbours, // yet greater than its upper neighbour. if (prev_pixel < pixel && (x == 0 || pixel == GET_DATA_BYTE(pixels - wpl, x - 1)) && (x == width - 1 || pixel == GET_DATA_BYTE(pixels - wpl, x + 1))) { if (pixel > next_pixel) { // Single local max, so an odd width. v_stats.add(pixel * 2 - 1, 1); } else if (pixel == next_pixel && y + 1 < height && pixel > GET_DATA_BYTE(pixels + wpl, x)) { // Double local max, so an even width. v_stats.add(pixel * 2, 1); } } prev_pixel = pixel; pixel = next_pixel; } } if (debug) { v_stats.print(stderr, true); } pixDestroy(&dist_pix); // Store the horizontal and vertical width in the blob, keeping both // widths if there is enough information, otherwse only the one with // the most samples. // If there are insufficent samples, store zero, rather than using // 2*area/perimeter, as the numbers that gives do not match the numbers // from the distance method. if (debug) { tprintf("box=%d,%d->%d,%d, hcount=%d, vcount=%d, target=%d\n", box.left(), box.bottom(), box.right(), box.top(), h_stats.get_total(), v_stats.get_total(), (width+height) /4); tprintf("hstats median=%f, lq=%f, uq=%f, sd=%f\n", h_stats.median(), h_stats.ile(0.25f), h_stats.ile(0.75f), h_stats.sd()); tprintf("vstats median=%f, lq=%f, uq=%f, sd=%f\n", v_stats.median(), v_stats.ile(0.25f), v_stats.ile(0.75f), v_stats.sd()); } if (h_stats.get_total() >= (width + height) / 4) { blob->set_horz_stroke_width(h_stats.ile(0.5f)); if (v_stats.get_total() >= (width + height) / 4) blob->set_vert_stroke_width(v_stats.ile(0.5f)); else blob->set_vert_stroke_width(0.0f); } else { if (v_stats.get_total() >= (width + height) / 4 || v_stats.get_total() > h_stats.get_total()) { blob->set_horz_stroke_width(0.0f); blob->set_vert_stroke_width(v_stats.ile(0.5f)); } else { blob->set_horz_stroke_width(h_stats.get_total() > 2 ? h_stats.ile(0.5f) : 0.0f); blob->set_vert_stroke_width(0.0f); } } #else // Without leptonica present, use the 2*area/perimeter as an approximation. float width = 2.0f * blob->cblob()->area(); width /= blob->cblob()->perimeter(); blob->set_horz_stroke_width(width); blob->set_vert_stroke_width(width); #endif }