// create a union of two arbitrary pix
Pix *CubeLineSegmenter::PixUnion(Pix *dest_pix, Box *dest_box,
    Pix *src_pix, Box *src_box) {
  // compute dimensions of union rect
  BOX *union_box = boxBoundingRegion(src_box, dest_box);

  // create the union pix
  Pix *union_pix = pixCreate(union_box->w, union_box->h, src_pix->d);
  if (union_pix == NULL) {
    return NULL;
  }

  // blt the src and dest pix
  pixRasterop(union_pix,
    src_box->x - union_box->x, src_box->y - union_box->y,
    src_box->w, src_box->h, PIX_SRC | PIX_DST, src_pix, 0, 0);

  pixRasterop(union_pix,
    dest_box->x - union_box->x, dest_box->y - union_box->y,
    dest_box->w, dest_box->h, PIX_SRC | PIX_DST, dest_pix, 0, 0);

  // replace the dest_box
  *dest_box = *union_box;

  boxDestroy(&union_box);

  return union_pix;
}
/*!
 * \brief   pixTilingPaintTile()
 *
 * \param[in]    pixd dest: paint tile onto this, without overlap
 * \param[in]    i tile row index
 * \param[in]    j tile column index
 * \param[in]    pixs source: tile to be painted from
 * \param[in]    pt pixtiling struct
 * \return  0 if OK, 1 on error
 */
l_int32
pixTilingPaintTile(PIX        *pixd,
                   l_int32     i,
                   l_int32     j,
                   PIX        *pixs,
                   PIXTILING  *pt)
{
l_int32  w, h;

    PROCNAME("pixTilingPaintTile");

    if (!pixd)
        return ERROR_INT("pixd not defined", procName, 1);
    if (!pixs)
        return ERROR_INT("pixs not defined", procName, 1);
    if (!pt)
        return ERROR_INT("pt not defined", procName, 1);
    if (i < 0 || i >= pt->ny)
        return ERROR_INT("invalid row index i", procName, 1);
    if (j < 0 || j >= pt->nx)
        return ERROR_INT("invalid column index j", procName, 1);

        /* Strip added border pixels off if requested */
    pixGetDimensions(pixs, &w, &h, NULL);
    if (pt->strip == TRUE) {
        pixRasterop(pixd, j * pt->w, i * pt->h,
                    w - 2 * pt->xoverlap, h - 2 * pt->yoverlap, PIX_SRC,
                    pixs, pt->xoverlap, pt->yoverlap);
    } else {
        pixRasterop(pixd, j * pt->w, i * pt->h, w, h, PIX_SRC, pixs, 0, 0);
    }

    return 0;
}
Exemple #3
0
void Java_com_example_ocr_Pixa_nativeMergeAndReplacePix(JNIEnv *env, jclass clazz,
                                                                         jint nativePixa,
                                                                         jint indexA, jint indexB) {
  PIXA *pixa = (PIXA *) nativePixa;

  l_int32 op;
  l_int32 x, y, w, h;
  l_int32 dx, dy, dw, dh;
  PIX *pixs, *pixd;
  BOX *boxA, *boxB, *boxd;

  boxA = pixaGetBox(pixa, indexA, L_CLONE);
  boxB = pixaGetBox(pixa, indexB, L_CLONE);
  boxd = boxBoundingRegion(boxA, boxB);

  boxGetGeometry(boxd, &x, &y, &w, &h);
  pixd = pixCreate(w, h, 1);

  op = PIX_SRC | PIX_DST;

  pixs = pixaGetPix(pixa, indexA, L_CLONE);
  boxGetGeometry(boxA, &dx, &dy, &dw, &dh);
  pixRasterop(pixd, dx - x, dy - y, dw, dh, op, pixs, 0, 0);
  pixDestroy(&pixs);
  boxDestroy(&boxA);

  pixs = pixaGetPix(pixa, indexB, L_CLONE);
  boxGetGeometry(boxB, &dx, &dy, &dw, &dh);
  pixRasterop(pixd, dx - x, dy - y, dw, dh, op, pixs, 0, 0);
  pixDestroy(&pixs);
  boxDestroy(&boxB);

  pixaReplacePix(pixa, indexA, pixd, boxd);

}
Exemple #4
0
/*!
 *  pixRasteropHip()
 *
 *      Input:  pixd (in-place operation)
 *              by  (top of horizontal band)
 *              bh  (height of horizontal band)
 *              hshift (horizontal shift of band; hshift > 0 is to right)
 *              incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK)
 *      Return: 0 if OK; 1 on error
 *
 *  Notes:
 *      (1) This rasterop translates a horizontal band of the
 *          image either left or right, bringing in either white
 *          or black pixels from outside the image.
 *      (2) The horizontal band extends the full width of pixd.
 *      (3) If a colormap exists, the nearest color to white or black
 *          is brought in.
 */
