mirror of http://192.168.1.51:8099/lmh188/twain3.0
422 lines
14 KiB
C
422 lines
14 KiB
C
/*====================================================================*
|
|
- Copyright (C) 2001 Leptonica. All rights reserved.
|
|
-
|
|
- Redistribution and use in source and binary forms, with or without
|
|
- modification, are permitted provided that the following conditions
|
|
- are met:
|
|
- 1. Redistributions of source code must retain the above copyright
|
|
- notice, this list of conditions and the following disclaimer.
|
|
- 2. Redistributions in binary form must reproduce the above
|
|
- copyright notice, this list of conditions and the following
|
|
- disclaimer in the documentation and/or other materials
|
|
- provided with the distribution.
|
|
-
|
|
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
- ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY
|
|
- CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
- EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
- PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
|
- OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
- NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*====================================================================*/
|
|
|
|
|
|
/*!
|
|
* \file pixtiling.c
|
|
* <pre>
|
|
*
|
|
* PIXTILING *pixTilingCreate()
|
|
* void *pixTilingDestroy()
|
|
* l_int32 pixTilingGetCount()
|
|
* l_int32 pixTilingGetSize()
|
|
* PIX *pixTilingGetTile()
|
|
* l_int32 pixTilingNoStripOnPaint()
|
|
* l_int32 pixTilingPaintTile()
|
|
*
|
|
* This provides a simple way to split an image into tiles
|
|
* and to perform operations independently on each tile.
|
|
*
|
|
* The tile created with pixTilingGetTile() can have pixels in
|
|
* adjacent tiles for computation. The number of extra pixels
|
|
* on each side of the tile is given by an 'overlap' parameter
|
|
* to pixTilingCreate(). For tiles at the boundary of
|
|
* the input image, quasi-overlap pixels are created by reflection
|
|
* symmetry into the tile.
|
|
*
|
|
* Here's a typical intended usage. Suppose you want to parallelize
|
|
* the operation on an image, by operating on tiles. For each
|
|
* tile, you want to generate an in-place image result at the same
|
|
* resolution. Suppose you choose a one-dimensional vertical tiling,
|
|
* where the desired tile width is 256 pixels and the overlap is
|
|
* 30 pixels on left and right sides:
|
|
*
|
|
* PIX *pixd = pixCreateTemplate(pixs); // output
|
|
* PIXTILING *pt = pixTilingCreate(pixs, 0, 1, 256, 30, 0);
|
|
* pixTilingGetCount(pt, &nx, NULL);
|
|
* for (j = 0; j < nx; j++) {
|
|
* PIX *pixt = pixTilingGetTile(pt, 0, j);
|
|
* SomeInPlaceOperation(pixt, 30, 0, ...);
|
|
* pixTilingPaintTile(pixd, 0, j, pixt, pt);
|
|
* pixDestroy(&pixt);
|
|
* }
|
|
*
|
|
* In this example, note the following:
|
|
* ~ The unspecfified in-place operation could instead generate
|
|
* a new pix. If this is done, the resulting pix must be the
|
|
* same size as pixt, because pixTilingPaintTile() makes that
|
|
* assumption, removing the overlap pixels before painting
|
|
* into the destination.
|
|
* ~ The 'overlap' parameters have been included in your function,
|
|
* to indicate which pixels are not in the exterior overlap region.
|
|
* You will need to change only pixels that are not in the overlap
|
|
* region, because those are the pixels that will be painted
|
|
* into the destination.
|
|
* ~ For tiles on the outside of the image, mirrored pixels are
|
|
* added to substitute for the overlap that is added to interior
|
|
* tiles. This allows you to implement your function without
|
|
* reference to which tile it is; no special coding is necessary
|
|
* for pixels that are near the image boundary.
|
|
* ~ The tiles are labeled by (i, j) = (row, column),
|
|
* and in this example there is one row and nx columns.
|
|
* </pre>
|
|
*/
|
|
|
|
#include "allheaders.h"
|
|
|
|
|
|
/*!
|
|
* \brief pixTilingCreate()
|
|
*
|
|
* \param[in] pixs pix to be tiled; any depth; colormap OK
|
|
* \param[in] nx number of tiles across image
|
|
* \param[in] ny number of tiles down image
|
|
* \param[in] w desired width of each tile
|
|
* \param[in] h desired height of each tile
|
|
* \param[in] xoverlap overlap into neighboring tiles on each side
|
|
* \param[in] yoverlap overlap into neighboring tiles above and below
|
|
* \return pixtiling, or NULL on error
|
|
*
|
|
* <pre>
|
|
* Notes:
|
|
* (1) We put a clone of pixs in the PixTiling.
|
|
* (2) The input to pixTilingCreate() for horizontal tiling can be
|
|
* either the number of tiles across the image or the approximate
|
|
* width of the tiles. If the latter, the actual width will be
|
|
* determined by making all tiles but the last of equal width, and
|
|
* making the last as close to the others as possible. The same
|
|
* consideration is applied independently to the vertical tiling.
|
|
* To specify tile width, set nx = 0; to specify the number of
|
|
* tiles horizontally across the image, set w = 0.
|
|
* (3) If pixs is to be tiled in one-dimensional strips, use ny = 1 for
|
|
* vertical strips and nx = 1 for horizontal strips.
|
|
* (4) The overlap must not be larger than the width or height of
|
|
* the leftmost or topmost tile(s).
|
|
* </pre>
|
|
*/
|
|
PIXTILING *
|
|
pixTilingCreate(PIX *pixs,
|
|
l_int32 nx,
|
|
l_int32 ny,
|
|
l_int32 w,
|
|
l_int32 h,
|
|
l_int32 xoverlap,
|
|
l_int32 yoverlap)
|
|
{
|
|
l_int32 width, height;
|
|
PIXTILING *pt;
|
|
|
|
PROCNAME("pixTilingCreate");
|
|
|
|
if (!pixs)
|
|
return (PIXTILING *)ERROR_PTR("pixs not defined", procName, NULL);
|
|
if (nx < 1 && w < 1)
|
|
return (PIXTILING *)ERROR_PTR("invalid width spec", procName, NULL);
|
|
if (ny < 1 && h < 1)
|
|
return (PIXTILING *)ERROR_PTR("invalid height spec", procName, NULL);
|
|
|
|
/* Find the tile width and number of tiles. All tiles except the
|
|
* rightmost ones have the same width. The width of the
|
|
* rightmost ones are at least the width of the others and
|
|
* less than twice that width. Ditto for tile height. */
|
|
pixGetDimensions(pixs, &width, &height, NULL);
|
|
if (nx == 0)
|
|
nx = L_MAX(1, width / w);
|
|
w = width / nx; /* possibly reset */
|
|
if (ny == 0)
|
|
ny = L_MAX(1, height / h);
|
|
h = height / ny; /* possibly reset */
|
|
if (xoverlap > w || yoverlap > h) {
|
|
L_INFO("tile width = %d, tile height = %d\n", procName, w, h);
|
|
return (PIXTILING *)ERROR_PTR("overlap too large", procName, NULL);
|
|
}
|
|
|
|
pt = (PIXTILING *)LEPT_CALLOC(1, sizeof(PIXTILING));
|
|
pt->pix = pixClone(pixs);
|
|
pt->xoverlap = xoverlap;
|
|
pt->yoverlap = yoverlap;
|
|
pt->nx = nx;
|
|
pt->ny = ny;
|
|
pt->w = w;
|
|
pt->h = h;
|
|
pt->strip = TRUE;
|
|
return pt;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief pixTilingDestroy()
|
|
*
|
|
* \param[in,out] ppt will be set to null before returning
|
|
* \return void
|
|
*/
|
|
void
|
|
pixTilingDestroy(PIXTILING **ppt)
|
|
{
|
|
PIXTILING *pt;
|
|
|
|
PROCNAME("pixTilingDestroy");
|
|
|
|
if (ppt == NULL) {
|
|
L_WARNING("ptr address is null!\n", procName);
|
|
return;
|
|
}
|
|
|
|
if ((pt = *ppt) == NULL)
|
|
return;
|
|
|
|
pixDestroy(&pt->pix);
|
|
LEPT_FREE(pt);
|
|
*ppt = NULL;
|
|
return;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief pixTilingGetCount()
|
|
*
|
|
* \param[in] pt pixtiling
|
|
* \param[out] pnx [optional] nx; can be null
|
|
* \param[out] pny [optional] ny; can be null
|
|
* \return 0 if OK, 1 on error
|
|
*/
|
|
l_ok
|
|
pixTilingGetCount(PIXTILING *pt,
|
|
l_int32 *pnx,
|
|
l_int32 *pny)
|
|
{
|
|
PROCNAME("pixTilingGetCount");
|
|
|
|
if (!pt)
|
|
return ERROR_INT("pt not defined", procName, 1);
|
|
if (pnx) *pnx = pt->nx;
|
|
if (pny) *pny = pt->ny;
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief pixTilingGetSize()
|
|
*
|
|
* \param[in] pt pixtiling
|
|
* \param[out] pw [optional] tile width; can be null
|
|
* \param[out] ph [optional] tile height; can be null
|
|
* \return 0 if OK, 1 on error
|
|
*/
|
|
l_ok
|
|
pixTilingGetSize(PIXTILING *pt,
|
|
l_int32 *pw,
|
|
l_int32 *ph)
|
|
{
|
|
PROCNAME("pixTilingGetSize");
|
|
|
|
if (!pt)
|
|
return ERROR_INT("pt not defined", procName, 1);
|
|
if (pw) *pw = pt->w;
|
|
if (ph) *ph = pt->h;
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief pixTilingGetTile()
|
|
*
|
|
* \param[in] pt pixtiling
|
|
* \param[in] i tile row index
|
|
* \param[in] j tile column index
|
|
* \return pixd tile with appropriate boundary (overlap) pixels added,
|
|
* or NULL on error
|
|
*/
|
|
PIX *
|
|
pixTilingGetTile(PIXTILING *pt,
|
|
l_int32 i,
|
|
l_int32 j)
|
|
{
|
|
l_int32 wpix, hpix, wt, ht, nx, ny;
|
|
l_int32 xoverlap, yoverlap, wtlast, htlast;
|
|
l_int32 left, top, xtraleft, xtraright, xtratop, xtrabot, width, height;
|
|
BOX *box;
|
|
PIX *pixs, *pixt, *pixd;
|
|
|
|
PROCNAME("pixTilingGetTile");
|
|
|
|
if (!pt)
|
|
return (PIX *)ERROR_PTR("pt not defined", procName, NULL);
|
|
if ((pixs = pt->pix) == NULL)
|
|
return (PIX *)ERROR_PTR("pix not found", procName, NULL);
|
|
pixTilingGetCount(pt, &nx, &ny);
|
|
if (i < 0 || i >= ny)
|
|
return (PIX *)ERROR_PTR("invalid row index i", procName, NULL);
|
|
if (j < 0 || j >= nx)
|
|
return (PIX *)ERROR_PTR("invalid column index j", procName, NULL);
|
|
|
|
/* Grab the tile with as much overlap as exists within the
|
|
* input pix. First, compute the (left, top) coordinates. */
|
|
pixGetDimensions(pixs, &wpix, &hpix, NULL);
|
|
pixTilingGetSize(pt, &wt, &ht);
|
|
xoverlap = pt->xoverlap;
|
|
yoverlap = pt->yoverlap;
|
|
wtlast = wpix - wt * (nx - 1);
|
|
htlast = hpix - ht * (ny - 1);
|
|
left = L_MAX(0, j * wt - xoverlap);
|
|
top = L_MAX(0, i * ht - yoverlap);
|
|
|
|
/* Get the width and height of the tile, including whatever
|
|
* overlap is available. */
|
|
if (nx == 1)
|
|
width = wpix;
|
|
else if (j == 0)
|
|
width = wt + xoverlap;
|
|
else if (j == nx - 1)
|
|
width = wtlast + xoverlap;
|
|
else
|
|
width = wt + 2 * xoverlap;
|
|
|
|
if (ny == 1)
|
|
height = hpix;
|
|
else if (i == 0)
|
|
height = ht + yoverlap;
|
|
else if (i == ny - 1)
|
|
height = htlast + yoverlap;
|
|
else
|
|
height = ht + 2 * yoverlap;
|
|
box = boxCreate(left, top, width, height);
|
|
pixt = pixClipRectangle(pixs, box, NULL);
|
|
boxDestroy(&box);
|
|
|
|
/* If no overlap, do not add any special case borders */
|
|
if (xoverlap == 0 && yoverlap == 0)
|
|
return pixt;
|
|
|
|
/* Add overlap as a mirrored border, in the 8 special cases where
|
|
* the tile touches the border of the input pix. The xtratop (etc)
|
|
* parameters are required where the tile is either full width
|
|
* or full height. */
|
|
xtratop = xtrabot = xtraleft = xtraright = 0;
|
|
if (nx == 1)
|
|
xtraleft = xtraright = xoverlap;
|
|
if (ny == 1)
|
|
xtratop = xtrabot = yoverlap;
|
|
if (i == 0 && j == 0)
|
|
pixd = pixAddMirroredBorder(pixt, xoverlap, xtraright,
|
|
yoverlap, xtrabot);
|
|
else if (i == 0 && j == nx - 1)
|
|
pixd = pixAddMirroredBorder(pixt, xtraleft, xoverlap,
|
|
yoverlap, xtrabot);
|
|
else if (i == ny - 1 && j == 0)
|
|
pixd = pixAddMirroredBorder(pixt, xoverlap, xtraright,
|
|
xtratop, yoverlap);
|
|
else if (i == ny - 1 && j == nx - 1)
|
|
pixd = pixAddMirroredBorder(pixt, xtraleft, xoverlap,
|
|
xtratop, yoverlap);
|
|
else if (i == 0)
|
|
pixd = pixAddMirroredBorder(pixt, 0, 0, yoverlap, xtrabot);
|
|
else if (i == ny - 1)
|
|
pixd = pixAddMirroredBorder(pixt, 0, 0, xtratop, yoverlap);
|
|
else if (j == 0)
|
|
pixd = pixAddMirroredBorder(pixt, xoverlap, xtraright, 0, 0);
|
|
else if (j == nx - 1)
|
|
pixd = pixAddMirroredBorder(pixt, xtraleft, xoverlap, 0, 0);
|
|
else
|
|
pixd = pixClone(pixt);
|
|
pixDestroy(&pixt);
|
|
|
|
return pixd;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief pixTilingNoStripOnPaint()
|
|
*
|
|
* \param[in] pt pixtiling
|
|
* \return 0 if OK, 1 on error
|
|
*
|
|
* <pre>
|
|
* Notes:
|
|
* (1) The default for paint is to strip out the overlap pixels
|
|
* that are added by pixTilingGetTile(). However, some
|
|
* operations will generate an image with these pixels
|
|
* stripped off. This tells the paint operation not
|
|
* to strip the added boundary pixels when painting.
|
|
* </pre>
|
|
*/
|
|
l_ok
|
|
pixTilingNoStripOnPaint(PIXTILING *pt)
|
|
{
|
|
PROCNAME("pixTilingNoStripOnPaint");
|
|
|
|
if (!pt)
|
|
return ERROR_INT("pt not defined", procName, 1);
|
|
pt->strip = FALSE;
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*!
|
|
* \brief pixTilingPaintTile()
|
|
*
|
|
* \param[in] pixd dest: paint tile onto this, without overlap
|
|
* \param[in] i tile row index
|
|
* \param[in] j tile column index
|
|
* \param[in] pixs source: tile to be painted from
|
|
* \param[in] pt pixtiling struct
|
|
* \return 0 if OK, 1 on error
|
|
*/
|
|
l_ok
|
|
pixTilingPaintTile(PIX *pixd,
|
|
l_int32 i,
|
|
l_int32 j,
|
|
PIX *pixs,
|
|
PIXTILING *pt)
|
|
{
|
|
l_int32 w, h;
|
|
|
|
PROCNAME("pixTilingPaintTile");
|
|
|
|
if (!pixd)
|
|
return ERROR_INT("pixd not defined", procName, 1);
|
|
if (!pixs)
|
|
return ERROR_INT("pixs not defined", procName, 1);
|
|
if (!pt)
|
|
return ERROR_INT("pt not defined", procName, 1);
|
|
if (i < 0 || i >= pt->ny)
|
|
return ERROR_INT("invalid row index i", procName, 1);
|
|
if (j < 0 || j >= pt->nx)
|
|
return ERROR_INT("invalid column index j", procName, 1);
|
|
|
|
/* Strip added border pixels off if requested */
|
|
pixGetDimensions(pixs, &w, &h, NULL);
|
|
if (pt->strip == TRUE) {
|
|
pixRasterop(pixd, j * pt->w, i * pt->h,
|
|
w - 2 * pt->xoverlap, h - 2 * pt->yoverlap, PIX_SRC,
|
|
pixs, pt->xoverlap, pt->yoverlap);
|
|
} else {
|
|
pixRasterop(pixd, j * pt->w, i * pt->h, w, h, PIX_SRC, pixs, 0, 0);
|
|
}
|
|
|
|
return 0;
|
|
}
|