Leptonica 1.68
C Image Processing Library

pixtiling.c

Go to the documentation of this file.
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 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines