• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*====================================================================*
2  -  Copyright (C) 2001 Leptonica.  All rights reserved.
3  -  This software is distributed in the hope that it will be
4  -  useful, but with NO WARRANTY OF ANY KIND.
5  -  No author or distributor accepts responsibility to anyone for the
6  -  consequences of using this software, or for whether it serves any
7  -  particular purpose or works at all, unless he or she says so in
8  -  writing.  Everyone is granted permission to copy, modify and
9  -  redistribute this source code, for commercial or non-commercial
10  -  purposes, with the following restrictions: (1) the origin of this
11  -  source code must not be misrepresented; (2) modified versions must
12  -  be plainly marked as such; and (3) this notice may not be removed
13  -  or altered from any source or modified source distribution.
14  *====================================================================*/
15 
16 
17 /*
18  *   pixtiling.c
19  *
20  *        PIXTILING       *pixTilingCreate()
21  *        void            *pixTilingDestroy()
22  *        l_int32          pixTilingGetCount()
23  *        l_int32          pixTilingGetSize()
24  *        PIX             *pixTilingGetTile()
25  *        l_int32          pixTilingNoStripOnPaint()
26  *        l_int32          pixTilingPaintTile()
27  *
28  *
29  *   This provides a simple way to split an image into tiles
30  *   and to perform operations independently on each tile.
31  *
32  *   The tile created with pixTilingGetTile() can have pixels in
33  *   adjacent tiles for computation.  The number of extra pixels
34  *   on each side of the tile is given by an 'overlap' parameter
35  *   to pixTilingCreate().  For tiles at the boundary of
36  *   the input image, quasi-overlap pixels are created by reflection
37  *   symmetry into the tile.
38  *
39  *   Here's a typical intended usage.  Suppose you want to parallelize
40  *   the operation on an image, by operating on tiles.  For each
41  *   tile, you want to generate an in-place image result at the same
42  *   resolution.  Suppose you choose a one-dimensional vertical tiling,
43  *   where the desired tile width is 256 pixels and the overlap is
44  *   30 pixels on left and right sides:
45  *
46  *     PIX *pixd = pixCreateTemplateNoInit(pixs);  // output
47  *     PIXTILING  *pt = pixTilingCreate(pixs, 0, 1, 256, 30, 0);
48  *     pixTilingGetCount(pt, &nx, NULL);
49  *     for (j = 0; j < nx; j++) {
50  *         PIX *pixt = pixTilingGetTile(pt, 0, j);
51  *         SomeInPlaceOperation(pixt, 30, 0, ...);
52  *         pixTilingPaintTile(pixd, 0, j, pixt, pt);
53  *         pixDestroy(&pixt);
54  *     }
55  *
56  *   In this example, note the following:
57  *    - The unspecfified in-place operation could instead generate
58  *      a new pix.  If this is done, the resulting pix must be the
59  *      same size as pixt, because pixTilingPaintTile() makes that
60  *      assumption, removing the overlap pixels before painting
61  *      into the destination.
62  *    - The 'overlap' parameters have been included in your function,
63  *      to indicate which pixels are not in the exterior overlap region.
64  *      You will need to change only pixels that are not in the overlap
65  *      region, because those are the pixels that will be painted
66  *      into the destination.
67  *    - For tiles on the outside of the image, mirrored pixels are
68  *      added to substitute for the overlap that is added to interior
69  *      tiles.  This allows you to implement your function without
70  *      reference to which tile it is; no special coding is necessary
71  *      for pixels that are near the image boundary.
72  *    - The tiles are labeled by (i, j) = (row, column),
73  *      and in this example there is one row and nx columns.
74  */
75 
76 #include <stdio.h>
77 #include <stdlib.h>
78 #include "allheaders.h"
79 
80 
81 /*!
82  *  pixTilingCreate()
83  *
84  *      Input:  pixs  (pix to be tiled; any depth; colormap OK)
85  *              nx    (number of tiles across image)
86  *              ny    (number of tiles down image)
87  *              w     (desired width of each tile)
88  *              h     (desired height of each tile)
89  *              overlap (amount of overlap into neighboring tile on each side)
90  *      Return: pixtiling, or null on error
91  *
92  *  Notes:
93  *      (1) We put a clone of pixs in the PixTiling.
94  *      (2) The input to pixTilingCreate() for horizontal tiling can be
95  *          either the number of tiles across the image or the approximate
96  *          width of the tiles.  If the latter, the actual width will be
97  *          determined by making all tiles but the last of equal width, and
98  *          making the last as close to the others as possible.  The same
99  *          consideration is applied independently to the vertical tiling.
100  *          To specify tile width, set nx = 0; to specify the number of
101  *          tiles horizontally across the image, set w = 0.
102  *      (3) If pixs is to be tiled in one-dimensional strips, use ny = 1 for
103  *          vertical strips and nx = 1 for horizontal strips.
104  *      (4) The overlap must not be larger than the width or height of
105  *          the leftmost or topmost tile(s).
106  */
107 PIXTILING *
pixTilingCreate(PIX * pixs,l_int32 nx,l_int32 ny,l_int32 w,l_int32 h,l_int32 xoverlap,l_int32 yoverlap)108 pixTilingCreate(PIX     *pixs,
109 		l_int32  nx,
110 		l_int32  ny,
111 		l_int32  w,
112 		l_int32  h,
113 		l_int32  xoverlap,
114                 l_int32  yoverlap)
115 {
116 l_int32     width, height;
117 PIXTILING  *pt;
118 
119     PROCNAME("pixTilingCreate");
120 
121     if (!pixs)
122         return (PIXTILING *)ERROR_PTR("pixs not defined", procName, NULL);
123     if (nx < 1 && w < 1)
124         return (PIXTILING *)ERROR_PTR("invalid width spec", procName, NULL);
125     if (ny < 1 && h < 1)
126         return (PIXTILING *)ERROR_PTR("invalid height spec", procName, NULL);
127 
128         /* Find the tile width and number of tiles.  All tiles except the
129          * rightmost ones have the same width.  The width of the
130          * rightmost ones are at least the width of the others and
131          * less than twice that width.  Ditto for tile height. */
132     pixGetDimensions(pixs, &width, &height, NULL);
133     if (nx == 0)
134         nx = L_MAX(1, width / w);
135     w = width / nx;  /* possibly reset */
136     if (ny == 0)
137         ny = L_MAX(1, height / h);
138     h = height / ny;  /* possibly reset */
139     if (xoverlap > w || yoverlap > h) {
140         L_INFO_INT2("tile width = %d, tile height = %d", procName, w, h);
141         return (PIXTILING *)ERROR_PTR("overlap too large", procName, NULL);
142     }
143 
144     if ((pt = (PIXTILING *)CALLOC(1, sizeof(PIXTILING))) == NULL)
145         return (PIXTILING *)ERROR_PTR("pt not made", procName, NULL);
146     pt->pix = pixClone(pixs);
147     pt->xoverlap = xoverlap;
148     pt->yoverlap = yoverlap;
149     pt->nx = nx;
150     pt->ny = ny;
151     pt->w = w;
152     pt->h = h;
153     pt->strip = TRUE;
154     return pt;
155 }
156 
157 
158 /*!
159  *  pixTilingDestroy()
160  *
161  *      Input:  &pt (<will be set to null before returning>)
162  *      Return: void
163  */
164 void
pixTilingDestroy(PIXTILING ** ppt)165 pixTilingDestroy(PIXTILING  **ppt)
166 {
167 PIXTILING  *pt;
168 
169     PROCNAME("pixTilingDestroy");
170 
171     if (ppt == NULL) {
172         L_WARNING("ptr address is null!", procName);
173         return;
174     }
175 
176     if ((pt = *ppt) == NULL)
177         return;
178 
179     pixDestroy(&pt->pix);
180     FREE(pt);
181     *ppt = NULL;
182     return;
183 }
184 
185 
186 /*!
187  *  pixTilingGetCount()
188  *
189  *      Input:  pt (pixtiling)
190  *              &nx (<optional return> nx; can be null)
191  *              &ny (<optional return> ny; can be null)
192  *      Return: 0 if OK, 1 on error
193  */
194 l_int32
pixTilingGetCount(PIXTILING * pt,l_int32 * pnx,l_int32 * pny)195 pixTilingGetCount(PIXTILING  *pt,
196                   l_int32    *pnx,
197                   l_int32    *pny)
198 {
199     PROCNAME("pixTilingGetCount");
200 
201     if (!pt)
202         return ERROR_INT("pt not defined", procName, 1);
203     if (pnx) *pnx = pt->nx;
204     if (pny) *pny = pt->ny;
205     return 0;
206 }
207 
208 
209 /*!
210  *  pixTilingGetSize()
211  *
212  *      Input:  pt (pixtiling)
213  *              &w (<optional return> tile width; can be null)
214  *              &h (<optional return> tile height; can be null)
215  *      Return: 0 if OK, 1 on error
216  */
217 l_int32
pixTilingGetSize(PIXTILING * pt,l_int32 * pw,l_int32 * ph)218 pixTilingGetSize(PIXTILING  *pt,
219                  l_int32    *pw,
220                  l_int32    *ph)
221 {
222     PROCNAME("pixTilingGetSize");
223 
224     if (!pt)
225         return ERROR_INT("pt not defined", procName, 1);
226     if (pw) *pw = pt->w;
227     if (ph) *ph = pt->h;
228     return 0;
229 }
230 
231 
232 /*!
233  *  pixTilingGetTile()
234  *
235  *      Input:  pt (pixtiling)
236  *              i (tile row index)
237  *              j (tile column index)
238  *      Return: pixd (tile with appropriate boundary (overlap) pixels added),
239  *                    or null on error
240  */
241 PIX *
pixTilingGetTile(PIXTILING * pt,l_int32 i,l_int32 j)242 pixTilingGetTile(PIXTILING  *pt,
243                  l_int32     i,
244                  l_int32     j)
245 {
246 l_int32  wpix, hpix, wt, ht, nx, ny;
247 l_int32  xoverlap, yoverlap, wtlast, htlast;
248 l_int32  left, top, xtraleft, xtraright, xtratop, xtrabot, width, height;
249 BOX     *box;
250 PIX     *pixs, *pixt, *pixd;
251 
252     PROCNAME("pixTilingGetTile");
253 
254     if (!pt)
255         return (PIX *)ERROR_PTR("pt not defined", procName, NULL);
256     if ((pixs = pt->pix) == NULL)
257         return (PIX *)ERROR_PTR("pix not found", procName, NULL);
258     pixTilingGetCount(pt, &nx, &ny);
259     if (i < 0 || i >= ny)
260         return (PIX *)ERROR_PTR("invalid row index i", procName, NULL);
261     if (j < 0 || j >= nx)
262         return (PIX *)ERROR_PTR("invalid column index j", procName, NULL);
263 
264         /* Grab the tile with as much overlap as exists within the
265 	 * input pix.   First, compute the (left, top) coordinates.  */
266     pixGetDimensions(pixs, &wpix, &hpix, NULL);
267     pixTilingGetSize(pt, &wt, &ht);
268     xoverlap = pt->xoverlap;
269     yoverlap = pt->yoverlap;
270     wtlast = wpix - wt * (nx - 1);
271     htlast = hpix - ht * (ny - 1);
272     left = L_MAX(0, j * wt - xoverlap);
273     top = L_MAX(0, i * ht - yoverlap);
274 
275         /* Get the width and height of the tile, including whatever
276 	 * overlap is available. */
277     if (nx == 1)
278         width = wpix;
279     else if (j == 0)
280         width = wt + xoverlap;
281     else if (j == nx - 1)
282         width = wtlast + xoverlap;
283     else
284         width = wt + 2 * xoverlap;
285 
286     if (ny == 1)
287         height = hpix;
288     else if (i == 0)
289         height = ht + yoverlap;
290     else if (i == ny - 1)
291         height = htlast + yoverlap;
292     else
293         height = ht + 2 * yoverlap;
294     box = boxCreate(left, top, width, height);
295     pixt = pixClipRectangle(pixs, box, NULL);
296     boxDestroy(&box);
297 
298        /* Add overlap as a mirrored border, in the 8 special cases where
299 	* the tile touches the border of the input pix.  The xtratop (etc)
300 	* parameters are required where the tile is either full width
301 	* or full height.  */
302     xtratop = xtrabot = xtraleft = xtraright = 0;
303     if (nx == 1)
304         xtraleft = xtraright = xoverlap;
305     if (ny == 1)
306         xtratop = xtrabot = yoverlap;
307     if (i == 0 && j == 0)
308         pixd = pixAddMirroredBorder(pixt, xoverlap, xtraright,
309                                     yoverlap, xtrabot);
310     else if (i == 0 && j == nx - 1)
311         pixd = pixAddMirroredBorder(pixt, xtraleft, xoverlap,
312                                     yoverlap, xtrabot);
313     else if (i == ny - 1 && j == 0)
314         pixd = pixAddMirroredBorder(pixt, xoverlap, xtraright,
315                                     xtratop, yoverlap);
316     else if (i == ny - 1 && j == nx - 1)
317         pixd = pixAddMirroredBorder(pixt, xtraleft, xoverlap,
318                                     xtratop, yoverlap);
319     else if (i == 0)
320         pixd = pixAddMirroredBorder(pixt, 0, 0, yoverlap, xtrabot);
321     else if (i == ny - 1)
322         pixd = pixAddMirroredBorder(pixt, 0, 0, xtratop, yoverlap);
323     else if (j == 0)
324         pixd = pixAddMirroredBorder(pixt, xoverlap, xtraright, 0, 0);
325     else if (j == nx - 1)
326         pixd = pixAddMirroredBorder(pixt, xtraleft, xoverlap, 0, 0);
327     else
328         pixd = pixClone(pixt);
329     pixDestroy(&pixt);
330 
331     return pixd;
332 }
333 
334 
335 /*!
336  *  pixTilingNoStripOnPaint()
337  *
338  *      Input:  pt (pixtiling)
339  *      Return: 0 if OK, 1 on error
340  *
341  *  Notes:
342  *      (1) The default for paint is to strip out the overlap pixels
343  *          that are added by pixTilingGetTile().  However, some
344  *          operations will generate an image with these pixels
345  *          stripped off.  This tells the paint operation not
346  *          to strip the added boundary pixels when painting.
347  */
348 l_int32
pixTilingNoStripOnPaint(PIXTILING * pt)349 pixTilingNoStripOnPaint(PIXTILING  *pt)
350 {
351     PROCNAME("pixTilingNoStripOnPaint");
352 
353     if (!pt)
354         return ERROR_INT("pt not defined", procName, 1);
355     pt->strip = FALSE;
356     return 0;
357 }
358 
359 
360 /*!
361  *  pixTilingPaintTile()
362  *
363  *      Input:  pixd (dest: paint tile onto this, without overlap)
364  *              i (tile row index)
365  *              j (tile column index)
366  *              pixs (source: tile to be painted from)
367  *              pt (pixtiling struct)
368  *      Return: 0 if OK, 1 on error
369  */
370 l_int32
pixTilingPaintTile(PIX * pixd,l_int32 i,l_int32 j,PIX * pixs,PIXTILING * pt)371 pixTilingPaintTile(PIX        *pixd,
372                    l_int32     i,
373                    l_int32     j,
374                    PIX        *pixs,
375                    PIXTILING  *pt)
376 {
377 l_int32  w, h;
378 
379     PROCNAME("pixTilingPaintTile");
380 
381     if (!pixd)
382         return ERROR_INT("pixd not defined", procName, 1);
383     if (!pixs)
384         return ERROR_INT("pixs not defined", procName, 1);
385     if (!pt)
386         return ERROR_INT("pt not defined", procName, 1);
387     if (i < 0 || i >= pt->ny)
388         return ERROR_INT("invalid row index i", procName, 1);
389     if (j < 0 || j >= pt->nx)
390         return ERROR_INT("invalid column index j", procName, 1);
391 
392         /* Strip added border pixels off if requested */
393     pixGetDimensions(pixs, &w, &h, NULL);
394     if (pt->strip == TRUE)
395         pixRasterop(pixd, j * pt->w, i * pt->h,
396                     w - 2 * pt->xoverlap, h - 2 * pt->yoverlap, PIX_SRC,
397                     pixs, pt->xoverlap, pt->yoverlap);
398     else
399         pixRasterop(pixd, j * pt->w, i * pt->h, w, h, PIX_SRC, pixs, 0, 0);
400 
401     return 0;
402 }
403 
404 
405