l_int32
pixRasteropHip(PIX     *pixd,
               l_int32  by,
               l_int32  bh,
               l_int32  hshift,
               l_int32  incolor)
{
l_int32   w, h, d, index, op;
PIX      *pixt;
PIXCMAP  *cmap;

    PROCNAME("pixRasteropHip");

    if (!pixd)
        return ERROR_INT("pixd not defined", procName, 1);
    if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK)
        return ERROR_INT("invalid value for incolor", procName, 1);
    if (bh <= 0)
        return ERROR_INT("bh must be > 0", procName, 1);

    if (hshift == 0)
        return 0;

    pixGetDimensions(pixd, &w, &h, &d);
    rasteropHipLow(pixGetData(pixd), h, d, pixGetWpl(pixd), by, bh, hshift);

    cmap = pixGetColormap(pixd);
    if (!cmap) {
        if ((d == 1 && incolor == L_BRING_IN_BLACK) ||
            (d > 1 && incolor == L_BRING_IN_WHITE))
            op = PIX_SET;
        else
            op = PIX_CLR;

            /* Set the pixels brought in at left or right */
        if (hshift > 0)
            pixRasterop(pixd, 0, by, hshift, bh, op, NULL, 0, 0);
        else  /* hshift < 0 */
            pixRasterop(pixd, w + hshift, by, -hshift, bh, op, NULL, 0, 0);
        return 0;
    }

        /* Get the nearest index and fill with that */
    if (incolor == L_BRING_IN_BLACK)
        pixcmapGetRankIntensity(cmap, 0.0, &index);
    else  /* white */
        pixcmapGetRankIntensity(cmap, 1.0, &index);
    pixt = pixCreate(L_ABS(hshift), bh, d);
    pixSetAllArbitrary(pixt, index);
    if (hshift > 0)
        pixRasterop(pixd, 0, by, hshift, bh, PIX_SRC, pixt, 0, 0);
    else  /* hshift < 0 */
        pixRasterop(pixd, w + hshift, by, -hshift, bh, PIX_SRC, pixt, 0, 0);
    pixDestroy(&pixt);
    return 0;
}
Exemple #5
0
main(int    argc,
     char **argv)
{
l_int32      w, h, d, n;
char        *filein1, *filein2, *fileout;
PIX         *pixs1, *pixs2, *pixd;
static char  mainName[] = "bincompare";

    if (argc != 4)
	exit(ERROR_INT(" Syntax:  bincompare filein1 filein2 fileout",
	               mainName, 1));

    filein1 = argv[1];
    filein2 = argv[2];
    fileout = argv[3];

    if ((pixs1 = pixRead(filein1)) == NULL)
	exit(ERROR_INT("pixs1 not made", mainName, 1));
    if ((pixs2 = pixRead(filein2)) == NULL)
	exit(ERROR_INT("pixs2 not made", mainName, 1));

    w = pixGetWidth(pixs1);
    h = pixGetHeight(pixs1);
    d = pixGetDepth(pixs1);
    if (d != 1)
	exit(ERROR_INT("pixs1 not binary", mainName, 1));

    pixCountPixels(pixs1, &n, NULL);
    fprintf(stderr, "Number of fg pixels in file1 = %d\n", n);
    pixCountPixels(pixs2, &n, NULL);
    fprintf(stderr, "Number of fg pixels in file2 = %d\n", n);

#if XOR 
    fprintf(stderr, "xor: 1 ^ 2\n");
    pixRasterop(pixs1, 0, 0, w, h, PIX_SRC ^ PIX_DST, pixs2, 0, 0);
    pixCountPixels(pixs1, &n, NULL);
    fprintf(stderr, "Number of fg pixels in XOR = %d\n", n);
    pixWrite(fileout, pixs1, IFF_PNG);
#elif  SUBTRACT_1_FROM_2
    fprintf(stderr, "subtract: 2 - 1\n");
    pixRasterop(pixs1, 0, 0, w, h, PIX_SRC & PIX_NOT(PIX_DST), pixs2, 0, 0);
    pixCountPixels(pixs1, &n, NULL);
    fprintf(stderr, "Number of fg pixels in 2 - 1 = %d\n", n);
    pixWrite(fileout, pixs1, IFF_PNG);
#elif  SUBTRACT_2_FROM_1
    fprintf(stderr, "subtract: 1 - 2\n");
    pixRasterop(pixs1, 0, 0, w, h, PIX_DST & PIX_NOT(PIX_SRC), pixs2, 0, 0);
    pixCountPixels(pixs1, &n, NULL);
    fprintf(stderr, "Number of fg pixels in 1 - 2 = %d\n", n);
    pixWrite(fileout, pixs1, IFF_PNG);
#else
    fprintf(stderr, "no comparison selected\n");
#endif

    return 0;
}
// Tests each blob in the list to see if it is certain non-text using 2
// conditions:
// 1. blob overlaps a cell with high value in noise_density_ (previously set
// by ComputeNoiseDensity).
// OR 2. The blob overlaps more than max_blob_overlaps in *this grid. This
// condition is disabled with max_blob_overlaps == -1.
// If it does, the blob is declared non-text, and is used to mark up the
// nontext_mask. Such blobs are fully deleted, and non-noise blobs have their
// neighbours reset, as they may now point to deleted data.
// WARNING: The blobs list blobs may be in the *this grid, but they are
// not removed. If any deleted blobs might be in *this, then this must be
// Clear()ed immediately after MarkAndDeleteNonTextBlobs is called.
// If the win is not NULL, deleted blobs are drawn on it in red, and kept
// blobs are drawn on it in ok_color.
void CCNonTextDetect::MarkAndDeleteNonTextBlobs(BLOBNBOX_LIST* blobs,
        int max_blob_overlaps,
        ScrollView* win,
        ScrollView::Color ok_color,
        Pix* nontext_mask) {
    int imageheight = tright().y() - bleft().x();
    BLOBNBOX_IT blob_it(blobs);
    BLOBNBOX_LIST dead_blobs;
    BLOBNBOX_IT dead_it(&dead_blobs);
    for (blob_it.mark_cycle_pt(); !blob_it.cycled_list(); blob_it.forward()) {
        BLOBNBOX* blob = blob_it.data();
        TBOX box = blob->bounding_box();
        if (!noise_density_->RectMostlyOverThreshold(box, max_noise_count_) &&
                (max_blob_overlaps < 0 ||
                 !BlobOverlapsTooMuch(blob, max_blob_overlaps))) {
            blob->ClearNeighbours();
#ifndef GRAPHICS_DISABLED
            if (win != NULL)
                blob->plot(win, ok_color, ok_color);
#endif  // GRAPHICS_DISABLED
        } else {
            if (noise_density_->AnyZeroInRect(box)) {
                // There is a danger that the bounding box may overlap real text, so
                // we need to render the outline.
                Pix* blob_pix = blob->cblob()->render_outline();
                pixRasterop(nontext_mask, box.left(), imageheight - box.top(),
                            box.width(), box.height(), PIX_SRC | PIX_DST,
                            blob_pix, 0, 0);
                pixDestroy(&blob_pix);
            } else {
                if (box.area() < gridsize() * gridsize()) {
                    // It is a really bad idea to make lots of small components in the
                    // photo mask, so try to join it to a bigger area by expanding the
                    // box in a way that does not touch any zero noise density cell.
                    box = AttemptBoxExpansion(box, *noise_density_, gridsize());
                }
                // All overlapped cells are non-zero, so just mark the rectangle.
                pixRasterop(nontext_mask, box.left(), imageheight - box.top(),
                            box.width(), box.height(), PIX_SET, NULL, 0, 0);
            }
#ifndef GRAPHICS_DISABLED
            if (win != NULL)
                blob->plot(win, ScrollView::RED, ScrollView::RED);
#endif  // GRAPHICS_DISABLED
            // It is safe to delete the cblob now, as it isn't used by the grid
            // or BlobOverlapsTooMuch, and the BLOBNBOXes will go away with the
            // dead_blobs list.
            // TODO(rays) delete the delete when the BLOBNBOX destructor deletes
            // the cblob.
            delete blob->cblob();
            dead_it.add_to_end(blob_it.extract());
        }
    }
}
Exemple #7
0
/*!
 *  pixaDisplay()
 *
 *      Input:  pixa
 *              w, h (if set to 0, determines the size from the
 *                    b.b. of the components in pixa)
 *      Return: pix, or null on error
 *
 *  Notes:
 *      (1) This uses the boxes to place each pix in the rendered composite.
 *      (2) Set w = h = 0 to use the b.b. of the components to determine
 *          the size of the returned pix.
 *      (3) Uses the first pix in pixa to determine the depth.
 *      (4) The background is written "white".  On 1 bpp, each successive
 *          pix is "painted" (adding foreground), whereas for grayscale
 *          or color each successive pix is blitted with just the src.
 *      (5) If the pixa is empty, returns an empty 1 bpp pix.
 */
