Leptonica 1.68
C Image Processing Library
|
00001 /*====================================================================* 00002 - Copyright (C) 2001 Leptonica. All rights reserved. 00003 - This software is distributed in the hope that it will be 00004 - useful, but with NO WARRANTY OF ANY KIND. 00005 - No author or distributor accepts responsibility to anyone for the 00006 - consequences of using this software, or for whether it serves any 00007 - particular purpose or works at all, unless he or she says so in 00008 - writing. Everyone is granted permission to copy, modify and 00009 - redistribute this source code, for commercial or non-commercial 00010 - purposes, with the following restrictions: (1) the origin of this 00011 - source code must not be misrepresented; (2) modified versions must 00012 - be plainly marked as such; and (3) this notice may not be removed 00013 - or altered from any source or modified source distribution. 00014 *====================================================================*/ 00015 00016 00017 /* 00018 * pixtiling.c 00019 * 00020 * PIXTILING *pixTilingCreate() 00021 * void *pixTilingDestroy() 00022 * l_int32 pixTilingGetCount() 00023 * l_int32 pixTilingGetSize() 00024 * PIX *pixTilingGetTile() 00025 * l_int32 pixTilingNoStripOnPaint() 00026 * l_int32 pixTilingPaintTile() 00027 * 00028 * 00029 * This provides a simple way to split an image into tiles 00030 * and to perform operations independently on each tile. 00031 * 00032 * The tile created with pixTilingGetTile() can have pixels in 00033 * adjacent tiles for computation. The number of extra pixels 00034 * on each side of the tile is given by an 'overlap' parameter 00035 * to pixTilingCreate(). For tiles at the boundary of 00036 * the input image, quasi-overlap pixels are created by reflection 00037 * symmetry into the tile. 00038 * 00039 * Here's a typical intended usage. Suppose you want to parallelize 00040 * the operation on an image, by operating on tiles. For each 00041 * tile, you want to generate an in-place image result at the same 00042 * resolution. Suppose you choose a one-dimensional vertical tiling, 00043 * where the desired tile width is 256 pixels and the overlap is 00044 * 30 pixels on left and right sides: 00045 * 00046 * PIX *pixd = pixCreateTemplateNoInit(pixs); // output 00047 * PIXTILING *pt = pixTilingCreate(pixs, 0, 1, 256, 30, 0); 00048 * pixTilingGetCount(pt, &nx, NULL); 00049 * for (j = 0; j < nx; j++) { 00050 * PIX *pixt = pixTilingGetTile(pt, 0, j); 00051 * SomeInPlaceOperation(pixt, 30, 0, ...); 00052 * pixTilingPaintTile(pixd, 0, j, pixt, pt); 00053 * pixDestroy(&pixt); 00054 * } 00055 * 00056 * In this example, note the following: 00057 * - The unspecfified in-place operation could instead generate 00058 * a new pix. If this is done, the resulting pix must be the 00059 * same size as pixt, because pixTilingPaintTile() makes that 00060 * assumption, removing the overlap pixels before painting 00061 * into the destination. 00062 * - The 'overlap' parameters have been included in your function, 00063 * to indicate which pixels are not in the exterior overlap region. 00064 * You will need to change only pixels that are not in the overlap 00065 * region, because those are the pixels that will be painted 00066 * into the destination. 00067 * - For tiles on the outside of the image, mirrored pixels are 00068 * added to substitute for the overlap that is added to interior 00069 * tiles. This allows you to implement your function without 00070 * reference to which tile it is; no special coding is necessary 00071 * for pixels that are near the image boundary. 00072 * - The tiles are labeled by (i, j) = (row, column), 00073 * and in this example there is one row and nx columns. 00074 */ 00075 00076 #include <stdio.h> 00077 #include <stdlib.h> 00078 #include "allheaders.h" 00079 00080 00081 /*! 00082 * pixTilingCreate() 00083 * 00084 * Input: pixs (pix to be tiled; any depth; colormap OK) 00085 * nx (number of tiles across image) 00086 * ny (number of tiles down image) 00087 * w (desired width of each tile) 00088 * h (desired height of each tile) 00089 * overlap (amount of overlap into neighboring tile on each side) 00090 * Return: pixtiling, or null on error 00091 * 00092 * Notes: 00093 * (1) We put a clone of pixs in the PixTiling. 00094 * (2) The input to pixTilingCreate() for horizontal tiling can be 00095 * either the number of tiles across the image or the approximate 00096 * width of the tiles. If the latter, the actual width will be 00097 * determined by making all tiles but the last of equal width, and 00098 * making the last as close to the others as possible. The same 00099 * consideration is applied independently to the vertical tiling. 00100 * To specify tile width, set nx = 0; to specify the number of 00101 * tiles horizontally across the image, set w = 0. 00102 * (3) If pixs is to be tiled in one-dimensional strips, use ny = 1 for 00103 * vertical strips and nx = 1 for horizontal strips. 00104 * (4) The overlap must not be larger than the width or height of 00105 * the leftmost or topmost tile(s). 00106 */ 00107 PIXTILING * 00108 pixTilingCreate(PIX *pixs, 00109 l_int32 nx, 00110 l_int32 ny, 00111 l_int32 w, 00112 l_int32 h, 00113 l_int32 xoverlap, 00114 l_int32 yoverlap) 00115 { 00116 l_int32 width, height; 00117 PIXTILING *pt; 00118 00119 PROCNAME("pixTilingCreate"); 00120 00121 if (!pixs) 00122 return (PIXTILING *)ERROR_PTR("pixs not defined", procName, NULL); 00123 if (nx < 1 && w < 1) 00124 return (PIXTILING *)ERROR_PTR("invalid width spec", procName, NULL); 00125 if (ny < 1 && h < 1) 00126 return (PIXTILING *)ERROR_PTR("invalid height spec", procName, NULL); 00127 00128 /* Find the tile width and number of tiles. All tiles except the 00129 * rightmost ones have the same width. The width of the 00130 * rightmost ones are at least the width of the others and 00131 * less than twice that width. Ditto for tile height. */ 00132 pixGetDimensions(pixs, &width, &height, NULL); 00133 if (nx == 0) 00134 nx = L_MAX(1, width / w); 00135 w = width / nx; /* possibly reset */ 00136 if (ny == 0) 00137 ny = L_MAX(1, height / h); 00138 h = height / ny; /* possibly reset */ 00139 if (xoverlap > w || yoverlap > h) { 00140 L_INFO_INT2("tile width = %d, tile height = %d", procName, w, h); 00141 return (PIXTILING *)ERROR_PTR("overlap too large", procName, NULL); 00142 } 00143 00144 if ((pt = (PIXTILING *)CALLOC(1, sizeof(PIXTILING))) == NULL) 00145 return (PIXTILING *)ERROR_PTR("pt not made", procName, NULL); 00146 pt->pix = pixClone(pixs); 00147 pt->xoverlap = xoverlap; 00148 pt->yoverlap = yoverlap; 00149 pt->nx = nx; 00150 pt->ny = ny; 00151 pt->w = w; 00152 pt->h = h; 00153 pt->strip = TRUE; 00154 return pt; 00155 } 00156 00157 00158 /*! 00159 * pixTilingDestroy() 00160 * 00161 * Input: &pt (<will be set to null before returning>) 00162 * Return: void 00163 */ 00164 void 00165 pixTilingDestroy(PIXTILING **ppt) 00166 { 00167 PIXTILING *pt; 00168 00169 PROCNAME("pixTilingDestroy"); 00170 00171 if (ppt == NULL) { 00172 L_WARNING("ptr address is null!", procName); 00173 return; 00174 } 00175 00176 if ((pt = *ppt) == NULL) 00177 return; 00178 00179 pixDestroy(&pt->pix); 00180 FREE(pt); 00181 *ppt = NULL; 00182 return; 00183 } 00184 00185 00186 /*! 00187 * pixTilingGetCount() 00188 * 00189 * Input: pt (pixtiling) 00190 * &nx (<optional return> nx; can be null) 00191 * &ny (<optional return> ny; can be null) 00192 * Return: 0 if OK, 1 on error 00193 */ 00194 l_int32 00195 pixTilingGetCount(PIXTILING *pt, 00196 l_int32 *pnx, 00197 l_int32 *pny) 00198 { 00199 PROCNAME("pixTilingGetCount"); 00200 00201 if (!pt) 00202 return ERROR_INT("pt not defined", procName, 1); 00203 if (pnx) *pnx = pt->nx; 00204 if (pny) *pny = pt->ny; 00205 return 0; 00206 } 00207 00208 00209 /*! 00210 * pixTilingGetSize() 00211 * 00212 * Input: pt (pixtiling) 00213 * &w (<optional return> tile width; can be null) 00214 * &h (<optional return> tile height; can be null) 00215 * Return: 0 if OK, 1 on error 00216 */ 00217 l_int32 00218 pixTilingGetSize(PIXTILING *pt, 00219 l_int32 *pw, 00220 l_int32 *ph) 00221 { 00222 PROCNAME("pixTilingGetSize"); 00223 00224 if (!pt) 00225 return ERROR_INT("pt not defined", procName, 1); 00226 if (pw) *pw = pt->w; 00227 if (ph) *ph = pt->h; 00228 return 0; 00229 } 00230 00231 00232 /*! 00233 * pixTilingGetTile() 00234 * 00235 * Input: pt (pixtiling) 00236 * i (tile row index) 00237 * j (tile column index) 00238 * Return: pixd (tile with appropriate boundary (overlap) pixels added), 00239 * or null on error 00240 */ 00241 PIX * 00242 pixTilingGetTile(PIXTILING *pt, 00243 l_int32 i, 00244 l_int32 j) 00245 { 00246 l_int32 wpix, hpix, wt, ht, nx, ny; 00247 l_int32 xoverlap, yoverlap, wtlast, htlast; 00248 l_int32 left, top, xtraleft, xtraright, xtratop, xtrabot, width, height; 00249 BOX *box; 00250 PIX *pixs, *pixt, *pixd; 00251 00252 PROCNAME("pixTilingGetTile"); 00253 00254 if (!pt) 00255 return (PIX *)ERROR_PTR("pt not defined", procName, NULL); 00256 if ((pixs = pt->pix) == NULL) 00257 return (PIX *)ERROR_PTR("pix not found", procName, NULL); 00258 pixTilingGetCount(pt, &nx, &ny); 00259 if (i < 0 || i >= ny) 00260 return (PIX *)ERROR_PTR("invalid row index i", procName, NULL); 00261 if (j < 0 || j >= nx) 00262 return (PIX *)ERROR_PTR("invalid column index j", procName, NULL); 00263 00264 /* Grab the tile with as much overlap as exists within the 00265 * input pix. First, compute the (left, top) coordinates. */ 00266 pixGetDimensions(pixs, &wpix, &hpix, NULL); 00267 pixTilingGetSize(pt, &wt, &ht); 00268 xoverlap = pt->xoverlap; 00269 yoverlap = pt->yoverlap; 00270 wtlast = wpix - wt * (nx - 1); 00271 htlast = hpix - ht * (ny - 1); 00272 left = L_MAX(0, j * wt - xoverlap); 00273 top = L_MAX(0, i * ht - yoverlap); 00274 00275 /* Get the width and height of the tile, including whatever 00276 * overlap is available. */ 00277 if (nx == 1) 00278 width = wpix; 00279 else if (j == 0) 00280 width = wt + xoverlap; 00281 else if (j == nx - 1) 00282 width = wtlast + xoverlap; 00283 else 00284 width = wt + 2 * xoverlap; 00285 00286 if (ny == 1) 00287 height = hpix; 00288 else if (i == 0) 00289 height = ht + yoverlap; 00290 else if (i == ny - 1) 00291 height = htlast + yoverlap; 00292 else 00293 height = ht + 2 * yoverlap; 00294 box = boxCreate(left, top, width, height); 00295 pixt = pixClipRectangle(pixs, box, NULL); 00296 boxDestroy(&box); 00297 00298 /* Add overlap as a mirrored border, in the 8 special cases where 00299 * the tile touches the border of the input pix. The xtratop (etc) 00300 * parameters are required where the tile is either full width 00301 * or full height. */ 00302 xtratop = xtrabot = xtraleft = xtraright = 0; 00303 if (nx == 1) 00304 xtraleft = xtraright = xoverlap; 00305 if (ny == 1) 00306 xtratop = xtrabot = yoverlap; 00307 if (i == 0 && j == 0) 00308 pixd = pixAddMirroredBorder(pixt, xoverlap, xtraright, 00309 yoverlap, xtrabot); 00310 else if (i == 0 && j == nx - 1) 00311 pixd = pixAddMirroredBorder(pixt, xtraleft, xoverlap, 00312 yoverlap, xtrabot); 00313 else if (i == ny - 1 && j == 0) 00314 pixd = pixAddMirroredBorder(pixt, xoverlap, xtraright, 00315 xtratop, yoverlap); 00316 else if (i == ny - 1 && j == nx - 1) 00317 pixd = pixAddMirroredBorder(pixt, xtraleft, xoverlap, 00318 xtratop, yoverlap); 00319 else if (i == 0) 00320 pixd = pixAddMirroredBorder(pixt, 0, 0, yoverlap, xtrabot); 00321 else if (i == ny - 1) 00322 pixd = pixAddMirroredBorder(pixt, 0, 0, xtratop, yoverlap); 00323 else if (j == 0) 00324 pixd = pixAddMirroredBorder(pixt, xoverlap, xtraright, 0, 0); 00325 else if (j == nx - 1) 00326 pixd = pixAddMirroredBorder(pixt, xtraleft, xoverlap, 0, 0); 00327 else 00328 pixd = pixClone(pixt); 00329 pixDestroy(&pixt); 00330 00331 return pixd; 00332 } 00333 00334 00335 /*! 00336 * pixTilingNoStripOnPaint() 00337 * 00338 * Input: pt (pixtiling) 00339 * Return: 0 if OK, 1 on error 00340 * 00341 * Notes: 00342 * (1) The default for paint is to strip out the overlap pixels 00343 * that are added by pixTilingGetTile(). However, some 00344 * operations will generate an image with these pixels 00345 * stripped off. This tells the paint operation not 00346 * to strip the added boundary pixels when painting. 00347 */ 00348 l_int32 00349 pixTilingNoStripOnPaint(PIXTILING *pt) 00350 { 00351 PROCNAME("pixTilingNoStripOnPaint"); 00352 00353 if (!pt) 00354 return ERROR_INT("pt not defined", procName, 1); 00355 pt->strip = FALSE; 00356 return 0; 00357 } 00358 00359 00360 /*! 00361 * pixTilingPaintTile() 00362 * 00363 * Input: pixd (dest: paint tile onto this, without overlap) 00364 * i (tile row index) 00365 * j (tile column index) 00366 * pixs (source: tile to be painted from) 00367 * pt (pixtiling struct) 00368 * Return: 0 if OK, 1 on error 00369 */ 00370 l_int32 00371 pixTilingPaintTile(PIX *pixd, 00372 l_int32 i, 00373 l_int32 j, 00374 PIX *pixs, 00375 PIXTILING *pt) 00376 { 00377 l_int32 w, h; 00378 00379 PROCNAME("pixTilingPaintTile"); 00380 00381 if (!pixd) 00382 return ERROR_INT("pixd not defined", procName, 1); 00383 if (!pixs) 00384 return ERROR_INT("pixs not defined", procName, 1); 00385 if (!pt) 00386 return ERROR_INT("pt not defined", procName, 1); 00387 if (i < 0 || i >= pt->ny) 00388 return ERROR_INT("invalid row index i", procName, 1); 00389 if (j < 0 || j >= pt->nx) 00390 return ERROR_INT("invalid column index j", procName, 1); 00391 00392 /* Strip added border pixels off if requested */ 00393 pixGetDimensions(pixs, &w, &h, NULL); 00394 if (pt->strip == TRUE) 00395 pixRasterop(pixd, j * pt->w, i * pt->h, 00396 w - 2 * pt->xoverlap, h - 2 * pt->yoverlap, PIX_SRC, 00397 pixs, pt->xoverlap, pt->yoverlap); 00398 else 00399 pixRasterop(pixd, j * pt->w, i * pt->h, w, h, PIX_SRC, pixs, 0, 0); 00400 00401 return 0; 00402 } 00403 00404