/*! * pixApplyHorizontalDisparity() * * Input: pixs (1, 8 or 32 bpp) * fpix (horizontal disparity array) * extraw (extra width added to pixd) * Return: pixd (modified by fpix), or null on error * * Notes: * (1) This applies the horizontal disparity array to the specified * image. */ PIX * pixApplyHorizontalDisparity(PIX *pixs, FPIX *fpix, l_int32 extraw) { l_int32 i, j, w, h, d, wd, fw, fh, wpls, wpld, wplf, jsrc, val8; l_uint32 *datas, *lines, *datad, *lined; l_float32 *dataf, *linef; PIX *pixd; PROCNAME("pixApplyHorizontalDisparity"); if (!pixs) return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); if (!fpix) return (PIX *)ERROR_PTR("fpix not defined", procName, NULL); pixGetDimensions(pixs, &w, &h, &d); if (d != 1 && d != 8 && d != 32) return (PIX *)ERROR_PTR("pix not 1, 8 or 32 bpp", procName, NULL); fpixGetDimensions(fpix, &fw, &fh); if (fw < w + extraw || fh < h) { fprintf(stderr, "fw = %d, w = %d, fh = %d, h = %d\n", fw, w, fh, h); return (PIX *)ERROR_PTR("invalid fpix size", procName, NULL); } wd = w + extraw; pixd = pixCreate(wd, h, d); datas = pixGetData(pixs); datad = pixGetData(pixd); dataf = fpixGetData(fpix); wpls = pixGetWpl(pixs); wpld = pixGetWpl(pixd); wplf = fpixGetWpl(fpix); if (d == 1) { for (i = 0; i < h; i++) { lines = datas + i * wpls; lined = datad + i * wpld; linef = dataf + i * wplf; for (j = 0; j < wd; j++) { jsrc = (l_int32)(j - linef[j] + 0.5); if (jsrc < 0) jsrc = 0; if (jsrc > w - 1) jsrc = w - 1; if (GET_DATA_BIT(lines, jsrc)) SET_DATA_BIT(lined, j); } } } else if (d == 8) { for (i = 0; i < h; i++) { lines = datas + i * wpls; lined = datad + i * wpld; linef = dataf + i * wplf; for (j = 0; j < wd; j++) { jsrc = (l_int32)(j - linef[j] + 0.5); if (jsrc < 0) jsrc = 0; if (jsrc > w - 1) jsrc = w - 1; val8 = GET_DATA_BYTE(lines, jsrc); SET_DATA_BYTE(lined, j, val8); } } } else { /* d == 32 */ for (i = 0; i < h; i++) { lines = datas + i * wpls; lined = datad + i * wpld; linef = dataf + i * wplf; for (j = 0; j < wd; j++) { jsrc = (l_int32)(j - linef[j] + 0.5); if (jsrc < 0) jsrc = 0; if (jsrc > w - 1) jsrc = w - 1; lined[j] = lines[jsrc]; } } } return pixd; }
/*! * pixSetSelectCmap() * * Input: pixs (1, 2, 4 or 8 bpp, with colormap) * box (<optional> region to set color; can be NULL) * sindex (colormap index of pixels to be changed) * rval, gval, bval (new color to paint) * Return: 0 if OK, 1 on error * * Note: * (1) This is an in-place operation. * (2) It sets all pixels in region that have the color specified * by the colormap index 'sindex' to the new color. * (3) sindex must be in the existing colormap; otherwise an * error is returned. * (4) If the new color exists in the colormap, it is used; * otherwise, it is added to the colormap. If it cannot be * added because the colormap is full, an error is returned. * (5) If box is NULL, applies function to the entire image; otherwise, * clips the operation to the intersection of the box and pix. * (6) An example of use would be to set to a specific color all * the light (background) pixels within a certain region of * a 3-level 2 bpp image, while leaving light pixels outside * this region unchanged. */ l_int32 pixSetSelectCmap(PIX *pixs, BOX *box, l_int32 sindex, l_int32 rval, l_int32 gval, l_int32 bval) { l_int32 i, j, w, h, d, n, x1, y1, x2, y2, bw, bh, val, wpls; l_int32 index; /* of new color to be set */ l_uint32 *lines, *datas; PIXCMAP *cmap; PROCNAME("pixSetSelectCmap"); if (!pixs) return ERROR_INT("pixs not defined", procName, 1); if ((cmap = pixGetColormap(pixs)) == NULL) return ERROR_INT("no colormap", procName, 1); d = pixGetDepth(pixs); if (d != 1 && d != 2 && d != 4 && d != 8) return ERROR_INT("depth not in {1,2,4,8}", procName, 1); /* Add new color if necessary; get index of this color in cmap */ n = pixcmapGetCount(cmap); if (sindex >= n) return ERROR_INT("sindex too large; no cmap entry", procName, 1); if (pixcmapGetIndex(cmap, rval, gval, bval, &index)) { /* not found */ if (pixcmapAddColor(cmap, rval, gval, bval)) return ERROR_INT("error adding cmap entry", procName, 1); else index = n; /* we've added one color */ } /* Determine the region of substitution */ pixGetDimensions(pixs, &w, &h, NULL); if (!box) { x1 = y1 = 0; x2 = w; y2 = h; } else { boxGetGeometry(box, &x1, &y1, &bw, &bh); x2 = x1 + bw - 1; y2 = y1 + bh - 1; } /* Replace pixel value sindex by index in the region */ datas = pixGetData(pixs); wpls = pixGetWpl(pixs); for (i = y1; i <= y2; i++) { if (i < 0 || i >= h) /* clip */ continue; lines = datas + i * wpls; for (j = x1; j <= x2; j++) { if (j < 0 || j >= w) /* clip */ continue; switch (d) { case 1: val = GET_DATA_BIT(lines, j); if (val == sindex) { if (index == 0) CLEAR_DATA_BIT(lines, j); else SET_DATA_BIT(lines, j); } break; case 2: val = GET_DATA_DIBIT(lines, j); if (val == sindex) SET_DATA_DIBIT(lines, j, index); break; case 4: val = GET_DATA_QBIT(lines, j); if (val == sindex) SET_DATA_QBIT(lines, j, index); break; case 8: val = GET_DATA_BYTE(lines, j); if (val == sindex) SET_DATA_BYTE(lines, j, index); break; default: return ERROR_INT("depth not in {1,2,4,8}", procName, 1); } } } return 0; }
/*! * pixApplyVerticalDisparity() * * Input: pixs (1, 8 or 32 bpp) * fpix (vertical disparity array) * Return: pixd (modified by fpix), or null on error * * Notes: * (1) This applies the vertical disparity array to the specified * image. For src pixels above the image, we use the pixels * in the first raster line. */ PIX * pixApplyVerticalDisparity(PIX *pixs, FPIX *fpix) { l_int32 i, j, w, h, d, fw, fh, wpld, wplf, isrc, val8; l_uint32 *datad, *lined; l_float32 *dataf, *linef; void **lineptrs; PIX *pixd; PROCNAME("pixApplyVerticalDisparity"); if (!pixs) return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); if (!fpix) return (PIX *)ERROR_PTR("fpix not defined", procName, NULL); pixGetDimensions(pixs, &w, &h, &d); if (d != 1 && d != 8 && d != 32) return (PIX *)ERROR_PTR("pix not 1, 8 or 32 bpp", procName, NULL); fpixGetDimensions(fpix, &fw, &fh); if (fw < w || fh < h) { fprintf(stderr, "fw = %d, w = %d, fh = %d, h = %d\n", fw, w, fh, h); return (PIX *)ERROR_PTR("invalid fpix size", procName, NULL); } pixd = pixCreateTemplate(pixs); datad = pixGetData(pixd); dataf = fpixGetData(fpix); wpld = pixGetWpl(pixd); wplf = fpixGetWpl(fpix); if (d == 1) { lineptrs = pixGetLinePtrs(pixs, NULL); for (i = 0; i < h; i++) { lined = datad + i * wpld; linef = dataf + i * wplf; for (j = 0; j < w; j++) { isrc = (l_int32)(i - linef[j] + 0.5); if (isrc < 0) isrc = 0; if (isrc > h - 1) isrc = h - 1; if (GET_DATA_BIT(lineptrs[isrc], j)) SET_DATA_BIT(lined, j); } } } else if (d == 8) { lineptrs = pixGetLinePtrs(pixs, NULL); for (i = 0; i < h; i++) { lined = datad + i * wpld; linef = dataf + i * wplf; for (j = 0; j < w; j++) { isrc = (l_int32)(i - linef[j] + 0.5); if (isrc < 0) isrc = 0; if (isrc > h - 1) isrc = h - 1; val8 = GET_DATA_BYTE(lineptrs[isrc], j); SET_DATA_BYTE(lined, j, val8); } } } else { /* d == 32 */ lineptrs = pixGetLinePtrs(pixs, NULL); for (i = 0; i < h; i++) { lined = datad + i * wpld; linef = dataf + i * wplf; for (j = 0; j < w; j++) { isrc = (l_int32)(i - linef[j] + 0.5); if (isrc < 0) isrc = 0; if (isrc > h - 1) isrc = h - 1; lined[j] = GET_DATA_FOUR_BYTES(lineptrs[isrc], j); } } } FREE(lineptrs); return pixd; }
/*! * identifyWatershedBasin() * * Input: wshed * index (index of basin to be located) * level (of basin at point at which the two basins met) * &box (<return> bounding box of basin) * &pixd (<return> pix of basin, cropped to its bounding box) * Return: 0 if OK, 1 on error * * Notes: * (1) This is a static function, so we assume pixlab, pixs and pixt * exist and are the same size. * (2) It selects all pixels that have the label @index in pixlab * and that have a value in pixs that is less than @level. * (3) It is used whenever two seeded basins meet (typically at a saddle), * or when one seeded basin meets a 'filler'. All identified * basins are saved as a watershed. */ static l_int32 identifyWatershedBasin(L_WSHED *wshed, l_int32 index, l_int32 level, BOX **pbox, PIX **ppixd) { l_int32 imin, imax, jmin, jmax, minx, miny, maxx, maxy; l_int32 bw, bh, i, j, w, h, x, y; l_int32 *lut; l_uint32 label, bval, lval; void **lines8, **linelab32, **linet1; BOX *box; PIX *pixs, *pixt, *pixd; L_QUEUE *lq; PROCNAME("identifyWatershedBasin"); if (!pbox) return ERROR_INT("&box not defined", procName, 1); *pbox = NULL; if (!ppixd) return ERROR_INT("&pixd not defined", procName, 1); *ppixd = NULL; if (!wshed) return ERROR_INT("wshed not defined", procName, 1); /* Make a queue and an auxiliary stack */ lq = lqueueCreate(0); lq->stack = lstackCreate(0); pixs = wshed->pixs; pixt = wshed->pixt; lines8 = wshed->lines8; linelab32 = wshed->linelab32; linet1 = wshed->linet1; lut = wshed->lut; pixGetDimensions(pixs, &w, &h, NULL); /* Prime the queue with the seed pixel for this watershed. */ minx = miny = 1000000; maxx = maxy = 0; ptaGetIPt(wshed->ptas, index, &x, &y); pixSetPixel(pixt, x, y, 1); pushNewPixel(lq, x, y, &minx, &maxx, &miny, &maxy); if (wshed->debug) fprintf(stderr, "prime: (x,y) = (%d, %d)\n", x, y); /* Each pixel in a spreading breadth-first search is inspected. * It is accepted as part of this watershed, and pushed on * the search queue, if: * (1) It has a label value equal to @index * (2) The pixel value is less than @level, the overflow * height at which the two basins join. * (3) It has not yet been seen in this search. */ while (lqueueGetCount(lq) > 0) { popNewPixel(lq, &x, &y); imin = L_MAX(0, y - 1); imax = L_MIN(h - 1, y + 1); jmin = L_MAX(0, x - 1); jmax = L_MIN(w - 1, x + 1); for (i = imin; i <= imax; i++) { for (j = jmin; j <= jmax; j++) { if (j == x && i == y) continue; /* parent */ label = GET_DATA_FOUR_BYTES(linelab32[i], j); if (label == MAX_LABEL_VALUE || lut[label] != index) continue; bval = GET_DATA_BIT(linet1[i], j); if (bval == 1) continue; /* already seen */ lval = GET_DATA_BYTE(lines8[i], j); if (lval >= level) continue; /* too high */ SET_DATA_BIT(linet1[i], j); pushNewPixel(lq, j, i, &minx, &maxx, &miny, &maxy); } } } /* Extract the box and pix, and clear pixt */ bw = maxx - minx + 1; bh = maxy - miny + 1; box = boxCreate(minx, miny, bw, bh); pixd = pixClipRectangle(pixt, box, NULL); pixRasterop(pixt, minx, miny, bw, bh, PIX_SRC ^ PIX_DST, pixd, 0, 0); *pbox = box; *ppixd = pixd; lqueueDestroy(&lq, 1); return 0; }
/*! * pixSetSelectMaskedCmap() * * Input: pixs (2, 4 or 8 bpp, with colormap) * pixm (<optional> 1 bpp mask; no-op if NULL) * x, y (UL corner of mask relative to pixs) * sindex (colormap index of pixels in pixs to be changed) * rval, gval, bval (new color to substitute) * Return: 0 if OK, 1 on error * * Note: * (1) This is an in-place operation. * (2) This paints through the fg of pixm and replaces all pixels * in pixs that have a particular value (sindex) with the new color. * (3) If pixm == NULL, a warning is given. * (4) sindex must be in the existing colormap; otherwise an * error is returned. * (5) If the new color exists in the colormap, it is used; * otherwise, it is added to the colormap. If the colormap * is full, an error is returned. */ l_int32 pixSetSelectMaskedCmap(PIX *pixs, PIX *pixm, l_int32 x, l_int32 y, l_int32 sindex, l_int32 rval, l_int32 gval, l_int32 bval) { l_int32 i, j, w, h, d, n, wm, hm, wpls, wplm, val; l_int32 index; /* of new color to be set */ l_uint32 *lines, *linem, *datas, *datam; PIXCMAP *cmap; PROCNAME("pixSetSelectMaskedCmap"); if (!pixs) return ERROR_INT("pixs not defined", procName, 1); if ((cmap = pixGetColormap(pixs)) == NULL) return ERROR_INT("no colormap", procName, 1); if (!pixm) { L_WARNING("no mask; nothing to do", procName); return 0; } d = pixGetDepth(pixs); if (d != 2 && d != 4 && d != 8) return ERROR_INT("depth not in {2, 4, 8}", procName, 1); /* add new color if necessary; get index of this color in cmap */ n = pixcmapGetCount(cmap); if (sindex >= n) return ERROR_INT("sindex too large; no cmap entry", procName, 1); if (pixcmapGetIndex(cmap, rval, gval, bval, &index)) { /* not found */ if (pixcmapAddColor(cmap, rval, gval, bval)) return ERROR_INT("error adding cmap entry", procName, 1); else index = n; /* we've added one color */ } /* replace pixel value sindex by index when fg pixel in pixmc * overlays it */ w = pixGetWidth(pixs); h = pixGetHeight(pixs); datas = pixGetData(pixs); wpls = pixGetWpl(pixs); wm = pixGetWidth(pixm); hm = pixGetHeight(pixm); datam = pixGetData(pixm); wplm = pixGetWpl(pixm); for (i = 0; i < hm; i++) { if (i + y < 0 || i + y >= h) continue; lines = datas + (y + i) * wpls; linem = datam + i * wplm; for (j = 0; j < wm; j++) { if (j + x < 0 || j + x >= w) continue; if (GET_DATA_BIT(linem, j)) { switch (d) { case 1: val = GET_DATA_BIT(lines, x + j); if (val == sindex) { if (index == 0) CLEAR_DATA_BIT(lines, x + j); else SET_DATA_BIT(lines, x + j); } break; case 2: val = GET_DATA_DIBIT(lines, x + j); if (val == sindex) SET_DATA_DIBIT(lines, x + j, index); break; case 4: val = GET_DATA_QBIT(lines, x + j); if (val == sindex) SET_DATA_QBIT(lines, x + j, index); break; case 8: val = GET_DATA_BYTE(lines, x + j); if (val == sindex) SET_DATA_BYTE(lines, x + j, index); break; default: return ERROR_INT("depth not in {1,2,4,8}", procName, 1); } } } } return 0; }
/*! * pixReadStreamGif() * * Input: stream * Return: pix, or null on error */ PIX * pixReadStreamGif(FILE *fp) { l_int32 fd, wpl, i, j, w, h, d, cindex, ncolors; l_int32 rval, gval, bval; l_uint32 *data, *line; GifFileType *gif; PIX *pixd, *pixdi; PIXCMAP *cmap; ColorMapObject *gif_cmap; SavedImage si; PROCNAME("pixReadStreamGif"); if ((fd = fileno(fp)) < 0) return (PIX *)ERROR_PTR("invalid file descriptor", procName, NULL); #ifndef _MSC_VER lseek(fd, 0, SEEK_SET); #else _lseek(fd, 0, SEEK_SET); #endif /* _MSC_VER */ if ((gif = DGifOpenFileHandle(fd)) == NULL) return (PIX *)ERROR_PTR("invalid file or file not found", procName, NULL); /* Read all the data, but use only the first image found */ if (DGifSlurp(gif) != GIF_OK) { DGifCloseFile(gif); return (PIX *)ERROR_PTR("failed to read GIF data", procName, NULL); } if (gif->SavedImages == NULL) { DGifCloseFile(gif); return (PIX *)ERROR_PTR("no images found in GIF", procName, NULL); } si = gif->SavedImages[0]; w = si.ImageDesc.Width; h = si.ImageDesc.Height; if (w <= 0 || h <= 0) { DGifCloseFile(gif); return (PIX *)ERROR_PTR("invalid image dimensions", procName, NULL); } if (si.RasterBits == NULL) { DGifCloseFile(gif); return (PIX *)ERROR_PTR("no raster data in GIF", procName, NULL); } if (si.ImageDesc.ColorMap) { /* private cmap for this image */ gif_cmap = si.ImageDesc.ColorMap; } else if (gif->SColorMap) { /* global cmap for whole picture */ gif_cmap = gif->SColorMap; } else { /* don't know where to take cmap from */ DGifCloseFile(gif); return (PIX *)ERROR_PTR("color map is missing", procName, NULL); } ncolors = gif_cmap->ColorCount; if (ncolors <= 2) d = 1; else if (ncolors <= 4) d = 2; else if (ncolors <= 16) d = 4; else d = 8; if ((cmap = pixcmapCreate(d)) == NULL) return (PIX *)ERROR_PTR("cmap creation failed", procName, NULL); for (cindex = 0; cindex < ncolors; cindex++) { rval = gif_cmap->Colors[cindex].Red; gval = gif_cmap->Colors[cindex].Green; bval = gif_cmap->Colors[cindex].Blue; pixcmapAddColor(cmap, rval, gval, bval); } if ((pixd = pixCreate(w, h, d)) == NULL) { DGifCloseFile(gif); pixcmapDestroy(&cmap); return (PIX *)ERROR_PTR("failed to allocate pixd", procName, NULL); } pixSetColormap(pixd, cmap); wpl = pixGetWpl(pixd); data = pixGetData(pixd); for (i = 0; i < h; i++) { line = data + i * wpl; if (d == 1) { for (j = 0; j < w; j++) { if (si.RasterBits[i * w + j]) SET_DATA_BIT(line, j); } } else if (d == 2) { for (j = 0; j < w; j++) SET_DATA_DIBIT(line, j, si.RasterBits[i * w + j]); } else if (d == 4) { for (j = 0; j < w; j++) SET_DATA_QBIT(line, j, si.RasterBits[i * w + j]); } else { /* d == 8 */ for (j = 0; j < w; j++) SET_DATA_BYTE(line, j, si.RasterBits[i * w + j]); } } if (gif->Image.Interlace) { pixdi = pixInterlaceGIF(pixd); pixTransferAllData(pixd, &pixdi, 0, 0); } DGifCloseFile(gif); return pixd; }
/*! * \brief gifToPix() * * \param[in] gif opened gif stream * \return pix, or NULL on error * * <pre> * Notes: * (1) This decodes the pix from the compressed gif stream and * closes the stream. * (2) It is static so that the stream is not exposed to clients. * </pre> */ static PIX * gifToPix(GifFileType *gif) { l_int32 wpl, i, j, w, h, d, cindex, ncolors; l_int32 rval, gval, bval; l_uint32 *data, *line; PIX *pixd; PIXCMAP *cmap; ColorMapObject *gif_cmap; SavedImage si; int giferr; PROCNAME("gifToPix"); /* Read all the data, but use only the first image found */ if (DGifSlurp(gif) != GIF_OK) { DGifCloseFile(gif, &giferr); return (PIX *)ERROR_PTR("failed to read GIF data", procName, NULL); } if (gif->SavedImages == NULL) { DGifCloseFile(gif, &giferr); return (PIX *)ERROR_PTR("no images found in GIF", procName, NULL); } si = gif->SavedImages[0]; w = si.ImageDesc.Width; h = si.ImageDesc.Height; if (w <= 0 || h <= 0) { DGifCloseFile(gif, &giferr); return (PIX *)ERROR_PTR("invalid image dimensions", procName, NULL); } if (si.RasterBits == NULL) { DGifCloseFile(gif, &giferr); return (PIX *)ERROR_PTR("no raster data in GIF", procName, NULL); } if (si.ImageDesc.ColorMap) { /* private cmap for this image */ gif_cmap = si.ImageDesc.ColorMap; } else if (gif->SColorMap) { /* global cmap for whole picture */ gif_cmap = gif->SColorMap; } else { /* don't know where to take cmap from */ DGifCloseFile(gif, &giferr); return (PIX *)ERROR_PTR("color map is missing", procName, NULL); } ncolors = gif_cmap->ColorCount; if (ncolors <= 2) d = 1; else if (ncolors <= 4) d = 2; else if (ncolors <= 16) d = 4; else d = 8; if ((cmap = pixcmapCreate(d)) == NULL) { DGifCloseFile(gif, &giferr); return (PIX *)ERROR_PTR("cmap creation failed", procName, NULL); } for (cindex = 0; cindex < ncolors; cindex++) { rval = gif_cmap->Colors[cindex].Red; gval = gif_cmap->Colors[cindex].Green; bval = gif_cmap->Colors[cindex].Blue; pixcmapAddColor(cmap, rval, gval, bval); } if ((pixd = pixCreate(w, h, d)) == NULL) { DGifCloseFile(gif, &giferr); pixcmapDestroy(&cmap); return (PIX *)ERROR_PTR("failed to allocate pixd", procName, NULL); } pixSetInputFormat(pixd, IFF_GIF); pixSetColormap(pixd, cmap); wpl = pixGetWpl(pixd); data = pixGetData(pixd); for (i = 0; i < h; i++) { line = data + i * wpl; if (d == 1) { for (j = 0; j < w; j++) { if (si.RasterBits[i * w + j]) SET_DATA_BIT(line, j); } } else if (d == 2) { for (j = 0; j < w; j++) SET_DATA_DIBIT(line, j, si.RasterBits[i * w + j]); } else if (d == 4) { for (j = 0; j < w; j++) SET_DATA_QBIT(line, j, si.RasterBits[i * w + j]); } else { /* d == 8 */ for (j = 0; j < w; j++) SET_DATA_BYTE(line, j, si.RasterBits[i * w + j]); } } /* Versions before 5.0 required un-interlacing to restore * the raster lines to normal order if the image * had been interlaced (for viewing in a browser): if (gif->Image.Interlace) { PIX *pixdi = pixUninterlaceGIF(pixd); pixTransferAllData(pixd, &pixdi, 0, 0); } * This is no longer required. */ DGifCloseFile(gif, &giferr); return pixd; }
/*! * pixApplyHorizDisparity() * * Input: dew * pixs (1, 8 or 32 bpp) * grayin (gray value, from 0 to 255, for pixels brought in; * use -1 to use pixels on the boundary of pixs) * Return: pixd (modified to remove horizontal disparity if possible), * or null on error. * * Notes: * (1) This applies the horizontal disparity array to the specified * image. * (2) Specify gray color for pixels brought in from the outside: * 0 is black, 255 is white. Use -1 to select pixels from the * boundary of the source image. * (3) The input pixs has already been corrected for vertical disparity. * If the horizontal disparity array doesn't exist, this returns * a clone of @pixs. */ static PIX * pixApplyHorizDisparity(L_DEWARP *dew, PIX *pixs, l_int32 grayin) { l_int32 i, j, w, h, d, fw, fh, wpls, wpld, wplf, jsrc, val8; l_uint32 *datas, *lines, *datad, *lined; l_float32 *dataf, *linef; FPIX *fpix; PIX *pixd; PROCNAME("pixApplyHorizDisparity"); if (!dew) return (PIX *)ERROR_PTR("dew not defined", procName, pixs); if (!pixs) return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); pixGetDimensions(pixs, &w, &h, &d); if (d != 1 && d != 8 && d != 32) return (PIX *)ERROR_PTR("pix not 1, 8 or 32 bpp", procName, NULL); if ((fpix = dew->fullhdispar) == NULL) return (PIX *)ERROR_PTR("fullhdispar not defined", procName, NULL); fpixGetDimensions(fpix, &fw, &fh); if (fw < w || fh < h) { fprintf(stderr, "fw = %d, w = %d, fh = %d, h = %d\n", fw, w, fh, h); return (PIX *)ERROR_PTR("invalid fpix size", procName, NULL); } /* Two choices for requested pixels outside pixs: (1) use pixels' * from the boundary of pixs; use white or light gray pixels. */ pixd = pixCreateTemplate(pixs); if (grayin >= 0) pixSetAllGray(pixd, grayin); datas = pixGetData(pixs); datad = pixGetData(pixd); dataf = fpixGetData(fpix); wpls = pixGetWpl(pixs); wpld = pixGetWpl(pixd); wplf = fpixGetWpl(fpix); if (d == 1) { for (i = 0; i < h; i++) { lines = datas + i * wpls; lined = datad + i * wpld; linef = dataf + i * wplf; for (j = 0; j < w; j++) { jsrc = (l_int32)(j - linef[j] + 0.5); if (grayin < 0) /* use value at boundary if outside */ jsrc = L_MIN(L_MAX(jsrc, 0), w - 1); if (jsrc >= 0 && jsrc < w) { /* remains gray if outside */ if (GET_DATA_BIT(lines, jsrc)) SET_DATA_BIT(lined, j); } } } } else if (d == 8) { for (i = 0; i < h; i++) { lines = datas + i * wpls; lined = datad + i * wpld; linef = dataf + i * wplf; for (j = 0; j < w; j++) { jsrc = (l_int32)(j - linef[j] + 0.5); if (grayin < 0) jsrc = L_MIN(L_MAX(jsrc, 0), w - 1); if (jsrc >= 0 && jsrc < w) { val8 = GET_DATA_BYTE(lines, jsrc); SET_DATA_BYTE(lined, j, val8); } } } } else { /* d == 32 */ for (i = 0; i < h; i++) { lines = datas + i * wpls; lined = datad + i * wpld; linef = dataf + i * wplf; for (j = 0; j < w; j++) { jsrc = (l_int32)(j - linef[j] + 0.5); if (grayin < 0) jsrc = L_MIN(L_MAX(jsrc, 0), w - 1); if (jsrc >= 0 && jsrc < w) lined[j] = lines[jsrc]; } } } return pixd; }
main(int argc, char **argv) { l_int32 x, y, i, j, k, w, h, w2, w4, w8, w16, w32, wpl, nerrors; l_int32 count1, count2, count3, ret, val1, val2; l_uint32 val32; l_uint32 *data, *line, *line1, *line2, *data1, *data2; void **lines1, **linet1, **linet2; PIX *pixs, *pixt1, *pixt2; static char mainName[] = "lowaccess_reg"; pixs = pixRead("feyn.tif"); /* width divisible by 16 */ pixGetDimensions(pixs, &w, &h, NULL); data = pixGetData(pixs); wpl = pixGetWpl(pixs); lines1 = pixGetLinePtrs(pixs, NULL); /* Get timing for the 3 different methods */ startTimer(); for (k = 0; k < 10; k++) { count1 = 0; for (i = 0; i < h; i++) { for (j = 0; j < w; j++) { if (GET_DATA_BIT(lines1[i], j)) count1++; } } } fprintf(stderr, "Time with line ptrs = %5.3f sec, count1 = %d\n", stopTimer(), count1); startTimer(); for (k = 0; k < 10; k++) { count2 = 0; for (i = 0; i < h; i++) { line = data + i * wpl; for (j = 0; j < w; j++) { if (l_getDataBit(line, j)) count2++; } } } fprintf(stderr, "Time with l_get* = %5.3f sec, count2 = %d\n", stopTimer(), count2); startTimer(); for (k = 0; k < 10; k++) { count3 = 0; for (i = 0; i < h; i++) { for (j = 0; j < w; j++) { pixGetPixel(pixs, j, i, &val32); count3 += val32; } } } fprintf(stderr, "Time with pixGetPixel() = %5.3f sec, count3 = %d\n", stopTimer(), count3); pixt1 = pixCreateTemplate(pixs); data1 = pixGetData(pixt1); linet1 = pixGetLinePtrs(pixt1, NULL); pixt2 = pixCreateTemplate(pixs); data2 = pixGetData(pixt2); linet2 = pixGetLinePtrs(pixt2, NULL); nerrors = 0; /* Test different methods for 1 bpp */ count1 = 0; for (i = 0; i < h; i++) { for (j = 0; j < w; j++) { val1 = GET_DATA_BIT(lines1[i], j); count1 += val1; if (val1) SET_DATA_BIT(linet1[i], j); } } count2 = 0; for (i = 0; i < h; i++) { line = data + i * wpl; line2 = data2 + i * wpl; for (j = 0; j < w; j++) { val2 = l_getDataBit(line, j); count2 += val2; if (val2) l_setDataBit(line2, j); } } ret = compareResults(pixs, pixt1, pixt2, count1, count2, "1 bpp"); nerrors += ret; /* Test different methods for 2 bpp */ count1 = 0; w2 = w / 2; for (i = 0; i < h; i++) { for (j = 0; j < w2; j++) { val1 = GET_DATA_DIBIT(lines1[i], j); count1 += val1; val1 += 0xbbbbbbbc; SET_DATA_DIBIT(linet1[i], j, val1); } } count2 = 0; for (i = 0; i < h; i++) { line = data + i * wpl; line2 = data2 + i * wpl; for (j = 0; j < w2; j++) { val2 = l_getDataDibit(line, j); count2 += val2; val2 += 0xbbbbbbbc; l_setDataDibit(line2, j, val2); } } ret = compareResults(pixs, pixt1, pixt2, count1, count2, "2 bpp"); nerrors += ret; /* Test different methods for 4 bpp */ count1 = 0; w4 = w / 4; for (i = 0; i < h; i++) { for (j = 0; j < w4; j++) { val1 = GET_DATA_QBIT(lines1[i], j); count1 += val1; val1 += 0xbbbbbbb0; SET_DATA_QBIT(linet1[i], j, val1); } } count2 = 0; for (i = 0; i < h; i++) { line = data + i * wpl; line2 = data2 + i * wpl; for (j = 0; j < w4; j++) { val2 = l_getDataQbit(line, j); count2 += val2; val2 += 0xbbbbbbb0; l_setDataQbit(line2, j, val2); } } ret = compareResults(pixs, pixt1, pixt2, count1, count2, "4 bpp"); nerrors += ret; /* Test different methods for 8 bpp */ count1 = 0; w8 = w / 8; for (i = 0; i < h; i++) { for (j = 0; j < w8; j++) { val1 = GET_DATA_BYTE(lines1[i], j); count1 += val1; val1 += 0xbbbbbb00; SET_DATA_BYTE(linet1[i], j, val1); } } count2 = 0; for (i = 0; i < h; i++) { line = data + i * wpl; line2 = data2 + i * wpl; for (j = 0; j < w8; j++) { val2 = l_getDataByte(line, j); count2 += val2; val2 += 0xbbbbbb00; l_setDataByte(line2, j, val2); } } ret = compareResults(pixs, pixt1, pixt2, count1, count2, "8 bpp"); nerrors += ret; /* Test different methods for 16 bpp */ count1 = 0; w16 = w / 16; for (i = 0; i < h; i++) { for (j = 0; j < w16; j++) { val1 = GET_DATA_TWO_BYTES(lines1[i], j); count1 += val1; val1 += 0xbbbb0000; SET_DATA_TWO_BYTES(linet1[i], j, val1); } } count2 = 0; for (i = 0; i < h; i++) { line = data + i * wpl; line2 = data2 + i * wpl; for (j = 0; j < w16; j++) { val2 = l_getDataTwoBytes(line, j); count2 += val2; val2 += 0xbbbb0000; l_setDataTwoBytes(line2, j, val2); } } ret = compareResults(pixs, pixt1, pixt2, count1, count2, "16 bpp"); nerrors += ret; /* Test different methods for 32 bpp */ count1 = 0; w32 = w / 32; for (i = 0; i < h; i++) { for (j = 0; j < w32; j++) { val1 = GET_DATA_FOUR_BYTES(lines1[i], j); count1 += val1 & 0xfff; SET_DATA_FOUR_BYTES(linet1[i], j, val1); } } count2 = 0; for (i = 0; i < h; i++) { line = data + i * wpl; line2 = data2 + i * wpl; for (j = 0; j < w32; j++) { val2 = l_getDataFourBytes(line, j); count2 += val2 & 0xfff; l_setDataFourBytes(line2, j, val2); } } ret = compareResults(pixs, pixt1, pixt2, count1, count2, "32 bpp"); nerrors += ret; if (!nerrors) fprintf(stderr, "**** No errors ****\n"); else fprintf(stderr, "**** %d errors found! ****\n", nerrors); pixDestroy(&pixs); pixDestroy(&pixt1); pixDestroy(&pixt2); lept_free(lines1); lept_free(linet1); lept_free(linet2); return 0; }
/*! * pixRotateBySampling() * * Input: pixs (1, 2, 4, 8, 16, 32 bpp rgb; can be cmapped) * xcen (x value of center of rotation) * ycen (y value of center of rotation) * angle (radians; clockwise is positive) * 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) Rotation brings either white or black pixels in * from outside the image. * (3) Colormaps are retained. */ PIX * pixRotateBySampling(PIX *pixs, l_int32 xcen, l_int32 ycen, l_float32 angle, l_int32 incolor) { l_int32 w, h, d, i, j, x, y, xdif, ydif, wm1, hm1, wpld; l_uint32 val; l_float32 sina, cosa; l_uint32 *datad, *lined; void **lines; PIX *pixd; PROCNAME("pixRotateBySampling"); if (!pixs) return (PIX *) ERROR_PTR("pixs not defined", procName, NULL); if (incolor != L_BRING_IN_WHITE && incolor != L_BRING_IN_BLACK) return (PIX *) ERROR_PTR("invalid incolor", procName, NULL); pixGetDimensions(pixs, &w, &h, &d); if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 32) return (PIX *) ERROR_PTR("invalid depth", procName, NULL); if (L_ABS(angle) < MIN_ANGLE_TO_ROTATE) return pixClone(pixs); if ((pixd = pixCreateTemplateNoInit(pixs)) == NULL) return (PIX *) ERROR_PTR("pixd not made", procName, NULL); pixSetBlackOrWhite(pixd, incolor); sina = sin(angle); cosa = cos(angle); datad = pixGetData(pixd); wpld = pixGetWpl(pixd); wm1 = w - 1; hm1 = h - 1; lines = pixGetLinePtrs(pixs, NULL); /* Treat 1 bpp case specially */ if (d == 1) { for (i = 0; i < h; i++) { /* scan over pixd */ lined = datad + i * wpld; ydif = ycen - i; for (j = 0; j < w; j++) { xdif = xcen - j; x = xcen + (l_int32)(-xdif * cosa - ydif * sina); if (x < 0 || x > wm1) continue; y = ycen + (l_int32)(-ydif * cosa + xdif * sina); if (y < 0 || y > hm1) continue; if (incolor == L_BRING_IN_WHITE) { if (GET_DATA_BIT(lines[y], x)) SET_DATA_BIT(lined, j); } else { if (!GET_DATA_BIT(lines[y], x)) CLEAR_DATA_BIT(lined, j); } } } FREE(lines); return pixd; } for (i = 0; i < h; i++) { /* scan over pixd */ lined = datad + i * wpld; ydif = ycen - i; for (j = 0; j < w; j++) { xdif = xcen - j; x = xcen + (l_int32)(-xdif * cosa - ydif * sina); if (x < 0 || x > wm1) continue; y = ycen + (l_int32)(-ydif * cosa + xdif * sina); if (y < 0 || y > hm1) continue; switch (d) { case 8: val = GET_DATA_BYTE(lines[y], x); SET_DATA_BYTE(lined, j, val); break; case 32: val = GET_DATA_FOUR_BYTES(lines[y], x); SET_DATA_FOUR_BYTES(lined, j, val); break; case 2: val = GET_DATA_DIBIT(lines[y], x); SET_DATA_DIBIT(lined, j, val); break; case 4: val = GET_DATA_QBIT(lines[y], x); SET_DATA_QBIT(lined, j, val); break; case 16: val = GET_DATA_TWO_BYTES(lines[y], x); SET_DATA_TWO_BYTES(lined, j, val); break; default: return (PIX *) ERROR_PTR("invalid depth", procName, NULL); } } } FREE(lines); return pixd; }