PIX *
pixaDisplay(PIXA    *pixa,
            l_int32  w,
            l_int32  h)
{
l_int32  i, n, d, xb, yb, wb, hb;
BOXA    *boxa;
PIX     *pixt, *pixd;

    PROCNAME("pixaDisplay");

    if (!pixa)
        return (PIX *)ERROR_PTR("pixa not defined", procName, NULL);
    
    n = pixaGetCount(pixa);
    if (n == 0 && w == 0 && h == 0)
        return (PIX *)ERROR_PTR("no components; no size", procName, NULL);
    if (n == 0) {
        L_WARNING("no components; returning empty 1 bpp pix", procName);
        return pixCreate(w, h, 1);
    }

        /* If w and h not input, determine the minimum size required
         * to contain the origin and all c.c. */
    if (w == 0 || h == 0) {
        boxa = pixaGetBoxa(pixa, L_CLONE);
        boxaGetExtent(boxa, &w, &h, NULL);
        boxaDestroy(&boxa);
    }

        /* Use the first pix in pixa to determine the depth.  */
    pixt = pixaGetPix(pixa, 0, L_CLONE);
    d = pixGetDepth(pixt);
    pixDestroy(&pixt);

    if ((pixd = pixCreate(w, h, d)) == NULL)
        return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
    if (d > 1)
        pixSetAll(pixd);
    for (i = 0; i < n; i++) {
        if (pixaGetBoxGeometry(pixa, i, &xb, &yb, &wb, &hb)) {
            L_WARNING("no box found!", procName);
            continue;
        }
        pixt = pixaGetPix(pixa, i, L_CLONE);
        if (d == 1)
            pixRasterop(pixd, xb, yb, wb, hb, PIX_PAINT, pixt, 0, 0);
        else
            pixRasterop(pixd, xb, yb, wb, hb, PIX_SRC, pixt, 0, 0);
        pixDestroy(&pixt);
    }

    return pixd;
}
Exemple #8
0
// Renders the outline to the given pix, with left and top being
// the coords of the upper-left corner of the pix.
void C_OUTLINE::render(int left, int top, Pix* pix) const {
  ICOORD pos = start;
  for (int stepindex = 0; stepindex < stepcount; ++stepindex) {
    ICOORD next_step = step(stepindex);
    if (next_step.y() < 0) {
      pixRasterop(pix, 0, top - pos.y(), pos.x() - left, 1,
                  PIX_NOT(PIX_DST), NULL, 0, 0);
    } else if (next_step.y() > 0) {
      pixRasterop(pix, 0, top - pos.y() - 1, pos.x() - left, 1,
                  PIX_NOT(PIX_DST), NULL, 0, 0);
    }
    pos += next_step;
  }
}
Exemple #9
0
/*!
 * \brief   pixConnCompTransform()
 *
 * \param[in]     pixs 1 bpp
 * \param[in]     connect connectivity: 4 or 8
 * \param[in]     depth of pixd: 8 or 16 bpp; use 0 for auto determination
 * \return   pixd 8, 16 or 32 bpp, or NULL on error
 *
 * <pre>
 * Notes:
 *      (1) pixd is 8, 16 or 32 bpp, and the pixel values label the
 *          fg component, starting with 1.  Pixels in the bg are labelled 0.
 *      (2) If %depth = 0, the depth of pixd is 8 if the number of c.c.
 *          is less than 254, 16 if the number of c.c is less than 0xfffe,
 *          and 32 otherwise.
 *      (3) If %depth = 8, the assigned label for the n-th component is
 *          1 + n % 254.  We use mod 254 because 0 is uniquely assigned
 *          to black: e.g., see pixcmapCreateRandom().  Likewise,
 *          if %depth = 16, the assigned label uses mod(2^16 - 2), and
 *          if %depth = 32, no mod is taken.
 * </pre>
 */
PIX *
pixConnCompTransform(PIX     *pixs,
                     l_int32  connect,
                     l_int32  depth)
{
l_int32  i, n, index, w, h, xb, yb, wb, hb;
BOXA    *boxa;
PIX     *pix1, *pix2, *pixd;
PIXA    *pixa;

    PROCNAME("pixConnCompTransform");

    if (!pixs || pixGetDepth(pixs) != 1)
        return (PIX *)ERROR_PTR("pixs undefined or not 1 bpp", procName, NULL);
    if (connect != 4 && connect != 8)
        return (PIX *)ERROR_PTR("connectivity must be 4 or 8", procName, NULL);
    if (depth != 0 && depth != 8 && depth != 16 && depth != 32)
        return (PIX *)ERROR_PTR("depth must be 0, 8, 16 or 32", procName, NULL);

    boxa = pixConnComp(pixs, &pixa, connect);
    n = pixaGetCount(pixa);
    boxaDestroy(&boxa);
    pixGetDimensions(pixs, &w, &h, NULL);
    if (depth == 0) {
        if (n < 254)
            depth = 8;
        else if (n < 0xfffe)
            depth = 16;
        else
            depth = 32;
    }
    pixd = pixCreate(w, h, depth);
    pixSetSpp(pixd, 1);
    if (n == 0) {  /* no fg */
        pixaDestroy(&pixa);
        return pixd;
    }

       /* Label each component and blit it in */
    for (i = 0; i < n; i++) {
        pixaGetBoxGeometry(pixa, i, &xb, &yb, &wb, &hb);
        pix1 = pixaGetPix(pixa, i, L_CLONE);
        if (depth == 8) {
            index = 1 + (i % 254);
            pix2 = pixConvert1To8(NULL, pix1, 0, index);
        } else if (depth == 16) {
            index = 1 + (i % 0xfffe);
            pix2 = pixConvert1To16(NULL, pix1, 0, index);
        } else {  /* depth == 32 */
            index = 1 + i;
            pix2 = pixConvert1To32(NULL, pix1, 0, index);
        }
        pixRasterop(pixd, xb, yb, wb, hb, PIX_PAINT, pix2, 0, 0);
        pixDestroy(&pix1);
        pixDestroy(&pix2);
    }

    pixaDestroy(&pixa);
    return pixd;
}
Exemple #10
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;
}
Exemple #11
0
/*!
 *  pixAddWithIndicator()
 *
 *      Input:  pixs (1 bpp pix from which components are added; in-place)
 *              pixa (of connected components, some of which will be put
 *                    into pixs)
 *              na (numa indicator: add components corresponding to 1s)
 *      Return: 0 if OK, 1 on error
 *
 *  Notes:
 *      (1) This complements pixRemoveWithIndicator().   Here, the selected
 *          components are added to pixs.
 */
