I have an image as shown in the attached figure.
Sometimes, the digit's black color intensity is not much difference from their neighbour pixels and I have problem to extract these digits (for example, setting a threshold is not efficient as black color's intensity is close to gray color's intensity because of reflection or not well focus during the image capture). I like to make it more difference between black and background gray color so I can extract the digit without much noise. What I do is I increase the difference using addWeighted
function from OpenCV
. color
is the original RGB image. Does it make sense with my processing or is there any more efficient approach?
Mat blur_img = new Mat(color.size(), color.type());
org.opencv.core.Size size = new Size(9,9);
Imgproc.GaussianBlur(color, blur_img, size, 2);
Mat sharpened = new Mat(color.size(), CvType.CV_32FC3);
Core.addWeighted(color, 1.5, blur_img, -0.5, 0, sharpened);
you need to do local thresholding(bernsen,sauvola,local otsu etc), opencv also happens to have adaptiveThreshold
function. Here's an example. Just make sure to play around with the parameters.
adaptiveThreshold
bernsen
code
#include <opencv2/opencv.hpp>
using namespace cv;
Mat thresh_bernsen(Mat& gray,int ksize,int contrast_limit)
{
Mat ret = Mat::zeros(gray.size(),gray.type());
for(int i=0;i<gray.cols;i++ )
{
for(int j=0;j<gray.rows;j++ )
{
double mn=999,mx=0;
int ti=0,tj=0;
int tlx=i-ksize/2;
int tly=j-ksize/2;
int brx=i+ksize/2;
int bry=j+ksize/2;
if(tlx<0) tlx=0;
if(tly<0) tly=0;
if(brx>=gray.cols) brx=gray.cols-1;
if(bry>=gray.rows) bry=gray.rows-1;
minMaxIdx(gray(Rect(Point(tlx,tly),Point(brx,bry))),&mn,&mx,0,0);
/* this does the above
for(int ik=-ksize/2;ik<=ksize/2;ik++)
{
for(int jk=-ksize/2;jk<=ksize/2;jk++)
{
ti=i+ik;
tj=j+jk;
if(ti>0 && ti<gray.cols && tj>0 && tj<gray.rows)
{
uchar pix = gray.at<uchar>(tj,ti);
if(pix<mn) mn=pix;
if(pix>mx) mx=pix;
}
}
}*/
int median = 0.5 * (mn+mx);
if(median<contrast_limit)
{
ret.at<uchar>(j,i)=0;
}else
{
uchar pix = gray.at<uchar>(j,i);
ret.at<uchar>(j,i) = pix>median?255:0;
}
}
}
return ret;
}
int main()
{
Mat gray = imread("c:/data/number.jpg",0);
gray=255-gray;
Mat adaptthresh,bernsen;
adaptiveThreshold(gray,adaptthresh,255,ADAPTIVE_THRESH_GAUSSIAN_C,THRESH_BINARY,41,1);
bernsen=thresh_bernsen(gray,25,40);
imshow("gray",gray);
imshow("adaptthresh",adaptthresh);
imshow("bernsen",bernsen);
waitKey(0);
}
Simple thresholding doesn’t account for lighting variations across the image and adaptive thresholding doesn’t take advantage of connected regions.
The current leader in extraction of segments like this is MSER. It goes through all possible thresholds and finds connected most stable regions (across all thresholds). Don’t re-invent a bicycle, use the proven best features and open source such as openCV MSER. There are more links on stack overflow.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With