Skip to content

Commit

Permalink
1.0.18: feature #47: joint from prefilters EdgePlus and BlurDiv to pr…
Browse files Browse the repository at this point in the history
…efilter EdgeDiv
  • Loading branch information
zvezdochiot committed Jul 12, 2023
1 parent ae131a0 commit 5deb2ea
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 157 deletions.
6 changes: 3 additions & 3 deletions src/core/filters/output/OutputGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2241,23 +2241,23 @@ BinaryImage OutputGenerator::Processor::binarize(const QImage& image) const {
QSize windowsSize = QSize(blackWhiteOptions.getWindowSize(), blackWhiteOptions.getWindowSize());
double thresholdCoef = blackWhiteOptions.getSauvolaCoef();

binarized = binarizeEdgePlus(image, windowsSize, thresholdCoef, thresholdDelta);
binarized = binarizeEdgeDiv(image, windowsSize, thresholdCoef, 0.0, thresholdDelta);
break;
}
case BLURDIV: {
double thresholdDelta = blackWhiteOptions.thresholdAdjustment();
QSize windowsSize = QSize(blackWhiteOptions.getWindowSize(), blackWhiteOptions.getWindowSize());
double thresholdCoef = blackWhiteOptions.getSauvolaCoef();

binarized = binarizeBlurDiv(image, windowsSize, thresholdCoef, thresholdDelta);
binarized = binarizeEdgeDiv(image, windowsSize, 0.0, thresholdCoef, thresholdDelta);
break;
}
case EDGEDIV: {
double thresholdDelta = blackWhiteOptions.thresholdAdjustment();
QSize windowsSize = QSize(blackWhiteOptions.getWindowSize(), blackWhiteOptions.getWindowSize());
double thresholdCoef = blackWhiteOptions.getSauvolaCoef();

binarized = binarizeEdgeDiv(image, windowsSize, thresholdCoef, thresholdDelta);
binarized = binarizeEdgeDiv(image, windowsSize, thresholdCoef, thresholdCoef, thresholdDelta);
break;
}
}
Expand Down
161 changes: 22 additions & 139 deletions src/imageproc/Binarize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -201,131 +201,7 @@ BinaryImage binarizeWolf(const QImage& src,
return bwImg;
} // binarizeWolf

BinaryImage binarizeEdgePlus(const QImage& src, const QSize windowSize, const double k, const double delta) {
if (windowSize.isEmpty()) {
throw std::invalid_argument("binarizeEdgePlus: invalid windowSize");
}

if (src.isNull()) {
return BinaryImage();
}

QImage gray(toGrayscale(src));
const int w = gray.width();
const int h = gray.height();

IntegralImage<uint32_t> integralImage(w, h);

uint8_t* grayLine = gray.bits();
const int grayBpl = gray.bytesPerLine();

for (int y = 0; y < h; ++y) {
integralImage.beginRow();
for (int x = 0; x < w; ++x) {
const uint32_t pixel = grayLine[x];
integralImage.push(pixel);
}
grayLine += grayBpl;
}

const int windowLowerHalf = windowSize.height() >> 1;
const int windowUpperHalf = windowSize.height() - windowLowerHalf;
const int windowLeftHalf = windowSize.width() >> 1;
const int windowRightHalf = windowSize.width() - windowLeftHalf;

grayLine = gray.bits();
for (int y = 0; y < h; ++y) {
const int top = std::max(0, y - windowLowerHalf);
const int bottom = std::min(h, y + windowUpperHalf); // exclusive
for (int x = 0; x < w; ++x) {
const int left = std::max(0, x - windowLeftHalf);
const int right = std::min(w, x + windowRightHalf); // exclusive
const int area = (bottom - top) * (right - left);
assert(area > 0); // because windowSize > 0 and w > 0 and h > 0
const QRect rect(left, top, right - left, bottom - top);
const double windowSum = integralImage.sum(rect);

const double rArea = 1.0 / area;
const double mean = windowSum * rArea;
const double origin = grayLine[x];
// edge = I / blur (shift = -0.5) {0.0 .. >1.0}, mean value = 0.5
const double edge = (origin + 1) / (mean + 1) - 0.5;
// edgeplus = I * edge, mean value = 0.5 * mean(I)
const double edgeplus = origin * edge;
// return k * edgeplus + (1 - k) * I
double retval = k * edgeplus + (1.0 - k) * origin;
// trim value {0..255}
retval = (retval < 0.0) ? 0.0 : (retval < 255.0) ? retval : 255.0;
grayLine[x] = (int) retval;
}
grayLine += grayBpl;
}
return BinaryImage(gray, (BinaryThreshold::otsuThreshold(gray) + delta));
} // binarizeEdgePlus