l_int32
pixAddWithIndicator(PIX   *pixs,
                    PIXA  *pixa,
                    NUMA  *na)
{
l_int32  i, n, ival, x, y, w, h;
BOX     *box;
PIX     *pix;

    PROCNAME("pixAddWithIndicator");

    if (!pixs)
        return ERROR_INT("pixs not defined", procName, 1);
    if (!pixa)
        return ERROR_INT("pixa not defined", procName, 1);
    if (!na)
        return ERROR_INT("na not defined", procName, 1);
    n = pixaGetCount(pixa);
    if (n != numaGetCount(na))
        return ERROR_INT("pixa and na sizes not equal", procName, 1);

    for (i = 0; i < n; i++) {
        numaGetIValue(na, i, &ival);
        if (ival == 1) {
            pix = pixaGetPix(pixa, i, L_CLONE);
            box = pixaGetBox(pixa, i, L_CLONE);
            boxGetGeometry(box, &x, &y, &w, &h);
            pixRasterop(pixs, x, y, w, h, PIX_SRC | PIX_DST, pix, 0, 0);
            boxDestroy(&box);
            pixDestroy(&pix);
        }
    }

    return 0;
}
// Compute the connected components in a line
Boxa * CubeLineSegmenter::ComputeLineConComps(Pix *line_mask_pix,
                                              Box *line_box,
                                              Pixa **con_comps_pixa) {
  // clone the line mask
  Pix *line_pix = pixClone(line_mask_pix);

  if (line_pix == NULL) {
    return NULL;
  }

  // AND with the image to get the actual line
  pixRasterop(line_pix, 0, 0, line_pix->w, line_pix->h,
    PIX_SRC & PIX_DST, img_, line_box->x, line_box->y);

  // compute the connected components of the line to be merged
  Boxa *line_con_comps = pixConnComp(line_pix, con_comps_pixa, 8);

  pixDestroy(&line_pix);

  // offset boxes by the bbox of the line
  for (int con = 0; con < line_con_comps->n; con++) {
    line_con_comps->box[con]->x += line_box->x;
    line_con_comps->box[con]->y += line_box->y;
  }

  return line_con_comps;
}
main(int    argc,
char **argv)
{
l_int32      i, j, equal;
PIX         *pixs, *pixt, *pixd;
static char  mainName[] = "rasteropip_reg";


    pixs = pixRead("test8.jpg");
    pixt = pixCopy(NULL, pixs);

        /* Copy, in-place and one COLUMN at a time, from the right
           side to the left side. */
    for (j = 0; j < 200; j++)
        pixRasterop(pixs, 20 + j, 20, 1, 250, PIX_SRC, pixs, 250 + j, 20);
    pixDisplay(pixs, 50, 50);

        /* Copy, in-place and one ROW at a time, from the right
           side to the left side. */
    for (i = 0; i < 250; i++)
        pixRasterop(pixt, 20, 20 + i, 200, 1, PIX_SRC, pixt, 250, 20 + i);
    pixDisplay(pixt, 620, 50);

        /* Test */
    pixEqual(pixs, pixt, &equal);
    if (equal)
         fprintf(stderr, "OK: images are the same\n");
    else
         fprintf(stderr, "Error: images are different\n");
    pixWrite("/tmp/junkpix.png", pixs, IFF_PNG);
    pixDestroy(&pixs);
    pixDestroy(&pixt);


        /* Show the mirrored border, which uses the general
           pixRasterop() on an image in-place.  */
    pixs = pixRead("test8.jpg");
    pixt = pixRemoveBorder(pixs, 40);
    pixd = pixAddMirroredBorder(pixt, 25, 25, 25, 25);
    pixDisplay(pixd, 50, 550);
    pixDestroy(&pixs);
    pixDestroy(&pixt);
    pixDestroy(&pixd);

    return 0;
}
Exemple #14
0
main(int    argc,
     char **argv)
{
l_int32      i, j, w, h, same, width, height, cx, cy;
l_uint32     val;
PIX         *pixs, *pixse, *pixd1, *pixd2;
SEL         *sel;
static char  mainName[] = "rasterop_reg";

    if (argc != 1)
	return ERROR_INT(" Syntax:  rasterop_reg", mainName, 1);
    pixs = pixRead("feyn.tif");

    for (width = 1; width <= 25; width += 3) {
	for (height = 1; height <= 25; height += 4) {

	    cx = width / 2;
	    cy = height / 2;

		/* Dilate using an actual sel */
	    sel = selCreateBrick(height, width, cy, cx, SEL_HIT);
	    pixd1 = pixDilate(NULL, pixs, sel);

		/* Dilate using a pix as a sel */
	    pixse = pixCreate(width, height, 1);
	    pixSetAll(pixse);
	    pixd2 = pixCopy(NULL, pixs);
	    w = pixGetWidth(pixs);
	    h = pixGetHeight(pixs);
	    for (i = 0; i < h; i++) {
		for (j = 0; j < w; j++) {
		    pixGetPixel(pixs, j, i, &val);
		    if (val)
			pixRasterop(pixd2, j - cx, i - cy, width, height,
				    PIX_SRC | PIX_DST, pixse, 0, 0);
		}
	    }

	    pixEqual(pixd1, pixd2, &same);
	    if (same == 1)
		fprintf(stderr, "Correct for (%d,%d)\n", width, height);
	    else {
		fprintf(stderr, "Error: results are different!\n");
		fprintf(stderr, "SE: width = %d, height = %d\n", width, height);
		pixWrite("/tmp/junkout1", pixd1, IFF_PNG);
		pixWrite("/tmp/junkout2", pixd2, IFF_PNG);
                return 1;
	    }

	    pixDestroy(&pixse);
	    pixDestroy(&pixd1);
	    pixDestroy(&pixd2);
	    selDestroy(&sel);
	}
    }
    pixDestroy(&pixs);
    return 0;
}
Exemple #15
0
/*!
 *  pixEmbedForRotation()
 *
 *      Input:  pixs (1, 2, 4, 8, 32 bpp rgb)
 *              angle (radians; clockwise is positive)
 *              incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK)
 *              width (original width; use 0 to avoid embedding)
 *              height (original height; use 0 to avoid embedding)
 *      Return: pixd, or null on error
 *
 *  Notes:
 *      (1) For very small rotations, just return a clone.
 *      (2) Generate larger image to embed pixs if necessary, and
 *          place the center of the input image in the center.
 *      (3) Rotation brings either white or black pixels in
 *          from outside the image.  For colormapped images where
 *          there is no white or black, a new color is added if
 *          possible for these pixels; otherwise, either the
 *          lightest or darkest color is used.  In most cases,
 *          the colormap will be removed prior to rotation.
 *      (4) The dest is to be expanded so that no image pixels
 *          are lost after rotation.  Input of the original width
 *          and height allows the expansion to stop at the maximum
 *          required size, which is a square with side equal to
 *          sqrt(w*w + h*h).
 *      (5) For an arbitrary angle, the expansion can be found by
 *          considering the UL and UR corners.  As the image is
 *          rotated, these move in an arc centered at the center of
 *          the image.  Normalize to a unit circle by dividing by half
 *          the image diagonal.  After a rotation of T radians, the UL
 *          and UR corners are at points T radians along the unit
 *          circle.  Compute the x and y coordinates of both these
 *          points and take the max of absolute values; these represent
 *          the half width and half height of the containing rectangle.
 *          The arithmetic is done using formulas for sin(a+b) and cos(a+b),
 *          where b = T.  For the UR corner, sin(a) = h/d and cos(a) = w/d.
 *          For the UL corner, replace a by (pi - a), and you have
 *          sin(pi - a) = h/d, cos(pi - a) = -w/d.  The equations
 *          given below follow directly.
 */
