Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

how to get a better binary image from low quality image?

I need to get contour from hand image, usually I process image with 4 steps:

1.get raw RGB gray image from 3 channels to 1 channel:

cvtColor(sourceGrayImage, sourceGrayImage, COLOR_BGR2GRAY);

2. use Gaussian blur to filter gray image:

 GaussianBlur(sourceGrayImage, sourceGrayImage, Size(3,3), 0);

3.binary gray image, I separate image by height, normally I split image to 8 pieces by its height, then each one I do threshold process: // we split source picture to binaryImageSectionCount(here it's 8) pieces by its height, // then we for every piece, we do threshold, // and at last we combine them agin to binaryImage

const binaryImageSectionCount = 8;
void GetBinaryImage(Mat &grayImage, Mat &binaryImage)
{
    // get every partial gray image's height
    int partImageHeight = grayImage.rows / binaryImageSectionCount;
    for (int i = 0; i < binaryImageSectionCount; i++)
    {
        Mat partialGrayImage;            
        Mat partialBinaryImage;
        Rect partialRect;
        if (i != binaryImageSectionCount - 1)
        {
            // if it's not last piece, Rect's height should be partImageHeight
            partialRect = Rect(0, i * partImageHeight, grayImage.cols, partImageHeight);
        }
        else
        {
            // if it's last piece, Rect's height should be (grayImage.rows - i  * partImageHeight)
            partialRect = Rect(0, i * partImageHeight, grayImage.cols, grayImage.rows - i  * partImageHeight);
        }

        Mat partialResource = grayImage(partialRect);    
        partialResource.copyTo(partialGrayImage);    
        threshold( partialGrayImage, partialBinaryImage, 0, 255, THRESH_OTSU);

        // combin partial binary image to one piece
        partialBinaryImage.copyTo(binaryImage(partialRect));

        ///*stringstream resultStrm;
        //resultStrm << "partial_" << (i + 1);
        //string string = resultStrm.str();

        //imshow(string, partialBinaryImage);
        //waitKey(0);*/
    }
    imshow("result binary image.", binaryImage);
    waitKey(0);
    return;
}

4. findcontour of binary image:

vector<vector<Point> > contours;        
findContours(binaryImage, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);

normally it works fine, But for some low quality gray image, it doesn't work,like these below: lowqualityGrayImage1 lowqualityGrayImage2lowqualityGrayImage3lowqualityGrayImage4

because step 3 binary image is very bad, so step 4 cant get right contour of hand, the result of step3 is below:

binaryImage1binaryImage2binaryImage3binrayImage4

Is there any way to get clean hand binary image? Thank you very much if you can give me any comment or help...

the complete code is below:

#include <opencv2/imgproc/imgproc.hpp>
#include<opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>

using namespace std;
using namespace cv;


// we split source picture to binaryImageSectionCount(here it's 8) pieces by its height, 
// then we for every piece, we do threshold, 
// and at last we combine them agin to binaryImage        
const binaryImageSectionCount = 8;
void GetBinaryImage(Mat &grayImage, Mat &binaryImage)
{
    // get every partial gray image's height
    int partImageHeight = grayImage.rows / binaryImageSectionCount;
    for (int i = 0; i < binaryImageSectionCount; i++)
    {
        Mat partialGrayImage;            
        Mat partialBinaryImage;
        Rect partialRect;
        if (i != binaryImageSectionCount - 1)
        {
            // if it's not last piece, Rect's height should be partImageHeight
            partialRect = Rect(0, i * partImageHeight, grayImage.cols, partImageHeight);
        }
        else
        {
            // if it's last piece, Rect's height should be (grayImage.rows - i  * partImageHeight)
            partialRect = Rect(0, i * partImageHeight, grayImage.cols, grayImage.rows - i  * partImageHeight);
        }

        Mat partialResource = grayImage(partialRect);    
        partialResource.copyTo(partialGrayImage);    
        threshold( partialGrayImage, partialBinaryImage, 0, 255, THRESH_OTSU);

        // combin partial binary image to one piece
        partialBinaryImage.copyTo(binaryImage(partialRect));

        ///*stringstream resultStrm;
        //resultStrm << "partial_" << (i + 1);
        //string string = resultStrm.str();

        //imshow(string, partialBinaryImage);
        //waitKey(0);*/
    }
    imshow("result binary image.", binaryImage);
    waitKey(0);
    return;
}


