main(int argc, char **argv) { l_int32 same; l_uint32 *rtab, *gtab, *btab; l_int32 *cmaptab; BOX *box; PIX *pixs, *pixt1, *pixt2, *pixt3, *pixt4; PIXCMAP *cmap; static char mainName[] = "cmapquant_reg"; pixs = pixRead("lucasta-frag.jpg"); if (argc != 1) exit(ERROR_INT("syntax: cmapquant_req", mainName, 1)); /* Convert to 4 bpp with 6 levels and a colormap */ pixt1 = pixThresholdTo4bpp(pixs, 6, 1); /* Color some non-white pixels, preserving antialiasing, and * adding these colors to the colormap */ box = boxCreate(120, 30, 200, 200); pixColorGray(pixt1, box, L_PAINT_DARK, 220, 0, 0, 255); pixDisplayWrite(pixt1, 1); boxDestroy(&box); /* Scale up by 1.5; losing the colormap */ startTimer(); pixt2 = pixScale(pixt1, 1.5, 1.5); fprintf(stderr, "Time to scale by 1.5x = %7.3f sec\n", stopTimer()); pixDisplayWrite(pixt2, 1); /* Re-quantize using the same colormap */ startTimer(); cmap = pixGetColormap(pixt1); pixt3 = pixOctcubeQuantFromCmap(pixt2, cmap, MIN_DEPTH, LEVEL, L_EUCLIDEAN_DISTANCE); fprintf(stderr, "Time to requantize to cmap = %7.3f sec\n", stopTimer()); pixDisplayWrite(pixt3, 1); /* Re-quantize first making the tables and then * using the lower-level function */ startTimer(); makeRGBToIndexTables(&rtab, >ab, &btab, LEVEL); cmaptab = pixcmapToOctcubeLUT(cmap, LEVEL, L_EUCLIDEAN_DISTANCE); fprintf(stderr, "Time to make tables = %7.3f sec\n", stopTimer()); startTimer(); pixt4 = pixOctcubeQuantFromCmapLUT(pixt2, cmap, MIN_DEPTH, cmaptab, rtab, gtab, btab); fprintf(stderr, "Time for lowlevel re-quant = %7.3f sec\n", stopTimer()); pixDisplayWrite(pixt4, 1); pixEqual(pixt3, pixt4, &same); if (same) fprintf(stderr, "Correct: images are the same\n"); else fprintf(stderr, "Error: images differ\n"); FREE(cmaptab); FREE(rtab); FREE(gtab); FREE(btab); pixDisplayMultiple("/tmp/junk_write_display*"); pixDestroy(&pixs); pixDestroy(&pixt1); pixDestroy(&pixt2); pixDestroy(&pixt3); pixDestroy(&pixt4); return 0; }
/*! * \brief pixAssignToNearestColor() * * \param[in] pixd 8 bpp, colormapped * \param[in] pixs 32 bpp; 24-bit color * \param[in] pixm [optional] 1 bpp * \param[in] level of octcube used for finding nearest color in cmap * \param[in] countarray [optional] ptr to array, in which we can store * the number of pixels found in each color in * the colormap in pixd * \return 0 if OK, 1 on error * * <pre> * Notes: * (1) This is used in phase 2 of color segmentation, where pixs * is the original input image to pixColorSegment(), and * pixd is the colormapped image returned from * pixColorSegmentCluster(). It is also used, with a mask, * in phase 4. * (2) This is an in-place operation. * (3) The colormap in pixd is unchanged. * (4) pixs and pixd must be the same size (w, h). * (5) The selection mask pixm can be null. If it exists, it must * be the same size as pixs and pixd, and only pixels * corresponding to fg in pixm are assigned. Set to * NULL if all pixels in pixd are to be assigned. * (6) The countarray can be null. If it exists, it is pre-allocated * and of a size at least equal to the size of the colormap in pixd. * (7) This does a best-fit (non-greedy) assignment of pixels to * existing clusters. Specifically, it assigns each pixel * in pixd to the color index in the pixd colormap that has a * color closest to the corresponding rgb pixel in pixs. * (8) 'level' is the octcube level used to quickly find the nearest * color in the colormap for each pixel. For color segmentation, * this parameter is set to LEVEL_IN_OCTCUBE. * (9) We build a mapping table from octcube to colormap index so * that this function can run in a time (otherwise) independent * of the number of colors in the colormap. This avoids a * brute-force search for the closest colormap color to each * pixel in the image. * </pre> */ l_ok pixAssignToNearestColor(PIX *pixd, PIX *pixs, PIX *pixm, l_int32 level, l_int32 *countarray) { l_int32 w, h, wpls, wpld, wplm, i, j, success; l_int32 rval, gval, bval, index; l_int32 *cmaptab; l_uint32 octindex; l_uint32 *rtab, *gtab, *btab; l_uint32 *ppixel; l_uint32 *datas, *datad, *datam, *lines, *lined, *linem; PIXCMAP *cmap; PROCNAME("pixAssignToNearestColor"); if (!pixd) return ERROR_INT("pixd not defined", 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); if (pixGetDepth(pixs) != 32) return ERROR_INT("pixs not 32 bpp", procName, 1); if (level < 1 || level > 6) return ERROR_INT("level not in [1 ... 6]", procName, 1); /* Set up the tables to map rgb to the nearest colormap index */ success = TRUE; makeRGBToIndexTables(&rtab, >ab, &btab, level); cmaptab = pixcmapToOctcubeLUT(cmap, level, L_MANHATTAN_DISTANCE); if (!rtab || !gtab || !btab || !cmaptab) { L_ERROR("failure to make a table\n", procName); success = FALSE; goto cleanup_arrays; } pixGetDimensions(pixs, &w, &h, NULL); datas = pixGetData(pixs); datad = pixGetData(pixd); wpls = pixGetWpl(pixs); wpld = pixGetWpl(pixd); if (pixm) { datam = pixGetData(pixm); wplm = pixGetWpl(pixm); } for (i = 0; i < h; i++) { lines = datas + i * wpls; lined = datad + i * wpld; if (pixm) linem = datam + i * wplm; for (j = 0; j < w; j++) { if (pixm) { if (!GET_DATA_BIT(linem, j)) continue; } ppixel = lines + j; rval = GET_DATA_BYTE(ppixel, COLOR_RED); gval = GET_DATA_BYTE(ppixel, COLOR_GREEN); bval = GET_DATA_BYTE(ppixel, COLOR_BLUE); /* Map from rgb to octcube index */ getOctcubeIndexFromRGB(rval, gval, bval, rtab, gtab, btab, &octindex); /* Map from octcube index to nearest colormap index */ index = cmaptab[octindex]; if (countarray) countarray[index]++; SET_DATA_BYTE(lined, j, index); } } cleanup_arrays: LEPT_FREE(cmaptab); LEPT_FREE(rtab); LEPT_FREE(gtab); LEPT_FREE(btab); return (success) ? 0 : 1; }
/*! * pixAssignToNearestColor() * * Input: pixd (8 bpp, colormapped) * pixs (32 bpp; 24-bit color) * pixm (<optional> 1 bpp) * level (of octcube used for finding nearest color in cmap) * countarray (<optional> ptr to array, in which we can store * the number of pixels found in each color in * the colormap in pixd) * Return: 0 if OK, 1 on error * * Notes: * (1) This is used in phase 2 of color segmentation, where pixs * is the original input image to pixColorSegment(), and * pixd is the colormapped image returned from * pixColorSegmentCluster(). It is also used, with a mask, * in phase 4. * (2) This is an in-place operation. * (3) The colormap in pixd is unchanged. * (4) pixs and pixd must be the same size (w, h). * (5) The selection mask pixm can be null. If it exists, it must * be the same size as pixs and pixd, and only pixels * corresponding to fg in pixm are assigned. Set to * NULL if all pixels in pixd are to be assigned. * (6) The countarray can be null. If it exists, it is pre-allocated * and of a size at least equal to the size of the colormap in pixd. * (7) This does a best-fit (non-greedy) assignment of pixels to * existing clusters. Specifically, it assigns each pixel * in pixd to the color index in the pixd colormap that has a * color closest to the corresponding rgb pixel in pixs. * (8) 'level' is the octcube level used to quickly find the nearest * color in the colormap for each pixel. For color segmentation, * this parameter is set to LEVEL_IN_OCTCUBE. * (9) We build a mapping table from octcube to colormap index so * that this function can run in a time (otherwise) independent * of the number of colors in the colormap. This avoids a * brute-force search for the closest colormap color to each * pixel in the image. */ l_int32 pixAssignToNearestColor(PIX *pixd, PIX *pixs, PIX *pixm, l_int32 level, l_int32 *countarray) { l_int32 w, h, wpls, wpld, wplm, i, j; l_int32 rval, gval, bval, index; l_int32 *cmaptab; l_uint32 octindex; l_uint32 *rtab, *gtab, *btab; l_uint32 *ppixel; l_uint32 *datas, *datad, *datam, *lines, *lined, *linem; PIXCMAP *cmap; PROCNAME("pixAssignToNearestColor"); if (!pixd) return ERROR_INT("pixd not defined", 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); if (pixGetDepth(pixs) != 32) return ERROR_INT("pixs not 32 bpp", procName, 1); /* Set up the tables to map rgb to the nearest colormap index */ if (makeRGBToIndexTables(&rtab, >ab, &btab, level)) return ERROR_INT("index tables not made", procName, 1); if ((cmaptab = pixcmapToOctcubeLUT(cmap, level, L_MANHATTAN_DISTANCE)) == NULL) return ERROR_INT("cmaptab not made", procName, 1); w = pixGetWidth(pixs); h = pixGetHeight(pixs); datas = pixGetData(pixs); datad = pixGetData(pixd); wpls = pixGetWpl(pixs); wpld = pixGetWpl(pixd); if (pixm) { datam = pixGetData(pixm); wplm = pixGetWpl(pixm); } for (i = 0; i < h; i++) { lines = datas + i * wpls; lined = datad + i * wpld; if (pixm) linem = datam + i * wplm; for (j = 0; j < w; j++) { if (pixm) { if (!GET_DATA_BIT(linem, j)) continue; } ppixel = lines + j; rval = GET_DATA_BYTE(ppixel, COLOR_RED); gval = GET_DATA_BYTE(ppixel, COLOR_GREEN); bval = GET_DATA_BYTE(ppixel, COLOR_BLUE); /* Map from rgb to octcube index */ getOctcubeIndexFromRGB(rval, gval, bval, rtab, gtab, btab, &octindex); /* Map from octcube index to nearest colormap index */ index = cmaptab[octindex]; if (countarray) countarray[index]++; SET_DATA_BYTE(lined, j, index); } } FREE(cmaptab); FREE(rtab); FREE(gtab); FREE(btab); return 0; }