Skip to content

[Feature request] binarizeEdgePlus #47

@zvezdochiot

Description

@zvezdochiot

Hi @vigri .

/**
 * \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);
BinaryImage binarizeEdgePlus(const QImage& src, const QSize windowSize, const double k) {
  if (windowSize.isEmpty()) {
    throw std::invalid_argument("binarizeSauvola: 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, grayLine += grayBpl) {
    integralImage.beginRow();
    for (int x = 0; x < w; ++x) {
      const uint32_t pixel = grayLine[x];
      integralImage.push(pixel);
    }
  }

  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(src, BinaryThreshold::otsuThreshold(gray));
}  // binarizeEdgePlus

See also:

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions