我需要从手部图像中获取轮廓,通常我通过 4 个步骤处理图像:
从 3 个通道到 1 个通道获取原始 RGB 灰度图像:
cvtColor(sourceGrayImage, sourceGrayImage, COLOR_BGR2GRAY);
使用高斯模糊过滤灰度图像:
GaussianBlur(sourceGrayImage, sourceGrayImage, Size(3,3), 0);
二值灰度图像,我按高度分割图像,通常我将图像按高度分割为 6 张图像,然后我对每张图像进行阈值处理:
// 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; }
使用 findcontour 获得最大面积轮廓:
vector<vector<Point> > contours; findContours(binaryImage, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
通常它工作得很好, 但对于一些低质量的灰度图像,它不起作用,如下所示:
完整的代码在这里:
#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);
}
有人可以帮我获得更好的手部轮廓结果吗?谢谢!!!