void MakeWordBoxes2(PIX *pixs, l_int32 reduction, L_REGPARAMS *rp) { l_int32 default_minwidth = 10; l_int32 default_minheight = 10; l_int32 default_maxwidth = 400; l_int32 default_maxheight = 70; l_int32 minwidth, minheight, maxwidth, maxheight; BOXA *boxa1, *boxa2; NUMA *na; PIX *pixd1, *pixd2; PIXA *pixa; minwidth = default_minwidth / reduction; minheight = default_minheight / reduction; maxwidth = default_maxwidth / reduction; maxheight = default_maxheight / reduction; /* Get the word boxes */ pixGetWordsInTextlines(pixs, reduction, minwidth, minheight, maxwidth, maxheight, &boxa1, &pixa, &na); pixaDestroy(&pixa); numaDestroy(&na); if (reduction == 1) boxa2 = boxaCopy(boxa1, L_CLONE); else boxa2 = boxaTransform(boxa1, 0, 0, 2.0, 2.0); pixd1 = pixConvertTo8(pixs, 1); pixRenderBoxaArb(pixd1, boxa2, 2, 255, 0, 0); regTestWritePixAndCheck(rp, pixd1, IFF_PNG); pixDisplayWithTitle(pixd1, 800, 100, NULL, rp->display); boxaDestroy(&boxa1); boxaDestroy(&boxa2); /* Do it again with this interface. The result should be the same. */ pixGetWordBoxesInTextlines(pixs, reduction, minwidth, minheight, maxwidth, maxheight, &boxa1, NULL); if (reduction == 1) boxa2 = boxaCopy(boxa1, L_CLONE); else boxa2 = boxaTransform(boxa1, 0, 0, 2.0, 2.0); pixd2 = pixConvertTo8(pixs, 1); pixRenderBoxaArb(pixd2, boxa2, 2, 255, 0, 0); if (regTestComparePix(rp, pixd1, pixd2)) { L_ERROR("pix not the same", "MakeWordBoxes2"); pixDisplayWithTitle(pixd2, 800, 100, NULL, rp->display); } pixDestroy(&pixd1); pixDestroy(&pixd2); boxaDestroy(&boxa1); boxaDestroy(&boxa2); return; }
/* static */ void Input::PreparePixInput(const StaticShape& shape, const Pix* pix, TRand* randomizer, NetworkIO* input) { bool color = shape.depth() == 3; Pix* var_pix = const_cast<Pix*>(pix); int depth = pixGetDepth(var_pix); Pix* normed_pix = nullptr; // On input to BaseAPI, an image is forced to be 1, 8 or 24 bit, without // colormap, so we just have to deal with depth conversion here. if (color) { // Force RGB. if (depth == 32) normed_pix = pixClone(var_pix); else normed_pix = pixConvertTo32(var_pix); } else { // Convert non-8-bit images to 8 bit. if (depth == 8) normed_pix = pixClone(var_pix); else normed_pix = pixConvertTo8(var_pix, false); } int height = pixGetHeight(normed_pix); int target_height = shape.height(); if (target_height == 1) target_height = shape.depth(); if (target_height != 0 && target_height != height) { // Get the scaled image. float im_factor = static_cast<float>(target_height) / height; Pix* scaled_pix = pixScale(normed_pix, im_factor, im_factor); pixDestroy(&normed_pix); normed_pix = scaled_pix; } input->FromPix(shape, normed_pix, randomizer); pixDestroy(&normed_pix); }
/*! * pixRotateBinaryNice() * * Input: pixs (1 bpp) * angle (radians; clockwise is positive; about the center) * incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK) * Return: pixd, or null on error * * Notes: * (1) For very small rotations, just return a clone. * (2) This does a computationally expensive rotation of 1 bpp images. * The fastest rotators (using shears or subsampling) leave * visible horizontal and vertical shear lines across which * the image shear changes by one pixel. To ameliorate the * visual effect one can introduce random dithering. One * way to do this in a not-too-random fashion is given here. * We convert to 8 bpp, do a very small blur, rotate using * linear interpolation (same as area mapping), do a * small amount of sharpening to compensate for the initial * blur, and threshold back to binary. The shear lines * are magically removed. * (3) This operation is about 5x slower than rotation by sampling. */ PIX * pixRotateBinaryNice(PIX *pixs, l_float32 angle, l_int32 incolor) { PIX *pixt1, *pixt2, *pixt3, *pixt4, *pixd; PROCNAME("pixRotateBinaryNice"); if (!pixs || pixGetDepth(pixs) != 1) return (PIX *)ERROR_PTR("pixs undefined or not 1 bpp", procName, NULL); if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK) return (PIX *)ERROR_PTR("invalid incolor", procName, NULL); pixt1 = pixConvertTo8(pixs, 0); pixt2 = pixBlockconv(pixt1, 1, 1); /* smallest blur allowed */ pixt3 = pixRotateAM(pixt2, angle, incolor); pixt4 = pixUnsharpMasking(pixt3, 1, 1.0); /* sharpen a bit */ pixd = pixThresholdToBinary(pixt4, 128); pixDestroy(&pixt1); pixDestroy(&pixt2); pixDestroy(&pixt3); pixDestroy(&pixt4); return pixd; }
/*! * dewarpSinglePageInit() * * Input: pixs (with text, any depth) * thresh (for global thresholding to 1 bpp; ignored otherwise) * adaptive (1 for adaptive thresholding; 0 for global threshold) * use_both (1 for horizontal and vertical; 0 for vertical only) * &pixb (<return> 1 bpp image) * &dewa (<return> initialized dewa) * Return: 0 if OK, 1 on error (list of page numbers), or null on error * * Notes: * (1) This binarizes the input pixs if necessary, returning the * binarized image. It also initializes the dewa to default values * for the model parameters. * (2) If pixs is 1 bpp, the parameters @adaptive and @thresh are ignored. * (3) To change the model parameters, call dewarpaSetCurvatures() * before running dewarpSinglePageRun(). For DC: * dewarpSinglePageInit(pixs, 0, 1, 1, &pixb, &dewa); * dewarpaSetCurvatures(dewa, 250, -1, -1, 80, 70, 150); * dewarpSinglePageRun(pixs, pixb, dewa, &pixd, 0); * dewarpaDestroy(&dewa); * pixDestroy(&pixb); */ l_int32 dewarpSinglePageInit(PIX *pixs, l_int32 thresh, l_int32 adaptive, l_int32 use_both, PIX **ppixb, L_DEWARPA **pdewa) { PIX *pix1; PROCNAME("dewarpSinglePageInit"); if (ppixb) *ppixb = NULL; if (pdewa) *pdewa = NULL; if (!ppixb || !pdewa) return ERROR_INT("&pixb and &dewa not both defined", procName, 1); if (!pixs) return ERROR_INT("pixs not defined", procName, 1); *pdewa = dewarpaCreate(1, 0, 1, 0, -1); dewarpaUseBothArrays(*pdewa, use_both); /* Generate a binary image, if necessary */ if (pixGetDepth(pixs) > 1) { pix1 = pixConvertTo8(pixs, 0); if (adaptive) *ppixb = pixAdaptThresholdToBinary(pix1, NULL, 1.0); else *ppixb = pixThresholdToBinary(pix1, thresh); pixDestroy(&pix1); } else { *ppixb = pixClone(pixs); } return 0; }
jint Java_com_googlecode_leptonica_android_Convert_nativeConvertTo8(JNIEnv *env, jclass clazz, jint nativePix) { PIX *pixs = (PIX *) nativePix; PIX *pixd = pixConvertTo8(pixs, FALSE); return (jint) pixd; }
// Helper gets the image of a rectangle, using the block.re_rotation() if // needed to get to the image, and rotating the result back to horizontal // layout. (CJK characters will be on their left sides) The vertical text flag // is set in the returned ImageData if the text was originally vertical, which // can be used to invoke a different CJK recognition engine. The revised_box // is also returned to enable calculation of output bounding boxes. ImageData* Tesseract::GetRectImage(const TBOX& box, const BLOCK& block, int padding, TBOX* revised_box) const { TBOX wbox = box; wbox.pad(padding, padding); *revised_box = wbox; // Number of clockwise 90 degree rotations needed to get back to tesseract // coords from the clipped image. int num_rotations = 0; if (block.re_rotation().y() > 0.0f) num_rotations = 1; else if (block.re_rotation().x() < 0.0f) num_rotations = 2; else if (block.re_rotation().y() < 0.0f) num_rotations = 3; // Handle two cases automatically: 1 the box came from the block, 2 the box // came from a box file, and refers to the image, which the block may not. if (block.bounding_box().major_overlap(*revised_box)) revised_box->rotate(block.re_rotation()); // Now revised_box always refers to the image. // BestPix is never colormapped, but may be of any depth. Pix* pix = BestPix(); int width = pixGetWidth(pix); int height = pixGetHeight(pix); TBOX image_box(0, 0, width, height); // Clip to image bounds; *revised_box &= image_box; if (revised_box->null_box()) return NULL; Box* clip_box = boxCreate(revised_box->left(), height - revised_box->top(), revised_box->width(), revised_box->height()); Pix* box_pix = pixClipRectangle(pix, clip_box, NULL); if (box_pix == NULL) return NULL; boxDestroy(&clip_box); if (num_rotations > 0) { Pix* rot_pix = pixRotateOrth(box_pix, num_rotations); pixDestroy(&box_pix); box_pix = rot_pix; } // Convert sub-8-bit images to 8 bit. int depth = pixGetDepth(box_pix); if (depth < 8) { Pix* grey; grey = pixConvertTo8(box_pix, false); pixDestroy(&box_pix); box_pix = grey; } bool vertical_text = false; if (num_rotations > 0) { // Rotated the clipped revised box back to internal coordinates. FCOORD rotation(block.re_rotation().x(), -block.re_rotation().y()); revised_box->rotate(rotation); if (num_rotations != 2) vertical_text = true; } return new ImageData(vertical_text, box_pix); }
l_int32 main(int argc, char **argv) { l_uint32 *colors; l_int32 ncolors; PIX *pix1, *pix2, *pix3; L_REGPARAMS *rp; if (regTestSetup(argc, argv, &rp)) return 1; /* Find the most populated colors */ pix1 = pixRead("fish24.jpg"); pixGetMostPopulatedColors(pix1, 2, 3, 10, &colors, NULL); pix2 = pixDisplayColorArray(colors, 10, 190, 5, 1); pixDisplayWithTitle(pix2, 0, 0, NULL, rp->display); regTestWritePixAndCheck(rp, pix2, IFF_PNG); /* 0 */ lept_free(colors); pixDestroy(&pix2); /* Do a simple color quantization with sigbits = 2 */ pix2 = pixSimpleColorQuantize(pix1, 2, 3, 10); pixDisplayWithTitle(pix2, 0, 400, NULL, rp->display); regTestWritePixAndCheck(rp, pix2, IFF_PNG); /* 1 */ pix3 = pixRemoveColormap(pix2, REMOVE_CMAP_TO_FULL_COLOR); regTestComparePix(rp, pix2, pix3); /* 2 */ pixNumColors(pix3, 1, &ncolors); regTestCompareValues(rp, ncolors, 10, 0.0); /* 3 */ pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); /* Do a simple color quantization with sigbits = 3 */ pix1 = pixRead("wyom.jpg"); pixNumColors(pix1, 1, &ncolors); /* >255, so should give 0 */ regTestCompareValues(rp, ncolors, 0, 0.0); /* 4 */ pix2 = pixSimpleColorQuantize(pix1, 3, 3, 20); pixDisplayWithTitle(pix2, 1000, 0, NULL, rp->display); regTestWritePixAndCheck(rp, pix2, IFF_PNG); /* 5 */ ncolors = pixcmapGetCount(pixGetColormap(pix2)); regTestCompareValues(rp, ncolors, 20, 0.0); /* 6 */ pixDestroy(&pix1); pixDestroy(&pix2); /* Find the number of perceptually significant gray intensities */ pix1 = pixRead("marge.jpg"); pix2 = pixConvertTo8(pix1, 0); pixNumSignificantGrayColors(pix2, 20, 236, 0.0001, 1, &ncolors); regTestCompareValues(rp, ncolors, 219, 0.0); /* 7 */ pixDestroy(&pix1); pixDestroy(&pix2); return regTestCleanup(rp); }
/*! * pixProjectivePta() * * Input: pixs (all depths; colormap ok) * ptad (4 pts of final coordinate space) * ptas (4 pts of initial coordinate space) * incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK) * Return: pixd, or null on error * * Notes: * (1) Brings in either black or white pixels from the boundary * (2) Removes any existing colormap, if necessary, before transforming */ PIX * pixProjectivePta(PIX *pixs, PTA *ptad, PTA *ptas, l_int32 incolor) { l_int32 d; l_uint32 colorval; PIX *pixt1, *pixt2, *pixd; PROCNAME("pixProjectivePta"); if (!pixs) return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); if (!ptas) return (PIX *)ERROR_PTR("ptas not defined", procName, NULL); if (!ptad) return (PIX *)ERROR_PTR("ptad not defined", procName, NULL); if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK) return (PIX *)ERROR_PTR("invalid incolor", procName, NULL); if (ptaGetCount(ptas) != 4) return (PIX *)ERROR_PTR("ptas count not 4", procName, NULL); if (ptaGetCount(ptad) != 4) return (PIX *)ERROR_PTR("ptad count not 4", procName, NULL); if (pixGetDepth(pixs) == 1) return pixProjectiveSampledPta(pixs, ptad, ptas, incolor); /* Remove cmap if it exists, and unpack to 8 bpp if necessary */ pixt1 = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC); d = pixGetDepth(pixt1); if (d < 8) pixt2 = pixConvertTo8(pixt1, FALSE); else pixt2 = pixClone(pixt1); d = pixGetDepth(pixt2); /* Compute actual color to bring in from edges */ colorval = 0; if (incolor == L_BRING_IN_WHITE) { if (d == 8) colorval = 255; else /* d == 32 */ colorval = 0xffffff00; } if (d == 8) pixd = pixProjectivePtaGray(pixt2, ptad, ptas, colorval); else /* d == 32 */ pixd = pixProjectivePtaColor(pixt2, ptad, ptas, colorval); pixDestroy(&pixt1); pixDestroy(&pixt2); return pixd; }
// Get a clone/copy of the source image rectangle, reduced to greyscale. // 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::GetPixRectGrey() { Pix* pix = GetPixRect(); // May have to be reduced to grey. int depth = pixGetDepth(pix); if (depth != 8) { Pix* result = depth < 8 ? pixConvertTo8(pix, false) : pixConvertRGBToLuminance(pix); pixDestroy(&pix); return result; } return pix; }
l_int32 main(int argc, char **argv) { l_int32 pageno; L_DEWARP *dew1; L_DEWARPA *dewa; PIX *pixs, *pixn, *pixg, *pixb; static char mainName[] = "dewarptest2"; if (argc != 1 && argc != 3) return ERROR_INT("Syntax: dewarptest2 [image pageno]", mainName, 1); if (argc == 1) { pixs = pixRead("cat-35.jpg"); pageno = 35; } else { pixs = pixRead(argv[1]); pageno = atoi(argv[2]); } if (!pixs) return ERROR_INT("image not read", mainName, 1); dewa = dewarpaCreate(40, 30, 1, 6, 50); #if NORMALIZE /* Normalize for varying background and binarize */ pixn = pixBackgroundNormSimple(pixs, NULL, NULL); pixg = pixConvertRGBToGray(pixn, 0.5, 0.3, 0.2); pixb = pixThresholdToBinary(pixg, 130); pixDestroy(&pixn); #else /* Don't normalize; just threshold and clean edges */ pixg = pixConvertTo8(pixs, 0); pixb = pixThresholdToBinary(pixg, 100); pixSetOrClearBorder(pixb, 30, 30, 40, 40, PIX_CLR); #endif /* Run the basic functions */ dew1 = dewarpCreate(pixb, pageno); dewarpaInsertDewarp(dewa, dew1); dewarpBuildModel(dew1, "/tmp/dewarp_model1.pdf"); dewarpaApplyDisparity(dewa, pageno, pixg, "/tmp/dewarp_apply1.pdf"); dewarpaDestroy(&dewa); pixDestroy(&pixs); pixDestroy(&pixg); pixDestroy(&pixb); return 0; }
static PIX * QuantizeNonImageRegion(PIX *pixs, PIX *pixm, l_int32 levels) { PIX *pix1, *pix2, *pixd; pix1 = pixConvertTo8(pixs, 0); pix2 = pixThresholdOn8bpp(pix1, levels, 1); pixd = pixConvertTo32(pix2); /* save in rgb */ pixCombineMasked(pixd, pixs, pixm); /* rgb result */ pixDestroy(&pix1); pixDestroy(&pix2); return pixd; }
/*! * pixRotateAM() * * Input: pixs (2, 4, 8 bpp gray or colormapped, or 32 bpp RGB) * angle (radians; clockwise is positive) * incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK) * Return: pixd, or null on error * * Notes: * (1) Rotates about image center. * (2) A positive angle gives a clockwise rotation. * (3) Brings in either black or white pixels from the boundary. */ PIX * pixRotateAM(PIX *pixs, l_float32 angle, l_int32 incolor) { l_int32 d; l_uint32 fillval; PIX *pixt1, *pixt2, *pixd; PROCNAME("pixRotateAM"); if (!pixs) return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); if (pixGetDepth(pixs) == 1) return (PIX *)ERROR_PTR("pixs is 1 bpp", procName, NULL); if (L_ABS(angle) < MIN_ANGLE_TO_ROTATE) return pixClone(pixs); /* Remove cmap if it exists, and unpack to 8 bpp if necessary */ pixt1 = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC); d = pixGetDepth(pixt1); if (d < 8) pixt2 = pixConvertTo8(pixt1, FALSE); else pixt2 = pixClone(pixt1); d = pixGetDepth(pixt2); /* Compute actual incoming color */ fillval = 0; if (incolor == L_BRING_IN_WHITE) { if (d == 8) fillval = 255; else /* d == 32 */ fillval = 0xffffff00; } if (d == 8) pixd = pixRotateAMGray(pixt2, angle, fillval); else /* d == 32 */ pixd = pixRotateAMColor(pixt2, angle, fillval); pixDestroy(&pixt1); pixDestroy(&pixt2); return pixd; }
/*! * pixProjective() * * Input: pixs (all depths; colormap ok) * vc (vector of 8 coefficients for projective transformation) * incolor (L_BRING_IN_WHITE, L_BRING_IN_BLACK) * Return: pixd, or null on error * * Notes: * (1) Brings in either black or white pixels from the boundary * (2) Removes any existing colormap, if necessary, before transforming */ PIX * pixProjective(PIX *pixs, l_float32 *vc, l_int32 incolor) { l_int32 d; l_uint32 colorval; PIX *pixt1, *pixt2, *pixd; PROCNAME("pixProjective"); if (!pixs) return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); if (!vc) return (PIX *)ERROR_PTR("vc not defined", procName, NULL); if (pixGetDepth(pixs) == 1) return pixProjectiveSampled(pixs, vc, incolor); /* Remove cmap if it exists, and unpack to 8 bpp if necessary */ pixt1 = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC); d = pixGetDepth(pixt1); if (d < 8) pixt2 = pixConvertTo8(pixt1, FALSE); else pixt2 = pixClone(pixt1); d = pixGetDepth(pixt2); /* Compute actual color to bring in from edges */ colorval = 0; if (incolor == L_BRING_IN_WHITE) { if (d == 8) colorval = 255; else /* d == 32 */ colorval = 0xffffff00; } if (d == 8) pixd = pixProjectiveGray(pixt2, vc, colorval); else /* d == 32 */ pixd = pixProjectiveColor(pixt2, vc, colorval); pixDestroy(&pixt1); pixDestroy(&pixt2); return pixd; }
/*! * pixColorGrayCmap() * * Input: pixs (2, 4 or 8 bpp, with colormap) * box (<optional> region to set color; can be NULL) * type (L_PAINT_LIGHT, L_PAINT_DARK) * rval, gval, bval (target color) * Return: 0 if OK, 1 on error * * Notes: * (1) This is an in-place operation. * (2) If type == L_PAINT_LIGHT, it colorizes non-black pixels, * preserving antialiasing. * If type == L_PAINT_DARK, it colorizes non-white pixels, * preserving antialiasing. * (3) box gives the region to apply color; if NULL, this * colorizes the entire image. * (4) If the cmap is only 2 or 4 bpp, pixs is converted in-place * to an 8 bpp cmap. A 1 bpp cmap is not a valid input pix. * (5) This can also be called through pixColorGray(). * (6) This operation increases the colormap size by the number of * different gray (non-black or non-white) colors in the * input colormap. If there is not enough room in the colormap * for this expansion, it returns 1 (error), and the caller * should check the return value. * (7) Using the darkness of each original pixel in the rect, * it generates a new color (based on the input rgb values). * If type == L_PAINT_LIGHT, the new color is a (generally) * darken-to-black version of the input rgb color, where the * amount of darkening increases with the darkness of the * original pixel color. * If type == L_PAINT_DARK, the new color is a (generally) * faded-to-white version of the input rgb color, where the * amount of fading increases with the brightness of the * original pixel color. */ l_int32 pixColorGrayCmap(PIX *pixs, BOX *box, l_int32 type, l_int32 rval, l_int32 gval, l_int32 bval) { l_int32 w, h, d, ret; PIX *pixt; BOXA *boxa; PIXCMAP *cmap; PROCNAME("pixColorGrayCmap"); if (!pixs) return ERROR_INT("pixs not defined", procName, 1); if ((cmap = pixGetColormap(pixs)) == NULL) return ERROR_INT("no colormap", procName, 1); pixGetDimensions(pixs, &w, &h, &d); if (d != 2 && d != 4 && d != 8) return ERROR_INT("depth not in {2, 4, 8}", procName, 1); if (type != L_PAINT_DARK && type != L_PAINT_LIGHT) return ERROR_INT("invalid type", procName, 1); /* If 2 bpp or 4 bpp, convert in-place to 8 bpp. */ if (d == 2 || d == 4) { pixt = pixConvertTo8(pixs, 1); pixTransferAllData(pixs, &pixt, 0, 0); } /* If box == NULL, color the entire image */ boxa = boxaCreate(1); if (box) { boxaAddBox(boxa, box, L_COPY); } else { box = boxCreate(0, 0, w, h); boxaAddBox(boxa, box, L_INSERT); } ret = pixColorGrayRegionsCmap(pixs, boxa, type, rval, gval, bval); boxaDestroy(&boxa); return ret; }
void MakeWordBoxes1(PIX *pixs, l_int32 maxdil, L_REGPARAMS *rp) { BOXA *boxa; PIX *pix1, *pixd; pixWordMaskByDilation(pixs, maxdil, &pix1, NULL); pixd = NULL; if (pix1) { boxa = pixConnComp(pix1, NULL, 8); pixd = pixConvertTo8(pixs, 1); pixRenderBoxaArb(pixd, boxa, 2, 255, 0, 0); boxaDestroy(&boxa); } regTestWritePixAndCheck(rp, pixd, IFF_PNG); pixDisplayWithTitle(pixd, 0, 100, NULL, rp->display); pixDestroy(&pix1); pixDestroy(&pixd); return; }
// NOTE: Opposite to SetImage for raw images, SetImage for Pix clones its // input, so the source pix may be pixDestroyed immediately after. void ImageThresholder::SetImage(const Pix* pix) { image_data_ = NULL; if (pix_ != NULL) pixDestroy(&pix_); Pix* src = const_cast<Pix*>(pix); int depth; pixGetDimensions(src, &image_width_, &image_height_, &depth); // Convert the image as necessary so it is one of binary, plain RGB, or // 8 bit with no colormap. if (depth > 1 && depth < 8) { pix_ = pixConvertTo8(src, false); } else if (pixGetColormap(src)) { pix_ = pixRemoveColormap(src, REMOVE_CMAP_BASED_ON_SRC); } else { pix_ = pixClone(src); } depth = pixGetDepth(pix_); image_bytespp_ = depth / 8; image_bytespl_ = pixGetWpl(pix_) * sizeof(l_uint32); scale_ = 1; estimated_res_ = yres_ = pixGetYRes(src); Init(); }
main(int argc, char **argv) { PIX *pixs, *pixg1, *pixg2; L_REGPARAMS *rp; if (regTestSetup(argc, argv, &rp)) return 1; /* Use for input two different images */ pixs = pixRead("projectionstats.jpg"); pixg1 = pixConvertTo8(pixs, 0); pixDestroy(&pixs); pixs = pixRead("feyn.tif"); pixg2 = pixScaleToGray4(pixs); pixDestroy(&pixs); TestProjection(rp, pixg1); TestProjection(rp, pixg2); pixDestroy(&pixg1); pixDestroy(&pixg2); regTestCleanup(rp); return 0; }
main(int argc, char **argv) { char *errorstr; l_int32 same, error; PIX *pixs1, *pixs2, *pixs4, *pixs8, *pixs16, *pixs32, *pixd; PIX *pixc2, *pixc4, *pixc8; PIX *pixt1, *pixt2, *pixt3, *pixt4, *pixt5, *pixt6; PIXCMAP *cmap; SARRAY *sa; static char mainName[] = "convert_reg"; if (argc != 1) exit(ERROR_INT(" Syntax: convert_rt", mainName, 1)); if ((pixs1 = pixRead("test1.png")) == NULL) exit(ERROR_INT("pixs1 not made", mainName, 1)); if ((pixs2 = pixRead("dreyfus2.png")) == NULL) exit(ERROR_INT("pixs2 not made", mainName, 1)); if ((pixc2 = pixRead("weasel2.4c.png")) == NULL) exit(ERROR_INT("pixc2 not made", mainName, 1)); if ((pixs4 = pixRead("weasel4.16g.png")) == NULL) exit(ERROR_INT("pixs4 not made", mainName, 1)); if ((pixc4 = pixRead("weasel4.11c.png")) == NULL) exit(ERROR_INT("pixc4 not made", mainName, 1)); if ((pixs8 = pixRead("karen8.jpg")) == NULL) exit(ERROR_INT("pixs8 not made", mainName, 1)); if ((pixc8 = pixRead("weasel8.240c.png")) == NULL) exit(ERROR_INT("pixc8 not made", mainName, 1)); if ((pixs16 = pixRead("test16.tif")) == NULL) exit(ERROR_INT("pixs16 not made", mainName, 1)); if ((pixs32 = pixRead("marge.jpg")) == NULL) exit(ERROR_INT("pixs32 not made", mainName, 1)); error = FALSE; sa = sarrayCreate(0); /* Conversion: 1 bpp --> 8 bpp --> 1 bpp */ pixt1 = pixConvertTo8(pixs1, FALSE); pixt2 = pixThreshold8(pixt1, 1, 0, 0); pixEqual(pixs1, pixt2, &same); if (!same) { pixDisplayWithTitle(pixs1, 100, 100, "1 bpp, no cmap", DFLAG); pixDisplayWithTitle(pixt2, 500, 100, "1 bpp, no cmap", DFLAG); error = TRUE; sarrayAddString(sa, (char *)"conversion 1 bpp <==> 8 bpp", L_COPY); } else fprintf(stderr, "OK: conversion 1 bpp <==> 8 bpp\n"); pixDestroy(&pixt1); pixDestroy(&pixt2); /* Conversion: 2 bpp --> 8 bpp --> 2 bpp */ /* Conversion: 2 bpp cmap --> 8 bpp cmap --> 2 bpp cmap */ pixt1 = pixRemoveColormap(pixs2, REMOVE_CMAP_TO_GRAYSCALE); pixt2 = pixThreshold8(pixt1, 2, 4, 0); pixt3 = pixConvertTo8(pixt2, FALSE); pixt4 = pixThreshold8(pixt3, 2, 4, 0); pixEqual(pixt2, pixt4, &same); if (!same) { pixDisplayWithTitle(pixt2, 100, 100, "2 bpp, no cmap", DFLAG); pixDisplayWithTitle(pixt4, 500, 100, "2 bpp, no cmap", DFLAG); error = TRUE; sarrayAddString(sa, (char *)"conversion 2 bpp <==> 8 bpp", L_COPY); } else fprintf(stderr, "OK: conversion 2 bpp <==> 8 bpp\n"); pixt5 = pixConvertTo8(pixs2, TRUE); pixt6 = pixThreshold8(pixt5, 2, 4, 1); pixEqual(pixs2, pixt6, &same); if (!same) { pixDisplayWithTitle(pixs2, 100, 100, "2 bpp, cmap", DFLAG); pixDisplayWithTitle(pixt6, 500, 100, "2 bpp, cmap", DFLAG); error = TRUE; sarrayAddString(sa, (char *)"conversion 2 bpp <==> 8 bpp; cmap", L_COPY); } else fprintf(stderr, "OK: conversion 2 bpp <==> 8 bpp; cmap\n"); pixDestroy(&pixt1); pixDestroy(&pixt2); pixDestroy(&pixt3); pixDestroy(&pixt4); pixDestroy(&pixt5); pixDestroy(&pixt6); /* Conversion: 4 bpp --> 8 bpp --> 4 bpp */ /* Conversion: 4 bpp cmap --> 8 bpp cmap --> 4 bpp cmap */ pixt1 = pixRemoveColormap(pixs4, REMOVE_CMAP_TO_GRAYSCALE); pixt2 = pixThreshold8(pixt1, 4, 16, 0); pixt3 = pixConvertTo8(pixt2, FALSE); pixt4 = pixThreshold8(pixt3, 4, 16, 0); pixEqual(pixt2, pixt4, &same); if (!same) { pixDisplayWithTitle(pixt2, 100, 100, "4 bpp, no cmap", DFLAG); pixDisplayWithTitle(pixt4, 500, 100, "4 bpp, no cmap", DFLAG); error = TRUE; sarrayAddString(sa, (char *)"conversion 4 bpp <==> 8 bpp", L_COPY); } else fprintf(stderr, "OK: conversion 4 bpp <==> 8 bpp\n"); pixt5 = pixConvertTo8(pixs4, TRUE); pixt6 = pixThreshold8(pixt5, 4, 16, 1); pixEqual(pixs4, pixt6, &same); if (!same) { pixDisplayWithTitle(pixs4, 100, 100, "4 bpp, cmap", DFLAG); pixDisplayWithTitle(pixt6, 500, 100, "4 bpp, cmap", DFLAG); error = TRUE; sarrayAddString(sa, (char *)"conversion 4 bpp <==> 8 bpp, cmap", L_COPY); } else fprintf(stderr, "OK: conversion 4 bpp <==> 8 bpp; cmap\n"); pixDestroy(&pixt1); pixDestroy(&pixt2); pixDestroy(&pixt3); pixDestroy(&pixt4); pixDestroy(&pixt5); pixDestroy(&pixt6); /* Conversion: 2 bpp cmap --> 2 bpp --> 2 bpp cmap --> 2 bpp */ pixt1 = pixRemoveColormap(pixs2, REMOVE_CMAP_TO_GRAYSCALE); pixt2 = pixConvertGrayToColormap(pixt1); pixt3 = pixRemoveColormap(pixt2, REMOVE_CMAP_TO_GRAYSCALE); pixt4 = pixThresholdTo2bpp(pixt3, 4, 1); pixEqual(pixt1, pixt4, &same); if (!same) { pixDisplayWithTitle(pixs2, 100, 100, "2 bpp, cmap", DFLAG); pixDisplayWithTitle(pixt4, 500, 100, "2 bpp, cmap", DFLAG); error = TRUE; sarrayAddString(sa, (char *)"conversion 2 bpp <==> 2 bpp", L_COPY); } else fprintf(stderr, "OK: conversion 2 bpp <==> 2 bpp\n"); pixDestroy(&pixt1); pixDestroy(&pixt2); pixDestroy(&pixt3); pixDestroy(&pixt4); /* Conversion: 4 bpp cmap --> 4 bpp --> 4 bpp cmap --> 4 bpp */ pixt1 = pixRemoveColormap(pixs4, REMOVE_CMAP_TO_GRAYSCALE); pixt2 = pixConvertGrayToColormap(pixt1); pixt3 = pixRemoveColormap(pixt2, REMOVE_CMAP_TO_GRAYSCALE); pixt4 = pixThresholdTo4bpp(pixt3, 16, 1); pixEqual(pixt1, pixt4, &same); if (!same) { pixDisplayWithTitle(pixs4, 100, 100, "4 bpp, cmap", DFLAG); pixDisplayWithTitle(pixt4, 500, 100, "4 bpp, cmap", DFLAG); error = TRUE; sarrayAddString(sa, (char *)"conversion 4 bpp <==> 4 bpp", L_COPY); } else fprintf(stderr, "OK: conversion 4 bpp <==> 4 bpp\n"); pixDestroy(&pixt1); pixDestroy(&pixt2); pixDestroy(&pixt3); pixDestroy(&pixt4); /* Conversion: 8 bpp --> 8 bpp cmap --> 8 bpp */ pixt1 = pixConvertTo8(pixs8, TRUE); pixt2 = pixConvertTo8(pixt1, FALSE); pixEqual(pixs8, pixt2, &same); if (!same) { pixDisplayWithTitle(pixt1, 100, 100, "8 bpp, cmap", DFLAG); pixDisplayWithTitle(pixt2, 500, 100, "8 bpp, no cmap", DFLAG); error = TRUE; sarrayAddString(sa, (char *)"conversion 8 bpp <==> 8 bpp", L_COPY); } else fprintf(stderr, "OK: conversion 8 bpp <==> 8 bpp\n"); pixDestroy(&pixt1); pixDestroy(&pixt2); /* Conversion: 2 bpp cmap --> 32 bpp --> 2 bpp cmap */ pixt1 = pixConvertTo8(pixc2, TRUE); pixt2 = pixConvertTo32(pixt1); pixt3 = pixConvertTo32(pixc2); pixEqual(pixt2, pixt3, &same); if (!same) { pixDisplayWithTitle(pixt2, 100, 100, "32 bpp", DFLAG); pixDisplayWithTitle(pixt3, 500, 100, "32 bpp", DFLAG); error = TRUE; sarrayAddString(sa, (char *)"conversion 2 bpp ==> 32 bpp", L_COPY); } else fprintf(stderr, "OK: conversion 2 bpp <==> 32 bpp\n"); cmap = pixGetColormap(pixc2); pixt4 = pixOctcubeQuantFromCmap(pixt3, cmap, 2, 4, L_EUCLIDEAN_DISTANCE); pixEqual(pixc2, pixt4, &same); if (!same) { pixDisplayWithTitle(pixc2, 100, 100, "4 bpp, cmap", DFLAG); pixDisplayWithTitle(pixt4, 500, 100, "4 bpp, cmap", DFLAG); error = TRUE; sarrayAddString(sa, (char *)"conversion 2 bpp <==> 32 bpp", L_COPY); } else fprintf(stderr, "OK: conversion 2 bpp <==> 32 bpp\n"); pixDestroy(&pixt1); pixDestroy(&pixt2); pixDestroy(&pixt3); pixDestroy(&pixt4); /* Conversion: 4 bpp cmap --> 32 bpp --> 4 bpp cmap */ pixt1 = pixConvertTo8(pixc4, TRUE); pixt2 = pixConvertTo32(pixt1); pixt3 = pixConvertTo32(pixc4); pixEqual(pixt2, pixt3, &same); if (!same) { pixDisplayWithTitle(pixt2, 100, 100, "32 bpp", DFLAG); pixDisplayWithTitle(pixt3, 500, 100, "32 bpp", DFLAG); error = TRUE; sarrayAddString(sa, (char *)"conversion 4 bpp ==> 32 bpp", L_COPY); } else fprintf(stderr, "OK: conversion 4 bpp <==> 32 bpp\n"); cmap = pixGetColormap(pixc4); pixt4 = pixOctcubeQuantFromCmap(pixt3, cmap, 2, 4, L_EUCLIDEAN_DISTANCE); pixEqual(pixc4, pixt4, &same); if (!same) { pixDisplayWithTitle(pixc4, 100, 100, "4 bpp, cmap", DFLAG); pixDisplayWithTitle(pixt4, 500, 100, "4 bpp, cmap", DFLAG); error = TRUE; sarrayAddString(sa, (char *)"conversion 4 bpp <==> 32 bpp", L_COPY); } else fprintf(stderr, "OK: conversion 4 bpp <==> 32 bpp\n"); pixDestroy(&pixt1); pixDestroy(&pixt2); pixDestroy(&pixt3); pixDestroy(&pixt4); /* Conversion: 8 bpp --> 32 bpp --> 8 bpp */ pixt1 = pixConvertTo32(pixs8); pixt2 = pixConvertTo8(pixt1, FALSE); pixEqual(pixs8, pixt2, &same); if (!same) { pixDisplayWithTitle(pixs8, 100, 100, "8 bpp", DFLAG); pixDisplayWithTitle(pixt2, 500, 100, "8 bpp", DFLAG); error = TRUE; sarrayAddString(sa, (char *)"conversion 8 bpp <==> 32 bpp", L_COPY); } else fprintf(stderr, "OK: conversion 8 bpp <==> 32 bpp\n"); pixDestroy(&pixt1); pixDestroy(&pixt2); /* Conversion: 8 bpp --> 16 bpp --> 8 bpp */ pixt1 = pixConvert8To16(pixs8, 8); pixt2 = pixConvertTo8(pixt1, FALSE); pixEqual(pixs8, pixt2, &same); if (!same) { pixDisplayWithTitle(pixs8, 100, 100, "8 bpp", DFLAG); pixDisplayWithTitle(pixt2, 500, 100, "8 bpp", DFLAG); error = TRUE; sarrayAddString(sa, (char *)"conversion 8 bpp <==> 16 bpp", L_COPY); } else fprintf(stderr, "OK: conversion 8 bpp <==> 16 bpp\n"); pixDestroy(&pixt1); pixDestroy(&pixt2); /* Conversion: 16 bpp --> 8 bpp --> 16 bpp */ pixt1 = pixConvert16To8(pixs16, 1); pixt2 = pixConvertTo16(pixt1); pixWrite("/tmp/junkpix.png", pixt2, IFF_PNG); pixEqual(pixs16, pixt2, &same); if (!same) { pixDisplayWithTitle(pixs16, 100, 100, "16 bpp", DFLAG); pixDisplayWithTitle(pixt2, 500, 100, "16 bpp", DFLAG); error = TRUE; sarrayAddString(sa, (char *)"conversion 16 bpp <==> 8 bpp", L_COPY); } else fprintf(stderr, "OK: conversion 16 bpp <==> 8 bpp\n"); pixDestroy(&pixt1); pixDestroy(&pixt2); /* Conversion: 8 bpp cmap --> 32 bpp --> 8 bpp cmap */ /* Required to go to level 6 of octcube to get identical result */ pixt1 = pixConvertTo32(pixc8); cmap = pixGetColormap(pixc8); pixt2 = pixOctcubeQuantFromCmap(pixt1, cmap, 2, 6, L_EUCLIDEAN_DISTANCE); pixEqual(pixc8, pixt2, &same); if (!same) { pixDisplayWithTitle(pixc8, 100, 100, "8 bpp cmap", DFLAG); pixDisplayWithTitle(pixt2, 500, 100, "8 bpp cmap", DFLAG); error = TRUE; sarrayAddString(sa, (char *)"conversion 8 bpp cmap <==> 32 bpp cmap", L_COPY); } else fprintf(stderr, "OK: conversion 8 bpp <==> 32 bpp\n"); pixDestroy(&pixt1); pixDestroy(&pixt2); /* Summarize results */ if (error == FALSE) fprintf(stderr, "No errors found\n"); else { errorstr = sarrayToString(sa, 1); fprintf(stderr, "Errors in the following:\n %s", errorstr); lept_free(errorstr); } sarrayDestroy(&sa); pixDestroy(&pixs1); pixDestroy(&pixs2); pixDestroy(&pixs4); pixDestroy(&pixc2); pixDestroy(&pixc4); pixDestroy(&pixs8); pixDestroy(&pixc8); pixDestroy(&pixs16); pixDestroy(&pixs32); return 0; }
/*! * pixSaveTiledOutline() * * Input: pixs (1, 2, 4, 8, 32 bpp) * pixa (the pix are accumulated here) * scalefactor (0.0 to disable; otherwise this is a scale factor) * newrow (0 if placed on the same row as previous; 1 otherwise) * space (horizontal and vertical spacing, in pixels) * linewidth (width of added outline for image; 0 for no outline) * dp (depth of pixa; 8 or 32 bpp; only used on first call) * Return: 0 if OK, 1 on error. * * Notes: * (1) Before calling this function for the first time, use * pixaCreate() to make the @pixa that will accumulate the pix. * This is passed in each time pixSaveTiled() is called. * (2) @scalefactor scales the input image. After scaling and * possible depth conversion, the image is saved in the input * pixa, along with a box that specifies the location to * place it when tiled later. Disable saving the pix by * setting @scalefactor == 0.0. * (3) @newrow and @space specify the location of the new pix * with respect to the last one(s) that were entered. * (4) @dp specifies the depth at which all pix are saved. It can * be only 8 or 32 bpp. Any colormap is removed. This is only * used at the first invocation. * (5) This function uses two variables from call to call. * If they were static, the function would not be .so or thread * safe, and furthermore, there would be interference with two or * more pixa accumulating images at a time. Consequently, * we use the first pix in the pixa to store and obtain both * the depth and the current position of the bottom (one pixel * below the lowest image raster line when laid out using * the boxa). The bottom variable is stored in the input format * field, which is the only field available for storing an int. */ l_int32 pixSaveTiledOutline(PIX *pixs, PIXA *pixa, l_float32 scalefactor, l_int32 newrow, l_int32 space, l_int32 linewidth, l_int32 dp) { l_int32 n, top, left, bx, by, bw, w, h, depth, bottom; BOX *box; PIX *pix1, *pix2, *pix3, *pix4; PROCNAME("pixSaveTiledOutline"); if (scalefactor == 0.0) return 0; if (!pixs) return ERROR_INT("pixs not defined", procName, 1); if (!pixa) return ERROR_INT("pixa not defined", procName, 1); n = pixaGetCount(pixa); if (n == 0) { bottom = 0; if (dp != 8 && dp != 32) { L_WARNING("dp not 8 or 32 bpp; using 32\n", procName); depth = 32; } else { depth = dp; } } else { /* extract the depth and bottom params from the first pix */ pix1 = pixaGetPix(pixa, 0, L_CLONE); depth = pixGetDepth(pix1); bottom = pixGetInputFormat(pix1); /* not typical usage! */ pixDestroy(&pix1); } /* Remove colormap if it exists; otherwise a copy. This * guarantees that pix4 is not a clone of pixs. */ pix1 = pixRemoveColormapGeneral(pixs, REMOVE_CMAP_BASED_ON_SRC, L_COPY); /* Scale and convert to output depth */ if (scalefactor == 1.0) { pix2 = pixClone(pix1); } else if (scalefactor > 1.0) { pix2 = pixScale(pix1, scalefactor, scalefactor); } else if (scalefactor < 1.0) { if (pixGetDepth(pix1) == 1) pix2 = pixScaleToGray(pix1, scalefactor); else pix2 = pixScale(pix1, scalefactor, scalefactor); } pixDestroy(&pix1); if (depth == 8) pix3 = pixConvertTo8(pix2, 0); else pix3 = pixConvertTo32(pix2); pixDestroy(&pix2); /* Add black outline */ if (linewidth > 0) pix4 = pixAddBorder(pix3, linewidth, 0); else pix4 = pixClone(pix3); pixDestroy(&pix3); /* Find position of current pix (UL corner plus size) */ if (n == 0) { top = 0; left = 0; } else if (newrow == 1) { top = bottom + space; left = 0; } else if (n > 0) { pixaGetBoxGeometry(pixa, n - 1, &bx, &by, &bw, NULL); top = by; left = bx + bw + space; } pixGetDimensions(pix4, &w, &h, NULL); bottom = L_MAX(bottom, top + h); box = boxCreate(left, top, w, h); pixaAddPix(pixa, pix4, L_INSERT); pixaAddBox(pixa, box, L_INSERT); /* Save the new bottom value */ pix1 = pixaGetPix(pixa, 0, L_CLONE); pixSetInputFormat(pix1, bottom); /* not typical usage! */ pixDestroy(&pix1); return 0; }
// Degrade the pix as if by a print/copy/scan cycle with exposure > 0 // corresponding to darkening on the copier and <0 lighter and 0 not copied. // Exposures in [-2,2] are most useful, with -3 and 3 being extreme. // If rotation is nullptr, rotation is skipped. If *rotation is non-zero, the // pix // is rotated by *rotation else it is randomly rotated and *rotation is // modified. // // HOW IT WORKS: // Most of the process is really dictated by the fact that the minimum // available convolution is 3X3, which is too big really to simulate a // good quality print/scan process. (2X2 would be better.) // 1 pixel wide inputs are heavily smeared by the 3X3 convolution, making the // images generally biased to being too light, so most of the work is to make // them darker. 3 levels of thickening/darkening are achieved with 2 dilations, // (using a greyscale erosion) one heavy (by being before convolution) and one // light (after convolution). // With no dilation, after covolution, the images are so light that a heavy // constant offset is required to make the 0 image look reasonable. A simple // constant offset multiple of exposure to undo this value is enough to achieve // all the required lightening. This gives the advantage that exposure level 1 // with a single dilation gives a good impression of the broken-yet-too-dark // problem that is often seen in scans. // A small random rotation gives some varying greyscale values on the edges, // and some random salt and pepper noise on top helps to realistically jaggy-up // the edges. // Finally a greyscale ramp provides a continuum of effects between exposure // levels. Pix* DegradeImage(Pix* input, int exposure, TRand* randomizer, float* rotation) { Pix* pix = pixConvertTo8(input, false); pixDestroy(&input); input = pix; int width = pixGetWidth(input); int height = pixGetHeight(input); if (exposure >= 2) { // An erosion simulates the spreading darkening of a dark copy. // This is backwards to binary morphology, // see http://www.leptonica.com/grayscale-morphology.html pix = input; input = pixErodeGray(pix, 3, 3); pixDestroy(&pix); } // A convolution is essential to any mode as no scanner produces an // image as sharp as the electronic image. pix = pixBlockconv(input, 1, 1); pixDestroy(&input); // A small random rotation helps to make the edges jaggy in a realistic way. if (rotation != nullptr) { float radians_clockwise = 0.0f; if (*rotation) { radians_clockwise = *rotation; } else if (randomizer != nullptr) { radians_clockwise = randomizer->SignedRand(kRotationRange); } input = pixRotate(pix, radians_clockwise, L_ROTATE_AREA_MAP, L_BRING_IN_WHITE, 0, 0); // Rotate the boxes to match. *rotation = radians_clockwise; pixDestroy(&pix); } else { input = pix; } if (exposure >= 3 || exposure == 1) { // Erosion after the convolution is not as heavy as before, so it is // good for level 1 and in addition as a level 3. // This is backwards to binary morphology, // see http://www.leptonica.com/grayscale-morphology.html pix = input; input = pixErodeGray(pix, 3, 3); pixDestroy(&pix); } // The convolution really needed to be 2x2 to be realistic enough, but // we only have 3x3, so we have to bias the image darker or lose thin // strokes. int erosion_offset = 0; // For light and 0 exposure, there is no dilation, so compensate for the // convolution with a big darkening bias which is undone for lighter // exposures. if (exposure <= 0) erosion_offset = -3 * kExposureFactor; // Add in a general offset of the greyscales for the exposure level so // a threshold of 128 gives a reasonable binary result. erosion_offset -= exposure * kExposureFactor; // Add a gradual fade over the page and a small amount of salt and pepper // noise to simulate noise in the sensor/paper fibres and varying // illumination. l_uint32* data = pixGetData(input); for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) { int pixel = GET_DATA_BYTE(data, x); if (randomizer != nullptr) pixel += randomizer->IntRand() % (kSaltnPepper*2 + 1) - kSaltnPepper; if (height + width > kMinRampSize) pixel -= (2*x + y) * 32 / (height + width); pixel += erosion_offset; if (pixel < 0) pixel = 0; if (pixel > 255) pixel = 255; SET_DATA_BYTE(data, x, pixel); } data += input->wpl; } return input; }
int main(int argc, char **argv) { l_int32 w, h, x, y, i, n; l_float32 *vc; PIX *pix1, *pix2, *pix3, *pix4, *pix5; PIXA *pixas, *pixa; L_REGPARAMS *rp; if (regTestSetup(argc, argv, &rp)) return 1; pixas = pixaCreate(11); for (i = 0; i < 10; i++) { /* this preserves any alpha */ pix1 = pixRead(fnames[i]); pix2 = pixScaleBySamplingToSize(pix1, 250, 150); pixaAddPix(pixas, pix2, L_INSERT); pixDestroy(&pix1); } /* Add a transparent grid over the rgb image */ pix1 = pixaGetPix(pixas, 8, L_COPY); pixGetDimensions(pix1, &w, &h, NULL); pix2 = pixCreate(w, h, 1); for (i = 0; i < 5; i++) { y = h * (i + 1) / 6; pixRenderLine(pix2, 0, y, w, y, 3, L_SET_PIXELS); } for (i = 0; i < 7; i++) { x = w * (i + 1) / 8; pixRenderLine(pix2, x, 0, x, h, 3, L_SET_PIXELS); } pix3 = pixConvertTo8(pix2, 0); /* 1 --> 0 ==> transparent */ pixSetRGBComponent(pix1, pix3, L_ALPHA_CHANNEL); pixaAddPix(pixas, pix1, L_INSERT); n = pixaGetCount(pixas); pixDestroy(&pix2); pixDestroy(&pix3); #if DO_ALL /* Display with and without removing alpha with white bg */ pix1 = pixaDisplayTiledInRows(pixas, 32, 1200, 1.0, 0, 25, 2); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 0 */ pixDisplayWithTitle(pix1, 0, 0, NULL, rp->display); pixDestroy(&pix1); pixa = pixaCreate(n); for (i = 0; i < n; i++) { pix1 = pixaGetPix(pixas, i, L_COPY); pix2 = pixRemoveAlpha(pix1); pixaAddPix(pixa, pix2, L_INSERT); pixDestroy(&pix1); } pix1 = pixaDisplayTiledInRows(pixa, 32, 1200, 1.0, 0, 25, 2); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 1 */ pixDisplayWithTitle(pix1, 200, 0, NULL, rp->display); pixDestroy(&pix1); pixaDestroy(&pixa); #endif #if DO_ALL /* Setting to gray */ pixa = pixaCreate(n); for (i = 0; i < n; i++) { pix1 = pixaGetPix(pixas, i, L_COPY); pixSetAllGray(pix1, 170); pix2 = pixRemoveAlpha(pix1); pixaAddPix(pixa, pix2, L_INSERT); pixDestroy(&pix1); } pix1 = pixaDisplayTiledInRows(pixa, 32, 1200, 1.0, 0, 25, 2); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 2 */ pixDisplayWithTitle(pix1, 400, 0, NULL, rp->display); pixDestroy(&pix1); pixaDestroy(&pixa); #endif #if DO_ALL /* General scaling */ pixa = pixaCreate(n); for (i = 0; i < n; i++) { pix1 = pixaGetPix(pixas, i, L_COPY); pix2 = pixScaleToSize(pix1, 350, 650); pix3 = pixScaleToSize(pix2, 200, 200); pix4 = pixRemoveAlpha(pix3); pixaAddPix(pixa, pix4, L_INSERT); pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); } pix1 = pixaDisplayTiledInRows(pixa, 32, 1200, 1.0, 0, 25, 2); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 3 */ pixDisplayWithTitle(pix1, 600, 0, NULL, rp->display); pixDestroy(&pix1); pixaDestroy(&pixa); #endif #if DO_ALL /* Scaling by sampling */ pixa = pixaCreate(n); for (i = 0; i < n; i++) { pix1 = pixaGetPix(pixas, i, L_COPY); pix2 = pixScaleBySamplingToSize(pix1, 350, 650); pix3 = pixScaleBySamplingToSize(pix2, 200, 200); pix4 = pixRemoveAlpha(pix3); pixaAddPix(pixa, pix4, L_INSERT); pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); } pix1 = pixaDisplayTiledInRows(pixa, 32, 1200, 1.0, 0, 25, 2); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 4 */ pixDisplayWithTitle(pix1, 800, 0, NULL, rp->display); pixDestroy(&pix1); pixaDestroy(&pixa); #endif #if DO_ALL /* Rotation by area mapping; no embedding */ pixa = pixaCreate(n); for (i = 0; i < n; i++) { pix1 = pixaGetPix(pixas, i, L_COPY); pix2 = pixRotate(pix1, 0.25, L_ROTATE_AREA_MAP, L_BRING_IN_WHITE, 0, 0); pix3 = pixRotate(pix2, -0.35, L_ROTATE_AREA_MAP, L_BRING_IN_WHITE, 0, 0); pix4 = pixRemoveAlpha(pix3); pixaAddPix(pixa, pix4, L_INSERT); pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); } pix1 = pixaDisplayTiledInRows(pixa, 32, 1200, 1.0, 0, 25, 2); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 5 */ pixDisplayWithTitle(pix1, 1000, 0, NULL, rp->display); pixDestroy(&pix1); pixaDestroy(&pixa); #endif #if DO_ALL /* Rotation by area mapping; with embedding */ pixa = pixaCreate(n); for (i = 0; i < n; i++) { pix1 = pixaGetPix(pixas, i, L_COPY); pix2 = pixRotate(pix1, 0.25, L_ROTATE_AREA_MAP, L_BRING_IN_WHITE, 250, 150); pix3 = pixRotate(pix2, -0.35, L_ROTATE_AREA_MAP, L_BRING_IN_WHITE, 250, 150); pix4 = pixRemoveBorderToSize(pix3, 250, 150); pix5 = pixRemoveAlpha(pix4); pixaAddPix(pixa, pix5, L_INSERT); pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); pixDestroy(&pix4); } pix1 = pixaDisplayTiledInRows(pixa, 32, 1200, 1.0, 0, 25, 2); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 6 */ pixDisplayWithTitle(pix1, 0, 400, NULL, rp->display); pixDestroy(&pix1); pixaDestroy(&pixa); #endif #if DO_ALL /* Rotation by 3-shear; no embedding */ pixa = pixaCreate(n); for (i = 0; i < n; i++) { pix1 = pixaGetPix(pixas, i, L_COPY); pix2 = pixRotate(pix1, 0.25, L_ROTATE_SHEAR, L_BRING_IN_WHITE, 0, 0); pix3 = pixRotate(pix2, -0.35, L_ROTATE_SHEAR, L_BRING_IN_WHITE, 0, 0); pix4 = pixRemoveAlpha(pix3); pixaAddPix(pixa, pix4, L_INSERT); pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); } pix1 = pixaDisplayTiledInRows(pixa, 32, 1200, 1.0, 0, 25, 2); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 7 */ pixDisplayWithTitle(pix1, 200, 400, NULL, rp->display); pixDestroy(&pix1); pixaDestroy(&pixa); #endif #if DO_ALL /* Rotation by 3-shear; with embedding */ pixa = pixaCreate(n); for (i = 0; i < n; i++) { pix1 = pixaGetPix(pixas, i, L_COPY); pix2 = pixRotate(pix1, 0.25, L_ROTATE_SHEAR, L_BRING_IN_WHITE, 250, 150); pix3 = pixRotate(pix2, -0.35, L_ROTATE_SHEAR, L_BRING_IN_WHITE, 250, 150); pix4 = pixRemoveBorderToSize(pix3, 250, 150); pix5 = pixRemoveAlpha(pix4); pixaAddPix(pixa, pix5, L_INSERT); pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); pixDestroy(&pix4); } pix1 = pixaDisplayTiledInRows(pixa, 32, 1200, 1.0, 0, 25, 2); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 8 */ pixDisplayWithTitle(pix1, 400, 400, NULL, rp->display); pixDestroy(&pix1); pixaDestroy(&pixa); #endif #if DO_ALL /* Rotation by 2-shear about the center */ pixa = pixaCreate(n); for (i = 0; i < n; i++) { pix1 = pixaGetPix(pixas, i, L_COPY); pixGetDimensions(pix1, &w, &h, NULL); pix2 = pixRotate2Shear(pix1, w / 2, h / 2, 0.25, L_BRING_IN_WHITE); pix3 = pixRotate2Shear(pix2, w / 2, h / 2, -0.35, L_BRING_IN_WHITE); pix4 = pixRemoveAlpha(pix3); pixaAddPix(pixa, pix4, L_INSERT); pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); } pix1 = pixaDisplayTiledInRows(pixa, 32, 1200, 1.0, 0, 25, 2); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 9 */ pixDisplayWithTitle(pix1, 600, 400, NULL, rp->display); pixDestroy(&pix1); pixaDestroy(&pixa); #endif #if DO_ALL /* Rotation by sampling; no embedding */ pixa = pixaCreate(n); for (i = 0; i < n; i++) { pix1 = pixaGetPix(pixas, i, L_COPY); pix2 = pixRotate(pix1, 0.25, L_ROTATE_SAMPLING, L_BRING_IN_WHITE, 0, 0); pix3 = pixRotate(pix2, -0.35, L_ROTATE_SAMPLING, L_BRING_IN_WHITE, 0, 0); pix4 = pixRemoveAlpha(pix3); pixaAddPix(pixa, pix4, L_INSERT); pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); } pix1 = pixaDisplayTiledInRows(pixa, 32, 1200, 1.0, 0, 25, 2); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 10 */ pixDisplayWithTitle(pix1, 800, 400, NULL, rp->display); pixDestroy(&pix1); pixaDestroy(&pixa); #endif #if DO_ALL /* Rotation by sampling; with embedding */ pixa = pixaCreate(n); for (i = 0; i < n; i++) { pix1 = pixaGetPix(pixas, i, L_COPY); pix2 = pixRotate(pix1, 0.25, L_ROTATE_SAMPLING, L_BRING_IN_WHITE, 250, 150); pix3 = pixRotate(pix2, -0.35, L_ROTATE_SAMPLING, L_BRING_IN_WHITE, 250, 150); pix4 = pixRemoveBorderToSize(pix3, 250, 150); pix5 = pixRemoveAlpha(pix4); pixaAddPix(pixa, pix5, L_INSERT); pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); pixDestroy(&pix4); } pix1 = pixaDisplayTiledInRows(pixa, 32, 1200, 1.0, 0, 25, 2); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 11 */ pixDisplayWithTitle(pix1, 1000, 400, NULL, rp->display); pixDestroy(&pix1); pixaDestroy(&pixa); #endif #if DO_ALL /* Rotation by area mapping at corner */ pixa = pixaCreate(n); for (i = 0; i < n; i++) { pix1 = pixaGetPix(pixas, i, L_COPY); pix2 = pixRotateAMCorner(pix1, 0.25, L_BRING_IN_WHITE); pix3 = pixRotateAMCorner(pix2, -0.35, L_BRING_IN_WHITE); pix4 = pixRemoveAlpha(pix3); pixaAddPix(pixa, pix4, L_INSERT); pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); } pix1 = pixaDisplayTiledInRows(pixa, 32, 1200, 1.0, 0, 25, 2); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 12 */ pixDisplayWithTitle(pix1, 0, 800, NULL, rp->display); pixDestroy(&pix1); pixaDestroy(&pixa); #endif #if DO_ALL /* Affine transform by interpolation */ pixa = pixaCreate(n); vc = Generate3PtTransformVector(); for (i = 0; i < n; i++) { pix1 = pixaGetPix(pixas, i, L_COPY); pix2 = pixAffine(pix1, vc, L_BRING_IN_WHITE); /* pix2 = pixAffineSampled(pix1, vc, L_BRING_IN_WHITE); */ pix3 = pixRemoveAlpha(pix2); pixaAddPix(pixa, pix3, L_INSERT); pixDestroy(&pix1); pixDestroy(&pix2); } pix1 = pixaDisplayTiledInRows(pixa, 32, 1200, 1.0, 0, 25, 2); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 13 */ pixDisplayWithTitle(pix1, 200, 800, NULL, rp->display); pixDestroy(&pix1); pixaDestroy(&pixa); lept_free(vc); #endif #if DO_ALL /* Projective transform by sampling */ pixa = pixaCreate(n); vc = Generate4PtTransformVector(PROJECTIVE); for (i = 0; i < n; i++) { pix1 = pixaGetPix(pixas, i, L_COPY); pix2 = pixProjectiveSampled(pix1, vc, L_BRING_IN_WHITE); pix3 = pixRemoveAlpha(pix2); pixaAddPix(pixa, pix3, L_INSERT); pixDestroy(&pix1); pixDestroy(&pix2); } pix1 = pixaDisplayTiledInRows(pixa, 32, 1200, 1.0, 0, 25, 2); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 14 */ pixDisplayWithTitle(pix1, 400, 800, NULL, rp->display); pixDestroy(&pix1); pixaDestroy(&pixa); lept_free(vc); #endif #if DO_ALL /* Projective transform by interpolation */ pixa = pixaCreate(n); vc = Generate4PtTransformVector(PROJECTIVE); for (i = 0; i < n; i++) { pix1 = pixaGetPix(pixas, i, L_COPY); pix2 = pixProjective(pix1, vc, L_BRING_IN_WHITE); pix3 = pixRemoveAlpha(pix2); pixaAddPix(pixa, pix3, L_INSERT); pixDestroy(&pix1); pixDestroy(&pix2); } pix1 = pixaDisplayTiledInRows(pixa, 32, 1200, 1.0, 0, 25, 2); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 15 */ pixDisplayWithTitle(pix1, 600, 800, NULL, rp->display); pixDestroy(&pix1); pixaDestroy(&pixa); lept_free(vc); #endif #if DO_ALL /* Bilinear transform by interpolation */ pixa = pixaCreate(n); vc = Generate4PtTransformVector(BILINEAR); for (i = 0; i < n; i++) { pix1 = pixaGetPix(pixas, i, L_COPY); pix2 = pixBilinear(pix1, vc, L_BRING_IN_WHITE); pix3 = pixRemoveAlpha(pix2); pixaAddPix(pixa, pix3, L_INSERT); pixDestroy(&pix1); pixDestroy(&pix2); } pix1 = pixaDisplayTiledInRows(pixa, 32, 1200, 1.0, 0, 25, 2); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 16 */ pixDisplayWithTitle(pix1, 800, 800, NULL, rp->display); pixDestroy(&pix1); pixaDestroy(&pixa); lept_free(vc); #endif pixaDestroy(&pixas); return regTestCleanup(rp); }
l_int32 main(int argc, char **argv) { l_int32 method, pageno; L_DEWARP *dew1; L_DEWARPA *dewa; PIX *pixs, *pixn, *pixg, *pixb, *pixd; static char mainName[] = "dewarptest2"; if (argc != 2 && argc != 4) return ERROR_INT("Syntax: dewarptest2 method [image pageno]", mainName, 1); if (argc == 2) { pixs = pixRead("cat-35.jpg"); pageno = 35; } else { pixs = pixRead(argv[2]); pageno = atoi(argv[3]); } if (!pixs) return ERROR_INT("image not read", mainName, 1); method = atoi(argv[1]); lept_mkdir("lept"); if (method == 1) { /* Use single page dewarp function */ dewarpSinglePage(pixs, 1, 100, 1, &pixd, NULL, 1); pixDisplay(pixd, 100, 100); } else { /* Break down into multiple steps; require min of only 6 lines */ dewa = dewarpaCreate(40, 30, 1, 6, 50); dewarpaUseBothArrays(dewa, 1); #if NORMALIZE /* Normalize for varying background and binarize */ pixn = pixBackgroundNormSimple(pixs, NULL, NULL); pixg = pixConvertRGBToGray(pixn, 0.5, 0.3, 0.2); pixb = pixThresholdToBinary(pixg, 130); pixDestroy(&pixn); #else /* Don't normalize; just threshold and clean edges */ pixg = pixConvertTo8(pixs, 0); pixb = pixThresholdToBinary(pixg, 100); pixSetOrClearBorder(pixb, 30, 30, 40, 40, PIX_CLR); #endif /* Run the basic functions */ dew1 = dewarpCreate(pixb, pageno); dewarpaInsertDewarp(dewa, dew1); dewarpBuildPageModel(dew1, "/tmp/lept/test2_model.pdf"); dewarpaApplyDisparity(dewa, pageno, pixg, -1, 0, 0, &pixd, "/tmp/lept/test2_apply.pdf"); dewarpaInfo(stderr, dewa); dewarpaDestroy(&dewa); pixDestroy(&pixg); pixDestroy(&pixb); } pixDestroy(&pixs); pixDestroy(&pixd); return 0; }
main(int argc, char **argv) { l_float32 scalefact; L_BMF *bmf, *bmftop; L_KERNEL *kel, *kelx, *kely; PIX *pixs, *pixg, *pixt, *pixd; PIX *pix1, *pix2, *pix3, *pix4, *pix5, *pix6, *pix7, *pix8; PIXA *pixa; L_REGPARAMS *rp; if (regTestSetup(argc, argv, &rp)) return 1; /* ----------------- Test on 8 bpp grayscale ---------------------*/ pixa = pixaCreate(5); bmf = bmfCreate("./fonts", 6); bmftop = bmfCreate("./fonts", 10); pixs = pixRead("lucasta-47.jpg"); pixg = pixScale(pixs, 0.4, 0.4); /* 8 bpp grayscale */ pix1 = pixConvertTo32(pixg); /* 32 bpp rgb */ AddTextAndSave(pixa, pix1, 1, bmf, textstr[0], L_ADD_BELOW, 0xff000000); pix2 = pixConvertGrayToSubpixelRGB(pixs, 0.4, 0.4, L_SUBPIXEL_ORDER_RGB); AddTextAndSave(pixa, pix2, 0, bmf, textstr[1], L_ADD_BELOW, 0x00ff0000); pix3 = pixConvertGrayToSubpixelRGB(pixs, 0.4, 0.4, L_SUBPIXEL_ORDER_BGR); AddTextAndSave(pixa, pix3, 0, bmf, textstr[2], L_ADD_BELOW, 0x0000ff00); pix4 = pixConvertGrayToSubpixelRGB(pixs, 0.4, 0.4, L_SUBPIXEL_ORDER_VRGB); AddTextAndSave(pixa, pix4, 0, bmf, textstr[3], L_ADD_BELOW, 0x00ff0000); pix5 = pixConvertGrayToSubpixelRGB(pixs, 0.4, 0.4, L_SUBPIXEL_ORDER_VBGR); AddTextAndSave(pixa, pix5, 0, bmf, textstr[4], L_ADD_BELOW, 0x0000ff00); pixt = pixaDisplay(pixa, 0, 0); pixd = pixAddSingleTextblock(pixt, bmftop, "Regression test for subpixel scaling: gray", 0xff00ff00, L_ADD_ABOVE, NULL); regTestWritePixAndCheck(rp, pixd, IFF_JFIF_JPEG); /* 0 */ pixDisplayWithTitle(pixd, 50, 50, NULL, rp->display); pixaDestroy(&pixa); pixDestroy(&pixs); pixDestroy(&pixg); pixDestroy(&pixt); pixDestroy(&pixd); pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); pixDestroy(&pix4); pixDestroy(&pix5); /* ----------------- Test on 32 bpp rgb ---------------------*/ pixa = pixaCreate(5); pixs = pixRead("fish24.jpg"); pix1 = pixScale(pixs, 0.4, 0.4); AddTextAndSave(pixa, pix1, 1, bmf, textstr[0], L_ADD_BELOW, 0xff000000); pix2 = pixConvertToSubpixelRGB(pixs, 0.4, 0.4, L_SUBPIXEL_ORDER_RGB); AddTextAndSave(pixa, pix2, 0, bmf, textstr[1], L_ADD_BELOW, 0x00ff0000); pix3 = pixConvertToSubpixelRGB(pixs, 0.4, 0.35, L_SUBPIXEL_ORDER_BGR); AddTextAndSave(pixa, pix3, 0, bmf, textstr[2], L_ADD_BELOW, 0x0000ff00); pix4 = pixConvertToSubpixelRGB(pixs, 0.4, 0.45, L_SUBPIXEL_ORDER_VRGB); AddTextAndSave(pixa, pix4, 0, bmf, textstr[3], L_ADD_BELOW, 0x00ff0000); pix5 = pixConvertToSubpixelRGB(pixs, 0.4, 0.4, L_SUBPIXEL_ORDER_VBGR); AddTextAndSave(pixa, pix5, 0, bmf, textstr[4], L_ADD_BELOW, 0x0000ff00); pixt = pixaDisplay(pixa, 0, 0); pixd = pixAddSingleTextblock(pixt, bmftop, "Regression test for subpixel scaling: color", 0xff00ff00, L_ADD_ABOVE, NULL); regTestWritePixAndCheck(rp, pixd, IFF_JFIF_JPEG); /* 1 */ pixDisplayWithTitle(pixd, 50, 350, NULL, rp->display); pixaDestroy(&pixa); pixDestroy(&pixs); pixDestroy(&pixt); pixDestroy(&pixd); pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); pixDestroy(&pix4); pixDestroy(&pix5); bmfDestroy(&bmf); bmfDestroy(&bmftop); /* --------------- Test on images that are initially 1 bpp ------------*/ /* For these, it is better to apply a lowpass filter before scaling */ /* Normal scaling of 8 bpp grayscale */ scalefact = 800. / 2320.; pixs = pixRead("patent.png"); /* sharp, 300 ppi, 1 bpp image */ pix1 = pixConvertTo8(pixs, FALSE); /* use 8 bpp input */ pix2 = pixScale(pix1, scalefact, scalefact); regTestWritePixAndCheck(rp, pix2, IFF_PNG); /* 2 */ /* Subpixel scaling; bad because there is very little aliasing. */ pix3 = pixConvertToSubpixelRGB(pix1, scalefact, scalefact, L_SUBPIXEL_ORDER_RGB); regTestWritePixAndCheck(rp, pix3, IFF_PNG); /* 3 */ /* Get same (bad) result doing subpixel rendering on RGB input */ pix4 = pixConvertTo32(pixs); pix5 = pixConvertToSubpixelRGB(pix4, scalefact, scalefact, L_SUBPIXEL_ORDER_RGB); regTestComparePix(rp, pix3, pix5); /* 4 */ regTestWritePixAndCheck(rp, pix5, IFF_PNG); /* 5 */ /* Now apply a small lowpass filter before scaling. */ makeGaussianKernelSep(2, 2, 1.0, 1.0, &kelx, &kely); startTimer(); pix6 = pixConvolveSep(pix1, kelx, kely, 8, 1); /* normalized */ fprintf(stderr, "Time sep: %7.3f\n", stopTimer()); regTestWritePixAndCheck(rp, pix6, IFF_PNG); /* 6 */ /* Get same lowpass result with non-separated convolution */ kel = makeGaussianKernel(2, 2, 1.0, 1.0); startTimer(); pix7 = pixConvolve(pix1, kel, 8, 1); /* normalized */ fprintf(stderr, "Time non-sep: %7.3f\n", stopTimer()); regTestComparePix(rp, pix6, pix7); /* 7 */ /* Now do the subpixel scaling on this slightly blurred image */ pix8 = pixConvertToSubpixelRGB(pix6, scalefact, scalefact, L_SUBPIXEL_ORDER_RGB); regTestWritePixAndCheck(rp, pix8, IFF_PNG); /* 8 */ kernelDestroy(&kelx); kernelDestroy(&kely); kernelDestroy(&kel); pixDestroy(&pixs); pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); pixDestroy(&pix4); pixDestroy(&pix5); pixDestroy(&pix6); pixDestroy(&pix7); pixDestroy(&pix8); return regTestCleanup(rp); }
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 *infile; l_int32 w, d, threshval, ival, newval; l_uint32 val; PIX *pixs, *pixg, *pixg2; PIX *pix1, *pix2; PIXA *pixa; static char mainName[] = "binarize_set"; if (argc != 2) return ERROR_INT(" Syntax: binarize_set infile", mainName, 1); infile = argv[1]; pixa = pixaCreate(5); pixs = pixRead(infile); pixGetDimensions(pixs, &w, NULL, &d); pixSaveTiled(pixs, pixa, 1.0, 1, 50, 32); pixDisplay(pixs, 100, 0); #if ALL /* 1. Standard background normalization with a global threshold. */ pixg = pixConvertTo8(pixs, 0); pix1 = pixBackgroundNorm(pixg, NULL, NULL, 10, 15, 100, 50, 255, 2, 2); pix2 = pixThresholdToBinary(pix1, 160); pixWrite("/tmp/binar1.png", pix2, IFF_PNG); pixDisplay(pix2, 100, 0); pixSaveTiled(pix2, pixa, 1.0, 1, 50, 32); pixDestroy(&pixg); pixDestroy(&pix1); pixDestroy(&pix2); #endif #if ALL /* 2. Background normalization followed by Otsu thresholding. Otsu * binarization attempts to split the image into two roughly equal * sets of pixels, and it does a very poor job when there are large * amounts of dark background. By doing a background normalization * first (to get the background near 255), we remove this problem. * Then we use a modified Otsu to estimate the best global * threshold on the normalized image. */ pixg = pixConvertTo8(pixs, 0); pix1 = pixOtsuThreshOnBackgroundNorm(pixg, NULL, 10, 15, 100, 50, 255, 2, 2, 0.10, &threshval); fprintf(stderr, "thresh val = %d\n", threshval); pixSaveTiled(pix1, pixa, 1.0, 1, 50, 32); pixWrite("/tmp/binar2.png", pix1, IFF_PNG); pixDisplay(pix1, 100, 200); pixDestroy(&pixg); pixDestroy(&pix1); #endif #if ALL /* 3. Background normalization with Otsu threshold estimation and * masking for threshold selection. */ pixg = pixConvertTo8(pixs, 0); pix1 = pixMaskedThreshOnBackgroundNorm(pixg, NULL, 10, 15, 100, 50, 2, 2, 0.10, &threshval); fprintf(stderr, "thresh val = %d\n", threshval); pixSaveTiled(pix1, pixa, 1.0, 1, 50, 32); pixWrite("/tmp/binar3.png", pix1, IFF_PNG); pixDisplay(pix1, 100, 400); pixDestroy(&pixg); pixDestroy(&pix1); #endif #if ALL /* 4. Background normalization followed by Sauvola binarization */ if (d == 32) pixg = pixConvertRGBToGray(pixs, 0.2, 0.7, 0.1); else pixg = pixConvertTo8(pixs, 0); pixg2 = pixContrastNorm(NULL, pixg, 20, 20, 130, 2, 2); pixSauvolaBinarizeTiled(pixg2, 25, 0.40, 1, 1, NULL, &pix1); pixSaveTiled(pix1, pixa, 1.0, 1, 50, 32); pixWrite("/tmp/binar4.png", pix1, IFF_PNG); pixDisplay(pix1, 100, 600); pixDestroy(&pixg); pixDestroy(&pixg2); pixDestroy(&pix1); #endif #if ALL /* 5. Contrast normalization followed by background normalization, and * thresholding. */ if (d == 32) pixg = pixConvertRGBToGray(pixs, 0.2, 0.7, 0.1); else pixg = pixConvertTo8(pixs, 0); pixOtsuAdaptiveThreshold(pixg, 5000, 5000, 0, 0, 0.1, &pix1, NULL); pixGetPixel(pix1, 0, 0, &val); ival = (l_int32) val; newval = ival + (l_int32)(0.6 * (110 - ival)); fprintf(stderr, "th1 = %d, th2 = %d\n", ival, newval); pixDestroy(&pix1); pixContrastNorm(pixg, pixg, 50, 50, 130, 2, 2); pixg2 = pixBackgroundNorm(pixg, NULL, NULL, 20, 20, 70, 40, 200, 2, 2); ival = L_MIN(ival, 110); pix1 = pixThresholdToBinary(pixg2, ival); pixSaveTiled(pix1, pixa, 1.0, 1, 50, 32); pixWrite("/tmp/binar5.png", pix1, IFF_PNG); pixDisplay(pix1, 100, 800); pixDestroy(&pixg); pixDestroy(&pixg2); pixDestroy(&pix1); #endif pix1 = pixaDisplayTiledInRows(pixa, 32, w + 100, 1.0, 0, 30, 2); pixWrite("/tmp/binar6.png", pix1, IFF_PNG); pixDisplay(pix1, 1000, 0); pixDestroy(&pix1); pixaDestroy(&pixa); pixDestroy(&pixs); return 0; }
/*! * pixSaveTiledOutline() * * Input: pixs (1, 2, 4, 8, 32 bpp) * pixa (the pix are accumulated here) * reduction (0 to disable; otherwise this is a reduction factor) * newrow (0 if placed on the same row as previous; 1 otherwise) * space (horizontal and vertical spacing, in pixels) * linewidth (width of added outline for image; 0 for no outline) * dp (depth of pixa; 8 or 32 bpp; only used on first call) * Return: 0 if OK, 1 on error. * * Notes: * (1) Before calling this function for the first time, use * pixaCreate() to make the @pixa that will accumulate the pix. * This is passed in each time pixSaveTiled() is called. * (2) @reduction is the integer reduction factor for the input * image. After reduction and possible depth conversion, * the image is saved in the input pixa, along with a box * that specifies the location to place it when tiled later. * Disable saving the pix by setting reduction == 0. * (3) @newrow and @space specify the location of the new pix * with respect to the last one(s) that were entered. * (4) @dp specifies the depth at which all pix are saved. It can * be only 8 or 32 bpp. Any colormap is removed. This is only * used at the first invocation. * (5) This function uses two variables from call to call. * If they were static, the function would not be .so or thread * safe, and furthermore, there would be interference with two or * more pixa accumulating images at a time. Consequently, * we use the first pix in the pixa to store and obtain both * the depth and the current position of the bottom (one pixel * below the lowest image raster line when laid out using * the boxa). The bottom variable is stored in the input format * field, which is the only field available for storing an int. */ l_int32 pixSaveTiledOutline(PIX *pixs, PIXA *pixa, l_int32 reduction, l_int32 newrow, l_int32 space, l_int32 linewidth, l_int32 dp) { l_int32 n, top, left, bx, by, bw, w, h, depth, bottom; l_float32 scale; BOX *box; PIX *pix, *pixt1, *pixt2, *pixt3; PROCNAME("pixSaveTiledOutline"); if (reduction == 0) return 0; if (!pixs) return ERROR_INT("pixs not defined", procName, 1); if (!pixa) return ERROR_INT("pixa not defined", procName, 1); n = pixaGetCount(pixa); if (n == 0) { bottom = 0; if (dp != 8 && dp != 32) { L_WARNING("dp not 8 or 32 bpp; using 32", procName); depth = 32; } else depth = dp; } else { /* extract the depth and bottom params from the first pix */ pix = pixaGetPix(pixa, 0, L_CLONE); depth = pixGetDepth(pix); bottom = pixGetInputFormat(pix); /* not typical usage! */ pixDestroy(&pix); } /* Scale and convert to output depth */ if (reduction == 1) pixt1 = pixClone(pixs); else { scale = 1. / (l_float32)reduction; if (pixGetDepth(pixs) == 1) pixt1 = pixScaleToGray(pixs, scale); else pixt1 = pixScale(pixs, scale, scale); } if (depth == 8) pixt2 = pixConvertTo8(pixt1, 0); else pixt2 = pixConvertTo32(pixt1); pixDestroy(&pixt1); /* Add black outline */ if (linewidth > 0) pixt3 = pixAddBorder(pixt2, linewidth, 0); else pixt3 = pixClone(pixt2); pixDestroy(&pixt2); /* Find position of current pix (UL corner plus size) */ if (n == 0) { top = 0; left = 0; } else if (newrow == 1) { top = bottom + space; left = 0; } else if (n > 0) { pixaGetBoxGeometry(pixa, n - 1, &bx, &by, &bw, NULL); top = by; left = bx + bw + space; } pixGetDimensions(pixt3, &w, &h, NULL); bottom = L_MAX(bottom, top + h); box = boxCreate(left, top, w, h); pixaAddPix(pixa, pixt3, L_INSERT); pixaAddBox(pixa, box, L_INSERT); /* Save the new bottom value */ pix = pixaGetPix(pixa, 0, L_CLONE); pixSetInputFormat(pix, bottom); /* not typical usage! */ pixDestroy(&pix); return 0; }
/*! * \brief pixToGif() * * \param[in] pix 1, 2, 4, 8, 16 or 32 bpp * \param[in] gif opened gif stream * \return 0 if OK, 1 on error * * <pre> * Notes: * (1) This encodes the pix to the gif stream. The stream is not * closes by this function. * (2) It is static to make this function private. * </pre> */ static l_int32 pixToGif(PIX *pix, GifFileType *gif) { char *text; l_int32 wpl, i, j, w, h, d, ncolor, rval, gval, bval; l_int32 gif_ncolor = 0; l_uint32 *data, *line; PIX *pixd; PIXCMAP *cmap; ColorMapObject *gif_cmap; GifByteType *gif_line; #if (GIFLIB_MAJOR == 5 && GIFLIB_MINOR >= 1) || GIFLIB_MAJOR > 5 int giferr; #endif /* 5.1 and beyond */ PROCNAME("pixToGif"); if (!pix) return ERROR_INT("pix not defined", procName, 1); if (!gif) return ERROR_INT("gif not defined", procName, 1); d = pixGetDepth(pix); if (d == 32) { pixd = pixConvertRGBToColormap(pix, 1); } else if (d > 1) { pixd = pixConvertTo8(pix, TRUE); } else { /* d == 1; make sure there's a colormap */ pixd = pixClone(pix); if (!pixGetColormap(pixd)) { cmap = pixcmapCreate(1); pixcmapAddColor(cmap, 255, 255, 255); pixcmapAddColor(cmap, 0, 0, 0); pixSetColormap(pixd, cmap); } } if (!pixd) return ERROR_INT("failed to convert image to indexed", procName, 1); d = pixGetDepth(pixd); if ((cmap = pixGetColormap(pixd)) == NULL) { pixDestroy(&pixd); return ERROR_INT("cmap is missing", procName, 1); } /* 'Round' the number of gif colors up to a power of 2 */ ncolor = pixcmapGetCount(cmap); for (i = 0; i <= 8; i++) { if ((1 << i) >= ncolor) { gif_ncolor = (1 << i); break; } } if (gif_ncolor < 1) { pixDestroy(&pixd); return ERROR_INT("number of colors is invalid", procName, 1); } /* Save the cmap colors in a gif_cmap */ if ((gif_cmap = GifMakeMapObject(gif_ncolor, NULL)) == NULL) { pixDestroy(&pixd); return ERROR_INT("failed to create GIF color map", procName, 1); } for (i = 0; i < gif_ncolor; i++) { rval = gval = bval = 0; if (ncolor > 0) { if (pixcmapGetColor(cmap, i, &rval, &gval, &bval) != 0) { pixDestroy(&pixd); GifFreeMapObject(gif_cmap); return ERROR_INT("failed to get color from color map", procName, 1); } ncolor--; } gif_cmap->Colors[i].Red = rval; gif_cmap->Colors[i].Green = gval; gif_cmap->Colors[i].Blue = bval; } pixGetDimensions(pixd, &w, &h, NULL); if (EGifPutScreenDesc(gif, w, h, gif_cmap->BitsPerPixel, 0, gif_cmap) != GIF_OK) { pixDestroy(&pixd); GifFreeMapObject(gif_cmap); return ERROR_INT("failed to write screen description", procName, 1); } GifFreeMapObject(gif_cmap); /* not needed after this point */ if (EGifPutImageDesc(gif, 0, 0, w, h, FALSE, NULL) != GIF_OK) { pixDestroy(&pixd); return ERROR_INT("failed to image screen description", procName, 1); } data = pixGetData(pixd); wpl = pixGetWpl(pixd); if (d != 1 && d != 2 && d != 4 && d != 8) { pixDestroy(&pixd); return ERROR_INT("image depth is not in {1, 2, 4, 8}", procName, 1); } if ((gif_line = (GifByteType *)LEPT_CALLOC(sizeof(GifByteType), w)) == NULL) { pixDestroy(&pixd); return ERROR_INT("mem alloc fail for data line", procName, 1); } for (i = 0; i < h; i++) { line = data + i * wpl; /* Gif's way of setting the raster line up for compression */ for (j = 0; j < w; j++) { switch(d) { case 8: gif_line[j] = GET_DATA_BYTE(line, j); break; case 4: gif_line[j] = GET_DATA_QBIT(line, j); break; case 2: gif_line[j] = GET_DATA_DIBIT(line, j); break; case 1: gif_line[j] = GET_DATA_BIT(line, j); break; } } /* Compress and save the line */ if (EGifPutLine(gif, gif_line, w) != GIF_OK) { LEPT_FREE(gif_line); pixDestroy(&pixd); return ERROR_INT("failed to write data line into GIF", procName, 1); } } /* Write a text comment. This must be placed after writing the * data (!!) Note that because libgif does not provide a function * for reading comments from file, you will need another way * to read comments. */ if ((text = pixGetText(pix)) != NULL) { if (EGifPutComment(gif, text) != GIF_OK) L_WARNING("gif comment not written\n", procName); } LEPT_FREE(gif_line); pixDestroy(&pixd); return 0; }
l_int32 main(int argc, char **argv) { L_BMF *bmf; PIX *pixs1, *pixs2, *pixg, *pixt, *pixd; PIXA *pixa; L_REGPARAMS *rp; if (regTestSetup(argc, argv, &rp)) return 1; bmf = bmfCreate("./fonts", 8); pixs1 = pixCreate(301, 301, 32); pixs2 = pixCreate(601, 601, 32); pixSetAll(pixs1); pixSetAll(pixs2); pixRenderLineArb(pixs1, 0, 20, 300, 20, 5, 0, 0, 255); pixRenderLineArb(pixs1, 0, 70, 300, 70, 5, 0, 255, 0); pixRenderLineArb(pixs1, 0, 120, 300, 120, 5, 0, 255, 255); pixRenderLineArb(pixs1, 0, 170, 300, 170, 5, 255, 0, 0); pixRenderLineArb(pixs1, 0, 220, 300, 220, 5, 255, 0, 255); pixRenderLineArb(pixs1, 0, 270, 300, 270, 5, 255, 255, 0); pixRenderLineArb(pixs2, 0, 20, 300, 20, 5, 0, 0, 255); pixRenderLineArb(pixs2, 0, 70, 300, 70, 5, 0, 255, 0); pixRenderLineArb(pixs2, 0, 120, 300, 120, 5, 0, 255, 255); pixRenderLineArb(pixs2, 0, 170, 300, 170, 5, 255, 0, 0); pixRenderLineArb(pixs2, 0, 220, 300, 220, 5, 255, 0, 255); pixRenderLineArb(pixs2, 0, 270, 300, 270, 5, 255, 255, 0); /* Color, small pix */ pixa = pixaCreate(0); pixt = pixQuadraticVShear(pixs1, L_WARP_TO_LEFT, 60, -20, L_SAMPLED, L_BRING_IN_WHITE); PixSave(&pixt, pixa, 1, bmf, "sampled-left"); pixt = pixQuadraticVShear(pixs1, L_WARP_TO_RIGHT, 60, -20, L_SAMPLED, L_BRING_IN_WHITE); PixSave(&pixt, pixa, 0, bmf, "sampled-right"); pixt = pixQuadraticVShear(pixs1, L_WARP_TO_LEFT, 60, -20, L_INTERPOLATED, L_BRING_IN_WHITE); PixSave(&pixt, pixa, 1, bmf, "interpolated-left"); pixt = pixQuadraticVShear(pixs1, L_WARP_TO_RIGHT, 60, -20, L_INTERPOLATED, L_BRING_IN_WHITE); PixSave(&pixt, pixa, 0, bmf, "interpolated-right"); pixd = pixaDisplay(pixa, 0, 0); regTestWritePixAndCheck(rp, pixd, IFF_PNG); pixDisplayWithTitle(pixd, 50, 50, NULL, rp->display); pixDestroy(&pixd); pixaDestroy(&pixa); /* Grayscale, small pix */ pixg = pixConvertTo8(pixs1, 0); pixa = pixaCreate(0); pixt = pixQuadraticVShear(pixg, L_WARP_TO_LEFT, 60, -20, L_SAMPLED, L_BRING_IN_WHITE); PixSave(&pixt, pixa, 1, bmf, "sampled-left"); pixt = pixQuadraticVShear(pixg, L_WARP_TO_RIGHT, 60, -20, L_SAMPLED, L_BRING_IN_WHITE); PixSave(&pixt, pixa, 0, bmf, "sampled-right"); pixt = pixQuadraticVShear(pixg, L_WARP_TO_LEFT, 60, -20, L_INTERPOLATED, L_BRING_IN_WHITE); PixSave(&pixt, pixa, 1, bmf, "interpolated-left"); pixt = pixQuadraticVShear(pixg, L_WARP_TO_RIGHT, 60, -20, L_INTERPOLATED, L_BRING_IN_WHITE); PixSave(&pixt, pixa, 0, bmf, "interpolated-right"); pixd = pixaDisplay(pixa, 0, 0); regTestWritePixAndCheck(rp, pixd, IFF_PNG); pixDisplayWithTitle(pixd, 250, 50, NULL, rp->display); pixDestroy(&pixg); pixDestroy(&pixd); pixaDestroy(&pixa); /* Color, larger pix */ pixa = pixaCreate(0); pixt = pixQuadraticVShear(pixs2, L_WARP_TO_LEFT, 120, -40, L_SAMPLED, L_BRING_IN_WHITE); PixSave(&pixt, pixa, 1, bmf, "sampled-left"); pixt = pixQuadraticVShear(pixs2, L_WARP_TO_RIGHT, 120, -40, L_SAMPLED, L_BRING_IN_WHITE); PixSave(&pixt, pixa, 0, bmf, "sampled-right"); pixt = pixQuadraticVShear(pixs2, L_WARP_TO_LEFT, 120, -40, L_INTERPOLATED, L_BRING_IN_WHITE); PixSave(&pixt, pixa, 1, bmf, "interpolated-left"); pixt = pixQuadraticVShear(pixs2, L_WARP_TO_RIGHT, 120, -40, L_INTERPOLATED, L_BRING_IN_WHITE); PixSave(&pixt, pixa, 0, bmf, "interpolated-right"); pixd = pixaDisplay(pixa, 0, 0); regTestWritePixAndCheck(rp, pixd, IFF_PNG); pixDisplayWithTitle(pixd, 550, 50, NULL, rp->display); pixDestroy(&pixd); pixaDestroy(&pixa); /* Grayscale, larger pix */ pixg = pixConvertTo8(pixs2, 0); pixa = pixaCreate(0); pixt = pixQuadraticVShear(pixg, L_WARP_TO_LEFT, 60, -20, L_SAMPLED, L_BRING_IN_WHITE); PixSave(&pixt, pixa, 1, bmf, "sampled-left"); pixt = pixQuadraticVShear(pixg, L_WARP_TO_RIGHT, 60, -20, L_SAMPLED, L_BRING_IN_WHITE); PixSave(&pixt, pixa, 0, bmf, "sampled-right"); pixt = pixQuadraticVShear(pixg, L_WARP_TO_LEFT, 60, -20, L_INTERPOLATED, L_BRING_IN_WHITE); PixSave(&pixt, pixa, 1, bmf, "interpolated-left"); pixt = pixQuadraticVShear(pixg, L_WARP_TO_RIGHT, 60, -20, L_INTERPOLATED, L_BRING_IN_WHITE); PixSave(&pixt, pixa, 0, bmf, "interpolated-right"); pixd = pixaDisplay(pixa, 0, 0); regTestWritePixAndCheck(rp, pixd, IFF_PNG); pixDisplayWithTitle(pixd, 850, 50, NULL, rp->display); pixDestroy(&pixg); pixDestroy(&pixd); pixaDestroy(&pixa); pixDestroy(&pixs1); pixDestroy(&pixs2); bmfDestroy(&bmf); return regTestCleanup(rp); }
int main(int argc, char **argv) { l_uint8 *data; l_int32 w, h, n1, n2, n, i, minval, maxval; l_int32 ncolors, rval, gval, bval, equal; l_int32 *rmap, *gmap, *bmap; l_uint32 color; l_float32 gamma; BOX *box; FILE *fp; PIX *pix1, *pix2, *pix3, *pix4, *pix5, *pix6; PIX *pixs, *pixb, *pixg, *pixc, *pixd; PIX *pixg2, *pixcs1, *pixcs2, *pixd1, *pixd2; PIXA *pixa, *pixa2, *pixa3; PIXCMAP *cmap, *cmap2; RGBA_QUAD *cta; L_REGPARAMS *rp; if (regTestSetup(argc, argv, &rp)) return 1; /* ------------------------ (1) ----------------------------*/ /* Blend with a white background */ pix1 = pixRead("books_logo.png"); pixDisplayWithTitle(pix1, 100, 0, NULL, rp->display); pix2 = pixAlphaBlendUniform(pix1, 0xffffff00); pixDisplayWithTitle(pix2, 100, 150, NULL, rp->display); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 0 */ regTestWritePixAndCheck(rp, pix2, IFF_PNG); /* 1 */ /* Generate an alpha layer based on the white background */ pix3 = pixSetAlphaOverWhite(pix2); pixSetSpp(pix3, 3); pixWrite("/tmp/alphaops.2.png", pix3, IFF_PNG); /* without alpha */ regTestCheckFile(rp, "/tmp/alphaops.2.png"); /* 2 */ pixSetSpp(pix3, 4); regTestWritePixAndCheck(rp, pix3, IFF_PNG); /* 3, with alpha */ pixDisplayWithTitle(pix3, 100, 300, NULL, rp->display); /* Render on a light yellow background */ pix4 = pixAlphaBlendUniform(pix3, 0xffffe000); regTestWritePixAndCheck(rp, pix4, IFF_PNG); /* 4 */ pixDisplayWithTitle(pix4, 100, 450, NULL, rp->display); pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); pixDestroy(&pix4); /* ------------------------ (2) ----------------------------*/ lept_rmdir("alpha"); lept_mkdir("alpha"); /* Make the transparency (alpha) layer. * pixs is the mask. We turn it into a transparency (alpha) * layer by converting to 8 bpp. A small convolution fuzzes * the mask edges so that you don't see the pixels. */ pixs = pixRead("feyn-fract.tif"); pixGetDimensions(pixs, &w, &h, NULL); pixg = pixConvert1To8(NULL, pixs, 0, 255); pixg2 = pixBlockconvGray(pixg, NULL, 1, 1); regTestWritePixAndCheck(rp, pixg2, IFF_JFIF_JPEG); /* 5 */ pixDisplayWithTitle(pixg2, 0, 0, "alpha", rp->display); /* Make the viewable image. * pixc is the image that we see where the alpha layer is * opaque -- i.e., greater than 0. Scale it to the same * size as the mask. To visualize what this will look like * when displayed over a black background, create the black * background image, pixb, and do the blending with pixcs1 * explicitly using the alpha layer pixg2. */ pixc = pixRead("tetons.jpg"); pixcs1 = pixScaleToSize(pixc, w, h); regTestWritePixAndCheck(rp, pixcs1, IFF_JFIF_JPEG); /* 6 */ pixDisplayWithTitle(pixcs1, 300, 0, "viewable", rp->display); pixb = pixCreateTemplate(pixcs1); /* black */ pixd1 = pixBlendWithGrayMask(pixb, pixcs1, pixg2, 0, 0); regTestWritePixAndCheck(rp, pixd1, IFF_JFIF_JPEG); /* 7 */ pixDisplayWithTitle(pixd1, 600, 0, "alpha-blended 1", rp->display); /* Embed the alpha layer pixg2 into the color image pixc. * Write it out as is. Then clean pixcs1 (to 0) under the fully * transparent part of the alpha layer, and write that result * out as well. */ pixSetRGBComponent(pixcs1, pixg2, L_ALPHA_CHANNEL); pixWrite("/tmp/alpha/pixcs1.png", pixcs1, IFF_PNG); pixcs2 = pixSetUnderTransparency(pixcs1, 0, 0); pixWrite("/tmp/alpha/pixcs2.png", pixcs2, IFF_PNG); /* What will this look like over a black background? * Do the blending explicitly and display. It should * look identical to the blended result pixd1 before cleaning. */ pixd2 = pixBlendWithGrayMask(pixb, pixcs2, pixg2, 0, 0); regTestWritePixAndCheck(rp, pixd2, IFF_JFIF_JPEG); /* 8 */ pixDisplayWithTitle(pixd2, 0, 400, "alpha blended 2", rp->display); /* Read the two images back, ignoring the transparency layer. * The uncleaned image will come back identical to pixcs1. * However, the cleaned image will be black wherever * the alpha layer was fully transparent. It will * look the same when viewed through the alpha layer, * but have much better compression. */ pix1 = pixRead("/tmp/alpha/pixcs1.png"); /* just pixcs1 */ pix2 = pixRead("/tmp/alpha/pixcs2.png"); /* cleaned under transparent */ n1 = nbytesInFile("/tmp/alpha/pixcs1.png"); n2 = nbytesInFile("/tmp/alpha/pixcs2.png"); fprintf(stderr, " Original: %d bytes\n Cleaned: %d bytes\n", n1, n2); regTestWritePixAndCheck(rp, pix1, IFF_JFIF_JPEG); /* 9 */ regTestWritePixAndCheck(rp, pix2, IFF_JFIF_JPEG); /* 10 */ pixDisplayWithTitle(pix1, 300, 400, "without alpha", rp->display); pixDisplayWithTitle(pix2, 600, 400, "cleaned under transparent", rp->display); pixa = pixaCreate(0); pixSaveTiled(pixg2, pixa, 1.0, 1, 20, 32); pixSaveTiled(pixcs1, pixa, 1.0, 1, 20, 0); pixSaveTiled(pix1, pixa, 1.0, 0, 20, 0); pixSaveTiled(pixd1, pixa, 1.0, 1, 20, 0); pixSaveTiled(pixd2, pixa, 1.0, 0, 20, 0); pixSaveTiled(pix2, pixa, 1.0, 1, 20, 0); pixd = pixaDisplay(pixa, 0, 0); regTestWritePixAndCheck(rp, pixd, IFF_JFIF_JPEG); /* 11 */ pixDisplayWithTitle(pixd, 200, 200, "composite", rp->display); pixWrite("/tmp/alpha/alpha.png", pixd, IFF_JFIF_JPEG); pixDestroy(&pixd); pixaDestroy(&pixa); pixDestroy(&pixs); pixDestroy(&pixb); pixDestroy(&pixg); pixDestroy(&pixg2); pixDestroy(&pixc); pixDestroy(&pixcs1); pixDestroy(&pixcs2); pixDestroy(&pixd); pixDestroy(&pixd1); pixDestroy(&pixd2); pixDestroy(&pix1); pixDestroy(&pix2); /* ------------------------ (3) ----------------------------*/ color = 0xffffa000; gamma = 1.0; minval = 0; maxval = 200; box = boxCreate(0, 85, 600, 100); pixa = pixaCreate(6); pix1 = pixRead("blend-green1.jpg"); pixaAddPix(pixa, pix1, L_INSERT); pix1 = pixRead("blend-green2.png"); pixaAddPix(pixa, pix1, L_INSERT); pix1 = pixRead("blend-green3.png"); pixaAddPix(pixa, pix1, L_INSERT); pix1 = pixRead("blend-orange.jpg"); pixaAddPix(pixa, pix1, L_INSERT); pix1 = pixRead("blend-yellow.jpg"); pixaAddPix(pixa, pix1, L_INSERT); pix1 = pixRead("blend-red.png"); pixaAddPix(pixa, pix1, L_INSERT); n = pixaGetCount(pixa); pixa2 = pixaCreate(n); pixa3 = pixaCreate(n); for (i = 0; i < n; i++) { pix1 = pixaGetPix(pixa, i, L_CLONE); pix2 = DoBlendTest(pix1, box, color, gamma, minval, maxval, 1); regTestWritePixAndCheck(rp, pix2, IFF_JFIF_JPEG); /* 12, 14, ... 22 */ pixDisplayWithTitle(pix2, 150 * i, 0, NULL, rp->display); pixaAddPix(pixa2, pix2, L_INSERT); pix2 = DoBlendTest(pix1, box, color, gamma, minval, maxval, 2); regTestWritePixAndCheck(rp, pix2, IFF_JFIF_JPEG); /* 13, 15, ... 23 */ pixDisplayWithTitle(pix2, 150 * i, 200, NULL, rp->display); pixaAddPix(pixa3, pix2, L_INSERT); pixDestroy(&pix1); } if (rp->display) { pixaConvertToPdf(pixa2, 0, 0.75, L_FLATE_ENCODE, 0, "blend 1 test", "/tmp/alpha/blending1.pdf"); pixaConvertToPdf(pixa3, 0, 0.75, L_FLATE_ENCODE, 0, "blend 2 test", "/tmp/alpha/blending2.pdf"); } pixaDestroy(&pixa); pixaDestroy(&pixa2); pixaDestroy(&pixa3); boxDestroy(&box); /* ------------------------ (4) ----------------------------*/ /* Use one image as the alpha component for a second image */ pix1 = pixRead("test24.jpg"); pix2 = pixRead("marge.jpg"); pix3 = pixScale(pix2, 1.9, 2.2); pix4 = pixConvertTo8(pix3, 0); pixSetRGBComponent(pix1, pix4, L_ALPHA_CHANNEL); regTestWritePixAndCheck(rp, pix1, IFF_PNG); /* 24 */ pixDisplayWithTitle(pix1, 600, 0, NULL, rp->display); /* Set the alpha value in a colormap to bval */ pix5 = pixOctreeColorQuant(pix1, 128, 0); cmap = pixGetColormap(pix5); pixcmapToArrays(cmap, &rmap, &gmap, &bmap, NULL); n = pixcmapGetCount(cmap); for (i = 0; i < n; i++) { pixcmapGetColor(cmap, i, &rval, &gval, &bval); cta = (RGBA_QUAD *)cmap->array; cta[i].alpha = bval; } /* Test binary serialization/deserialization of colormap with alpha */ pixcmapSerializeToMemory(cmap, 4, &ncolors, &data); cmap2 = pixcmapDeserializeFromMemory(data, 4, ncolors); CmapEqual(cmap, cmap2, &equal); regTestCompareValues(rp, TRUE, equal, 0.0); /* 25 */ pixcmapDestroy(&cmap2); lept_free(data); /* Test ascii serialization/deserialization of colormap with alpha */ fp = fopenWriteStream("/tmp/alpha/cmap.4", "w"); pixcmapWriteStream(fp, cmap); fclose(fp); fp = fopenReadStream("/tmp/alpha/cmap.4"); cmap2 = pixcmapReadStream(fp); fclose(fp); CmapEqual(cmap, cmap2, &equal); regTestCompareValues(rp, TRUE, equal, 0.0); /* 26 */ pixcmapDestroy(&cmap2); /* Test r/w for cmapped pix with non-opaque alpha */ pixDisplayWithTitle(pix5, 900, 0, NULL, rp->display); regTestWritePixAndCheck(rp, pix5, IFF_PNG); /* 27 */ pixWrite("/tmp/alpha/fourcomp.png", pix5, IFF_PNG); pix6 = pixRead("/tmp/alpha/fourcomp.png"); regTestComparePix(rp, pix5, pix6); /* 28 */ pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); pixDestroy(&pix4); pixDestroy(&pix5); pixDestroy(&pix6); lept_free(rmap); lept_free(gmap); lept_free(bmap); return regTestCleanup(rp); }
main(int argc, char **argv) { l_float32 sum, sumx, sumy, diff; L_DEWARP *dew; L_DEWARPA *dewa; FPIX *fpixs, *fpixs2, *fpixs3, *fpixs4, *fpixg, *fpixd; FPIX *fpix1, *fpix2, *fpixt1, *fpixt2; DPIX *dpix, *dpix2; L_KERNEL *kel, *kelx, *kely; PIX *pixs, *pixs2, *pixs3, *pixt, *pixd, *pixg, *pixb, *pixn; PIX *pixt1, *pixt2, *pixt3, *pixt4, *pixt5, *pixt6; PIXA *pixa; PTA *ptas, *ptad; L_REGPARAMS *rp; if (regTestSetup(argc, argv, &rp)) return 1; pixa = pixaCreate(0); /* Gaussian kernel */ kel = makeGaussianKernel(5, 5, 3.0, 4.0); kernelGetSum(kel, &sum); if (rp->display) fprintf(stderr, "Sum for 2d gaussian kernel = %f\n", sum); pixt = kernelDisplayInPix(kel, 41, 2); regTestWritePixAndCheck(rp, pixt, IFF_PNG); /* 0 */ pixSaveTiled(pixt, pixa, 1, 1, 20, 8); pixDestroy(&pixt); /* Separable gaussian kernel */ makeGaussianKernelSep(5, 5, 3.0, 4.0, &kelx, &kely); kernelGetSum(kelx, &sumx); if (rp->display) fprintf(stderr, "Sum for x gaussian kernel = %f\n", sumx); kernelGetSum(kely, &sumy); if (rp->display) fprintf(stderr, "Sum for y gaussian kernel = %f\n", sumy); if (rp->display) fprintf(stderr, "Sum for x * y gaussian kernel = %f\n", sumx * sumy); pixt = kernelDisplayInPix(kelx, 41, 2); regTestWritePixAndCheck(rp, pixt, IFF_PNG); /* 1 */ pixSaveTiled(pixt, pixa, 1, 0, 20, 8); pixDestroy(&pixt); pixt = kernelDisplayInPix(kely, 41, 2); regTestWritePixAndCheck(rp, pixt, IFF_PNG); /* 2 */ pixSaveTiled(pixt, pixa, 1, 0, 20, 8); pixDestroy(&pixt); /* Use pixRasterop() to generate source image */ pixs = pixRead("test8.jpg"); pixs2 = pixRead("karen8.jpg"); pixRasterop(pixs, 150, 125, 150, 100, PIX_SRC, pixs2, 75, 100); regTestWritePixAndCheck(rp, pixs, IFF_JFIF_JPEG); /* 3 */ /* Convolution directly with pix */ pixt1 = pixConvolve(pixs, kel, 8, 1); regTestWritePixAndCheck(rp, pixt1, IFF_JFIF_JPEG); /* 4 */ pixSaveTiled(pixt1, pixa, 1, 1, 20, 8); pixt2 = pixConvolveSep(pixs, kelx, kely, 8, 1); regTestWritePixAndCheck(rp, pixt2, IFF_JFIF_JPEG); /* 5 */ pixSaveTiled(pixt2, pixa, 1, 0, 20, 8); /* Convolution indirectly with fpix, using fpixRasterop() * to generate the source image. */ fpixs = pixConvertToFPix(pixs, 3); fpixs2 = pixConvertToFPix(pixs2, 3); fpixRasterop(fpixs, 150, 125, 150, 100, fpixs2, 75, 100); fpixt1 = fpixConvolve(fpixs, kel, 1); pixt3 = fpixConvertToPix(fpixt1, 8, L_CLIP_TO_ZERO, 1); regTestWritePixAndCheck(rp, pixt3, IFF_JFIF_JPEG); /* 6 */ pixSaveTiled(pixt3, pixa, 1, 1, 20, 8); fpixt2 = fpixConvolveSep(fpixs, kelx, kely, 1); pixt4 = fpixConvertToPix(fpixt2, 8, L_CLIP_TO_ZERO, 1); regTestWritePixAndCheck(rp, pixt4, IFF_JFIF_JPEG); /* 7 */ pixSaveTiled(pixt4, pixa, 1, 0, 20, 8); pixDestroy(&pixs2); fpixDestroy(&fpixs2); fpixDestroy(&fpixt1); fpixDestroy(&fpixt2); /* Comparison of results */ pixCompareGray(pixt1, pixt2, L_COMPARE_ABS_DIFF, 0, NULL, &diff, NULL, NULL); if (rp->display) fprintf(stderr, "Ave diff of pixConvolve and pixConvolveSep: %f\n", diff); pixCompareGray(pixt3, pixt4, L_COMPARE_ABS_DIFF, 0, NULL, &diff, NULL, NULL); if (rp->display) fprintf(stderr, "Ave diff of fpixConvolve and fpixConvolveSep: %f\n", diff); pixCompareGray(pixt1, pixt3, L_COMPARE_ABS_DIFF, 0, NULL, &diff, NULL, NULL); if (rp->display) fprintf(stderr, "Ave diff of pixConvolve and fpixConvolve: %f\n", diff); pixCompareGray(pixt2, pixt4, L_COMPARE_ABS_DIFF, GPLOT_PNG, NULL, &diff, NULL, NULL); if (rp->display) fprintf(stderr, "Ave diff of pixConvolveSep and fpixConvolveSep: %f\n", diff); pixDestroy(&pixt1); pixDestroy(&pixt2); pixDestroy(&pixt3); pixDestroy(&pixt4); /* Test arithmetic operations; add in a fraction rotated by 180 */ pixs3 = pixRotate180(NULL, pixs); regTestWritePixAndCheck(rp, pixs3, IFF_JFIF_JPEG); /* 8 */ pixSaveTiled(pixs3, pixa, 1, 1, 20, 8); fpixs3 = pixConvertToFPix(pixs3, 3); fpixd = fpixLinearCombination(NULL, fpixs, fpixs3, 20.0, 5.0); fpixAddMultConstant(fpixd, 0.0, 23.174); /* multiply up in magnitude */ pixd = fpixDisplayMaxDynamicRange(fpixd); /* bring back to 8 bpp */ regTestWritePixAndCheck(rp, pixd, IFF_JFIF_JPEG); /* 9 */ pixSaveTiled(pixd, pixa, 1, 0, 20, 8); pixDestroy(&pixs3); fpixDestroy(&fpixs3); fpixDestroy(&fpixd); pixDestroy(&pixd); pixDestroy(&pixs); fpixDestroy(&fpixs); /* Save the comparison graph; gnuplot should have made it by now! */ #ifndef _WIN32 sleep(2); #else Sleep(2000); #endif /* _WIN32 */ pixt5 = pixRead("/tmp/grayroot.png"); regTestWritePixAndCheck(rp, pixt5, IFF_PNG); /* 10 */ pixSaveTiled(pixt5, pixa, 1, 1, 20, 8); pixDestroy(&pixt5); /* Display results */ pixd = pixaDisplay(pixa, 0, 0); regTestWritePixAndCheck(rp, pixd, IFF_JFIF_JPEG); /* 11 */ pixDisplayWithTitle(pixd, 100, 100, NULL, rp->display); pixDestroy(&pixd); pixaDestroy(&pixa); /* Test some more convolutions, with sampled output. First on pix */ pixa = pixaCreate(0); pixs = pixRead("1555-7.jpg"); pixg = pixConvertTo8(pixs, 0); l_setConvolveSampling(5, 5); pixt1 = pixConvolve(pixg, kel, 8, 1); regTestWritePixAndCheck(rp, pixt1, IFF_JFIF_JPEG); /* 12 */ pixSaveTiled(pixt1, pixa, 1, 1, 20, 32); pixt2 = pixConvolveSep(pixg, kelx, kely, 8, 1); regTestWritePixAndCheck(rp, pixt2, IFF_JFIF_JPEG); /* 13 */ pixSaveTiled(pixt2, pixa, 1, 0, 20, 32); pixt3 = pixConvolveRGB(pixs, kel); regTestWritePixAndCheck(rp, pixt3, IFF_JFIF_JPEG); /* 14 */ pixSaveTiled(pixt3, pixa, 1, 0, 20, 32); pixt4 = pixConvolveRGBSep(pixs, kelx, kely); regTestWritePixAndCheck(rp, pixt4, IFF_JFIF_JPEG); /* 15 */ pixSaveTiled(pixt4, pixa, 1, 0, 20, 32); /* Then on fpix */ fpixg = pixConvertToFPix(pixg, 1); fpixt1 = fpixConvolve(fpixg, kel, 1); pixt5 = fpixConvertToPix(fpixt1, 8, L_CLIP_TO_ZERO, 0); regTestWritePixAndCheck(rp, pixt5, IFF_JFIF_JPEG); /* 16 */ pixSaveTiled(pixt5, pixa, 1, 1, 20, 32); fpixt2 = fpixConvolveSep(fpixg, kelx, kely, 1); pixt6 = fpixConvertToPix(fpixt2, 8, L_CLIP_TO_ZERO, 0); regTestWritePixAndCheck(rp, pixt6, IFF_JFIF_JPEG); /* 17 */ pixSaveTiled(pixt2, pixa, 1, 0, 20, 32); regTestCompareSimilarPix(rp, pixt1, pixt5, 2, 0.00, 0); /* 18 */ regTestCompareSimilarPix(rp, pixt2, pixt6, 2, 0.00, 0); /* 19 */ pixDestroy(&pixt1); pixDestroy(&pixt2); pixDestroy(&pixt3); pixDestroy(&pixt4); pixDestroy(&pixt5); pixDestroy(&pixt6); fpixDestroy(&fpixg); fpixDestroy(&fpixt1); fpixDestroy(&fpixt2); pixd = pixaDisplay(pixa, 0, 0); regTestWritePixAndCheck(rp, pixd, IFF_JFIF_JPEG); /* 20 */ pixDisplayWithTitle(pixd, 600, 100, NULL, rp->display); pixDestroy(&pixs); pixDestroy(&pixg); pixDestroy(&pixd); pixaDestroy(&pixa); /* Test extension (continued and slope). * First, build a smooth vertical disparity array; * then extend and show the contours. */ pixs = pixRead("cat-35.jpg"); pixn = pixBackgroundNormSimple(pixs, NULL, NULL); pixg = pixConvertRGBToGray(pixn, 0.5, 0.3, 0.2); pixb = pixThresholdToBinary(pixg, 130); dewa = dewarpaCreate(1, 30, 1, 15, 0); dew = dewarpCreate(pixb, 35); dewarpaInsertDewarp(dewa, dew); dewarpBuildModel(dew, NULL); dewarpPopulateFullRes(dew, NULL); fpixs = dew->fullvdispar; fpixs2 = fpixAddContinuedBorder(fpixs, 200, 200, 100, 300); fpixs3 = fpixAddSlopeBorder(fpixs, 200, 200, 100, 300); dpix = fpixConvertToDPix(fpixs3); fpixs4 = dpixConvertToFPix(dpix); pixt1 = fpixRenderContours(fpixs, 2.0, 0.2); pixt2 = fpixRenderContours(fpixs2, 2.0, 0.2); pixt3 = fpixRenderContours(fpixs3, 2.0, 0.2); pixt4 = fpixRenderContours(fpixs4, 2.0, 0.2); pixt5 = pixRead("karen8.jpg"); dpix2 = pixConvertToDPix(pixt5, 1); pixt6 = dpixConvertToPix(dpix2, 8, L_CLIP_TO_ZERO, 0); regTestWritePixAndCheck(rp, pixt1, IFF_PNG); /* 21 */ pixDisplayWithTitle(pixt1, 0, 100, NULL, rp->display); regTestWritePixAndCheck(rp, pixt2, IFF_PNG); /* 22 */ pixDisplayWithTitle(pixt2, 470, 100, NULL, rp->display); regTestWritePixAndCheck(rp, pixt3, IFF_PNG); /* 23 */ pixDisplayWithTitle(pixt3, 1035, 100, NULL, rp->display); regTestComparePix(rp, pixt3, pixt4); /* 24 */ regTestComparePix(rp, pixt5, pixt6); /* 25 */ pixDestroy(&pixs); pixDestroy(&pixn); pixDestroy(&pixg); pixDestroy(&pixb); pixDestroy(&pixt1); pixDestroy(&pixt2); pixDestroy(&pixt3); pixDestroy(&pixt4); pixDestroy(&pixt5); pixDestroy(&pixt6); fpixDestroy(&fpixs2); fpixDestroy(&fpixs3); fpixDestroy(&fpixs4); dpixDestroy(&dpix); dpixDestroy(&dpix2); /* Test affine and projective transforms on fpix */ fpixWrite("/tmp/fpix1.fp", dew->fullvdispar); fpix1 = fpixRead("/tmp/fpix1.fp"); pixt1 = fpixAutoRenderContours(fpix1, 40); regTestWritePixAndCheck(rp, pixt1, IFF_PNG); /* 26 */ pixDisplayWithTitle(pixt1, 0, 500, NULL, rp->display); pixDestroy(&pixt1); MakePtasAffine(1, &ptas, &ptad); fpix2 = fpixAffinePta(fpix1, ptad, ptas, 200, 0.0); pixt2 = fpixAutoRenderContours(fpix2, 40); regTestWritePixAndCheck(rp, pixt2, IFF_PNG); /* 27 */ pixDisplayWithTitle(pixt2, 400, 500, NULL, rp->display); fpixDestroy(&fpix2); pixDestroy(&pixt2); ptaDestroy(&ptas); ptaDestroy(&ptad); MakePtas(1, &ptas, &ptad); fpix2 = fpixProjectivePta(fpix1, ptad, ptas, 200, 0.0); pixt3 = fpixAutoRenderContours(fpix2, 40); regTestWritePixAndCheck(rp, pixt3, IFF_PNG); /* 28 */ pixDisplayWithTitle(pixt3, 400, 500, NULL, rp->display); fpixDestroy(&fpix2); pixDestroy(&pixt3); ptaDestroy(&ptas); ptaDestroy(&ptad); fpixDestroy(&fpix1); dewarpaDestroy(&dewa); kernelDestroy(&kel); kernelDestroy(&kelx); kernelDestroy(&kely); return regTestCleanup(rp); }