Note that there are some explanatory texts on larger screens.

plurals
  1. POFast image thresholding
    primarykey
    data
    text
    <p><strong>What is a fast and reliable way to threshold images with possible blurring and non-uniform brightness?</strong></p> <p>Example (blurring but uniform brightness):</p> <p><img src="https://i.stack.imgur.com/8XWQZ.png" alt="enter image description here"></p> <p>Because the image is not guaranteed to have uniform brightness, it's not feasible to use a fixed threshold. An adaptive threshold works alright, but because of the blurriness it creates breaks and distortions in the features (here, the important features are the Sudoku digits):</p> <p><img src="https://i.stack.imgur.com/XDL1T.png" alt="enter image description here"></p> <p>I've also tried using Histogram Equalization (using OpenCV's <code>equalizeHist</code> function). It increases contrast without reducing differences in brightness.</p> <p>The best solution I've found is to divide the image by its morphological closing (credit to <a href="https://stackoverflow.com/a/10226971/1397061">this post</a>) to make the brightness uniform, then renormalize, then use a fixed threshold (using Otsu's algorithm to pick the optimal threshold level):</p> <p><img src="https://i.stack.imgur.com/aEzMa.png" alt="enter image description here"></p> <p>Here is code for this in OpenCV for Android:</p> <pre><code>Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_ELLIPSE, new Size(19,19)); Mat closed = new Mat(); // closed will have type CV_32F Imgproc.morphologyEx(image, closed, Imgproc.MORPH_CLOSE, kernel); Core.divide(image, closed, closed, 1, CvType.CV_32F); Core.normalize(closed, image, 0, 255, Core.NORM_MINMAX, CvType.CV_8U); Imgproc.threshold(image, image, -1, 255, Imgproc.THRESH_BINARY_INV +Imgproc.THRESH_OTSU); </code></pre> <p>This works great but the closing operation is very slow. Reducing the size of the structuring element increases speed but reduces accuracy. </p> <p>Edit: based on DCS's suggestion I tried using a high-pass filter. I chose the Laplacian filter, but I would expect similar results with Sobel and Scharr filters. The filter picks up high-frequency noise in the areas which do not contain features, and suffers from similar distortion to the adaptive threshold due to blurring. it also takes about as long as the closing operation. Here is an example with a 15x15 filter: </p> <p><img src="https://i.stack.imgur.com/CInE3.png" alt="enter image description here"></p> <p>Edit 2: Based on AruniRC's answer, I used Canny edge detection on the image with the suggested parameters:</p> <pre><code>double mean = Core.mean(image).val[0]; Imgproc.Canny(image, image, 0.66*mean, 1.33*mean); </code></pre> <p>I'm not sure how to reliably <em>automatically</em> fine-tune the parameters to get connected digits.</p> <p><img src="https://i.stack.imgur.com/nNXPm.png" alt="enter image description here"></p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload