Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to increase pixel intensity difference more in image processing?

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);
like image 562
batuman Avatar asked Feb 13 '23 12:02

batuman


2 Answers

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

adaptiveThreshold

bernsen

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);
}
like image 190
Zaw Lin Avatar answered Feb 16 '23 01:02

Zaw Lin


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.

like image 30
Vlad Avatar answered Feb 16 '23 03:02

Vlad