Skip to content

Commit

Permalink
1.0.19: Bradley's adaptive thresholding method
Browse files Browse the repository at this point in the history
  • Loading branch information
zvezdochiot committed Jul 26, 2023
1 parent b65ee43 commit e1ac0fd
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 3 deletions.
5 changes: 3 additions & 2 deletions src/app/DefaultParamsDialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ DefaultParamsDialog::DefaultParamsDialog(QWidget* parent)
thresholdMethodBox->addItem(tr("Otsu"), OTSU);
thresholdMethodBox->addItem(tr("Sauvola"), SAUVOLA);
thresholdMethodBox->addItem(tr("Wolf"), WOLF);
thresholdMethodBox->addItem(tr("Bradley"), BRADLEY);
thresholdMethodBox->addItem(tr("EdgePlus"), EDGEPLUS);
thresholdMethodBox->addItem(tr("BlurDiv"), BLURDIV);
thresholdMethodBox->addItem(tr("EdgeDiv"), EDGEDIV);
Expand Down Expand Up @@ -665,8 +666,8 @@ std::unique_ptr<DefaultParams> DefaultParamsDialog::buildParams() const {
blackWhiteOptions.setBinarizationMethod(binarizationMethod);
blackWhiteOptions.setThresholdAdjustment(thresholdSlider->value());
blackWhiteOptions.setSauvolaCoef(sauvolaCoef->value());
if (binarizationMethod == SAUVOLA || binarizationMethod == EDGEPLUS || binarizationMethod == BLURDIV
|| binarizationMethod == EDGEDIV) {
if (binarizationMethod == SAUVOLA || binarizationMethod == BRADLEY || binarizationMethod == EDGEPLUS
|| binarizationMethod == BLURDIV || binarizationMethod == EDGEDIV) {
blackWhiteOptions.setWindowSize(sauvolaWindowSize->value());
} else if (binarizationMethod == WOLF) {
blackWhiteOptions.setWindowSize(wolfWindowSize->value());
Expand Down
5 changes: 5 additions & 0 deletions src/core/filters/output/BlackWhiteOptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ BinarizationMethod BlackWhiteOptions::parseBinarizationMethod(const QString& str
return WOLF;
} else if (str == "sauvola") {
return SAUVOLA;
} else if (str == "bradley") {
return BRADLEY;
} else if (str == "edgeplus") {
return EDGEPLUS;
} else if (str == "blurdiv") {
Expand All @@ -95,6 +97,9 @@ QString BlackWhiteOptions::formatBinarizationMethod(BinarizationMethod type) {
case WOLF:
str = "wolf";
break;
case BRADLEY:
str = "bradley";
break;
case EDGEPLUS:
str = "edgeplus";
break;
Expand Down
2 changes: 1 addition & 1 deletion src/core/filters/output/BlackWhiteOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class QDomDocument;
class QDomElement;

namespace output {
enum BinarizationMethod { OTSU, SAUVOLA, WOLF, EDGEPLUS, BLURDIV, EDGEDIV };
enum BinarizationMethod { OTSU, SAUVOLA, WOLF, BRADLEY, EDGEPLUS, BLURDIV, EDGEDIV };

class BlackWhiteOptions {
public:
Expand Down
4 changes: 4 additions & 0 deletions src/core/filters/output/OptionsWidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ OptionsWidget::OptionsWidget(std::shared_ptr<Settings> settings, const PageSelec
thresholdMethodBox->addItem(tr("Otsu"), OTSU);
thresholdMethodBox->addItem(tr("Sauvola"), SAUVOLA);
thresholdMethodBox->addItem(tr("Wolf"), WOLF);
thresholdMethodBox->addItem(tr("Bradley"), BRADLEY);
thresholdMethodBox->addItem(tr("EdgePlus"), EDGEPLUS);
thresholdMethodBox->addItem(tr("BlurDiv"), BLURDIV);
thresholdMethodBox->addItem(tr("EdgeDiv"), EDGEDIV);
Expand All @@ -54,6 +55,8 @@ OptionsWidget::OptionsWidget(std::shared_ptr<Settings> settings, const PageSelec
QPointer<BinarizationOptionsWidget> sauvolaBinarizationOptionsWidget
= new SauvolaBinarizationOptionsWidget(m_settings);
QPointer<BinarizationOptionsWidget> wolfBinarizationOptionsWidget = new WolfBinarizationOptionsWidget(m_settings);
QPointer<BinarizationOptionsWidget> bradleyBinarizationOptionsWidget
= new SauvolaBinarizationOptionsWidget(m_settings);
QPointer<BinarizationOptionsWidget> edgeplusBinarizationOptionsWidget
= new SauvolaBinarizationOptionsWidget(m_settings);
QPointer<BinarizationOptionsWidget> blurdivBinarizationOptionsWidget
Expand All @@ -67,6 +70,7 @@ OptionsWidget::OptionsWidget(std::shared_ptr<Settings> settings, const PageSelec
addBinarizationOptionsWidget(otsuBinarizationOptionsWidget);
addBinarizationOptionsWidget(sauvolaBinarizationOptionsWidget);
addBinarizationOptionsWidget(wolfBinarizationOptionsWidget);
addBinarizationOptionsWidget(bradleyBinarizationOptionsWidget);
addBinarizationOptionsWidget(edgeplusBinarizationOptionsWidget);
addBinarizationOptionsWidget(blurdivBinarizationOptionsWidget);
addBinarizationOptionsWidget(edgedivBinarizationOptionsWidget);
Expand Down
8 changes: 8 additions & 0 deletions src/core/filters/output/OutputGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2306,6 +2306,14 @@ BinaryImage OutputGenerator::Processor::binarize(const QImage& image) const {
binarized = binarizeWolf(image, windowsSize, lowerBound, upperBound, thresholdCoef, thresholdDelta);
break;
}
case BRADLEY: {
const double thresholdDelta = blackWhiteOptions.thresholdAdjustment();
const QSize windowsSize = QSize(blackWhiteOptions.getWindowSize(), blackWhiteOptions.getWindowSize());
const double thresholdCoef = blackWhiteOptions.getSauvolaCoef();

binarized = binarizeBradley(image, windowsSize, thresholdCoef, thresholdDelta);
break;
}
case EDGEPLUS: {
const double thresholdDelta = blackWhiteOptions.thresholdAdjustment();
const QSize windowsSize = QSize(blackWhiteOptions.getWindowSize(), blackWhiteOptions.getWindowSize());
Expand Down
67 changes: 67 additions & 0 deletions src/imageproc/Binarize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,73 @@ BinaryImage binarizeWolf(const QImage& src,
return bwImg;
} // binarizeWolf

BinaryImage binarizeBradley(const QImage& src, const QSize windowSize, const double k, const double delta) {
if (windowSize.isEmpty()) {
throw std::invalid_argument("binarizeBradley: 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;

BinaryImage bwImg(w, h);
uint32_t* bwLine = bwImg.data();
const int bwWpl = bwImg.wordsPerLine();

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 threshold = (k < 1.0) ? (mean * (1.0 - k)) : 0;
const uint32_t msb = uint32_t(1) << 31;
const uint32_t mask = msb >> (x & 31);
if (int(grayLine[x]) < (threshold + delta)) {
// black
bwLine[x >> 5] |= mask;
} else {
// white
bwLine[x >> 5] &= ~mask;
}
}
grayLine += grayBpl;
bwLine += bwWpl;
}
return bwImg;
} // binarizeBradley

BinaryImage binarizeEdgeDiv(const QImage& src,
const QSize windowSize,
const double kep,
Expand Down
8 changes: 8 additions & 0 deletions src/imageproc/Binarize.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,14 @@ BinaryImage binarizeWolf(const QImage& src,
double k = 0.3,
double delta = 0.0);

/**
* \brief Image binarization using Bradley's adaptive thresholding method.
*
* Derek Bradley, Gerhard Roth. 2005. "Adaptive Thresholding Using the Integral Image".
* http://www.scs.carleton.ca/~roth/iit-publications-iti/docs/gerh-50002.pdf
*/
BinaryImage binarizeBradley(const QImage& src, QSize windowSize, double k = 0.34, double delta = 0.0);

/**
* \brief Image binarization using EdgeDiv (EdgePlus & BlurDiv) local/global thresholding method.
*
Expand Down

0 comments on commit e1ac0fd

Please sign in to comment.