static l_int32 GenerateSplitPlot(l_int32 i) { char title[256]; l_int32 split; l_float32 ave1, ave2, num1, num2, maxnum, maxscore; GPLOT *gplot; NUMA *na1, *na2, *nascore, *nax, *nay; PIX *pixs, *pixd; /* Generate */ na1 = MakeGaussian(gaussmean1[i], gaussstdev1[i], gaussfract1[i]); na2 = MakeGaussian(gaussmean2[i], gaussstdev1[i], 1.0 - gaussfract1[i]); numaArithOp(na1, na1, na2, L_ARITH_ADD); /* Otsu splitting */ numaSplitDistribution(na1, 0.08, &split, &ave1, &ave2, &num1, &num2, &nascore); fprintf(stderr, "split = %d, ave1 = %6.1f, ave2 = %6.1f\n", split, ave1, ave2); fprintf(stderr, "num1 = %8.0f, num2 = %8.0f\n", num1, num2); /* Prepare for plotting a vertical line at the split point */ nax = numaMakeConstant(split, 2); numaGetMax(na1, &maxnum, NULL); nay = numaMakeConstant(0, 2); numaReplaceNumber(nay, 1, (l_int32)(0.5 * maxnum)); /* Plot the input histogram with the split location */ sprintf(buf, "/tmp/junkplot.%d", i); sprintf(title, "Plot %d", i); gplot = gplotCreate(buf, GPLOT_PNG, "Histogram: mixture of 2 gaussians", "Grayscale value", "Number of pixels"); gplotAddPlot(gplot, NULL, na1, GPLOT_LINES, title); gplotAddPlot(gplot, nax, nay, GPLOT_LINES, NULL); gplotMakeOutput(gplot); gplotDestroy(&gplot); numaDestroy(&na1); numaDestroy(&na2); /* Plot the score function */ sprintf(buf, "/tmp/junkplots.%d", i); sprintf(title, "Plot %d", i); gplot = gplotCreate(buf, GPLOT_PNG, "Otsu score function for splitting", "Grayscale value", "Score"); gplotAddPlot(gplot, NULL, nascore, GPLOT_LINES, title); numaGetMax(nascore, &maxscore, NULL); numaReplaceNumber(nay, 1, maxscore); gplotAddPlot(gplot, nax, nay, GPLOT_LINES, NULL); gplotMakeOutput(gplot); gplotDestroy(&gplot); numaDestroy(&nax); numaDestroy(&nay); numaDestroy(&nascore); return 0; }
/*! * boxaEqual() * * Input: boxa1 * boxa2 * maxdist * &naindex (<optional return> index array of correspondences * &same (<return> 1 if equal; 0 otherwise) * Return 0 if OK, 1 on error * * Notes: * (1) The two boxa are the "same" if they contain the same * boxes and each box is within @maxdist of its counterpart * in their positions within the boxa. This allows for * small rearrangements. Use 0 for maxdist if the boxa * must be identical. * (2) This applies only to geometry and ordering; refcounts * are not considered. * (3) @maxdist allows some latitude in the ordering of the boxes. * For the boxa to be the "same", corresponding boxes must * be within @maxdist of each other. Note that for large * @maxdist, we should use a hash function for efficiency. * (4) naindex[i] gives the position of the box in boxa2 that * corresponds to box i in boxa1. It is only returned if the * boxa are equal. */ l_int32 boxaEqual(BOXA *boxa1, BOXA *boxa2, l_int32 maxdist, NUMA **pnaindex, l_int32 *psame) { l_int32 i, j, n, jstart, jend, found, samebox; l_int32 *countarray; BOX *box1, *box2; NUMA *na; PROCNAME("boxaEqual"); if (pnaindex) *pnaindex = NULL; if (!psame) return ERROR_INT("&same not defined", procName, 1); *psame = 0; if (!boxa1 || !boxa2) return ERROR_INT("boxa1 and boxa2 not both defined", procName, 1); n = boxaGetCount(boxa1); if (n != boxaGetCount(boxa2)) return 0; countarray = (l_int32 *)CALLOC(n, sizeof(l_int32)); na = numaMakeConstant(0.0, n); for (i = 0; i < n; i++) { box1 = boxaGetBox(boxa1, i, L_CLONE); jstart = L_MAX(0, i - maxdist); jend = L_MIN(n-1, i + maxdist); found = FALSE; for (j = jstart; j <= jend; j++) { box2 = boxaGetBox(boxa2, j, L_CLONE); boxEqual(box1, box2, &samebox); if (samebox && countarray[j] == 0) { countarray[j] = 1; numaReplaceNumber(na, i, j); found = TRUE; boxDestroy(&box2); break; } boxDestroy(&box2); } boxDestroy(&box1); if (!found) { numaDestroy(&na); FREE(countarray); return 0; } } *psame = 1; if (pnaindex) *pnaindex = na; else numaDestroy(&na); FREE(countarray); return 0; }
main(int argc, char **argv) { char fname[256]; l_int32 i, w, h, nbins, factor, success, display; l_int32 spike; l_uint32 *array, *marray; FILE *fp; NUMA *na, *nan, *nai, *narbin; PIX *pixs, *pixt, *pixd; PIXA *pixa; if (regTestSetup(argc, argv, &fp, &display, &success, NULL)) return 1; /* Find the rank bin colors */ pixs = pixRead("map1.jpg"); pixGetDimensions(pixs, &w, &h, NULL); factor = L_MAX(1, (l_int32)sqrt((l_float64)(w * h / 20000.0))); nbins = 10; pixGetRankColorArray(pixs, nbins, L_SELECT_MIN, factor, &array, 2); for (i = 0; i < nbins; i++) fprintf(stderr, "%d: %x\n", i, array[i]); pixd = pixDisplayColorArray(array, nbins, 200, 5, 1); pixWrite("/tmp/rankhisto.0.png", pixd, IFF_PNG); regTestCheckFile(fp, argv, "/tmp/rankhisto.0.png", 0, &success); pixDisplayWithTitle(pixd, 100, 100, NULL, display); pixDestroy(&pixd); /* Modify the rank bin colors by mapping them such * that the lightest color is mapped to white */ marray = (l_uint32 *)CALLOC(nbins, sizeof(l_uint32)); for (i = 0; i < nbins; i++) pixelLinearMapToTargetColor(array[i], array[nbins - 1], 0xffffff00, &marray[i]); pixd = pixDisplayColorArray(marray, nbins, 200, 5, 1); pixWrite("/tmp/rankhisto.1.png", pixd, IFF_PNG); regTestCheckFile(fp, argv, "/tmp/rankhisto.1.png", 1, &success); pixDisplayWithTitle(pixd, 100, 600, NULL, display); pixDestroy(&pixd); FREE(marray); /* Save the histogram plots */ #ifndef _WIN32 sleep(2); /* give gnuplot time to write out the files */ #else Sleep(2000); #endif /* _WIN32 */ pixa = PixSavePlots1(); pixd = pixaDisplay(pixa, 0, 0); pixWrite("/tmp/rankhisto.2.png", pixd, IFF_PNG); regTestCheckFile(fp, argv, "/tmp/rankhisto.2.png", 2, &success); pixDisplayWithTitle(pixd, 100, 600, NULL, display); pixaDestroy(&pixa); pixDestroy(&pixd); /* Map to the lightest bin; then do TRC adjustment */ pixt = pixLinearMapToTargetColor(NULL, pixs, array[nbins - 1], 0xffffff00); pixd = pixGammaTRC(NULL, pixt, 1.0, 0, 240); pixWrite("/tmp/rankhisto.3.png", pixd, IFF_PNG); regTestCheckFile(fp, argv, "/tmp/rankhisto.3.png", 3, &success); pixDisplayWithTitle(pixd, 600, 100, NULL, display); pixDestroy(&pixt); pixDestroy(&pixd); /* Now test the edge cases for the histogram and rank LUT, * where all the histo data is piled up at one place. * We only require that the result be sensible. */ for (i = 0; i < 3; i++) { if (i == 0) spike = 0; else if (i == 1) spike = 50; else spike = 99; na = numaMakeConstant(0, 100); numaReplaceNumber(na, spike, 200.0); nan = numaNormalizeHistogram(na, 1.0); numaDiscretizeRankAndIntensity(nan, 10, &narbin, &nai, NULL, NULL); snprintf(fname, sizeof(fname), "/tmp/rtnan%d", i + 1); gplotSimple1(nan, GPLOT_PNG, fname, "Normalized Histogram"); snprintf(fname, sizeof(fname), "/tmp/rtnai%d", i + 1); gplotSimple1(nai, GPLOT_PNG, fname, "Intensity vs. rank bin"); snprintf(fname, sizeof(fname), "/tmp/rtnarbin%d", i + 1); gplotSimple1(narbin, GPLOT_PNG, fname, "LUT: rank bin vs. Intensity"); numaDestroy(&na); numaDestroy(&nan); numaDestroy(&narbin); numaDestroy(&nai); } #ifndef _WIN32 sleep(2); /* give gnuplot time to write out the files */ #else Sleep(2000); #endif /* _WIN32 */ pixa = PixSavePlots2(); pixd = pixaDisplay(pixa, 0, 0); pixWrite("/tmp/rankhisto.4.png", pixd, IFF_PNG); regTestCheckFile(fp, argv, "/tmp/rankhisto.4.png", 4, &success); pixDisplayWithTitle(pixd, 500, 600, NULL, display); pixaDestroy(&pixa); pixDestroy(&pixd); pixDestroy(&pixs); FREE(array); regTestCleanup(argc, argv, fp, success, NULL); return 0; }
/*! * dewarpaInsertRefModels() * * Input: dewa * notests (if 1, ignore curvature constraints on model) * debug (1 to output information on invalid page models) * Return: 0 if OK, 1 on error * * Notes: * (1) This destroys all dewarp models that are invalid, and then * inserts reference models where possible. * (2) If @notests == 1, this ignores the curvature constraints * and assumes that all successfully built models are valid. * (3) If useboth == 0, it uses the closest valid model within the * distance and parity constraints. If useboth == 1, it tries * to use the closest allowed hvalid model; if it doesn't find * an hvalid model, it uses the closest valid model. * (4) For all pages without a model, this clears out any existing * invalid and reference dewarps, finds the nearest valid model * with the same parity, and inserts an empty dewarp with the * reference page. * (5) Then if it is requested to use both vertical and horizontal * disparity arrays (useboth == 1), it tries to replace any * hvalid == 0 model or reference with an hvalid == 1 reference. * (6) The distance constraint is that any reference model must * be within maxdist. Note that with the parity constraint, * no reference models will be used if maxdist < 2. * (7) This function must be called, even if reference models will * not be used. It should be called after building models on all * available pages, and after setting the rendering parameters. * (8) If the dewa has been serialized, this function is called by * dewarpaRead() when it is read back. It is also called * any time the rendering parameters are changed. * (9) Note: if this has been called with useboth == 1, and useboth * is reset to 0, you should first call dewarpRestoreModels() * to bring real models from the cache back to the primary array. */ l_int32 dewarpaInsertRefModels(L_DEWARPA *dewa, l_int32 notests, l_int32 debug) { l_int32 i, j, n, val, min, distdown, distup; L_DEWARP *dew; NUMA *na, *nah; PROCNAME("dewarpaInsertRefModels"); if (!dewa) return ERROR_INT("dewa not defined", procName, 1); if (dewa->maxdist < 2) L_INFO("maxdist < 2; no ref models can be used\n", procName); /* Make an indicator numa for pages with valid models. */ dewarpaSetValidModels(dewa, notests, debug); n = dewa->maxpage + 1; na = numaMakeConstant(0, n); for (i = 0; i < n; i++) { dew = dewarpaGetDewarp(dewa, i); if (dew && dew->vvalid) numaReplaceNumber(na, i, 1); } /* Remove all existing ref models and restore models from cache */ dewarpaRestoreModels(dewa); /* Move invalid models to the cache, and insert reference dewarps * for pages that need to borrow a model. * First, try to find a valid model for each page. */ for (i = 0; i < n; i++) { numaGetIValue(na, i, &val); if (val == 1) continue; /* already has a valid model */ if ((dew = dewa->dewarp[i]) != NULL) { /* exists but is not valid; */ dewa->dewarpcache[i] = dew; /* move it to the cache */ dewa->dewarp[i] = NULL; } if (dewa->maxdist < 2) continue; /* can't use a ref model */ /* Look back for nearest model */ distdown = distup = dewa->maxdist + 1; for (j = i - 2; j >= 0 && distdown > dewa->maxdist; j -= 2) { numaGetIValue(na, j, &val); if (val == 1) distdown = i - j; } /* Look ahead for nearest model */ for (j = i + 2; j < n && distup > dewa->maxdist; j += 2) { numaGetIValue(na, j, &val); if (val == 1) distup = j - i; } min = L_MIN(distdown, distup); if (min > dewa->maxdist) continue; /* no valid model in range */ if (distdown <= distup) dewarpaInsertDewarp(dewa, dewarpCreateRef(i, i - distdown)); else dewarpaInsertDewarp(dewa, dewarpCreateRef(i, i + distup)); } numaDestroy(&na); /* If a valid model will do, we're finished. */ if (dewa->useboth == 0) { dewa->modelsready = 1; /* validated */ return 0; } /* The request is useboth == 1. Now try to find an hvalid model */ nah = numaMakeConstant(0, n); for (i = 0; i < n; i++) { dew = dewarpaGetDewarp(dewa, i); if (dew && dew->hvalid) numaReplaceNumber(nah, i, 1); } for (i = 0; i < n; i++) { numaGetIValue(nah, i, &val); if (val == 1) continue; /* already has a hvalid model */ if (dewa->maxdist < 2) continue; /* can't use a ref model */ distdown = distup = 100000; for (j = i - 2; j >= 0; j -= 2) { /* look back for nearest model */ numaGetIValue(nah, j, &val); if (val == 1) { distdown = i - j; break; } } for (j = i + 2; j < n; j += 2) { /* look ahead for nearest model */ numaGetIValue(nah, j, &val); if (val == 1) { distup = j - i; break; } } min = L_MIN(distdown, distup); if (min > dewa->maxdist) continue; /* no hvalid model within range */ /* We can replace the existing valid model with an hvalid model. * If it's not a reference, save it in the cache. */ if ((dew = dewarpaGetDewarp(dewa, i)) == NULL) { L_ERROR("dew is null for page %d!\n", procName, i); } else { if (dew->hasref == 0) { /* not a ref model */ dewa->dewarpcache[i] = dew; /* move it to the cache */ dewa->dewarp[i] = NULL; /* must null the ptr */ } } if (distdown <= distup) /* insert the hvalid ref model */ dewarpaInsertDewarp(dewa, dewarpCreateRef(i, i - distdown)); else dewarpaInsertDewarp(dewa, dewarpCreateRef(i, i + distup)); } numaDestroy(&nah); dewa->modelsready = 1; /* validated */ return 0; }