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