PIX *
pixEmbedForRotation(PIX       *pixs,
                    l_float32  angle,
                    l_int32    incolor,
                    l_int32    width,
                    l_int32    height)
{
l_int32    w, h, d, w1, h1, w2, h2, maxside, wnew, hnew, xoff, yoff, setcolor;
l_float64  sina, cosa, fw, fh;
PIX       *pixd;

    PROCNAME("pixEmbedForRotation");

    if (!pixs)
        return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
    if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK)
        return (PIX *)ERROR_PTR("invalid incolor", procName, NULL);
    if (L_ABS(angle) < MIN_ANGLE_TO_ROTATE)
        return pixClone(pixs);

        /* Test if big enough to hold any rotation of the original image */
    pixGetDimensions(pixs, &w, &h, &d);
    maxside = (l_int32)(sqrt((l_float64)(width * width) +
                             (l_float64)(height * height)) + 0.5);
    if (w >= maxside && h >= maxside)  /* big enough */
        return pixClone(pixs);

        /* Find the new sizes required to hold the image after rotation.
         * Note that the new dimensions must be at least as large as those
         * of pixs, because we're rasterop-ing into it before rotation. */
    cosa = cos(angle);
    sina = sin(angle);
    fw = (l_float64)w;
    fh = (l_float64)h;
    w1 = (l_int32)(L_ABS(fw * cosa - fh * sina) + 0.5);
    w2 = (l_int32)(L_ABS(-fw * cosa - fh * sina) + 0.5);
    h1 = (l_int32)(L_ABS(fw * sina + fh * cosa) + 0.5);
    h2 = (l_int32)(L_ABS(-fw * sina + fh * cosa) + 0.5);
    wnew = L_MAX(w, L_MAX(w1, w2));
    hnew = L_MAX(h, L_MAX(h1, h2));

    if ((pixd = pixCreate(wnew, hnew, d)) == NULL)
        return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
    pixCopyResolution(pixd, pixs);
    pixCopyColormap(pixd, pixs);
    pixCopySpp(pixd, pixs);
    pixCopyText(pixd, pixs);
    xoff = (wnew - w) / 2;
    yoff = (hnew - h) / 2;

        /* Set background to color to be rotated in */
    setcolor = (incolor == L_BRING_IN_BLACK) ? L_SET_BLACK : L_SET_WHITE;
    pixSetBlackOrWhite(pixd, setcolor);

        /* Rasterop automatically handles all 4 channels for rgba */
    pixRasterop(pixd, xoff, yoff, w, h, PIX_SRC, pixs, 0, 0);
    return pixd;
}
/*!
 * \brief   recogGetWindowedArea()
 *
 * \param[in]    recog
 * \param[in]    index of template
 * \param[in]    x pixel position of left hand edge of template
 * \param[out]   pdely y shift of template relative to pix1
 * \param[out]   pwsum number of fg pixels in window of pixs
 * \return  0 if OK, 1 on error
 *
 * <pre>
 * Notes:
 *      (1) This is called after the best path has been found through
 *          the trellis, in order to produce a correlation that can be used
 *          to evaluate the confidence we have in the identification.
 *          The correlation is |1 \& 2|^2 / (|1| * |2|).
 *          |1 \& 2| is given by the count array, |2| is found from
 *          nasum_u[], and |1| is wsum returned from this function.
 * </pre>
 */
static l_int32
recogGetWindowedArea(L_RECOG  *recog,
                     l_int32   index,
                     l_int32   x,
                     l_int32  *pdely,
                     l_int32  *pwsum)
{
l_int32  w1, h1, w2, h2;
PIX     *pix1, *pix2, *pixt;
L_RDID  *did;

    PROCNAME("recogGetWindowedArea");

    if (pdely) *pdely = 0;
    if (pwsum) *pwsum = 0;
    if (!pdely || !pwsum)
        return ERROR_INT("&dely and &wsum not both defined", procName, 1);
    if (!recog)
        return ERROR_INT("recog not defined", procName, 1);
    if ((did = recogGetDid(recog)) == NULL)
        return ERROR_INT("did not defined", procName, 1);
    if (index < 0 || index >= did->narray)
        return ERROR_INT("invalid index", procName, 1);
    pix1 = did->pixs;
    pixGetDimensions(pix1, &w1, &h1, NULL);
    if (x >= w1)
        return ERROR_INT("invalid x position", procName, 1);

    pix2 = pixaGetPix(recog->pixa_u, index, L_CLONE);
    pixGetDimensions(pix2, &w2, &h2, NULL);
    if (w1 < w2) {
        L_INFO("template %d too small\n", procName, index);
        pixDestroy(&pix2);
        return 0;
    }

    *pdely = did->delya[index][x];
    pixt = pixCreate(w2, h1, 1);
    pixRasterop(pixt, 0, *pdely, w2, h2, PIX_SRC, pix2, 0, 0);
    pixRasterop(pixt, 0, 0, w2, h1, PIX_SRC & PIX_DST, pix1, x, 0);
    pixCountPixels(pixt, pwsum, recog->sumtab);
    pixDestroy(&pix2);
    pixDestroy(&pixt);
    return 0;
}
Exemple #17
0
main(int    argc,
char **argv)
{
l_int32       i, j;
PIX          *pixs, *pixt, *pixd;
L_REGPARAMS  *rp;

    if (regTestSetup(argc, argv, &rp))
        return 1;

    pixs = pixRead("test8.jpg");
    pixt = pixCopy(NULL, pixs);

        /* Copy, in-place and one COLUMN at a time, from the right
           side to the left side. */
    for (j = 0; j < 200; j++)
        pixRasterop(pixs, 20 + j, 20, 1, 250, PIX_SRC, pixs, 250 + j, 20);
    pixDisplayWithTitle(pixs, 50, 50, "in-place copy", rp->display);

        /* Copy, in-place and one ROW at a time, from the right
           side to the left side. */
    for (i = 0; i < 250; i++)
        pixRasterop(pixt, 20, 20 + i, 200, 1, PIX_SRC, pixt, 250, 20 + i);

        /* Test */
    regTestComparePix(rp, pixs, pixt);   /* 0 */
    pixDestroy(&pixs);
    pixDestroy(&pixt);

        /* Show the mirrored border, which uses the general
           pixRasterop() on an image in-place.  */
    pixs = pixRead("test8.jpg");
    pixt = pixRemoveBorder(pixs, 40);
    pixd = pixAddMirroredBorder(pixt, 40, 40, 40, 40);
    regTestWritePixAndCheck(rp, pixd, IFF_PNG);  /* 1 */
    pixDisplayWithTitle(pixd, 650, 50, "mirrored border", rp->display);
    pixDestroy(&pixs);
    pixDestroy(&pixt);
    pixDestroy(&pixd);
    return regTestCleanup(rp);
}
Exemple #18
0
/*!
 *  pixaDisplayRandomCmap()
 *
 *      Input:  pixa (of 1 bpp components, with boxa)
 *              w, h (if set to 0, determines the size from the
 *                    b.b. of the components in pixa)
 *      Return: pix (8 bpp, cmapped, with random colors on the components),
 *              or null on error
 *
 *  Notes:
 *      (1) This uses the boxes to place each pix in the rendered composite.
 *      (2) By default, the background color is: black, cmap index 0.
 *          This can be changed by pixcmapResetColor()
 */
