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:

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

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 ...
edit retag close merge delete