/src/leptonica/src/pixtiling.c
Line | Count | Source (jump to first uncovered line) |
1 | | /*====================================================================* |
2 | | - Copyright (C) 2001 Leptonica. All rights reserved. |
3 | | - |
4 | | - Redistribution and use in source and binary forms, with or without |
5 | | - modification, are permitted provided that the following conditions |
6 | | - are met: |
7 | | - 1. Redistributions of source code must retain the above copyright |
8 | | - notice, this list of conditions and the following disclaimer. |
9 | | - 2. Redistributions in binary form must reproduce the above |
10 | | - copyright notice, this list of conditions and the following |
11 | | - disclaimer in the documentation and/or other materials |
12 | | - provided with the distribution. |
13 | | - |
14 | | - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
15 | | - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
16 | | - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
17 | | - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY |
18 | | - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
19 | | - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
20 | | - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
21 | | - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
22 | | - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
23 | | - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
24 | | - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
25 | | *====================================================================*/ |
26 | | |
27 | | /*! |
28 | | * \file pixtiling.c |
29 | | * <pre> |
30 | | * |
31 | | * PIXTILING *pixTilingCreate() |
32 | | * void *pixTilingDestroy() |
33 | | * l_int32 pixTilingGetCount() |
34 | | * l_int32 pixTilingGetSize() |
35 | | * PIX *pixTilingGetTile() |
36 | | * l_int32 pixTilingNoStripOnPaint() |
37 | | * l_int32 pixTilingPaintTile() |
38 | | * |
39 | | * This provides a simple way to split an image into tiles |
40 | | * and to perform operations independently on each tile. |
41 | | * |
42 | | * The tile created with pixTilingGetTile() can have pixels in |
43 | | * adjacent tiles for computation. The number of extra pixels |
44 | | * on each side of the tile is given by an 'overlap' parameter |
45 | | * to pixTilingCreate(). For tiles at the boundary of |
46 | | * the input image, quasi-overlap pixels are created by reflection |
47 | | * symmetry into the tile. |
48 | | * |
49 | | * Here's a typical intended usage. Suppose you want to parallelize |
50 | | * the operation on an image, by operating on tiles. For each |
51 | | * tile, you want to generate an in-place image result at the same |
52 | | * resolution. Suppose you choose a one-dimensional vertical tiling, |
53 | | * where the desired tile width is 256 pixels and the overlap is |
54 | | * 30 pixels on left and right sides: |
55 | | * |
56 | | * PIX *pixd = pixCreateTemplate(pixs); // output |
57 | | * PIXTILING *pt = pixTilingCreate(pixs, 0, 1, 256, 30, 0); |
58 | | * pixTilingGetCount(pt, &nx, NULL); |
59 | | * for (j = 0; j < nx; j++) { |
60 | | * PIX *pixt = pixTilingGetTile(pt, 0, j); |
61 | | * SomeInPlaceOperation(pixt, 30, 0, ...); |
62 | | * pixTilingPaintTile(pixd, 0, j, pixt, pt); |
63 | | * pixDestroy(&pixt); |
64 | | * } |
65 | | * |
66 | | * In this example, note the following: |
67 | | * ~ The unspecfified in-place operation could instead generate |
68 | | * a new pix. If this is done, the resulting pix must be the |
69 | | * same size as pixt, because pixTilingPaintTile() makes that |
70 | | * assumption, removing the overlap pixels before painting |
71 | | * into the destination. |
72 | | * ~ The 'overlap' parameters have been included in your function, |
73 | | * to indicate which pixels are not in the exterior overlap region. |
74 | | * You will need to change only pixels that are not in the overlap |
75 | | * region, because those are the pixels that will be painted |
76 | | * into the destination. |
77 | | * ~ For tiles on the outside of the image, mirrored pixels are |
78 | | * added to substitute for the overlap that is added to interior |
79 | | * tiles. This allows you to implement your function without |
80 | | * reference to which tile it is; no special coding is necessary |
81 | | * for pixels that are near the image boundary. |
82 | | * ~ The tiles are labeled by (i, j) = (row, column), |
83 | | * and in this example there is one row and nx columns. |
84 | | * </pre> |
85 | | */ |
86 | | |
87 | | #ifdef HAVE_CONFIG_H |
88 | | #include <config_auto.h> |
89 | | #endif /* HAVE_CONFIG_H */ |
90 | | |
91 | | #include "allheaders.h" |
92 | | #include "pix_internal.h" |
93 | | |
94 | | /*! |
95 | | * \brief pixTilingCreate() |
96 | | * |
97 | | * \param[in] pixs pix to be tiled; any depth; colormap OK |
98 | | * \param[in] nx number of tiles across image |
99 | | * \param[in] ny number of tiles down image |
100 | | * \param[in] w desired width of each tile |
101 | | * \param[in] h desired height of each tile |
102 | | * \param[in] xoverlap overlap into neighboring tiles on each side |
103 | | * \param[in] yoverlap overlap into neighboring tiles above and below |
104 | | * \return pixtiling, or NULL on error |
105 | | * |
106 | | * <pre> |
107 | | * Notes: |
108 | | * (1) We put a clone of pixs in the PixTiling. |
109 | | * (2) The input to pixTilingCreate() for horizontal tiling can be |
110 | | * either the number of tiles across the image or the approximate |
111 | | * width of the tiles. If the latter, the actual width will be |
112 | | * determined by making all tiles but the last of equal width, and |
113 | | * making the last as close to the others as possible. The same |
114 | | * consideration is applied independently to the vertical tiling. |
115 | | * To specify tile width, set nx = 0; to specify the number of |
116 | | * tiles horizontally across the image, set w = 0. |
117 | | * (3) If pixs is to be tiled in one-dimensional strips, use ny = 1 for |
118 | | * vertical strips and nx = 1 for horizontal strips. |
119 | | * (4) The overlap must not be larger than the width or height of |
120 | | * the leftmost or topmost tile(s). |
121 | | * </pre> |
122 | | */ |
123 | | PIXTILING * |
124 | | pixTilingCreate(PIX *pixs, |
125 | | l_int32 nx, |
126 | | l_int32 ny, |
127 | | l_int32 w, |
128 | | l_int32 h, |
129 | | l_int32 xoverlap, |
130 | | l_int32 yoverlap) |
131 | 0 | { |
132 | 0 | l_int32 width, height; |
133 | 0 | PIXTILING *pt; |
134 | |
|
135 | 0 | if (!pixs) |
136 | 0 | return (PIXTILING *)ERROR_PTR("pixs not defined", __func__, NULL); |
137 | 0 | if (nx < 1 && w < 1) |
138 | 0 | return (PIXTILING *)ERROR_PTR("invalid width spec", __func__, NULL); |
139 | 0 | if (ny < 1 && h < 1) |
140 | 0 | return (PIXTILING *)ERROR_PTR("invalid height spec", __func__, NULL); |
141 | | |
142 | | /* Find the tile width and number of tiles. All tiles except the |
143 | | * rightmost ones have the same width. The width of the |
144 | | * rightmost ones are at least the width of the others and |
145 | | * less than twice that width. Ditto for tile height. */ |
146 | 0 | pixGetDimensions(pixs, &width, &height, NULL); |
147 | 0 | if (nx == 0) |
148 | 0 | nx = L_MAX(1, width / w); |
149 | 0 | w = width / nx; /* possibly reset */ |
150 | 0 | if (ny == 0) |
151 | 0 | ny = L_MAX(1, height / h); |
152 | 0 | h = height / ny; /* possibly reset */ |
153 | 0 | if (xoverlap > w || yoverlap > h) { |
154 | 0 | L_INFO("tile width = %d, tile height = %d\n", __func__, w, h); |
155 | 0 | return (PIXTILING *)ERROR_PTR("overlap too large", __func__, NULL); |
156 | 0 | } |
157 | | |
158 | 0 | pt = (PIXTILING *)LEPT_CALLOC(1, sizeof(PIXTILING)); |
159 | 0 | pt->pix = pixClone(pixs); |
160 | 0 | pt->xoverlap = xoverlap; |
161 | 0 | pt->yoverlap = yoverlap; |
162 | 0 | pt->nx = nx; |
163 | 0 | pt->ny = ny; |
164 | 0 | pt->w = w; |
165 | 0 | pt->h = h; |
166 | 0 | pt->strip = TRUE; |
167 | 0 | return pt; |
168 | 0 | } |
169 | | |
170 | | |
171 | | /*! |
172 | | * \brief pixTilingDestroy() |
173 | | * |
174 | | * \param[in,out] ppt will be set to null before returning |
175 | | * \return void |
176 | | */ |
177 | | void |
178 | | pixTilingDestroy(PIXTILING **ppt) |
179 | 0 | { |
180 | 0 | PIXTILING *pt; |
181 | |
|
182 | 0 | if (ppt == NULL) { |
183 | 0 | L_WARNING("ptr address is null!\n", __func__); |
184 | 0 | return; |
185 | 0 | } |
186 | | |
187 | 0 | if ((pt = *ppt) == NULL) |
188 | 0 | return; |
189 | | |
190 | 0 | pixDestroy(&pt->pix); |
191 | 0 | LEPT_FREE(pt); |
192 | 0 | *ppt = NULL; |
193 | 0 | } |
194 | | |
195 | | |
196 | | /*! |
197 | | * \brief pixTilingGetCount() |
198 | | * |
199 | | * \param[in] pt pixtiling |
200 | | * \param[out] pnx [optional] nx; can be null |
201 | | * \param[out] pny [optional] ny; can be null |
202 | | * \return 0 if OK, 1 on error |
203 | | */ |
204 | | l_ok |
205 | | pixTilingGetCount(PIXTILING *pt, |
206 | | l_int32 *pnx, |
207 | | l_int32 *pny) |
208 | 0 | { |
209 | 0 | if (!pt) |
210 | 0 | return ERROR_INT("pt not defined", __func__, 1); |
211 | 0 | if (pnx) *pnx = pt->nx; |
212 | 0 | if (pny) *pny = pt->ny; |
213 | 0 | return 0; |
214 | 0 | } |
215 | | |
216 | | |
217 | | /*! |
218 | | * \brief pixTilingGetSize() |
219 | | * |
220 | | * \param[in] pt pixtiling |
221 | | * \param[out] pw [optional] tile width; can be null |
222 | | * \param[out] ph [optional] tile height; can be null |
223 | | * \return 0 if OK, 1 on error |
224 | | */ |
225 | | l_ok |
226 | | pixTilingGetSize(PIXTILING *pt, |
227 | | l_int32 *pw, |
228 | | l_int32 *ph) |
229 | 0 | { |
230 | 0 | if (!pt) |
231 | 0 | return ERROR_INT("pt not defined", __func__, 1); |
232 | 0 | if (pw) *pw = pt->w; |
233 | 0 | if (ph) *ph = pt->h; |
234 | 0 | return 0; |
235 | 0 | } |
236 | | |
237 | | |
238 | | /*! |
239 | | * \brief pixTilingGetTile() |
240 | | * |
241 | | * \param[in] pt pixtiling |
242 | | * \param[in] i tile row index |
243 | | * \param[in] j tile column index |
244 | | * \return pixd tile with appropriate boundary (overlap) pixels added, |
245 | | * or NULL on error |
246 | | */ |
247 | | PIX * |
248 | | pixTilingGetTile(PIXTILING *pt, |
249 | | l_int32 i, |
250 | | l_int32 j) |
251 | 0 | { |
252 | 0 | l_int32 wpix, hpix, wt, ht, nx, ny; |
253 | 0 | l_int32 xoverlap, yoverlap, wtlast, htlast; |
254 | 0 | l_int32 left, top, xtraleft, xtraright, xtratop, xtrabot, width, height; |
255 | 0 | BOX *box; |
256 | 0 | PIX *pixs, *pixt, *pixd; |
257 | |
|
258 | 0 | if (!pt) |
259 | 0 | return (PIX *)ERROR_PTR("pt not defined", __func__, NULL); |
260 | 0 | if ((pixs = pt->pix) == NULL) |
261 | 0 | return (PIX *)ERROR_PTR("pix not found", __func__, NULL); |
262 | 0 | pixTilingGetCount(pt, &nx, &ny); |
263 | 0 | if (i < 0 || i >= ny) |
264 | 0 | return (PIX *)ERROR_PTR("invalid row index i", __func__, NULL); |
265 | 0 | if (j < 0 || j >= nx) |
266 | 0 | return (PIX *)ERROR_PTR("invalid column index j", __func__, NULL); |
267 | | |
268 | | /* Grab the tile with as much overlap as exists within the |
269 | | * input pix. First, compute the (left, top) coordinates. */ |
270 | 0 | pixGetDimensions(pixs, &wpix, &hpix, NULL); |
271 | 0 | pixTilingGetSize(pt, &wt, &ht); |
272 | 0 | xoverlap = pt->xoverlap; |
273 | 0 | yoverlap = pt->yoverlap; |
274 | 0 | wtlast = wpix - wt * (nx - 1); |
275 | 0 | htlast = hpix - ht * (ny - 1); |
276 | 0 | left = L_MAX(0, j * wt - xoverlap); |
277 | 0 | top = L_MAX(0, i * ht - yoverlap); |
278 | | |
279 | | /* Get the width and height of the tile, including whatever |
280 | | * overlap is available. */ |
281 | 0 | if (nx == 1) |
282 | 0 | width = wpix; |
283 | 0 | else if (j == 0) |
284 | 0 | width = wt + xoverlap; |
285 | 0 | else if (j == nx - 1) |
286 | 0 | width = wtlast + xoverlap; |
287 | 0 | else |
288 | 0 | width = wt + 2 * xoverlap; |
289 | |
|
290 | 0 | if (ny == 1) |
291 | 0 | height = hpix; |
292 | 0 | else if (i == 0) |
293 | 0 | height = ht + yoverlap; |
294 | 0 | else if (i == ny - 1) |
295 | 0 | height = htlast + yoverlap; |
296 | 0 | else |
297 | 0 | height = ht + 2 * yoverlap; |
298 | 0 | box = boxCreate(left, top, width, height); |
299 | 0 | pixt = pixClipRectangle(pixs, box, NULL); |
300 | 0 | boxDestroy(&box); |
301 | | |
302 | | /* If no overlap, do not add any special case borders */ |
303 | 0 | if (xoverlap == 0 && yoverlap == 0) |
304 | 0 | return pixt; |
305 | | |
306 | | /* Add overlap as a mirrored border, in the 8 special cases where |
307 | | * the tile touches the border of the input pix. The xtratop (etc) |
308 | | * parameters are required where the tile is either full width |
309 | | * or full height. */ |
310 | 0 | xtratop = xtrabot = xtraleft = xtraright = 0; |
311 | 0 | if (nx == 1) |
312 | 0 | xtraleft = xtraright = xoverlap; |
313 | 0 | if (ny == 1) |
314 | 0 | xtratop = xtrabot = yoverlap; |
315 | 0 | if (i == 0 && j == 0) |
316 | 0 | pixd = pixAddMirroredBorder(pixt, xoverlap, xtraright, |
317 | 0 | yoverlap, xtrabot); |
318 | 0 | else if (i == 0 && j == nx - 1) |
319 | 0 | pixd = pixAddMirroredBorder(pixt, xtraleft, xoverlap, |
320 | 0 | yoverlap, xtrabot); |
321 | 0 | else if (i == ny - 1 && j == 0) |
322 | 0 | pixd = pixAddMirroredBorder(pixt, xoverlap, xtraright, |
323 | 0 | xtratop, yoverlap); |
324 | 0 | else if (i == ny - 1 && j == nx - 1) |
325 | 0 | pixd = pixAddMirroredBorder(pixt, xtraleft, xoverlap, |
326 | 0 | xtratop, yoverlap); |
327 | 0 | else if (i == 0) |
328 | 0 | pixd = pixAddMirroredBorder(pixt, 0, 0, yoverlap, xtrabot); |
329 | 0 | else if (i == ny - 1) |
330 | 0 | pixd = pixAddMirroredBorder(pixt, 0, 0, xtratop, yoverlap); |
331 | 0 | else if (j == 0) |
332 | 0 | pixd = pixAddMirroredBorder(pixt, xoverlap, xtraright, 0, 0); |
333 | 0 | else if (j == nx - 1) |
334 | 0 | pixd = pixAddMirroredBorder(pixt, xtraleft, xoverlap, 0, 0); |
335 | 0 | else |
336 | 0 | pixd = pixClone(pixt); |
337 | 0 | pixDestroy(&pixt); |
338 | |
|
339 | 0 | return pixd; |
340 | 0 | } |
341 | | |
342 | | |
343 | | /*! |
344 | | * \brief pixTilingNoStripOnPaint() |
345 | | * |
346 | | * \param[in] pt pixtiling |
347 | | * \return 0 if OK, 1 on error |
348 | | * |
349 | | * <pre> |
350 | | * Notes: |
351 | | * (1) The default for paint is to strip out the overlap pixels |
352 | | * that are added by pixTilingGetTile(). However, some |
353 | | * operations will generate an image with these pixels |
354 | | * stripped off. This tells the paint operation not |
355 | | * to strip the added boundary pixels when painting. |
356 | | * </pre> |
357 | | */ |
358 | | l_ok |
359 | | pixTilingNoStripOnPaint(PIXTILING *pt) |
360 | 0 | { |
361 | 0 | if (!pt) |
362 | 0 | return ERROR_INT("pt not defined", __func__, 1); |
363 | 0 | pt->strip = FALSE; |
364 | 0 | return 0; |
365 | 0 | } |
366 | | |
367 | | |
368 | | /*! |
369 | | * \brief pixTilingPaintTile() |
370 | | * |
371 | | * \param[in] pixd dest: paint tile onto this, without overlap |
372 | | * \param[in] i tile row index |
373 | | * \param[in] j tile column index |
374 | | * \param[in] pixs source: tile to be painted from |
375 | | * \param[in] pt pixtiling struct |
376 | | * \return 0 if OK, 1 on error |
377 | | */ |
378 | | l_ok |
379 | | pixTilingPaintTile(PIX *pixd, |
380 | | l_int32 i, |
381 | | l_int32 j, |
382 | | PIX *pixs, |
383 | | PIXTILING *pt) |
384 | 0 | { |
385 | 0 | l_int32 w, h; |
386 | |
|
387 | 0 | if (!pixd) |
388 | 0 | return ERROR_INT("pixd not defined", __func__, 1); |
389 | 0 | if (!pixs) |
390 | 0 | return ERROR_INT("pixs not defined", __func__, 1); |
391 | 0 | if (!pt) |
392 | 0 | return ERROR_INT("pt not defined", __func__, 1); |
393 | 0 | if (i < 0 || i >= pt->ny) |
394 | 0 | return ERROR_INT("invalid row index i", __func__, 1); |
395 | 0 | if (j < 0 || j >= pt->nx) |
396 | 0 | return ERROR_INT("invalid column index j", __func__, 1); |
397 | | |
398 | | /* Strip added border pixels off if requested */ |
399 | 0 | pixGetDimensions(pixs, &w, &h, NULL); |
400 | 0 | if (pt->strip == TRUE) { |
401 | 0 | pixRasterop(pixd, j * pt->w, i * pt->h, |
402 | 0 | w - 2 * pt->xoverlap, h - 2 * pt->yoverlap, PIX_SRC, |
403 | 0 | pixs, pt->xoverlap, pt->yoverlap); |
404 | 0 | } else { |
405 | 0 | pixRasterop(pixd, j * pt->w, i * pt->h, w, h, PIX_SRC, pixs, 0, 0); |
406 | 0 | } |
407 | |
|
408 | 0 | return 0; |
409 | 0 | } |