PIX *
pixaDisplayRandomCmap(PIXA    *pixa,
                      l_int32  w,
                      l_int32  h)
{
l_int32   i, n, d, index, xb, yb, wb, hb;
BOXA     *boxa;
PIX      *pixs, *pixt, *pixd;
PIXCMAP  *cmap;

    PROCNAME("pixaDisplayRandomCmap");

    if (!pixa)
        return (PIX *)ERROR_PTR("pixa not defined", procName, NULL);
    
    n = pixaGetCount(pixa);
    if (n == 0)
        return (PIX *)ERROR_PTR("no components", procName, NULL);

        /* Use the first pix in pixa to verify depth is 1 bpp  */
    pixs = pixaGetPix(pixa, 0, L_CLONE);
    d = pixGetDepth(pixs);
    pixDestroy(&pixs);
    if (d != 1)
        return (PIX *)ERROR_PTR("components not 1 bpp", procName, NULL);

        /* If w and h not input, determine the minimum size required
         * to contain the origin and all c.c. */
    if (w == 0 || h == 0) {
        boxa = pixaGetBoxa(pixa, L_CLONE);
        boxaGetExtent(boxa, &w, &h, NULL);
        boxaDestroy(&boxa);
    }

        /* Set up an 8 bpp dest pix, with a colormap with 254 random colors */
    if ((pixd = pixCreate(w, h, 8)) == NULL)
        return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
    cmap = pixcmapCreateRandom(8, 1, 1);
    pixSetColormap(pixd, cmap);

        /* Color each component and blit it in */
    for (i = 0; i < n; i++) {
        index = 1 + (i % 254);
        pixaGetBoxGeometry(pixa, i, &xb, &yb, &wb, &hb);
        pixs = pixaGetPix(pixa, i, L_CLONE);
        pixt = pixConvert1To8(NULL, pixs, 0, index);
        pixRasterop(pixd, xb, yb, wb, hb, PIX_PAINT, pixt, 0, 0);
        pixDestroy(&pixs);
        pixDestroy(&pixt);
    }

    return pixd;
}
Exemple #19
0
// Returns a binary Pix mask with a 1 pixel for every pixel within the
// block. Rotates the coordinate system by rerotation prior to rendering.
Pix* PDBLK::render_mask(const FCOORD& rerotation, TBOX* mask_box) {
  TBOX rotated_box(box);
  rotated_box.rotate(rerotation);
  Pix* pix = pixCreate(rotated_box.width(), rotated_box.height(), 1);
  if (hand_poly != nullptr) {
    // We are going to rotate, so get a deep copy of the points and
    // make a new POLY_BLOCK with it.
    ICOORDELT_LIST polygon;
    polygon.deep_copy(hand_poly->points(), ICOORDELT::deep_copy);
    POLY_BLOCK image_block(&polygon, hand_poly->isA());
    image_block.rotate(rerotation);
    // Block outline is a polygon, so use a PB_LINE_IT to get the
    // rasterized interior. (Runs of interior pixels on a line.)
    auto *lines = new PB_LINE_IT(&image_block);
    for (int y = box.bottom(); y < box.top(); ++y) {
      const std::unique_ptr</*non-const*/ ICOORDELT_LIST> segments(
          lines->get_line(y));
      if (!segments->empty()) {
        ICOORDELT_IT s_it(segments.get());
        // Each element of segments is a start x and x size of the
        // run of interior pixels.
        for (s_it.mark_cycle_pt(); !s_it.cycled_list(); s_it.forward()) {
          int start = s_it.data()->x();
          int xext = s_it.data()->y();
          // Set the run of pixels to 1.
          pixRasterop(pix, start - rotated_box.left(),
                      rotated_box.height() - 1 - (y - rotated_box.bottom()),
                      xext, 1, PIX_SET, nullptr, 0, 0);
        }
      }
    }
    delete lines;
  } else {
    // Just fill the whole block as there is only a bounding box.
    pixRasterop(pix, 0, 0, rotated_box.width(), rotated_box.height(),
                PIX_SET, nullptr, 0, 0);
  }
  if (mask_box != nullptr) *mask_box = rotated_box;
  return pix;
}
Exemple #20
0
/*!
 *  boxaGetCoverage()
 *
 *      Input:  boxa
 *              wc, hc (dimensions of overall clipping rectangle with UL
 *                      corner at (0, 0) that is covered by the boxes.
 *              exactflag (1 for guaranteeing an exact result; 0 for getting
 *                         an exact result only if the boxes do not overlap)
 *              &fract (<return> sum of box area as fraction of w * h)
 *      Return: 0 if OK, 1 on error
 *
 *  Notes:
 *      (1) The boxes in boxa are clipped to the input rectangle.
 *      (2) * When @exactflag == 1, we generate a 1 bpp pix of size
 *            wc x hc, paint all the boxes black, and count the fg pixels.
 *            This can take 1 msec on a large page with many boxes.
 *          * When @exactflag == 0, we clip each box to the wc x hc region
 *            and sum the resulting areas.  This is faster.
 *          * The results are the same when none of the boxes overlap
 *            within the wc x hc region.
 */
l_int32
boxaGetCoverage(BOXA       *boxa,
                l_int32     wc,
                l_int32     hc,
                l_int32     exactflag,
                l_float32  *pfract)
{
l_int32  i, n, x, y, w, h, sum;
BOX     *box, *boxc;
PIX     *pixt;

    PROCNAME("boxaGetCoverage");

    if (!pfract)
        return ERROR_INT("&fract not defined", procName, 1);
    *pfract = 0.0;
    if (!boxa)
        return ERROR_INT("boxa not defined", procName, 1);

    n = boxaGetCount(boxa);
    if (n == 0)
        return ERROR_INT("no boxes in boxa", procName, 1);

    if (exactflag == 0) {  /* quick and dirty */
        sum = 0;
        for (i = 0; i < n; i++) {
            box = boxaGetBox(boxa, i, L_CLONE);
            if ((boxc = boxClipToRectangle(box, wc, hc)) != NULL) {
                boxGetGeometry(boxc, NULL, NULL, &w, &h);
                sum += w * h;
                boxDestroy(&boxc);
            }
            boxDestroy(&box);
        }
    }
    else {  /* slower and exact */
        pixt = pixCreate(wc, hc, 1);
        for (i = 0; i < n; i++) {
            box = boxaGetBox(boxa, i, L_CLONE);
            boxGetGeometry(box, &x, &y, &w, &h);
            pixRasterop(pixt, x, y, w, h, PIX_SET, NULL, 0, 0);
            boxDestroy(&box);
        }
        pixCountPixels(pixt, &sum, NULL);
        pixDestroy(&pixt);
    }

    *pfract = (l_float32)sum / (l_float32)(wc * hc);
    return 0;
}
Exemple #21
0
/*!
 *  pixaDisplayUnsplit()
 *
 *      Input:  pixa
 *              nx   (number of mosaic cells horizontally)
 *              ny   (number of mosaic cells vertically)
 *              borderwidth  (of added border on all sides)
 *              bordercolor  (in our RGBA format: 0xrrggbbaa)
 *      Return: pix of tiled images, or null on error
 *
 *  Notes:
 *      (1) This is a logical inverse of pixaSplitPix().  It
 *          constructs a pix from a mosaic of tiles, all of equal size.
 *      (2) For added generality, a border of arbitrary color can
 *          be added to each of the tiles.
 *      (3) In use, pixa will typically have either been generated
 *          from pixaSplitPix() or will derived from a pixa that
 *          was so generated.
 *      (4) All pix in the pixa must be of equal depth, and, if
 *          colormapped, have the same colormap.
 */