BinaryImage binarizeBlurDiv(const QImage& src, const QSize windowSize, const double k, const double delta) {
if (windowSize.isEmpty()) {
throw std::invalid_argument("binarizeBlurDiv: invalid windowSize");
}

if (src.isNull()) {
return BinaryImage();
}

QImage gray(toGrayscale(src));
const int w = gray.width();
const int h = gray.height();

IntegralImage<uint32_t> integralImage(w, h);

uint8_t* grayLine = gray.bits();
const int grayBpl = gray.bytesPerLine();

for (int y = 0; y < h; ++y) {
integralImage.beginRow();
for (int x = 0; x < w; ++x) {
const uint32_t pixel = grayLine[x];
integralImage.push(pixel);
}
grayLine += grayBpl;
}

const int windowLowerHalf = windowSize.height() >> 1;
const int windowUpperHalf = windowSize.height() - windowLowerHalf;
const int windowLeftHalf = windowSize.width() >> 1;
const int windowRightHalf = windowSize.width() - windowLeftHalf;

grayLine = gray.bits();
for (int y = 0; y < h; ++y) {
const int top = std::max(0, y - windowLowerHalf);
const int bottom = std::min(h, y + windowUpperHalf); // exclusive
for (int x = 0; x < w; ++x) {
const int left = std::max(0, x - windowLeftHalf);
const int right = std::min(w, x + windowRightHalf); // exclusive
const int area = (bottom - top) * (right - left);
assert(area > 0); // because windowSize > 0 and w > 0 and h > 0
const QRect rect(left, top, right - left, bottom - top);
const double windowSum = integralImage.sum(rect);

const double rArea = 1.0 / area;
const double mean = windowSum * rArea;
const double origin = grayLine[x];
// edge = blur / I (shift = -0.5) {0.0 .. >1.0}, mean value = 0.5
const double edge = (mean + 1) / (origin + 1) - 0.5;
// edgenorm = edge * k + max * (1 - k), mean value = {0.5 .. 1.0} * mean(I)
const double edgenorm = k * edge + (1.0 - k);
// return I / edgenorm
double retval = (edgenorm > 0.0) ? (origin / edgenorm) : origin;
// trim value {0..255}
retval = (retval < 0.0) ? 0.0 : (retval < 255.0) ? retval : 255.0;
grayLine[x] = (int) retval;
}
grayLine += grayBpl;
}
return BinaryImage(gray, (BinaryThreshold::otsuThreshold(gray) + delta));
} // binarizeBlurDiv

BinaryImage binarizeEdgeDiv(const QImage& src, const QSize windowSize, const double k, const double delta) {
BinaryImage binarizeEdgeDiv(const QImage& src, const QSize windowSize, const double kep, const double kbd, const double delta) {
if (windowSize.isEmpty()) {
throw std::invalid_argument("binarizeBlurDiv: invalid windowSize");
}
Expand Down Expand Up @@ -372,20 +248,27 @@ BinaryImage binarizeEdgeDiv(const QImage& src, const QSize windowSize, const dou
const double rArea = 1.0 / area;
const double mean = windowSum * rArea;
const double origin = grayLine[x];
// EdgePlus
// edge = I / blur (shift = -0.5) {0.0 .. >1.0}, mean value = 0.5
const double edge = (origin + 1) / (mean + 1) - 0.5;
// edgeplus = I * edge, mean value = 0.5 * mean(I)
const double edgeplus = origin * edge;
// return k * edgeplus + (1 - k) * I
double retval = k * edgeplus + (1.0 - k) * origin;
// BlurDiv
// edge = blur / I (shift = -0.5) {0.0 .. >1.0}, mean value = 0.5
const double edgeinv = (mean + 1) / (retval + 1) - 0.5;
// edgenorm = edge * k + max * (1 - k), mean value = {0.5 .. 1.0} * mean(I)
const double edgenorm = k * edgeinv + (1.0 - k);
// return I / edgenorm
retval = (edgenorm > 0.0) ? (origin / edgenorm) : origin;
double retval = origin;
if (kep > 0.0)
{
// EdgePlus
// edge = I / blur (shift = -0.5) {0.0 .. >1.0}, mean value = 0.5
const double edge = (retval + 1) / (mean + 1) - 0.5;
// edgeplus = I * edge, mean value = 0.5 * mean(I)
const double edgeplus = origin * edge;
// return k * edgeplus + (1 - k) * I
retval = kep * edgeplus + (1.0 - kep) * origin;
}
if (kbd > 0.0)
{
// BlurDiv
// edge = blur / I (shift = -0.5) {0.0 .. >1.0}, mean value = 0.5
const double edgeinv = (mean + 1) / (retval + 1) - 0.5;
// edgenorm = edge * k + max * (1 - k), mean value = {0.5 .. 1.0} * mean(I)
const double edgenorm = kbd * edgeinv + (1.0 - kbd);
// return I / edgenorm
retval = (edgenorm > 0.0) ? (origin / edgenorm) : origin;
}
// trim value {0..255}
retval = (retval < 0.0) ? 0.0 : (retval < 255.0) ? retval : 255.0;
grayLine[x] = (int) retval;
Expand Down
16 changes: 1 addition & 15 deletions src/imageproc/Binarize.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,26 +61,12 @@ BinaryImage binarizeWolf(const QImage& src,
double k = 0.3,
double delta = 0.0);

/**
* \brief Image binarization using EdgePlus local/global thresholding method.
*
* EdgePlus, zvezdochiot 2023. "Adaptive/global document image binarization".
*/
BinaryImage binarizeEdgePlus(const QImage& src, QSize windowSize, double k = 0.34, double delta = 0.0);

/**
* \brief Image binarization using BlurDiv local/global thresholding method.
*
* BlurDiv, zvezdochiot 2023. "Adaptive/global document image binarization".
*/
BinaryImage binarizeBlurDiv(const QImage& src, QSize windowSize, double k = 0.34, double delta = 0.0);

/**
* \brief Image binarization using EdgeDiv (EdgePlus & BlurDiv) local/global thresholding method.
*
* EdgeDiv, zvezdochiot 2023. "Adaptive/global document image binarization".
*/
BinaryImage binarizeEdgeDiv(const QImage& src, QSize windowSize, double k = 0.34, double delta = 0.0);
BinaryImage binarizeEdgeDiv(const QImage& src, QSize windowSize, double kep = 0.0, double kdb = 0.0, double delta = 0.0);

BinaryImage peakThreshold(const QImage& image);
} // namespace imageproc
Expand Down

0 comments on commit 5deb2ea

Please sign in to comment.