twain3.0/3rdparty/hgOCR/leptonica/correlscore.c

880 lines
37 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.
*====================================================================*/
/*
* correlscore.c
*
* These are functions for computing correlation between
* pairs of 1 bpp images.
*
* Optimized 2 pix correlators (for jbig2 clustering)
* l_int32 pixCorrelationScore()
* l_int32 pixCorrelationScoreThresholded()
*
* Simple 2 pix correlators
* l_int32 pixCorrelationScoreSimple()
* l_int32 pixCorrelationScoreShifted()
*
* There are other, more application-oriented functions, that
* compute the correlation between two binary images, taking into
* account small translational shifts, between two binary images.
* These are:
* compare.c: pixBestCorrelation()
* Uses coarse-to-fine translations of full image
* recogident.c: pixCorrelationBestShift()
* Uses small shifts between c.c. centroids.
*/
#include <math.h>
#include "allheaders.h"
/* -------------------------------------------------------------------- *
* Optimized 2 pix correlators (for jbig2 clustering) *
* -------------------------------------------------------------------- */
/*!
* \brief pixCorrelationScore()
*
* \param[in] pix1 test pix, 1 bpp
* \param[in] pix2 exemplar pix, 1 bpp
* \param[in] area1 number of on pixels in pix1
* \param[in] area2 number of on pixels in pix2
* \param[in] delx x comp of centroid difference
* \param[in] dely y comp of centroid difference
* \param[in] maxdiffw max width difference of pix1 and pix2
* \param[in] maxdiffh max height difference of pix1 and pix2
* \param[in] tab sum tab for byte
* \param[out] pscore correlation score
* \return 0 if OK, 1 on error
*
* <pre>
* Notes:
* We check first that the two pix are roughly the same size.
* For jbclass (jbig2) applications at roughly 300 ppi, maxdiffw and
* maxdiffh should be at least 2.
*
* Only if they meet that criterion do we compare the bitmaps.
* The centroid difference is used to align the two images to the
* nearest integer for the correlation.
*
* The correlation score is the ratio of the square of the number of
* pixels in the AND of the two bitmaps to the product of the number
* of ON pixels in each. Denote the number of ON pixels in pix1
* by |1|, the number in pix2 by |2|, and the number in the AND
* of pix1 and pix2 by |1 & 2|. The correlation score is then
* (|1 & 2|)**2 / (|1|*|2|).
*
* This score is compared with an input threshold, which can
* be modified depending on the weight of the template.
* The modified threshold is
* thresh + (1.0 - thresh) * weight * R
* where
* weight is a fixed input factor between 0.0 and 1.0
* R = |2| / area(2)
* and area(2) is the total number of pixels in 2 (i.e., width x height).
*
* To understand why a weight factor is useful, consider what happens
* with thick, sans-serif characters that look similar and have a value
* of R near 1. Different characters can have a high correlation value,
* and the classifier will make incorrect substitutions. The weight
* factor raises the threshold for these characters.
*
* Yet another approach to reduce such substitutions is to run the classifier
* in a non-greedy way, matching to the template with the highest
* score, not the first template with a score satisfying the matching
* constraint. However, this is not particularly effective.
*
* The implementation here gives the same result as in
* pixCorrelationScoreSimple(), where a temporary Pix is made to hold
* the AND and implementation uses rasterop:
* pixt = pixCreateTemplate(pix1);
* pixRasterop(pixt, idelx, idely, wt, ht, PIX_SRC, pix2, 0, 0);
* pixRasterop(pixt, 0, 0, wi, hi, PIX_SRC & PIX_DST, pix1, 0, 0);
* pixCountPixels(pixt, &count, tab);
* pixDestroy(&pixt);
* However, here it is done in a streaming fashion, counting as it goes,
* and touching memory exactly once, giving a 3-4x speedup over the
* simple implementation. This very fast correlation matcher was
* contributed by William Rucklidge.
* </pre>
*/
l_ok
pixCorrelationScore(PIX *pix1,
PIX *pix2,
l_int32 area1,
l_int32 area2,
l_float32 delx, /* x(1) - x(3) */
l_float32 dely, /* y(1) - y(3) */
l_int32 maxdiffw,
l_int32 maxdiffh,
l_int32 *tab,
l_float32 *pscore)
{
l_int32 wi, hi, wt, ht, delw, delh, idelx, idely, count;
l_int32 wpl1, wpl2, lorow, hirow, locol, hicol;
l_int32 x, y, pix1lskip, pix2lskip, rowwords1, rowwords2;
l_uint32 word1, word2, andw;
l_uint32 *row1, *row2;
PROCNAME("pixCorrelationScore");
if (!pscore)
return ERROR_INT("&score not defined", procName, 1);
*pscore = 0.0;
if (!pix1 || pixGetDepth(pix1) != 1)
return ERROR_INT("pix1 undefined or not 1 bpp", procName, 1);
if (!pix2 || pixGetDepth(pix2) != 1)
return ERROR_INT("pix2 undefined or not 1 bpp", procName, 1);
if (!tab)
return ERROR_INT("tab not defined", procName, 1);
if (area1 <= 0 || area2 <= 0)
return ERROR_INT("areas must be > 0", procName, 1);
/* Eliminate based on size difference */
pixGetDimensions(pix1, &wi, &hi, NULL);
pixGetDimensions(pix2, &wt, &ht, NULL);
delw = L_ABS(wi - wt);
if (delw > maxdiffw)
return 0;
delh = L_ABS(hi - ht);
if (delh > maxdiffh)
return 0;
/* Round difference to nearest integer */
if (delx >= 0)
idelx = (l_int32)(delx + 0.5);
else
idelx = (l_int32)(delx - 0.5);
if (dely >= 0)
idely = (l_int32)(dely + 0.5);
else
idely = (l_int32)(dely - 0.5);
count = 0;
wpl1 = pixGetWpl(pix1);
wpl2 = pixGetWpl(pix2);
rowwords2 = wpl2;
/* What rows of pix1 need to be considered? Only those underlying the
* shifted pix2. */
lorow = L_MAX(idely, 0);
hirow = L_MIN(ht + idely, hi);
/* Get the pointer to the first row of each image that will be
* considered. */
row1 = pixGetData(pix1) + wpl1 * lorow;
row2 = pixGetData(pix2) + wpl2 * (lorow - idely);
/* Similarly, figure out which columns of pix1 will be considered. */
locol = L_MAX(idelx, 0);
hicol = L_MIN(wt + idelx, wi);
if (idelx >= 32) {
/* pix2 is shifted far enough to the right that pix1's first
* word(s) won't contribute to the count. Increment its
* pointer to point to the first word that will contribute,
* and adjust other values accordingly. */
pix1lskip = idelx >> 5; /* # of words to skip on left */
row1 += pix1lskip;
locol -= pix1lskip << 5;
hicol -= pix1lskip << 5;
idelx &= 31;
} else if (idelx <= -32) {
/* pix2 is shifted far enough to the left that its first word(s)
* won't contribute to the count. Increment its pointer
* to point to the first word that will contribute,
* and adjust other values accordingly. */
pix2lskip = -((idelx + 31) >> 5); /* # of words to skip on left */
row2 += pix2lskip;
rowwords2 -= pix2lskip;
idelx += pix2lskip << 5;
}
if ((locol >= hicol) || (lorow >= hirow)) { /* there is no overlap */
count = 0;
} else {
/* How many words of each row of pix1 need to be considered? */
rowwords1 = (hicol + 31) >> 5;
if (idelx == 0) {
/* There's no lateral offset; simple case. */
for (y = lorow; y < hirow; y++, row1 += wpl1, row2 += wpl2) {
for (x = 0; x < rowwords1; x++) {
andw = row1[x] & row2[x];
count += tab[andw & 0xff] +
tab[(andw >> 8) & 0xff] +
tab[(andw >> 16) & 0xff] +
tab[andw >> 24];
}
}
} else if (idelx > 0) {
/* pix2 is shifted to the right. word 0 of pix1 is touched by
* word 0 of pix2; word 1 of pix1 is touched by word 0 and word
* 1 of pix2, and so on up to the last word of pix1 (word N),
* which is touched by words N-1 and N of pix1... if there is a
* word N. Handle the two cases (pix2 has N-1 words and pix2
* has at least N words) separately.
*
* Note: we know that pix2 has at least N-1 words (i.e.,
* rowwords2 >= rowwords1 - 1) by the following logic.
* We can pretend that idelx <= 31 because the >= 32 logic
* above adjusted everything appropriately. Then
* hicol <= wt + idelx <= wt + 31, so
* hicol + 31 <= wt + 62
* rowwords1 = (hicol + 31) >> 5 <= (wt + 62) >> 5
* rowwords2 == (wt + 31) >> 5, so
* rowwords1 <= rowwords2 + 1 */
if (rowwords2 < rowwords1) {
for (y = lorow; y < hirow; y++, row1 += wpl1, row2 += wpl2) {
/* Do the first iteration so the loop can be
* branch-free. */
word1 = row1[0];
word2 = row2[0] >> idelx;
andw = word1 & word2;
count += tab[andw & 0xff] +
tab[(andw >> 8) & 0xff] +
tab[(andw >> 16) & 0xff] +
tab[andw >> 24];
for (x = 1; x < rowwords2; x++) {
word1 = row1[x];
word2 = (row2[x] >> idelx) |
(row2[x - 1] << (32 - idelx));
andw = word1 & word2;
count += tab[andw & 0xff] +
tab[(andw >> 8) & 0xff] +
tab[(andw >> 16) & 0xff] +
tab[andw >> 24];
}
/* Now the last iteration - we know that this is safe
* (i.e. rowwords1 >= 2) because rowwords1 > rowwords2
* > 0 (if it was 0, we'd have taken the "count = 0"
* fast-path out of here). */
word1 = row1[x];
word2 = row2[x - 1] << (32 - idelx);
andw = word1 & word2;
count += tab[andw & 0xff] +
tab[(andw >> 8) & 0xff] +
tab[(andw >> 16) & 0xff] +
tab[andw >> 24];
}
} else {
for (y = lorow; y < hirow; y++, row1 += wpl1, row2 += wpl2) {
/* Do the first iteration so the loop can be
* branch-free. This section is the same as above
* except for the different limit on the loop, since
* the last iteration is the same as all the other
* iterations (beyond the first). */
word1 = row1[0];
word2 = row2[0] >> idelx;
andw = word1 & word2;
count += tab[andw & 0xff] +
tab[(andw >> 8) & 0xff] +
tab[(andw >> 16) & 0xff] +
tab[andw >> 24];
for (x = 1; x < rowwords1; x++) {
word1 = row1[x];
word2 = (row2[x] >> idelx) |
(row2[x - 1] << (32 - idelx));
andw = word1 & word2;
count += tab[andw & 0xff] +
tab[(andw >> 8) & 0xff] +
tab[(andw >> 16) & 0xff] +
tab[andw >> 24];
}
}
}
} else {
/* pix2 is shifted to the left. word 0 of pix1 is touched by
* word 0 and word 1 of pix2, and so on up to the last word of
* pix1 (word N), which is touched by words N and N+1 of
* pix2... if there is a word N+1. Handle the two cases (pix2
* has N words and pix2 has at least N+1 words) separately. */
if (rowwords1 < rowwords2) {
/* pix2 has at least N+1 words, so every iteration through
* the loop can be the same. */
for (y = lorow; y < hirow; y++, row1 += wpl1, row2 += wpl2) {
for (x = 0; x < rowwords1; x++) {
word1 = row1[x];
word2 = row2[x] << -idelx;
word2 |= row2[x + 1] >> (32 + idelx);
andw = word1 & word2;
count += tab[andw & 0xff] +
tab[(andw >> 8) & 0xff] +
tab[(andw >> 16) & 0xff] +
tab[andw >> 24];
}
}
} else {
/* pix2 has only N words, so the last iteration is broken
* out. */
for (y = lorow; y < hirow; y++, row1 += wpl1, row2 += wpl2) {
for (x = 0; x < rowwords1 - 1; x++) {
word1 = row1[x];
word2 = row2[x] << -idelx;
word2 |= row2[x + 1] >> (32 + idelx);
andw = word1 & word2;
count += tab[andw & 0xff] +
tab[(andw >> 8) & 0xff] +
tab[(andw >> 16) & 0xff] +
tab[andw >> 24];
}
word1 = row1[x];
word2 = row2[x] << -idelx;
andw = word1 & word2;
count += tab[andw & 0xff] +
tab[(andw >> 8) & 0xff] +
tab[(andw >> 16) & 0xff] +
tab[andw >> 24];
}
}
}
}
*pscore = (l_float32)count * (l_float32)count /
((l_float32)area1 * (l_float32)area2);
/* fprintf(stderr, "score = %5.3f, count = %d, area1 = %d, area2 = %d\n",
*pscore, count, area1, area2); */
return 0;
}
/*!
* \brief pixCorrelationScoreThresholded()
*
* \param[in] pix1 test pix, 1 bpp
* \param[in] pix2 exemplar pix, 1 bpp
* \param[in] area1 number of on pixels in pix1
* \param[in] area2 number of on pixels in pix2
* \param[in] delx x comp of centroid difference
* \param[in] dely y comp of centroid difference
* \param[in] maxdiffw max width difference of pix1 and pix2
* \param[in] maxdiffh max height difference of pix1 and pix2
* \param[in] tab sum tab for byte
* \param[in] downcount count of 1 pixels below each row of pix1
* \param[in] score_threshold
* \return whether the correlation score is >= score_threshold
*
*
* <pre>
* Notes:
* We check first that the two pix are roughly the same size.
* Only if they meet that criterion do we compare the bitmaps.
* The centroid difference is used to align the two images to the
* nearest integer for the correlation.
*
* The correlation score is the ratio of the square of the number of
* pixels in the AND of the two bitmaps to the product of the number
* of ON pixels in each. Denote the number of ON pixels in pix1
* by |1|, the number in pix2 by |2|, and the number in the AND
* of pix1 and pix2 by |1 & 2|. The correlation score is then
* (|1 & 2|)**2 / (|1|*|2|).
*
* This score is compared with an input threshold, which can
* be modified depending on the weight of the template.
* The modified threshold is
* thresh + (1.0 - thresh) * weight * R
* where
* weight is a fixed input factor between 0.0 and 1.0
* R = |2| / area(2)
* and area(2) is the total number of pixels in 2 (i.e., width x height).
*
* To understand why a weight factor is useful, consider what happens
* with thick, sans-serif characters that look similar and have a value
* of R near 1. Different characters can have a high correlation value,
* and the classifier will make incorrect substitutions. The weight
* factor raises the threshold for these characters.
*
* Yet another approach to reduce such substitutions is to run the classifier
* in a non-greedy way, matching to the template with the highest
* score, not the first template with a score satisfying the matching
* constraint. However, this is not particularly effective.
*
* This very fast correlation matcher was contributed by William Rucklidge.
* </pre>
*/
l_int32
pixCorrelationScoreThresholded(PIX *pix1,
PIX *pix2,
l_int32 area1,
l_int32 area2,
l_float32 delx, /* x(1) - x(3) */
l_float32 dely, /* y(1) - y(3) */
l_int32 maxdiffw,
l_int32 maxdiffh,
l_int32 *tab,
l_int32 *downcount,
l_float32 score_threshold)
{
l_int32 wi, hi, wt, ht, delw, delh, idelx, idely, count;
l_int32 wpl1, wpl2, lorow, hirow, locol, hicol, untouchable;
l_int32 x, y, pix1lskip, pix2lskip, rowwords1, rowwords2;
l_uint32 word1, word2, andw;
l_uint32 *row1, *row2;
l_float32 score;
l_int32 threshold;
PROCNAME("pixCorrelationScoreThresholded");
if (!pix1 || pixGetDepth(pix1) != 1)
return ERROR_INT("pix1 undefined or not 1 bpp", procName, 0);
if (!pix2 || pixGetDepth(pix2) != 1)
return ERROR_INT("pix2 undefined or not 1 bpp", procName, 0);
if (!tab)
return ERROR_INT("tab not defined", procName, 0);
if (area1 <= 0 || area2 <= 0)
return ERROR_INT("areas must be > 0", procName, 0);
/* Eliminate based on size difference */
pixGetDimensions(pix1, &wi, &hi, NULL);
pixGetDimensions(pix2, &wt, &ht, NULL);
delw = L_ABS(wi - wt);
if (delw > maxdiffw)
return FALSE;
delh = L_ABS(hi - ht);
if (delh > maxdiffh)
return FALSE;
/* Round difference to nearest integer */
if (delx >= 0)
idelx = (l_int32)(delx + 0.5);
else
idelx = (l_int32)(delx - 0.5);
if (dely >= 0)
idely = (l_int32)(dely + 0.5);
else
idely = (l_int32)(dely - 0.5);
/* Compute the correlation count that is needed so that
* count * count / (area1 * area2) >= score_threshold */
threshold = (l_int32)ceil(sqrt((l_float64)score_threshold * area1 * area2));
count = 0;
wpl1 = pixGetWpl(pix1);
wpl2 = pixGetWpl(pix2);
rowwords2 = wpl2;
/* What rows of pix1 need to be considered? Only those underlying the
* shifted pix2. */
lorow = L_MAX(idely, 0);
hirow = L_MIN(ht + idely, hi);
/* Get the pointer to the first row of each image that will be
* considered. */
row1 = pixGetData(pix1) + wpl1 * lorow;
row2 = pixGetData(pix2) + wpl2 * (lorow - idely);
if (hirow <= hi) {
/* Some rows of pix1 will never contribute to count */
untouchable = downcount[hirow - 1];
}
/* Similarly, figure out which columns of pix1 will be considered. */
locol = L_MAX(idelx, 0);
hicol = L_MIN(wt + idelx, wi);
if (idelx >= 32) {
/* pix2 is shifted far enough to the right that pix1's first
* word(s) won't contribute to the count. Increment its
* pointer to point to the first word that will contribute,
* and adjust other values accordingly. */
pix1lskip = idelx >> 5; /* # of words to skip on left */
row1 += pix1lskip;
locol -= pix1lskip << 5;
hicol -= pix1lskip << 5;
idelx &= 31;
} else if (idelx <= -32) {
/* pix2 is shifted far enough to the left that its first word(s)
* won't contribute to the count. Increment its pointer
* to point to the first word that will contribute,
* and adjust other values accordingly. */
pix2lskip = -((idelx + 31) >> 5); /* # of words to skip on left */
row2 += pix2lskip;
rowwords2 -= pix2lskip;
idelx += pix2lskip << 5;
}
if ((locol >= hicol) || (lorow >= hirow)) { /* there is no overlap */
count = 0;
} else {
/* How many words of each row of pix1 need to be considered? */
rowwords1 = (hicol + 31) >> 5;
if (idelx == 0) {
/* There's no lateral offset; simple case. */
for (y = lorow; y < hirow; y++, row1 += wpl1, row2 += wpl2) {
for (x = 0; x < rowwords1; x++) {
andw = row1[x] & row2[x];
count += tab[andw & 0xff] +
tab[(andw >> 8) & 0xff] +
tab[(andw >> 16) & 0xff] +
tab[andw >> 24];
}
/* If the count is over the threshold, no need to
* calculate any further. Likewise, return early if the
* count plus the maximum count attainable from further
* rows is below the threshold. */
if (count >= threshold) return TRUE;
if (count + downcount[y] - untouchable < threshold) {
return FALSE;
}
}
} else if (idelx > 0) {
/* pix2 is shifted to the right. word 0 of pix1 is touched by
* word 0 of pix2; word 1 of pix1 is touched by word 0 and word
* 1 of pix2, and so on up to the last word of pix1 (word N),
* which is touched by words N-1 and N of pix1... if there is a
* word N. Handle the two cases (pix2 has N-1 words and pix2
* has at least N words) separately.
*
* Note: we know that pix2 has at least N-1 words (i.e.,
* rowwords2 >= rowwords1 - 1) by the following logic.
* We can pretend that idelx <= 31 because the >= 32 logic
* above adjusted everything appropriately. Then
* hicol <= wt + idelx <= wt + 31, so
* hicol + 31 <= wt + 62
* rowwords1 = (hicol + 31) >> 5 <= (wt + 62) >> 5
* rowwords2 == (wt + 31) >> 5, so
* rowwords1 <= rowwords2 + 1 */
if (rowwords2 < rowwords1) {
for (y = lorow; y < hirow; y++, row1 += wpl1, row2 += wpl2) {
/* Do the first iteration so the loop can be
* branch-free. */
word1 = row1[0];
word2 = row2[0] >> idelx;
andw = word1 & word2;
count += tab[andw & 0xff] +
tab[(andw >> 8) & 0xff] +
tab[(andw >> 16) & 0xff] +
tab[andw >> 24];
for (x = 1; x < rowwords2; x++) {
word1 = row1[x];
word2 = (row2[x] >> idelx) |
(row2[x - 1] << (32 - idelx));
andw = word1 & word2;
count += tab[andw & 0xff] +
tab[(andw >> 8) & 0xff] +
tab[(andw >> 16) & 0xff] +
tab[andw >> 24];
}
/* Now the last iteration - we know that this is safe
* (i.e. rowwords1 >= 2) because rowwords1 > rowwords2
* > 0 (if it was 0, we'd have taken the "count = 0"
* fast-path out of here). */
word1 = row1[x];
word2 = row2[x - 1] << (32 - idelx);
andw = word1 & word2;
count += tab[andw & 0xff] +
tab[(andw >> 8) & 0xff] +
tab[(andw >> 16) & 0xff] +
tab[andw >> 24];
if (count >= threshold) return TRUE;
if (count + downcount[y] - untouchable < threshold) {
return FALSE;
}
}
} else {
for (y = lorow; y < hirow; y++, row1 += wpl1, row2 += wpl2) {
/* Do the first iteration so the loop can be
* branch-free. This section is the same as above
* except for the different limit on the loop, since
* the last iteration is the same as all the other
* iterations (beyond the first). */
word1 = row1[0];
word2 = row2[0] >> idelx;
andw = word1 & word2;
count += tab[andw & 0xff] +
tab[(andw >> 8) & 0xff] +
tab[(andw >> 16) & 0xff] +
tab[andw >> 24];
for (x = 1; x < rowwords1; x++) {
word1 = row1[x];
word2 = (row2[x] >> idelx) |
(row2[x - 1] << (32 - idelx));
andw = word1 & word2;
count += tab[andw & 0xff] +
tab[(andw >> 8) & 0xff] +
tab[(andw >> 16) & 0xff] +
tab[andw >> 24];
}
if (count >= threshold) return TRUE;
if (count + downcount[y] - untouchable < threshold) {
return FALSE;
}
}
}
} else {
/* pix2 is shifted to the left. word 0 of pix1 is touched by
* word 0 and word 1 of pix2, and so on up to the last word of
* pix1 (word N), which is touched by words N and N+1 of
* pix2... if there is a word N+1. Handle the two cases (pix2
* has N words and pix2 has at least N+1 words) separately. */
if (rowwords1 < rowwords2) {
/* pix2 has at least N+1 words, so every iteration through
* the loop can be the same. */
for (y = lorow; y < hirow; y++, row1 += wpl1, row2 += wpl2) {
for (x = 0; x < rowwords1; x++) {
word1 = row1[x];
word2 = row2[x] << -idelx;
word2 |= row2[x + 1] >> (32 + idelx);
andw = word1 & word2;
count += tab[andw & 0xff] +
tab[(andw >> 8) & 0xff] +
tab[(andw >> 16) & 0xff] +
tab[andw >> 24];
}
if (count >= threshold) return TRUE;
if (count + downcount[y] - untouchable < threshold) {
return FALSE;
}
}
} else {
/* pix2 has only N words, so the last iteration is broken
* out. */
for (y = lorow; y < hirow; y++, row1 += wpl1, row2 += wpl2) {
for (x = 0; x < rowwords1 - 1; x++) {
word1 = row1[x];
word2 = row2[x] << -idelx;
word2 |= row2[x + 1] >> (32 + idelx);
andw = word1 & word2;
count += tab[andw & 0xff] +
tab[(andw >> 8) & 0xff] +
tab[(andw >> 16) & 0xff] +
tab[andw >> 24];
}
word1 = row1[x];
word2 = row2[x] << -idelx;
andw = word1 & word2;
count += tab[andw & 0xff] +
tab[(andw >> 8) & 0xff] +
tab[(andw >> 16) & 0xff] +
tab[andw >> 24];
if (count >= threshold) return TRUE;
if (count + downcount[y] - untouchable < threshold) {
return FALSE;
}
}
}
}
}
score = (l_float32)count * (l_float32)count /
((l_float32)area1 * (l_float32)area2);
if (score >= score_threshold) {
fprintf(stderr, "count %d < threshold %d but score %g >= score_threshold %g\n",
count, threshold, score, score_threshold);
}
return FALSE;
}
/* -------------------------------------------------------------------- *
* Simple 2 pix correlators (for jbig2 clustering) *
* -------------------------------------------------------------------- */
/*!
* \brief pixCorrelationScoreSimple()
*
* \param[in] pix1 test pix, 1 bpp
* \param[in] pix2 exemplar pix, 1 bpp
* \param[in] area1 number of on pixels in pix1
* \param[in] area2 number of on pixels in pix2
* \param[in] delx x comp of centroid difference
* \param[in] dely y comp of centroid difference
* \param[in] maxdiffw max width difference of pix1 and pix2
* \param[in] maxdiffh max height difference of pix1 and pix2
* \param[in] tab sum tab for byte
* \param[out] pscore correlation score, in range [0.0 ... 1.0]
* \return 0 if OK, 1 on error
*
* <pre>
* Notes:
* (1) This calculates exactly the same value as pixCorrelationScore().
* It is 2-3x slower, but much simpler to understand.
* (2) The returned correlation score is 0.0 if the width or height
* exceed %maxdiffw or %maxdiffh.
* </pre>
*/
l_ok
pixCorrelationScoreSimple(PIX *pix1,
PIX *pix2,
l_int32 area1,
l_int32 area2,
l_float32 delx, /* x(1) - x(3) */
l_float32 dely, /* y(1) - y(3) */
l_int32 maxdiffw,
l_int32 maxdiffh,
l_int32 *tab,
l_float32 *pscore)
{
l_int32 wi, hi, wt, ht, delw, delh, idelx, idely, count;
PIX *pixt;
PROCNAME("pixCorrelationScoreSimple");
if (!pscore)
return ERROR_INT("&score not defined", procName, 1);
*pscore = 0.0;
if (!pix1 || pixGetDepth(pix1) != 1)
return ERROR_INT("pix1 undefined or not 1 bpp", procName, 1);
if (!pix2 || pixGetDepth(pix2) != 1)
return ERROR_INT("pix2 undefined or not 1 bpp", procName, 1);
if (!tab)
return ERROR_INT("tab not defined", procName, 1);
if (!area1 || !area2)
return ERROR_INT("areas must be > 0", procName, 1);
/* Eliminate based on size difference */
pixGetDimensions(pix1, &wi, &hi, NULL);
pixGetDimensions(pix2, &wt, &ht, NULL);
delw = L_ABS(wi - wt);
if (delw > maxdiffw)
return 0;
delh = L_ABS(hi - ht);
if (delh > maxdiffh)
return 0;
/* Round difference to nearest integer */
if (delx >= 0)
idelx = (l_int32)(delx + 0.5);
else
idelx = (l_int32)(delx - 0.5);
if (dely >= 0)
idely = (l_int32)(dely + 0.5);
else
idely = (l_int32)(dely - 0.5);
/* pixt = pixAnd(NULL, pix1, pix2), including shift.
* To insure that pixels are ON only within the
* intersection of pix1 and the shifted pix2:
* (1) Start with pixt cleared and equal in size to pix1.
* (2) Blit the shifted pix2 onto pixt. Then all ON pixels
* are within the intersection of pix1 and the shifted pix2.
* (3) AND pix1 with pixt. */
pixt = pixCreateTemplate(pix1);
pixRasterop(pixt, idelx, idely, wt, ht, PIX_SRC, pix2, 0, 0);
pixRasterop(pixt, 0, 0, wi, hi, PIX_SRC & PIX_DST, pix1, 0, 0);
pixCountPixels(pixt, &count, tab);
pixDestroy(&pixt);
*pscore = (l_float32)count * (l_float32)count /
((l_float32)area1 * (l_float32)area2);
/* fprintf(stderr, "score = %5.3f, count = %d, area1 = %d, area2 = %d\n",
*pscore, count, area1, area2); */
return 0;
}
/*!
* \brief pixCorrelationScoreShifted()
*
* \param[in] pix1 1 bpp
* \param[in] pix2 1 bpp
* \param[in] area1 number of on pixels in pix1
* \param[in] area2 number of on pixels in pix2
* \param[in] delx x translation of pix2 relative to pix1
* \param[in] dely y translation of pix2 relative to pix1
* \param[in] tab sum tab for byte
* \param[out] pscore correlation score
* \return 0 if OK, 1 on error
*
* <pre>
* Notes:
* (1) This finds the correlation between two 1 bpp images,
* when pix2 is shifted by (delx, dely) with respect
* to each other.
* (2) This is implemented by starting with a copy of pix1 and
* ANDing its pixels with those of a shifted pix2.
* (3) Get the pixel counts for area1 and area2 using piCountPixels().
* (4) A good estimate for a shift that would maximize the correlation
* is to align the centroids (cx1, cy1; cx2, cy2), giving the
* relative translations etransx and etransy:
* etransx = cx1 - cx2
* etransy = cy1 - cy2
* Typically delx is chosen to be near etransx; ditto for dely.
* This function is used in pixBestCorrelation(), where the
* translations delx and dely are varied to find the best alignment.
* (5) We do not check the sizes of pix1 and pix2, because they should
* be comparable.
* </pre>
*/
l_ok
pixCorrelationScoreShifted(PIX *pix1,
PIX *pix2,
l_int32 area1,
l_int32 area2,
l_int32 delx,
l_int32 dely,
l_int32 *tab,
l_float32 *pscore)
{
l_int32 w1, h1, w2, h2, count;
PIX *pixt;
PROCNAME("pixCorrelationScoreShifted");
if (!pscore)
return ERROR_INT("&score not defined", procName, 1);
*pscore = 0.0;
if (!pix1 || pixGetDepth(pix1) != 1)
return ERROR_INT("pix1 undefined or not 1 bpp", procName, 1);
if (!pix2 || pixGetDepth(pix2) != 1)
return ERROR_INT("pix2 undefined or not 1 bpp", procName, 1);
if (!tab)
return ERROR_INT("tab not defined", procName, 1);
if (!area1 || !area2)
return ERROR_INT("areas must be > 0", procName, 1);
pixGetDimensions(pix1, &w1, &h1, NULL);
pixGetDimensions(pix2, &w2, &h2, NULL);
/* To insure that pixels are ON only within the
* intersection of pix1 and the shifted pix2:
* (1) Start with pixt cleared and equal in size to pix1.
* (2) Blit the shifted pix2 onto pixt. Then all ON pixels
* are within the intersection of pix1 and the shifted pix2.
* (3) AND pix1 with pixt. */
pixt = pixCreateTemplate(pix1);
pixRasterop(pixt, delx, dely, w2, h2, PIX_SRC, pix2, 0, 0);
pixRasterop(pixt, 0, 0, w1, h1, PIX_SRC & PIX_DST, pix1, 0, 0);
pixCountPixels(pixt, &count, tab);
pixDestroy(&pixt);
*pscore = (l_float32)count * (l_float32)count /
((l_float32)area1 * (l_float32)area2);
return 0;
}