PIX *
pixaDisplayUnsplit(PIXA     *pixa,
                   l_int32   nx,
                   l_int32   ny,
                   l_int32   borderwidth,
                   l_uint32  bordercolor)
{
l_int32  w, h, d, wt, ht;
l_int32  i, j, k, x, y, n;
PIX     *pixt, *pixd;

    PROCNAME("pixaDisplayUnsplit");

    if (!pixa)
        return (PIX *)ERROR_PTR("pixa not defined", procName, NULL);
    if (nx <= 0 || ny <= 0)
        return (PIX *)ERROR_PTR("nx and ny must be > 0", procName, NULL);
    if ((n = pixaGetCount(pixa)) == 0)
        return (PIX *)ERROR_PTR("no components", procName, NULL);
    if (n != nx * ny)
        return (PIX *)ERROR_PTR("n != nx * ny", procName, NULL);
    borderwidth = L_MAX(0, borderwidth);

    pixaGetPixDimensions(pixa, 0, &wt, &ht, &d);
    w = nx * (wt + 2 * borderwidth);
    h = ny * (ht + 2 * borderwidth);

    if ((pixd = pixCreate(w, h, d)) == NULL)
        return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
    pixt = pixaGetPix(pixa, 0, L_CLONE);
    pixCopyColormap(pixd, pixt);
    pixDestroy(&pixt);
    if (borderwidth > 0)
        pixSetAllArbitrary(pixd, bordercolor);

    y = borderwidth;
    for (i = 0, k = 0; i < ny; i++) {
        x = borderwidth;
        for (j = 0; j < nx; j++, k++) {
            pixt = pixaGetPix(pixa, k, L_CLONE);
            pixRasterop(pixd, x, y, wt, ht, PIX_SRC, pixt, 0, 0);
            pixDestroy(&pixt);
            x += wt + 2 * borderwidth;
        }
        y += ht + 2 * borderwidth;
    }

    return pixd;
}
Exemple #22
0
/*!
 *  pixRasteropFullImage()
 *
 *      Input:  pixd
 *              pixs
 *              op (any of the op-codes)
 *      Return: 0 if OK; 1 on error
 *
 *  Notes:
 *      - this is a wrapper for a common 2-image raster operation
 *      - both pixs and pixd must be defined
 *      - the operation is performed with aligned UL corners of pixs and pixd
 *      - the operation clips to the smallest pix; if the width or height
 *        of pixd is larger than pixs, some pixels in pixd will be unchanged
 */
l_int32
pixRasteropFullImage(PIX     *pixd,
                     PIX     *pixs,
                     l_int32  op)
{
    PROCNAME("pixRasteropFullImage");

    if (!pixd)
        return ERROR_INT("pixd not defined", procName, 1);
    if (!pixs)
        return ERROR_INT("pixs not defined", procName, 1);

    pixRasterop(pixd, 0, 0, pixGetWidth(pixd), pixGetHeight(pixd), op,
                pixs, 0, 0);
    return 0;
}
Exemple #23
0
// Returns a full-resolution binary pix in which each cell over the given
// threshold is filled as a black square. pixDestroy after use.
// Edge cells, which have a zero 4-neighbour, are not marked.
Pix* IntGrid::ThresholdToPix(int threshold) const {
  Pix* pix = pixCreate(tright().x() - bleft().x(),
                       tright().y() - bleft().y(), 1);
  int cellsize = gridsize();
  for (int y = 0; y < gridheight(); ++y) {
    for (int x = 0; x < gridwidth(); ++x) {
      if (GridCellValue(x, y) > threshold &&
          GridCellValue(x - 1, y) > 0 && GridCellValue(x + 1, y) > 0 &&
              GridCellValue(x, y - 1) > 0 && GridCellValue(x, y + 1) > 0) {
        pixRasterop(pix, x * cellsize, tright().y() - ((y + 1) * cellsize),
                    cellsize, cellsize, PIX_SET, NULL, 0, 0);
      }
    }
  }
  return pix;
}
/*!
 *  pixaSplitPix()
 *
 *      Input:  pixs  (with individual components on a lattice)
 *              nx   (number of mosaic cells horizontally)
 *              ny   (number of mosaic cells vertically)
 *              borderwidth  (of added border on all sides)
 *              bordercolor  (in our RGBA format: 0xrrggbbaa)
 *      Return: pixa, or null on error
 *
 *  Notes:
 *      (1) This is a variant on pixaCreateFromPix(), where we
 *          simply divide the image up into (approximately) equal
 *          subunits.  If you want the subimages to have essentially
 *          the same aspect ratio as the input pix, use nx = ny.
 *      (2) If borderwidth is 0, we ignore the input bordercolor and
 *          redefine it to white.
 *      (3) The bordercolor is always used to initialize each tiled pix,
 *          so that if the src is clipped, the unblitted part will
 *          be this color.  This avoids 1 pixel wide black stripes at the
 *          left and lower edges.
 */
PIXA *
pixaSplitPix(PIX      *pixs,
             l_int32   nx,
             l_int32   ny,
             l_int32   borderwidth,
             l_uint32  bordercolor)
{
l_int32  w, h, d, cellw, cellh, i, j;
PIX     *pixt;
PIXA    *pixa;

    PROCNAME("pixaSplitPix");

    if (!pixs)
        return (PIXA *)ERROR_PTR("pixs not defined", procName, NULL);
    if (nx <= 0 || ny <= 0)
        return (PIXA *)ERROR_PTR("nx and ny must be > 0", procName, NULL);
    borderwidth = L_MAX(0, borderwidth);

    if ((pixa = pixaCreate(nx * ny)) == NULL)
        return (PIXA *)ERROR_PTR("pixa not made", procName, NULL);
    pixGetDimensions(pixs, &w, &h, &d);
    cellw = (w + nx - 1) / nx;  /* round up */
    cellh = (h + ny - 1) / ny;

    for (i = 0; i < ny; i++) {
        for (j = 0; j < nx; j++) {
            if ((pixt = pixCreate(cellw + 2 * borderwidth,
                                  cellh + 2 * borderwidth, d)) == NULL)
                return (PIXA *)ERROR_PTR("pixt not made", procName, NULL);
            pixCopyColormap(pixt, pixs);
            if (borderwidth == 0) {  /* initialize full image to white */
                if (d == 1)
                    pixClearAll(pixt);
                else
                    pixSetAll(pixt);
            }
            else
                pixSetAllArbitrary(pixt, bordercolor);
            pixRasterop(pixt, borderwidth, borderwidth, cellw, cellh,
                        PIX_SRC, pixs, j * cellw, i * cellh);
            pixaAddPix(pixa, pixt, L_INSERT);
        }
    }

    return pixa;
}
Exemple #25
0
/*!
 *  pixConnCompAreaTransform()
 *
 *      Input:   pixs (1 bpp)
 *               connect (connectivity: 4 or 8)
 *      Return:  pixd (16 bpp), or null on error
 *
 *  Notes:
 *      (1) The pixel values in pixd label the area of the fg component
 *          to which the pixel belongs.  Pixels in the bg are labelled 0.
 *      (2) The pixel values cannot exceed 2^16 - 1, even if the area
 *          of the c.c. is larger.
 *      (3) For purposes of visualization, the output can be converted
 *          to 8 bpp, using pixConvert16To8() or pixMaxDynamicRange().
 */
