2016-11-05 5 views
2

мне нужно, чтобы получить контур от руки изображения, как правило, я обработать изображение с 4 шагами:OpenCV - как получить лучший контур руки от изображения низкого качества серого?

  1. получают сырое RGB серое изображение от 3-х каналов 1 канал:

    cvtColor(sourceGrayImage, sourceGrayImage, COLOR_BGR2GRAY); 
    
  2. использование гауссова размывания фильтр серого изображения:

    GaussianBlur(sourceGrayImage, sourceGrayImage, Size(3,3), 0); 
    
  3. двоичное серое изображение, я разделить изображение по высоте, обычно я разделить изображение 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; 
    } 
    
  4. использовать findcontour, чтобы получить самую большую площадь контура:

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

обычно работает хорошо, Но для некоторого низкого качества серого изображения, не работает, как показано ниже:

LowQualityGrayImage1

LowQualityGrayImage2

полный код здесь:

#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); 

} 

может кто-нибудь, пожалуйста, помогите мне, чтобы получить лучший результат ручного контура? спасибо !!!

+0

Перед тем, как найти контур, почему бы вам не попробовать некоторые методы предварительной обработки, чтобы улучшить изображение и сделать руку более понятной? –

+0

но какую проработку я должен попробовать для этих двух изображений? Не могли бы вы дать мне несколько советов? – Alfred

+0

Вы можете использовать контрастную адаптивную гистограмму. –

ответ

1

У меня есть фрагмент кода в Python, вы можете следить за тот же подход, в C:

img = cv2.imread(x, 1) 
cv2.imshow("img",img) 

imgray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) 
cv2.imshow("gray",imgray) 

#Code for histogram equalization 
equ = cv2.equalizeHist(imgray) 
cv2.imshow('equ', equ) 

#Code for contrast limited adaptive histogram equalization 
#clahe = cv2.createCLAHE(clipLimit=3.0, tileGridSize=(8,8)) 
#cl2 = clahe.apply(imgray) 
#cv2.imshow('clahe2', cl2) 

Это результат я получил:

enter image description here

Если вы изображение ужасно плохо, вы можете попробовать код, который я прокомментировал, используя контрастную адаптивную гистограмму.

+0

Проверьте эти ссылки для получения дополнительной информации по теме: [ссылка 1] (http://docs.opencv.org/2.4/modules/imgproc/doc/histograms.html) и [ ссылка 2] (http://docs.opencv.org/3.1.0/d5/daf/tutorial_py_histogram_equalization.html) –