/*! * kernelCreateFromPix() * * Input: pix * cy, cx (origin of kernel) * Return: kernel, or null on error * * Notes: * (1) The origin must be positive and within the dimensions of the pix. */ L_KERNEL * kernelCreateFromPix(PIX *pix, l_int32 cy, l_int32 cx) { l_int32 i, j, w, h, d; l_uint32 val; L_KERNEL *kel; PROCNAME("kernelCreateFromPix"); if (!pix) return (L_KERNEL *)ERROR_PTR("pix not defined", procName, NULL); pixGetDimensions(pix, &w, &h, &d); if (d != 8) return (L_KERNEL *)ERROR_PTR("pix not 8 bpp", procName, NULL); if (cy < 0 || cx < 0 || cy >= h || cx >= w) return (L_KERNEL *)ERROR_PTR("(cy, cx) invalid", procName, NULL); kel = kernelCreate(h, w); kernelSetOrigin(kel, cy, cx); for (i = 0; i < h; i++) { for (j = 0; j < w; j++) { pixGetPixel(pix, j, i, &val); kernelSetElement(kel, i, j, (l_float32)val); } } return kel; }
/*! * kernelNormalize() * * Input: kels (source kel, to be normalized) * normsum (desired sum of elements in keld) * Return: keld (normalized version of kels), or null on error * or if sum of elements is very close to 0) * * Notes: * (1) If the sum of kernel elements is close to 0, do not * try to calculate the normalized kernel. Instead, * return a copy of the input kernel, with a warning. */ L_KERNEL * kernelNormalize(L_KERNEL *kels, l_float32 normsum) { l_int32 i, j, sx, sy, cx, cy; l_float32 sum, factor; L_KERNEL *keld; PROCNAME("kernelNormalize"); if (!kels) return (L_KERNEL *)ERROR_PTR("kels not defined", procName, NULL); kernelGetSum(kels, &sum); if (L_ABS(sum) < 0.00001) { L_WARNING("null sum; not normalizing; returning a copy\n", procName); return kernelCopy(kels); } kernelGetParameters(kels, &sy, &sx, &cy, &cx); if ((keld = kernelCreate(sy, sx)) == NULL) return (L_KERNEL *)ERROR_PTR("keld not made", procName, NULL); keld->cy = cy; keld->cx = cx; factor = normsum / sum; for (i = 0; i < sy; i++) for (j = 0; j < sx; j++) keld->data[i][j] = factor * kels->data[i][j]; return keld; }
/*! * kernelReadStream() * * Input: stream * Return: kernel, or null on error */ L_KERNEL * kernelReadStream(FILE *fp) { l_int32 sy, sx, cy, cx, i, j, ret, version, ignore; L_KERNEL *kel; PROCNAME("kernelReadStream"); if (!fp) return (L_KERNEL *)ERROR_PTR("stream not defined", procName, NULL); ret = fscanf(fp, " Kernel Version %d\n", &version); if (ret != 1) return (L_KERNEL *)ERROR_PTR("not a kernel file", procName, NULL); if (version != KERNEL_VERSION_NUMBER) return (L_KERNEL *)ERROR_PTR("invalid kernel version", procName, NULL); if (fscanf(fp, " sy = %d, sx = %d, cy = %d, cx = %d\n", &sy, &sx, &cy, &cx) != 4) return (L_KERNEL *)ERROR_PTR("dimensions not read", procName, NULL); if ((kel = kernelCreate(sy, sx)) == NULL) return (L_KERNEL *)ERROR_PTR("kel not made", procName, NULL); kernelSetOrigin(kel, cy, cx); for (i = 0; i < sy; i++) { for (j = 0; j < sx; j++) ignore = fscanf(fp, "%15f", &kel->data[i][j]); ignore = fscanf(fp, "\n"); } ignore = fscanf(fp, "\n"); return kel; }
/*! * makeDoGKernel() * * Input: halfheight, halfwidth (sx = 2 * halfwidth + 1, etc) * stdev (standard deviation of narrower gaussian) * ratio (of stdev for wide filter to stdev for narrow one) * Return: kernel, or null on error * * Notes: * (1) The DoG (difference of gaussians) is a wavelet mother * function with null total sum. By subtracting two blurred * versions of the image, it acts as a bandpass filter for * frequencies passed by the narrow gaussian but stopped * by the wide one.See: * http://en.wikipedia.org/wiki/Difference_of_Gaussians * (2) The kernel size (sx, sy) = (2 * halfwidth + 1, 2 * halfheight + 1). * (3) The kernel center (cx, cy) = (halfwidth, halfheight). * (4) The halfwidth and halfheight are typically equal, and * are typically several times larger than the standard deviation. * (5) The ratio is the ratio of standard deviations of the wide * to narrow gaussian. It must be >= 1.0; 1.0 is a no-op. * (6) Because the kernel is a null sum, it must be invoked without * normalization in pixConvolve(). */ L_KERNEL * makeDoGKernel(l_int32 halfheight, l_int32 halfwidth, l_float32 stdev, l_float32 ratio) { l_int32 sx, sy, i, j; l_float32 pi, squaredist, highnorm, lownorm, val; L_KERNEL *kel; PROCNAME("makeDoGKernel"); sx = 2 * halfwidth + 1; sy = 2 * halfheight + 1; if ((kel = kernelCreate(sy, sx)) == NULL) return (L_KERNEL *)ERROR_PTR("kel not made", procName, NULL); kernelSetOrigin(kel, halfheight, halfwidth); pi = 3.1415926535; for (i = 0; i < sy; i++) { for (j = 0; j < sx; j++) { squaredist = (l_float32)((i - halfheight) * (i - halfheight) + (j - halfwidth) * (j - halfwidth)); highnorm = 1. / (2 * stdev * stdev); lownorm = highnorm / (ratio * ratio); val = (highnorm / pi) * expf(-(highnorm * squaredist)) - (lownorm / pi) * expf(-(lownorm * squaredist)); kernelSetElement(kel, i, j, val); } } return kel; }
/*! * makeGaussianKernel() * * Input: halfheight, halfwidth (sx = 2 * halfwidth + 1, etc) * stdev (standard deviation) * max (value at (cx,cy)) * Return: kernel, or null on error * * Notes: * (1) The kernel size (sx, sy) = (2 * halfwidth + 1, 2 * halfheight + 1). * (2) The kernel center (cx, cy) = (halfwidth, halfheight). * (3) The halfwidth and halfheight are typically equal, and * are typically several times larger than the standard deviation. * (4) If pixConvolve() is invoked with normalization (the sum of * kernel elements = 1.0), use 1.0 for max (or any number that's * not too small or too large). */ L_KERNEL * makeGaussianKernel(l_int32 halfheight, l_int32 halfwidth, l_float32 stdev, l_float32 max) { l_int32 sx, sy, i, j; l_float32 val; L_KERNEL *kel; PROCNAME("makeGaussianKernel"); sx = 2 * halfwidth + 1; sy = 2 * halfheight + 1; if ((kel = kernelCreate(sy, sx)) == NULL) return (L_KERNEL *)ERROR_PTR("kel not made", procName, NULL); kernelSetOrigin(kel, halfheight, halfwidth); for (i = 0; i < sy; i++) { for (j = 0; j < sx; j++) { val = expf(-(l_float32)((i - halfheight) * (i - halfheight) + (j - halfwidth) * (j - halfwidth)) / (2. * stdev * stdev)); kernelSetElement(kel, i, j, max * val); } } return kel; }
/*! * kernelCreateFromString() * * Input: height, width * cy, cx (origin) * kdata * Return: kernel of the given size, or null on error * * Notes: * (1) The data is an array of chars, in row-major order, giving * space separated integers in the range [-255 ... 255]. * (2) The only other formatting limitation is that you must * leave space between the last number in each row and * the double-quote. If possible, it's also nice to have each * line in the string represent a line in the kernel; e.g., * static const char *kdata = * " 20 50 20 " * " 70 140 70 " * " 20 50 20 "; */ L_KERNEL * kernelCreateFromString(l_int32 h, l_int32 w, l_int32 cy, l_int32 cx, const char *kdata) { l_int32 n, i, j, index; l_float32 val; L_KERNEL *kel; NUMA *na; PROCNAME("kernelCreateFromString"); if (h < 1) return (L_KERNEL *)ERROR_PTR("height must be > 0", procName, NULL); if (w < 1) return (L_KERNEL *)ERROR_PTR("width must be > 0", procName, NULL); if (cy < 0 || cy >= h) return (L_KERNEL *)ERROR_PTR("cy invalid", procName, NULL); if (cx < 0 || cx >= w) return (L_KERNEL *)ERROR_PTR("cx invalid", procName, NULL); kel = kernelCreate(h, w); kernelSetOrigin(kel, cy, cx); na = parseStringForNumbers(kdata, " \t\n"); n = numaGetCount(na); if (n != w * h) { numaDestroy(&na); fprintf(stderr, "w = %d, h = %d, num ints = %d\n", w, h, n); return (L_KERNEL *)ERROR_PTR("invalid integer data", procName, NULL); } index = 0; for (i = 0; i < h; i++) { for (j = 0; j < w; j++) { numaGetFValue(na, index, &val); kernelSetElement(kel, i, j, val); index++; } } numaDestroy(&na); return kel; }
/*! * makeRangeKernel() * * Input: range_stdev (> 0) * Return: kel, or null on error * * Notes: * (1) Creates a one-sided Gaussian kernel with the given * standard deviation. At grayscale difference of one stdev, * the kernel falls to 0.6, and to 0.01 at three stdev. * (2) A typical input number might be 20. Then pixels whose * value differs by 60 from the center pixel have their * weight in the convolution reduced by a factor of about 0.01. */ L_KERNEL * makeRangeKernel(l_float32 range_stdev) { l_int32 x; l_float32 val, denom; L_KERNEL *kel; PROCNAME("makeRangeKernel"); if (range_stdev <= 0.0) return (L_KERNEL *) ERROR_PTR("invalid stdev <= 0", procName, NULL); denom = 2. * range_stdev * range_stdev; if ((kel = kernelCreate(1, 256)) == NULL) return (L_KERNEL *) ERROR_PTR("kel not made", procName, NULL); kernelSetOrigin(kel, 0, 0); for (x = 0; x < 256; x++) { val = expf(-(l_float32)(x * x) / denom); kernelSetElement(kel, 0, x, val); } return kel; }
/*! * kernelCopy() * * Input: kels (source kernel) * Return: keld (copy of kels), or null on error */ L_KERNEL * kernelCopy(L_KERNEL *kels) { l_int32 i, j, sx, sy, cx, cy; L_KERNEL *keld; PROCNAME("kernelCopy"); if (!kels) return (L_KERNEL *)ERROR_PTR("kels not defined", procName, NULL); kernelGetParameters(kels, &sy, &sx, &cy, &cx); if ((keld = kernelCreate(sy, sx)) == NULL) return (L_KERNEL *)ERROR_PTR("keld not made", procName, NULL); keld->cy = cy; keld->cx = cx; for (i = 0; i < sy; i++) for (j = 0; j < sx; j++) keld->data[i][j] = kels->data[i][j]; return keld; }
/*! * makeFlatKernel() * * Input: height, width * cy, cx (origin of kernel) * Return: kernel, or null on error * * Notes: * (1) This is the same low-pass filtering kernel that is used * in the block convolution functions. * (2) The kernel origin (@cy, @cx) is typically placed as near * the center of the kernel as possible. If height and * width are odd, then using cy = height / 2 and * cx = width / 2 places the origin at the exact center. * (3) This returns a normalized kernel. */ L_KERNEL * makeFlatKernel(l_int32 height, l_int32 width, l_int32 cy, l_int32 cx) { l_int32 i, j; l_float32 normval; L_KERNEL *kel; PROCNAME("makeFlatKernel"); if ((kel = kernelCreate(height, width)) == NULL) return (L_KERNEL *)ERROR_PTR("kel not made", procName, NULL); kernelSetOrigin(kel, cy, cx); normval = 1.0 / (l_float32)(height * width); for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { kernelSetElement(kel, i, j, normval); } } return kel; }
/*! * kernelCreateFromFile() * * Input: filename * Return: kernel, or null on error * * Notes: * (1) The file contains, in the following order: * - Any number of comment lines starting with '#' are ignored * - The height and width of the kernel * - The y and x values of the kernel origin * - The kernel data, formatted as lines of numbers (integers * or floats) for the kernel values in row-major order, * and with no other punctuation. * (Note: this differs from kernelCreateFromString(), * where each line must begin and end with a double-quote * to tell the compiler it's part of a string.) * - The kernel specification ends when a blank line, * a comment line, or the end of file is reached. * (2) All lines must be left-justified. * (3) See kernelCreateFromString() for a description of the string * format for the kernel data. As an example, here are the lines * of a valid kernel description file In the file, all lines * are left-justified: * # small 3x3 kernel * 3 3 * 1 1 * 25.5 51 24.3 * 70.2 146.3 73.4 * 20 50.9 18.4 */ L_KERNEL * kernelCreateFromFile(const char *filename) { char *filestr, *line; l_int32 nlines, i, j, first, index, w, h, cx, cy, n; l_float32 val; size_t size; NUMA *na, *nat; SARRAY *sa; L_KERNEL *kel; PROCNAME("kernelCreateFromFile"); if (!filename) return (L_KERNEL *)ERROR_PTR("filename not defined", procName, NULL); filestr = (char *)l_binaryRead(filename, &size); sa = sarrayCreateLinesFromString(filestr, 1); FREE(filestr); nlines = sarrayGetCount(sa); /* Find the first data line. */ for (i = 0; i < nlines; i++) { line = sarrayGetString(sa, i, L_NOCOPY); if (line[0] != '#') { first = i; break; } } /* Find the kernel dimensions and origin location. */ line = sarrayGetString(sa, first, L_NOCOPY); if (sscanf(line, "%d %d", &h, &w) != 2) return (L_KERNEL *)ERROR_PTR("error reading h,w", procName, NULL); line = sarrayGetString(sa, first + 1, L_NOCOPY); if (sscanf(line, "%d %d", &cy, &cx) != 2) return (L_KERNEL *)ERROR_PTR("error reading cy,cx", procName, NULL); /* Extract the data. This ends when we reach eof, or when we * encounter a line of data that is either a null string or * contains just a newline. */ na = numaCreate(0); for (i = first + 2; i < nlines; i++) { line = sarrayGetString(sa, i, L_NOCOPY); if (line[0] == '\0' || line[0] == '\n' || line[0] == '#') break; nat = parseStringForNumbers(line, " \t\n"); numaJoin(na, nat, 0, -1); numaDestroy(&nat); } sarrayDestroy(&sa); n = numaGetCount(na); if (n != w * h) { numaDestroy(&na); fprintf(stderr, "w = %d, h = %d, num ints = %d\n", w, h, n); return (L_KERNEL *)ERROR_PTR("invalid integer data", procName, NULL); } kel = kernelCreate(h, w); kernelSetOrigin(kel, cy, cx); index = 0; for (i = 0; i < h; i++) { for (j = 0; j < w; j++) { numaGetFValue(na, index, &val); kernelSetElement(kel, i, j, val); index++; } } numaDestroy(&na); return kel; }
int main(int argc, char **argv) { l_int32 i, j, sizex, sizey, bias; FPIX *fpixv, *fpixrv; L_KERNEL *kel1, *kel2, *kel3x, *kel3y; PIX *pixs, *pixacc, *pixg, *pixt, *pixd; PIX *pixb, *pixm, *pixms, *pixrv, *pix1, *pix2, *pix3, *pix4; L_REGPARAMS *rp; if (regTestSetup(argc, argv, &rp)) return 1; /* Test pixBlockconvGray() on 8 bpp */ pixs = pixRead("test8.jpg"); pixacc = pixBlockconvAccum(pixs); pixd = pixBlockconvGray(pixs, pixacc, 3, 5); regTestWritePixAndCheck(rp, pixd, IFF_JFIF_JPEG); /* 0 */ pixDisplayWithTitle(pixd, 100, 0, NULL, rp->display); pixDestroy(&pixacc); pixDestroy(&pixd); /* Test pixBlockconv() on 8 bpp */ pixd = pixBlockconv(pixs, 9, 8); regTestWritePixAndCheck(rp, pixd, IFF_JFIF_JPEG); /* 1 */ pixDisplayWithTitle(pixd, 200, 0, NULL, rp->display); pixDestroy(&pixd); pixDestroy(&pixs); /* Test pixBlockrank() on 1 bpp */ pixs = pixRead("test1.png"); pixacc = pixBlockconvAccum(pixs); for (i = 0; i < 3; i++) { pixd = pixBlockrank(pixs, pixacc, 4, 4, 0.25 + 0.25 * i); regTestWritePixAndCheck(rp, pixd, IFF_PNG); /* 2 - 4 */ pixDisplayWithTitle(pixd, 300 + 100 * i, 0, NULL, rp->display); pixDestroy(&pixd); } /* Test pixBlocksum() on 1 bpp */ pixd = pixBlocksum(pixs, pixacc, 16, 16); regTestWritePixAndCheck(rp, pixd, IFF_JFIF_JPEG); /* 5 */ pixDisplayWithTitle(pixd, 700, 0, NULL, rp->display); pixDestroy(&pixd); pixDestroy(&pixacc); pixDestroy(&pixs); /* Test pixCensusTransform() */ pixs = pixRead("test24.jpg"); pixg = pixScaleRGBToGrayFast(pixs, 2, COLOR_GREEN); pixd = pixCensusTransform(pixg, 10, NULL); regTestWritePixAndCheck(rp, pixd, IFF_PNG); /* 6 */ pixDisplayWithTitle(pixd, 800, 0, NULL, rp->display); pixDestroy(&pixd); /* Test generic convolution with kel1 */ kel1 = kernelCreateFromString(5, 5, 2, 2, kel1str); pixd = pixConvolve(pixg, kel1, 8, 1); regTestWritePixAndCheck(rp, pixd, IFF_JFIF_JPEG); /* 7 */ pixDisplayWithTitle(pixd, 100, 500, NULL, rp->display); pixDestroy(&pixd); /* Test convolution with flat rectangular kel */ kel2 = kernelCreate(11, 11); kernelSetOrigin(kel2, 5, 5); for (i = 0; i < 11; i++) { for (j = 0; j < 11; j++) kernelSetElement(kel2, i, j, 1); } pixd = pixConvolve(pixg, kel2, 8, 1); regTestWritePixAndCheck(rp, pixd, IFF_JFIF_JPEG); /* 8 */ pixDisplayWithTitle(pixd, 200, 500, NULL, rp->display); pixDestroy(&pixd); kernelDestroy(&kel1); kernelDestroy(&kel2); /* Test pixBlockconv() on 32 bpp */ pixt = pixScaleBySampling(pixs, 0.5, 0.5); pixd = pixBlockconv(pixt, 4, 6); regTestWritePixAndCheck(rp, pixd, IFF_JFIF_JPEG); /* 9 */ pixDisplayWithTitle(pixd, 300, 500, NULL, rp->display); pixDestroy(&pixt); pixDestroy(&pixs); pixDestroy(&pixg); pixDestroy(&pixd); /* Test bias convolution non-separable with kel2 */ pixs = pixRead("marge.jpg"); pixg = pixScaleRGBToGrayFast(pixs, 2, COLOR_GREEN); kel2 = kernelCreateFromString(5, 5, 2, 2, kel2str); pixd = pixConvolveWithBias(pixg, kel2, NULL, TRUE, &bias); regTestWritePixAndCheck(rp, pixd, IFF_JFIF_JPEG); /* 10 */ pixDisplayWithTitle(pixd, 400, 500, NULL, rp->display); fprintf(stderr, "bias = %d\n", bias); kernelDestroy(&kel2); pixDestroy(&pixd); /* Test bias convolution separable with kel3x and kel3y */ kel3x = kernelCreateFromString(1, 5, 0, 2, kel3xstr); kel3y = kernelCreateFromString(7, 1, 3, 0, kel3ystr); pixd = pixConvolveWithBias(pixg, kel3x, kel3y, TRUE, &bias); regTestWritePixAndCheck(rp, pixd, IFF_JFIF_JPEG); /* 11 */ pixDisplayWithTitle(pixd, 500, 500, NULL, rp->display); fprintf(stderr, "bias = %d\n", bias); kernelDestroy(&kel3x); kernelDestroy(&kel3y); pixDestroy(&pixd); pixDestroy(&pixs); pixDestroy(&pixg); /* Test pixWindowedMean() and pixWindowedMeanSquare() on 8 bpp */ pixs = pixRead("feyn-fract2.tif"); pixg = pixConvertTo8(pixs, 0); sizex = 5; sizey = 20; pixb = pixAddBorderGeneral(pixg, sizex + 1, sizex + 1, sizey + 1, sizey + 1, 0); pixm = pixWindowedMean(pixb, sizex, sizey, 1, 1); pixms = pixWindowedMeanSquare(pixb, sizex, sizey, 1); regTestWritePixAndCheck(rp, pixm, IFF_JFIF_JPEG); /* 12 */ pixDisplayWithTitle(pixm, 100, 0, NULL, rp->display); pixDestroy(&pixs); pixDestroy(&pixb); /* Test pixWindowedVariance() on 8 bpp */ pixWindowedVariance(pixm, pixms, &fpixv, &fpixrv); pixrv = fpixConvertToPix(fpixrv, 8, L_CLIP_TO_ZERO, 1); regTestWritePixAndCheck(rp, pixrv, IFF_JFIF_JPEG); /* 13 */ pixDisplayWithTitle(pixrv, 100, 250, NULL, rp->display); pix1 = fpixDisplayMaxDynamicRange(fpixv); pix2 = fpixDisplayMaxDynamicRange(fpixrv); pixDisplayWithTitle(pix1, 100, 500, "Variance", rp->display); pixDisplayWithTitle(pix2, 100, 750, "RMS deviation", rp->display); regTestWritePixAndCheck(rp, pix1, IFF_JFIF_JPEG); /* 14 */ regTestWritePixAndCheck(rp, pix2, IFF_JFIF_JPEG); /* 15 */ fpixDestroy(&fpixv); fpixDestroy(&fpixrv); pixDestroy(&pixm); pixDestroy(&pixms); pixDestroy(&pixrv); /* Test again all windowed functions with simpler interface */ pixWindowedStats(pixg, sizex, sizey, 0, NULL, NULL, &fpixv, &fpixrv); pix3 = fpixDisplayMaxDynamicRange(fpixv); pix4 = fpixDisplayMaxDynamicRange(fpixrv); regTestComparePix(rp, pix1, pix3); /* 16 */ regTestComparePix(rp, pix2, pix4); /* 17 */ pixDestroy(&pixg); pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); pixDestroy(&pix4); fpixDestroy(&fpixv); fpixDestroy(&fpixrv); return regTestCleanup(rp); }
int main(int argc, char **argv) { char textstr[256]; l_int32 w, h, d, i; l_uint32 srcval, dstval; l_float32 scalefact, sat, fract; L_BMF *bmf8; L_KERNEL *kel; NUMA *na; PIX *pix, *pixs, *pixs1, *pixs2, *pixd; PIX *pixt0, *pixt1, *pixt2, *pixt3, *pixt4; PIXA *pixa, *pixaf; L_REGPARAMS *rp; if (regTestSetup(argc, argv, &rp)) return 1; pix = pixRead(filein); pixGetDimensions(pix, &w, &h, &d); if (d != 32) return ERROR_INT("file not 32 bpp", argv[0], 1); scalefact = (l_float32)WIDTH / (l_float32)w; pixs = pixScale(pix, scalefact, scalefact); w = pixGetWidth(pixs); pixaf = pixaCreate(5); /* TRC: vary gamma */ pixa = pixaCreate(20); for (i = 0; i < 20; i++) { pixt0 = pixGammaTRC(NULL, pixs, 0.3 + 0.15 * i, 0, 255); pixaAddPix(pixa, pixt0, L_INSERT); } pixt1 = pixaDisplayTiledAndScaled(pixa, 32, w, 5, 0, 10, 2); pixSaveTiled(pixt1, pixaf, 1.0, 1, 20, 32); regTestWritePixAndCheck(rp, pixt1, IFF_PNG); /* 0 */ pixDisplayWithTitle(pixt1, 0, 100, "TRC Gamma", rp->display); pixDestroy(&pixt1); pixaDestroy(&pixa); /* TRC: vary black point */ pixa = pixaCreate(20); for (i = 0; i < 20; i++) { pixt0 = pixGammaTRC(NULL, pixs, 1.0, 5 * i, 255); pixaAddPix(pixa, pixt0, L_INSERT); } pixt1 = pixaDisplayTiledAndScaled(pixa, 32, w, 5, 0, 10, 2); pixSaveTiled(pixt1, pixaf, 1.0, 1, 20, 0); regTestWritePixAndCheck(rp, pixt1, IFF_PNG); /* 1 */ pixDisplayWithTitle(pixt1, 300, 100, "TRC", rp->display); pixDestroy(&pixt1); pixaDestroy(&pixa); /* Vary hue */ pixa = pixaCreate(20); for (i = 0; i < 20; i++) { pixt0 = pixModifyHue(NULL, pixs, 0.01 + 0.05 * i); pixaAddPix(pixa, pixt0, L_INSERT); } pixt1 = pixaDisplayTiledAndScaled(pixa, 32, w, 5, 0, 10, 2); pixSaveTiled(pixt1, pixaf, 1.0, 1, 20, 0); regTestWritePixAndCheck(rp, pixt1, IFF_PNG); /* 2 */ pixDisplayWithTitle(pixt1, 600, 100, "Hue", rp->display); pixDestroy(&pixt1); pixaDestroy(&pixa); /* Vary saturation */ pixa = pixaCreate(20); na = numaCreate(20); for (i = 0; i < 20; i++) { pixt0 = pixModifySaturation(NULL, pixs, -0.9 + 0.1 * i); pixMeasureSaturation(pixt0, 1, &sat); pixaAddPix(pixa, pixt0, L_INSERT); numaAddNumber(na, sat); } pixt1 = pixaDisplayTiledAndScaled(pixa, 32, w, 5, 0, 10, 2); pixSaveTiled(pixt1, pixaf, 1.0, 1, 20, 0); gplotSimple1(na, GPLOT_PNG, "/tmp/regout/enhance.7", "Average Saturation"); regTestWritePixAndCheck(rp, pixt1, IFF_PNG); /* 3 */ pixDisplayWithTitle(pixt1, 900, 100, "Saturation", rp->display); numaDestroy(&na); pixDestroy(&pixt1); pixaDestroy(&pixa); /* Vary contrast */ pixa = pixaCreate(20); for (i = 0; i < 20; i++) { pixt0 = pixContrastTRC(NULL, pixs, 0.1 * i); pixaAddPix(pixa, pixt0, L_INSERT); } pixt1 = pixaDisplayTiledAndScaled(pixa, 32, w, 5, 0, 10, 2); pixSaveTiled(pixt1, pixaf, 1.0, 1, 20, 0); regTestWritePixAndCheck(rp, pixt1, IFF_PNG); /* 4 */ pixDisplayWithTitle(pixt1, 0, 400, "Contrast", rp->display); pixDestroy(&pixt1); pixaDestroy(&pixa); /* Vary sharpening */ pixa = pixaCreate(20); for (i = 0; i < 20; i++) { pixt0 = pixUnsharpMasking(pixs, 3, 0.01 + 0.15 * i); pixaAddPix(pixa, pixt0, L_INSERT); } pixt1 = pixaDisplayTiledAndScaled(pixa, 32, w, 5, 0, 10, 2); pixSaveTiled(pixt1, pixaf, 1.0, 1, 20, 0); regTestWritePixAndCheck(rp, pixt1, IFF_PNG); /* 5 */ pixDisplayWithTitle(pixt1, 300, 400, "Sharp", rp->display); pixDestroy(&pixt1); pixaDestroy(&pixa); /* Hue constant mapping to lighter background */ pixa = pixaCreate(11); bmf8 = bmfCreate("fonts", 8); pixt0 = pixRead("candelabrum-11.jpg"); composeRGBPixel(230, 185, 144, &srcval); /* select typical bg pixel */ for (i = 0; i <= 10; i++) { fract = 0.10 * i; pixelFractionalShift(230, 185, 144, fract, &dstval); pixt1 = pixLinearMapToTargetColor(NULL, pixt0, srcval, dstval); snprintf(textstr, 50, "Fract = %5.1f", fract); pixt2 = pixAddSingleTextblock(pixt1, bmf8, textstr, 0xff000000, L_ADD_BELOW, NULL); pixSaveTiledOutline(pixt2, pixa, 1.0, (i % 4 == 0) ? 1 : 0, 30, 2, 32); pixDestroy(&pixt1); pixDestroy(&pixt2); } pixDestroy(&pixt0); pixd = pixaDisplay(pixa, 0, 0); regTestWritePixAndCheck(rp, pixd, IFF_JFIF_JPEG); /* 6 */ pixDisplayWithTitle(pixd, 600, 400, "Constant hue", rp->display); bmfDestroy(&bmf8); pixaDestroy(&pixa); pixDestroy(&pixd); /* Delayed testing of saturation plot */ regTestCheckFile(rp, "/tmp/regout/enhance.7.png"); /* 7 */ /* Display results */ pixd = pixaDisplay(pixaf, 0, 0); regTestWritePixAndCheck(rp, pixd, IFF_JFIF_JPEG); /* 8 */ pixDisplayWithTitle(pixd, 100, 100, "All", rp->display); pixDestroy(&pixd); pixaDestroy(&pixaf); pixDestroy(&pix); pixDestroy(&pixs); /* -----------------------------------------------* * Test global color transforms * * -----------------------------------------------*/ /* Make identical cmap and rgb images */ pix = pixRead("wet-day.jpg"); pixs1 = pixOctreeColorQuant(pix, 200, 0); pixs2 = pixRemoveColormap(pixs1, REMOVE_CMAP_TO_FULL_COLOR); regTestComparePix(rp, pixs1, pixs2); /* 9 */ /* Make a diagonal color transform matrix */ kel = kernelCreate(3, 3); kernelSetElement(kel, 0, 0, 0.7); kernelSetElement(kel, 1, 1, 0.4); kernelSetElement(kel, 2, 2, 1.3); /* Apply to both cmap and rgb images. */ pixt1 = pixMultMatrixColor(pixs1, kel); pixt2 = pixMultMatrixColor(pixs2, kel); regTestComparePix(rp, pixt1, pixt2); /* 10 */ kernelDestroy(&kel); /* Apply the same transform in the simpler interface */ pixt3 = pixMultConstantColor(pixs1, 0.7, 0.4, 1.3); pixt4 = pixMultConstantColor(pixs2, 0.7, 0.4, 1.3); regTestComparePix(rp, pixt3, pixt4); /* 11 */ regTestComparePix(rp, pixt1, pixt3); /* 12 */ regTestWritePixAndCheck(rp, pixt1, IFF_JFIF_JPEG); /* 13 */ pixDestroy(&pix); pixDestroy(&pixs1); pixDestroy(&pixs2); pixDestroy(&pixt1); pixDestroy(&pixt2); pixDestroy(&pixt3); pixDestroy(&pixt4); return regTestCleanup(rp); }
main(int argc, char **argv) { l_int32 i, j, wc, hc, d; L_KERNEL *kel1, *kel2; PIX *pixs, *pixg, *pixacc, *pixd, *pixt; char *filein, *fileout; static char mainName[] = "convolvetest"; if (argc != 5) exit(ERROR_INT(" Syntax: convolvetest filein wc hc fileout", mainName, 1)); filein = argv[1]; wc = atoi(argv[2]); hc = atoi(argv[3]); fileout = argv[4]; if ((pixs = pixRead(filein)) == NULL) exit(ERROR_INT("pix not made", mainName, 1)); #if 0 /* Measure speed */ pixacc = pixBlockconvAccum(pixs); for (i = 0; i < NTIMES; i++) { pixd = pixBlockconvGray(pixs, pixacc, wc, hc); if ((i+1) % 10 == 0) fprintf(stderr, "%d iters\n", i + 1); pixDestroy(&pixd); } pixd = pixBlockconvGray(pixs, pixacc, wc, hc); pixWrite(fileout, pixd, IFF_JFIF_JPEG); pixDestroy(&pixacc); #endif #if 0 /* Test pixBlockconvGray() */ pixacc = pixBlockconvAccum(pixs); pixd = pixBlockconvGray(pixs, pixacc, wc, hc); pixWrite(fileout, pixd, IFF_JFIF_JPEG); pixDestroy(&pixacc); #endif #if 0 /* Test pixBlockconv() */ pixd = pixBlockconv(pixs, wc, hc); pixWrite(fileout, pixd, IFF_JFIF_JPEG); #endif #if 0 /* Test pixBlockrank() */ pixacc = pixBlockconvAccum(pixs); pixd = pixBlockrank(pixs, pixacc, wc, hc, 0.5); pixWrite(fileout, pixd, IFF_TIFF_G4); pixDestroy(&pixacc); #endif #if 0 /* Test pixBlocksum() */ pixacc = pixBlockconvAccum(pixs); pixd = pixBlocksum(pixs, pixacc, wc, hc); pixInvert(pixd, pixd); pixWrite(fileout, pixd, IFF_JFIF_JPEG); pixDestroy(&pixacc); #endif #if 0 /* Test pixCensusTransform() */ d = pixGetDepth(pixs); if (d == 32) pixt = pixConvertRGBToLuminance(pixs); else pixt = pixClone(pixs); pixacc = pixBlockconvAccum(pixt); pixd = pixCensusTransform(pixt, wc, NULL); pixDestroy(&pixt); pixDestroy(&pixacc); pixWrite(fileout, pixd, IFF_PNG); #endif #if 1 /* Test generic convolution with kel1 */ if (pixGetDepth(pixs) == 32) pixg = pixScaleRGBToGrayFast(pixs, 2, COLOR_GREEN); else pixg = pixScale(pixs, 0.5, 0.5); pixDisplay(pixg, 0, 600); kel1 = kernelCreateFromString(5, 5, 2, 2, kdatastr); pixd = pixConvolve(pixg, kel1, 8, 1); pixDisplay(pixd, 700, 0); pixWrite("/tmp/junkpixd4.bmp", pixd, IFF_BMP); pixDestroy(&pixd); kernelDestroy(&kel1); /* Test convolution with flat rectangular kel */ kel2 = kernelCreate(11, 11); kernelSetOrigin(kel2, 5, 5); for (i = 0; i < 11; i++) { for (j = 0; j < 11; j++) kernelSetElement(kel2, i, j, 1); } startTimer(); pixd = pixConvolve(pixg, kel2, 8, 1); fprintf(stderr, "Generic convolution: %7.3f sec\n", stopTimer()); pixDisplay(pixd, 1200, 0); pixWrite("/tmp/junkpixd5.bmp", pixd, IFF_BMP); startTimer(); pixt = pixBlockconv(pixg, 5, 5); fprintf(stderr, "Block convolution: %7.3f sec\n", stopTimer()); pixDisplay(pixd, 1200, 600); pixWrite("/tmp/junkpixd6.bmp", pixt, IFF_BMP); pixCompareGray(pixd, pixt, L_COMPARE_ABS_DIFF, GPLOT_X11, NULL, NULL, NULL, NULL); pixDestroy(&pixg); pixDestroy(&pixt); kernelDestroy(&kel2); #endif pixDestroy(&pixs); pixDestroy(&pixd); return 0; }
int main(int argc, char **argv) { l_int32 i, j, wc, hc, d, bias; L_KERNEL *kel1, *kel2, *kel3x, *kel3y; PIX *pix, *pixs, *pixg, *pixacc, *pixd, *pixt; char *filein, *fileout; static char mainName[] = "convolvetest"; if (argc != 5) return ERROR_INT(" Syntax: convolvetest filein wc hc fileout", mainName, 1); filein = argv[1]; wc = atoi(argv[2]); hc = atoi(argv[3]); fileout = argv[4]; if ((pix = pixRead(filein)) == NULL) return ERROR_INT("pix not made", mainName, 1); d = pixGetDepth(pix); if (d != 1 && d != 8 && d != 32) pixs = pixConvertTo8(pix, 0); else pixs = pixClone(pix); pixDestroy(&pix); d = pixGetDepth(pixs); if (d == 8 && (ALL || 0)) { /* Measure speed */ pixacc = pixBlockconvAccum(pixs); for (i = 0; i < NTIMES; i++) { pixd = pixBlockconvGray(pixs, pixacc, wc, hc); if ((i+1) % 10 == 0) fprintf(stderr, "%d iters\n", i + 1); pixDestroy(&pixd); } pixd = pixBlockconvGray(pixs, pixacc, wc, hc); pixWrite(fileout, pixd, IFF_JFIF_JPEG); pixDestroy(&pixacc); } if (d == 8 && (ALL || 0)) { /* Test pixBlockconvGray() */ pixacc = pixBlockconvAccum(pixs); pixd = pixBlockconvGray(pixs, pixacc, wc, hc); pixWrite(fileout, pixd, IFF_JFIF_JPEG); pixDestroy(&pixacc); } if (ALL || 0) { /* Test pixBlockconv() */ pixd = pixBlockconv(pixs, wc, hc); pixWrite(fileout, pixd, IFF_JFIF_JPEG); } if (d == 1 && (ALL || 0)) { /* Test pixBlockrank() */ pixacc = pixBlockconvAccum(pixs); pixd = pixBlockrank(pixs, pixacc, wc, hc, 0.5); pixWrite(fileout, pixd, IFF_TIFF_G4); pixDestroy(&pixacc); } if (d == 1 && (ALL || 0)) { /* Test pixBlocksum() */ pixacc = pixBlockconvAccum(pixs); pixd = pixBlocksum(pixs, pixacc, wc, hc); pixInvert(pixd, pixd); pixWrite(fileout, pixd, IFF_JFIF_JPEG); pixDestroy(&pixacc); } if (ALL || 0) { /* Test pixCensusTransform() */ d = pixGetDepth(pixs); if (d == 32) pixt = pixConvertRGBToLuminance(pixs); else pixt = pixClone(pixs); pixacc = pixBlockconvAccum(pixt); pixd = pixCensusTransform(pixt, wc, NULL); pixDestroy(&pixt); pixDestroy(&pixacc); pixWrite(fileout, pixd, IFF_PNG); } if (ALL || 0) { /* Test generic convolution with kel1 */ lept_mkdir("lept"); if (pixGetDepth(pixs) == 32) pixg = pixScaleRGBToGrayFast(pixs, 2, COLOR_GREEN); else pixg = pixScale(pixs, 0.5, 0.5); pixDisplay(pixg, 0, 600); kel1 = kernelCreateFromString(5, 5, 2, 2, kel1str); pixd = pixConvolve(pixg, kel1, 8, 1); pixDisplay(pixd, 700, 0); pixWrite("/tmp/lept/convol_d4.bmp", pixd, IFF_BMP); pixDestroy(&pixd); kernelDestroy(&kel1); /* Test convolution with flat rectangular kel */ kel2 = kernelCreate(11, 11); kernelSetOrigin(kel2, 5, 5); for (i = 0; i < 11; i++) { for (j = 0; j < 11; j++) kernelSetElement(kel2, i, j, 1); } startTimer(); pixd = pixConvolve(pixg, kel2, 8, 1); fprintf(stderr, "Generic convolution: %7.3f sec\n", stopTimer()); pixDisplay(pixd, 1200, 0); pixWrite("/tmp/lept/convol_d5.bmp", pixd, IFF_BMP); startTimer(); pixt = pixBlockconv(pixg, 5, 5); fprintf(stderr, "Block convolution: %7.3f sec\n", stopTimer()); pixDisplay(pixd, 1200, 600); pixWrite("/tmp/lept/convol_d6.bmp", pixt, IFF_BMP); pixCompareGray(pixd, pixt, L_COMPARE_ABS_DIFF, GPLOT_X11, NULL, NULL, NULL, NULL); pixDestroy(&pixg); pixDestroy(&pixt); kernelDestroy(&kel2); } if (ALL || 0) { /* Test bias convolution with kel2 */ if (pixGetDepth(pixs) == 32) pixg = pixScaleRGBToGrayFast(pixs, 2, COLOR_GREEN); else pixg = pixScale(pixs, 0.5, 0.5); pixDisplay(pixg, 0, 600); kel2 = kernelCreateFromString(5, 5, 2, 2, kel2str); pixd = pixConvolveWithBias(pixg, kel2, NULL, TRUE, &bias); pixDisplay(pixd, 700, 0); fprintf(stderr, "bias = %d\n", bias); pixWrite("/tmp/lept/convol_d6.png", pixd, IFF_PNG); pixDestroy(&pixg); kernelDestroy(&kel2); pixDestroy(&pixd); } if (ALL || 1) { /* Test separable bias convolution with kel3x, kel3y */ if (pixGetDepth(pixs) == 32) pixg = pixScaleRGBToGrayFast(pixs, 2, COLOR_GREEN); else pixg = pixScale(pixs, 0.5, 0.5); pixDisplay(pixg, 0, 600); kel3x = kernelCreateFromString(1, 5, 0, 2, kel3xstr); kel3y = kernelCreateFromString(7, 1, 3, 0, kel3ystr); pixd = pixConvolveWithBias(pixg, kel3x, kel3y, TRUE, &bias); pixDisplay(pixd, 700, 0); fprintf(stderr, "bias = %d\n", bias); pixWrite("/tmp/lept/convol_d7.png", pixd, IFF_PNG); pixDestroy(&pixg); kernelDestroy(&kel3x); kernelDestroy(&kel3y); pixDestroy(&pixd); } pixDestroy(&pixs); return 0; }