I'm using opencv.js.
I'm trying to find the best way to implement a binary filter on images taken from a mobile phone, in order to clearly see text on the image. Adaptive Thresholds have not been great - too much noise. I'm trying to get an Otsu threshold to work and I'm failing.
From tutorials in the other OpenCV docs it looks like you'd ideally do a Gaussian Blur, then do an Otsu threshold (passing 0 in as the threshold value).
For threshold value, simply pass zero. Then the algorithm finds the optimal threshold value and returns you as the second output, retVal
When I use 0 as the threshold value I get an all white result. If I pass in something reasonable (e.g. 128), I get a decent result, but some darker areas of the image are washed out. How can I get this "Optimal Threshold" (pass zero) to work for opencv.js?
let src = cv.imread('canvasInput');
let dst = new cv.Mat();
let ksize = new cv.Size(3, 3);
//Blur & conver to gray
cv.GaussianBlur(src, dst, ksize, 0);
cv.cvtColor(dst, dst, cv.COLOR_BGR2GRAY, 0);
/* PROBLEM HERE:
* passing 0 returns all white, passing 128 is a reasonable result
*/
cv.threshold(dst, dst, 0, 255, cv.THRESH_BINARY&cv.THRESH_OTSU);
cv.imshow('canvasOutput', dst);
I'm using opencv.js.
I'm trying to find the best way to implement a binary filter on images taken from a mobile phone, in order to clearly see text on the image. Adaptive Thresholds have not been great - too much noise. I'm trying to get an Otsu threshold to work and I'm failing.
From tutorials in the other OpenCV docs it looks like you'd ideally do a Gaussian Blur, then do an Otsu threshold (passing 0 in as the threshold value).
For threshold value, simply pass zero. Then the algorithm finds the optimal threshold value and returns you as the second output, retVal
When I use 0 as the threshold value I get an all white result. If I pass in something reasonable (e.g. 128), I get a decent result, but some darker areas of the image are washed out. How can I get this "Optimal Threshold" (pass zero) to work for opencv.js?
let src = cv.imread('canvasInput');
let dst = new cv.Mat();
let ksize = new cv.Size(3, 3);
//Blur & conver to gray
cv.GaussianBlur(src, dst, ksize, 0);
cv.cvtColor(dst, dst, cv.COLOR_BGR2GRAY, 0);
/* PROBLEM HERE:
* passing 0 returns all white, passing 128 is a reasonable result
*/
cv.threshold(dst, dst, 0, 255, cv.THRESH_BINARY&cv.THRESH_OTSU);
cv.imshow('canvasOutput', dst);
The problem is this line
cv.threshold(dst, dst, 0, 255, cv.THRESH_BINARY&cv.THRESH_OTSU);
Since cv.THRESH_BINARY & cv.THRESH_OTSU = 0,
you actually doing this
cv.threshold(dst, dst, 0, 255, 0); <===== 0 = cv.THRESH_BINARY
To append a flag to another flag should use "OR" operator.
So this line should change to
cv.threshold(dst, dst, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU);
If the image has more content than just the text, a global thresholding method (such as Otsu) will fail.
Keep your adaptive threshold but add a small positive or negative constant to the threshold(s).
There is no AUTOMATIC WAY to get "Optimal Threshold".
But you can try to use Adaptive Threshold and I think CLAHE maybe helpful in thresholding issues.