static void DisplayMapHistogram(L_AMAP *m, PIXCMAP *cmap, const char *rootname) { l_int32 i, n, ival; l_uint32 val32; NUMA *na; RB_TYPE key; RB_TYPE *pval; n = pixcmapGetCount(cmap); na = numaCreate(n); for (i = 0; i < n; i++) { pixcmapGetColor32(cmap, i, &val32); key.utype = val32; pval = l_amapFind(m, key); if (pval) { ival = pval->itype; numaAddNumber(na, ival); } } /* numaWrite("/tmp/lept/map/map.na", na); */ gplotSimple1(na, GPLOT_X11, rootname, NULL); numaDestroy(&na); return; }
static void DisplayMapHistogram(L_AMAP *m, PIXCMAP *cmap, const char *rootname) { char buf[128]; l_int32 i, n, ival; l_uint32 val32; NUMA *na; RB_TYPE key; RB_TYPE *pval; n = pixcmapGetCount(cmap); na = numaCreate(n); for (i = 0; i < n; i++) { pixcmapGetColor32(cmap, i, &val32); key.utype = val32; pval = l_amapFind(m, key); if (pval) { ival = pval->itype; numaAddNumber(na, ival); } } gplotSimple1(na, GPLOT_PNG, rootname, NULL); snprintf(buf, sizeof(buf), "%s.png", rootname); l_fileDisplay(buf, 700, 0, 1.0); numaDestroy(&na); return; }
/*! * \brief pixColorSegmentClean() * * \param[in] pixs 8 bpp, colormapped * \param[in] selsize for closing * \param[in] countarray ptr to array containing the number of pixels * found in each color in the colormap * \return 0 if OK, 1 on error * * <pre> * Notes: * (1) This operation is in-place. * (2) This is phase 3 of color segmentation. It is the first * part of a two-step noise removal process. Colors with a * large population are closed first; this operation absorbs * small sets of intercolated pixels of a different color. * </pre> */ l_ok pixColorSegmentClean(PIX *pixs, l_int32 selsize, l_int32 *countarray) { l_int32 i, ncolors, val; l_uint32 val32; NUMA *na, *nasi; PIX *pixt1, *pixt2; PIXCMAP *cmap; PROCNAME("pixColorSegmentClean"); if (!pixs) return ERROR_INT("pixs not defined", procName, 1); if (pixGetDepth(pixs) != 8) return ERROR_INT("pixs not 8 bpp", procName, 1); if ((cmap = pixGetColormap(pixs)) == NULL) return ERROR_INT("cmap not found", procName, 1); if (!countarray) return ERROR_INT("countarray not defined", procName, 1); if (selsize <= 1) return 0; /* nothing to do */ /* Sort colormap indices in decreasing order of pixel population */ ncolors = pixcmapGetCount(cmap); na = numaCreate(ncolors); for (i = 0; i < ncolors; i++) numaAddNumber(na, countarray[i]); nasi = numaGetSortIndex(na, L_SORT_DECREASING); numaDestroy(&na); if (!nasi) return ERROR_INT("nasi not made", procName, 1); /* For each color, in order of decreasing population, * do a closing and absorb the added pixels. Note that * if the closing removes pixels at the border, they'll * still appear in the xor and will be properly (re)set. */ for (i = 0; i < ncolors; i++) { numaGetIValue(nasi, i, &val); pixt1 = pixGenerateMaskByValue(pixs, val, 1); pixt2 = pixCloseSafeCompBrick(NULL, pixt1, selsize, selsize); pixXor(pixt2, pixt2, pixt1); /* pixels to be added to type 'val' */ pixcmapGetColor32(cmap, val, &val32); pixSetMasked(pixs, pixt2, val32); /* add them */ pixDestroy(&pixt1); pixDestroy(&pixt2); } numaDestroy(&nasi); return 0; }
static L_AMAP * BuildMapHistogram(PIX *pix, l_int32 factor, l_int32 print) { l_int32 i, j, w, h, wpl, val; l_uint32 val32; l_uint32 *data, *line; L_AMAP *m; PIXCMAP *cmap; RB_TYPE key, value; RB_TYPE *pval; fprintf(stderr, "\n --------------- Begin building map --------------\n"); m = l_amapCreate(L_UINT_TYPE); data = pixGetData(pix); wpl = pixGetWpl(pix); cmap = pixGetColormap(pix); pixGetDimensions(pix, &w, &h, NULL); for (i = 0; i < h; i += factor) { line = data + i * wpl; for (j = 0; j < w; j += factor) { val = GET_DATA_BYTE(line, j); pixcmapGetColor32(cmap, val, &val32); key.utype = val32; pval = l_amapFind(m, key); if (!pval) value.itype = 1; else value.itype = 1 + pval->itype; if (print) { fprintf(stderr, "key = %llx, val = %lld\n", key.utype, value.itype); } l_amapInsert(m, key, value); } } fprintf(stderr, "Size: %d\n", l_amapSize(m)); if (print) l_rbtreePrint(stderr, m); fprintf(stderr, " ----------- End Building map -----------------\n"); return m; }
static L_ASET * BuildSet(PIX *pix, l_int32 factor, l_int32 print) { l_int32 i, j, w, h, wpl, val; l_uint32 val32; l_uint32 *data, *line; L_ASET *s; PIXCMAP *cmap; RB_TYPE key; RB_TYPE *pval; fprintf(stderr, "\n --------------- Begin building set --------------\n"); s = l_asetCreate(L_UINT_TYPE); data = pixGetData(pix); wpl = pixGetWpl(pix); cmap = pixGetColormap(pix); pixGetDimensions(pix, &w, &h, NULL); for (i = 0; i < h; i += factor) { line = data + i * wpl; for (j = 0; j < w; j += factor) { if (cmap) { val = GET_DATA_BYTE(line, j); pixcmapGetColor32(cmap, val, &val32); key.utype = val32; } else { key.utype = line[j]; } pval = l_asetFind(s, key); if (pval && print) fprintf(stderr, "key = %llx\n", key.utype); l_asetInsert(s, key); } } fprintf(stderr, "Size: %d\n", l_asetSize(s)); if (print) l_rbtreePrint(stderr, s); fprintf(stderr, " ----------- End Building set -----------------\n"); return s; }
l_int32 main(int argc, char **argv) { l_int32 i, n, w, h, val; l_uint32 val32; L_AMAP *m; NUMA *na; PIX *pix; PIXCMAP *cmap; RB_TYPE key, value; RB_TYPE *pval; lept_mkdir("lept/map"); pix = pixRead("weasel8.240c.png"); pixGetDimensions(pix, &w, &h, NULL); fprintf(stderr, "Image area in pixels: %d\n", w * h); cmap = pixGetColormap(pix); /* Build the histogram, stored in a map. Then compute * and display the histogram as the number of pixels vs * the colormap index */ m = BuildMapHistogram(pix, 1, FALSE); TestMapIterator1(m, FALSE); TestMapIterator2(m, FALSE); DisplayMapHistogram(m, cmap, "/tmp/lept/map/map1"); l_amapDestroy(&m); /* Ditto, but just with a few pixels */ m = BuildMapHistogram(pix, 14, TRUE); DisplayMapHistogram(m, cmap, "/tmp/lept/map/map2"); l_amapDestroy(&m); /* Do in-order tranversals, using the iterators */ m = BuildMapHistogram(pix, 7, FALSE); TestMapIterator1(m, TRUE); TestMapIterator2(m, TRUE); l_amapDestroy(&m); /* Do in-order tranversals, with iterators and destroying the map */ m = BuildMapHistogram(pix, 7, FALSE); TestMapIterator3(m, TRUE); lept_free(m); m = BuildMapHistogram(pix, 7, FALSE); TestMapIterator4(m, TRUE); lept_free(m); /* Do in-order tranversals, with iterators and reversing the map */ m = BuildMapHistogram(pix, 7, FALSE); TestMapIterator5(m, TRUE); l_amapDestroy(&m); /* Build a histogram the old-fashioned way */ na = pixGetCmapHistogram(pix, 1); numaWrite("/tmp/lept/map/map2.na", na); gplotSimple1(na, GPLOT_X11, "/tmp/lept/map/map1", NULL); numaDestroy(&na); /* Build a separate map from (rgb) --> colormap index ... */ m = l_amapCreate(L_UINT_TYPE); n = pixcmapGetCount(cmap); for (i = 0; i < n; i++) { pixcmapGetColor32(cmap, i, &val32); key.utype = val32; value.itype = i; l_amapInsert(m, key, value); } /* ... and test the map */ for (i = 0; i < n; i++) { pixcmapGetColor32(cmap, i, &val32); key.utype = val32; pval = l_amapFind(m, key); if (i != pval->itype) fprintf(stderr, "i = %d != val = %llx\n", i, pval->itype); } l_amapDestroy(&m); pixDestroy(&pix); return 0; }
/*! * \brief pixColorSegmentRemoveColors() * * \param[in] pixd 8 bpp, colormapped * \param[in] pixs 32 bpp rgb, with initial pixel values * \param[in] finalcolors max number of colors to retain * \return 0 if OK, 1 on error * * <pre> * Notes: * (1) This operation is in-place. * (2) This is phase 4 of color segmentation, and the second part * of the 2-step noise removal. Only 'finalcolors' different * colors are retained, with colors with smaller populations * being replaced by the nearest color of the remaining colors. * For highest accuracy, for pixels that are being replaced, * we find the nearest colormap color to the original rgb color. * </pre> */ l_ok pixColorSegmentRemoveColors(PIX *pixd, PIX *pixs, l_int32 finalcolors) { l_int32 i, ncolors, index, tempindex; l_int32 *tab; l_uint32 tempcolor; NUMA *na, *nasi; PIX *pixm; PIXCMAP *cmap; PROCNAME("pixColorSegmentRemoveColors"); if (!pixd) return ERROR_INT("pixd not defined", procName, 1); if (pixGetDepth(pixd) != 8) return ERROR_INT("pixd not 8 bpp", procName, 1); if ((cmap = pixGetColormap(pixd)) == NULL) return ERROR_INT("cmap not found", procName, 1); if (!pixs) return ERROR_INT("pixs not defined", procName, 1); ncolors = pixcmapGetCount(cmap); if (finalcolors >= ncolors) /* few enough colors already; nothing to do */ return 0; /* Generate a mask over all pixels that are not in the * 'finalcolors' most populated colors. Save the colormap * index of any one of the retained colors in 'tempindex'. * The LUT has values 0 for the 'finalcolors' most populated colors, * which will be retained; and 1 for the rest, which are marked * by fg pixels in pixm and will be removed. */ na = pixGetCmapHistogram(pixd, 1); if ((nasi = numaGetSortIndex(na, L_SORT_DECREASING)) == NULL) { numaDestroy(&na); return ERROR_INT("nasi not made", procName, 1); } numaGetIValue(nasi, finalcolors - 1, &tempindex); /* retain down to this */ pixcmapGetColor32(cmap, tempindex, &tempcolor); /* use this color */ tab = (l_int32 *)LEPT_CALLOC(256, sizeof(l_int32)); for (i = finalcolors; i < ncolors; i++) { numaGetIValue(nasi, i, &index); tab[index] = 1; } pixm = pixMakeMaskFromLUT(pixd, tab); LEPT_FREE(tab); /* Reassign the masked pixels temporarily to the saved index * (tempindex). This guarantees that no pixels are labeled by * a colormap index of any colors that will be removed. * The actual value doesn't matter, as long as it's one * of the retained colors, because these pixels will later * be reassigned based on the full set of colors retained * in the colormap. */ pixSetMasked(pixd, pixm, tempcolor); /* Now remove unused colors from the colormap. This reassigns * image pixels as required. */ pixRemoveUnusedColors(pixd); /* Finally, reassign the pixels under the mask (those that were * given a 'tempindex' value) to the nearest color in the colormap. * This is the function used in phase 2 on all image pixels; here * it is only used on the masked pixels given by pixm. */ pixAssignToNearestColor(pixd, pixs, pixm, LEVEL_IN_OCTCUBE, NULL); pixDestroy(&pixm); numaDestroy(&na); numaDestroy(&nasi); return 0; }