PIX *
pixConnCompAreaTransform(PIX     *pixs,
                         l_int32  connect)
{
l_int32   i, n, npix, w, h, xb, yb, wb, hb;
l_int32  *tab8;
BOXA     *boxa;
PIX      *pix1, *pix2, *pixd;
PIXA     *pixa;

    PROCNAME("pixConnCompTransform");

    if (!pixs || pixGetDepth(pixs) != 1)
        return (PIX *)ERROR_PTR("pixs undefined or not 1 bpp", procName, NULL);
    if (connect != 4 && connect != 8)
        return (PIX *)ERROR_PTR("connectivity must be 4 or 8", procName, NULL);

    boxa = pixConnComp(pixs, &pixa, connect);
    n = pixaGetCount(pixa);
    boxaDestroy(&boxa);
    pixGetDimensions(pixs, &w, &h, NULL);
    pixd = pixCreate(w, h, 16);
    if (n == 0) {  /* no fg */
        pixaDestroy(&pixa);
        return pixd;
    }

       /* Label each component and blit it in */
    tab8 = makePixelSumTab8();
    for (i = 0; i < n; i++) {
        pixaGetBoxGeometry(pixa, i, &xb, &yb, &wb, &hb);
        pix1 = pixaGetPix(pixa, i, L_CLONE);
        pixCountPixels(pix1, &npix, tab8);
        npix = L_MIN(npix, 0xffff);
        pix2 = pixConvert1To16(NULL, pix1, 0, npix);
        pixRasterop(pixd, xb, yb, wb, hb, PIX_PAINT, pix2, 0, 0);
        pixDestroy(&pix1);
        pixDestroy(&pix2);
    }

    pixaDestroy(&pixa);
    FREE(tab8);
    return pixd;
}
Exemple #26
0
/*!
 *  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;
}
Exemple #27
0
/**
 * 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;
}
// create a union of a number of arbitrary pix
Pix *CubeLineSegmenter::Pixa2Pix(Pixa *pixa, Box **dest_box,
                                 int start_pix, int pix_cnt) {
  // compute union_box
  int min_x = INT_MAX,
    max_x = INT_MIN,
    min_y = INT_MAX,
    max_y = INT_MIN;

  for (int pix_idx = start_pix; pix_idx < (start_pix + pix_cnt); pix_idx++) {
    Box *pix_box = pixa->boxa->box[pix_idx];

    UpdateRange(pix_box->x, pix_box->x + pix_box->w, &min_x, &max_x);
    UpdateRange(pix_box->y, pix_box->y + pix_box->h, &min_y, &max_y);
  }

  (*dest_box) = boxCreate(min_x, min_y, max_x - min_x, max_y - min_y);
  if ((*dest_box) == NULL) {
    return NULL;
  }

  // create the union pix
  Pix *union_pix = pixCreate((*dest_box)->w, (*dest_box)->h, img_->d);
  if (union_pix == NULL) {
    boxDestroy(dest_box);
    return NULL;
  }

  // create a pix corresponding to the union of all pixs
  // blt the src and dest pix
  for (int pix_idx = start_pix; pix_idx < (start_pix + pix_cnt); pix_idx++) {
    Box *pix_box = pixa->boxa->box[pix_idx];
    Pix *con_pix = pixa->pix[pix_idx];

    pixRasterop(union_pix,
                pix_box->x - (*dest_box)->x, pix_box->y - (*dest_box)->y,
                pix_box->w, pix_box->h, PIX_SRC | PIX_DST, con_pix, 0, 0);
  }

  return union_pix;
}
/*!
 *  pixaCreateFromPix()
 *
 *      Input:  pixs  (with individual components on a lattice)
 *              n   (number of components)
 *              cellw   (width of each cell)
 *              cellh   (height of each cell)
 *      Return: pixa, or null on error
 *
 *  Note: for bpp = 1, we truncate each retrieved pix to
 *        the ON pixels, which we assume for now start at (0,0)
 */
PIXA *
pixaCreateFromPix(PIX     *pixs,
                  l_int32  n,
                  l_int32  cellw,
                  l_int32  cellh)
{
l_int32  w, h, d, nw, nh, i, j, index;
PIX     *pix, *pixt;
PIXA    *pixa;

    PROCNAME("pixaCreateFromPix");

    if (!pixs)
        return (PIXA *)ERROR_PTR("pixs not defined", procName, NULL);
    if (n <= 0)
        return (PIXA *)ERROR_PTR("n must be > 0", procName, NULL);

    if ((pixa = pixaCreate(n)) == NULL)
        return (PIXA *)ERROR_PTR("pixa not made", procName, NULL);
    pixGetDimensions(pixs, &w, &h, &d);
    if ((pixt = pixCreate(cellw, cellh, d)) == NULL)
        return (PIXA *)ERROR_PTR("pixt not made", procName, NULL);

    nw = (w + cellw - 1) / cellw;
    nh = (h + cellh - 1) / cellh;
    for (i = 0, index = 0; i < nh; i++) {
        for (j = 0; j < nw && index < n; j++, index++) {
            pixRasterop(pixt, 0, 0, cellw, cellh, PIX_SRC, pixs,
                   j * cellw, i * cellh);
            if (d == 1 && !pixClipToForeground(pixt, &pix, NULL))
                pixaAddPix(pixa, pix, L_INSERT);
            else
                pixaAddPix(pixa, pixt, L_COPY);
        }
    }

    pixDestroy(&pixt);
    return pixa;
}
// clean up the image
Pix *CubeLineSegmenter::CleanUp(Pix *orig_img) {
  // get rid of long horizontal lines
  Pix *pix_temp0 = pixMorphCompSequence(orig_img, "o300.2", 0);
  pixXor(pix_temp0, pix_temp0, orig_img);

  // get rid of long vertical lines
  Pix *pix_temp1 = pixMorphCompSequence(pix_temp0, "o2.300", 0);
  pixXor(pix_temp1, pix_temp1, pix_temp0);

  pixDestroy(&pix_temp0);

  // detect connected components
  Pixa *con_comps;
  Boxa *boxa = pixConnComp(pix_temp1, &con_comps, 8);
  if (boxa == NULL) {
    return NULL;
  }

  // detect and remove suspicious conn comps
  for (int con = 0; con < con_comps->n; con++) {
    Box *box = boxa->box[con];

    // remove if suspc. conn comp
    if ((box->w > (box->h * kMaxHorzAspectRatio)) ||
         (box->h > (box->w * kMaxVertAspectRatio)) ||
         (box->w < kMinWid && box->h < kMinHgt)) {
      pixRasterop(pix_temp1, box->x, box->y, box->w, box->h,
        PIX_SRC ^ PIX_DST, con_comps->pix[con], 0, 0);
    }
  }

  pixaDestroy(&con_comps);
  boxaDestroy(&boxa);

  return pix_temp1;
}