int main(int argc, _TCHAR* argv[])
{   
    // get image path
    string imgPath("C:\\Users\\Alfred\\Desktop\\gray.bmp");     

    // read image
    Mat src = imread(imgPath);
    imshow("Source", src);        
    //medianBlur(src, src, 7);  
    cvtColor(src, src, COLOR_BGR2GRAY);     
    imshow("gray", src);    

    // do filter
    GaussianBlur(src, src, Size(3,3), 0);   

    // binary image
    Mat threshold_output(src.rows, src.cols, CV_8UC1, Scalar(0, 0, 0)); 
    GetBinaryImage(src, threshold_output);
    imshow("binaryImage", threshold_output);

    // get biggest contour
    vector<vector<Point> > contours;    
    findContours(threshold_output,contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
    int biggestContourIndex = 0;
    int maxContourArea = -1000;
    for (int i = 0; i < contours.size(); i++)
    {       
        if (contourArea(contours[i]) > maxContourArea)
        {
            maxContourArea = contourArea(contours[i]);
            biggestContourIndex = i;
        }
    }

    // show biggest contour
    Mat biggestContour(threshold_output.rows, threshold_output.cols, CV_8UC1, Scalar(0, 0, 0));
    drawContours(biggestContour, contours, biggestContourIndex, cv::Scalar(255,255,255), 2, 8, vector<Vec4i>(), 0, Point());
    imshow("maxContour", biggestContour);
    waitKey(0);

}

how to get a better binary image from low quality image?

I need to get contour from hand image, usually I process image with 4 steps:

1.get raw RGB gray image from 3 channels to 1 channel:

cvtColor(sourceGrayImage, sourceGrayImage, COLOR_BGR2GRAY);

2. use Gaussian blur to filter gray image:

 GaussianBlur(sourceGrayImage, sourceGrayImage, Size(3,3), 0);

3.binary gray image, I separate image by height, normally I split image to 8 pieces by its height, then each one I do threshold process: // we split source picture to binaryImageSectionCount(here it's 8) pieces by its height, // then we for every piece, we do threshold, // and at last we combine them agin to binaryImage

const binaryImageSectionCount = 8;
void GetBinaryImage(Mat &grayImage, Mat &binaryImage)
{
    // get every partial gray image's height
    int partImageHeight = grayImage.rows / binaryImageSectionCount;
    for (int i = 0; i < binaryImageSectionCount; i++)
    {
        Mat partialGrayImage;            
        Mat partialBinaryImage;
        Rect partialRect;
        if (i != binaryImageSectionCount - 1)
        {
            // if it's not last piece, Rect's height should be partImageHeight
            partialRect = Rect(0, i * partImageHeight, grayImage.cols, partImageHeight);
        }
        else
        {
            // if it's last piece, Rect's height should be (grayImage.rows - i  * partImageHeight)
            partialRect = Rect(0, i * partImageHeight, grayImage.cols, grayImage.rows - i  * partImageHeight);
        }

        Mat partialResource = grayImage(partialRect);    
        partialResource.copyTo(partialGrayImage);    
        threshold( partialGrayImage, partialBinaryImage, 0, 255, THRESH_OTSU);

        // combin partial binary image to one piece
        partialBinaryImage.copyTo(binaryImage(partialRect));

        ///*stringstream resultStrm;
        //resultStrm << "partial_" << (i + 1);
        //string string = resultStrm.str();

        //imshow(string, partialBinaryImage);
        //waitKey(0);*/
    }
    imshow("result binary image.", binaryImage);
    waitKey(0);
    return;
}

4. findcontour of binary image:

vector<vector<Point> > contours;        
findContours(binaryImage, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);

normally it works fine, But for some low quality gray image, it doesn't work,like these below: lowqualityGrayImage1 lowqualityGrayImage2lowqualityGrayImage3lowqualityGrayImage4

because step 3 binary image is very bad, so step 4 cant get right contour of hand, the result of step3 is below:

binaryImage1binaryImage2binaryImage3binrayImage4

Is there any way to get clean hand binary image? Thank you very much if you can give me any comment or help...

the complete code is below:

#include <opencv2/imgproc/imgproc.hpp>
#include<opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>

using namespace std;
using namespace cv;


// we split source picture to binaryImageSectionCount(here it's 8) pieces by its height, 
// then we for every piece, we do threshold, 
// and at last we combine them agin to binaryImage        
const binaryImageSectionCount = 8;
void GetBinaryImage(Mat &grayImage, Mat &binaryImage)
{
    // get every partial gray image's height
    int partImageHeight = grayImage.rows / binaryImageSectionCount;
    for (int i = 0; i < binaryImageSectionCount; i++)
    {
        Mat partialGrayImage;            
        Mat partialBinaryImage;
        Rect partialRect;
        if (i != binaryImageSectionCount - 1)
        {
            // if it's not last piece, Rect's height should be partImageHeight
            partialRect = Rect(0, i * partImageHeight, grayImage.cols, partImageHeight);
        }
        else
        {
            // if it's last piece, Rect's height should be (grayImage.rows - i  * partImageHeight)
            partialRect = Rect(0, i * partImageHeight, grayImage.cols, grayImage.rows - i  * partImageHeight);
        }

        Mat partialResource = grayImage(partialRect);    
        partialResource.copyTo(partialGrayImage);    
        threshold( partialGrayImage, partialBinaryImage, 0, 255, THRESH_OTSU);

        // combin partial binary image to one piece
        partialBinaryImage.copyTo(binaryImage(partialRect));

        ///*stringstream resultStrm;
        //resultStrm << "partial_" << (i + 1);
        //string string = resultStrm.str();

        //imshow(string, partialBinaryImage);
        //waitKey(0);*/
    }
    imshow("result binary image.", binaryImage);
    waitKey(0);
    return;
}


int main(int argc, _TCHAR* argv[])
{   
    // get image path
    string imgPath("C:\\Users\\Alfred\\Desktop\\gray.bmp");     

    // read image
    Mat src = imread(imgPath);
    imshow("Source", src);        
    //medianBlur(src, src, 7);  
    cvtColor(src, src, COLOR_BGR2GRAY);     
    imshow("gray", src);    

    // do filter
    GaussianBlur(src, src, Size(3,3), 0);   

    // binary image
    Mat threshold_output(src.rows, src.cols, CV_8UC1, Scalar(0, 0, 0)); 
    GetBinaryImage(src, threshold_output);
    imshow("binaryImage", threshold_output);

    // get biggest contour
    vector<vector<Point> > contours;    
    findContours(threshold_output,contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
    int biggestContourIndex = 0;
    int maxContourArea = -1000;
    for (int i = 0; i < contours.size(); i++)
    {       
        if (contourArea(contours[i]) > maxContourArea)
        {
            maxContourArea = contourArea(contours[i]);
            biggestContourIndex = i;
        }
    }

    // show biggest contour
    Mat biggestContour(threshold_output.rows, threshold_output.cols, CV_8UC1, Scalar(0, 0, 0));
    drawContours(biggestContour, contours, biggestContourIndex, cv::Scalar(255,255,255), 2, 8, vector<Vec4i>(), 0, Point());
    imshow("maxContour", biggestContour);
    waitKey(0);

}