2013-08-28 1 views
2

floodFill을 사용하여 매우 느린 순진한 세분화를 빠르게 재 작성하려고합니다. 색상을 표시하고 윤곽을 찾는 것이 어려워서 1 년 전에 meanShiftFiltering을 배제했습니다.meanShiftSegmentation() 출력에서 ​​findContours()를 실행하는 방법은 무엇입니까?

현재 버전의 opencv에는 mean shift : gpu :: meanShiftSegmentation()을 사용하여 세그먼트에 레이블을 지정하는 빠른 새 기능이있는 것으로 보입니다. 그것은 다음과 같이 이미지를 생성합니다

meanShiftSegmentation() output http://www.ekran.org/tmp/segments.png

그래서이 나에게 윤곽을 생성 할 수있을 아주 가까이 보인다. 어떻게 세그먼트를 생성하기 위해 findContours를 실행할 수 있습니까?

나에게 보이는 것처럼 이미지에서 레이블이있는 색을 추출한 다음 이미지의 픽셀 값이 각 레이블 색과 일치하는지 테스트하여 findContours에 적합한 부울 이미지를 만듭니다.

Mat image = imread("test.png"); 

... 
// gpu operations on image resulting in gpuOpen 
... 

// Mean shift 
TermCriteria iterations = TermCriteria(CV_TERMCRIT_ITER, 2, 0); 
gpu::meanShiftSegmentation(gpuOpen, segments, 10, 20, 300, iterations); 

// convert to greyscale (HSV image) 
vector<Mat> channels; 
split(segments, channels); 

// get labels from histogram of image. 
int size = 256; 
labels = Mat(256, 1, CV_32SC1); 
calcHist(&channels.at(2), 1, 0, Mat(), labels, 1, &size, 0); 

// Loop through hist bins 
for (int i=0; i<256; i++) { 
    float count = labels.at<float>(i); 

    // Does this bin represent a label in the image? 
    if (count > 0) { 
     // find areas of the image that match this label and findContours on the result. 
     Mat label = Mat(channels.at(2).rows, channels.at(2).cols, CV_8UC1, Scalar::all(i)); // image filled with label colour. 
     Mat boolImage = (channels.at(2) == label); // which pixels in labeled image are identical to this label? 
     vector<vector<Point>> labelContours; 
     findContours(boolImage, labelContours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE); 
     // Loop through contours. 
     for (int idx = 0; idx < labelContours.size(); idx++) { 
      // get bounds for this contour. 
      bounds = boundingRect(labelContours[idx]); 

      // create ROI for bounds to extract this region 
      Mat patchROI = image(bounds); 
      Mat maskROI = boolImage(bounds); 
     } 
    } 
} 

이것이 가장 좋은 방법인가 또는 라벨의 색상을 얻을 수있는 더 좋은 방법이있다 :이 (더 나은 방법이 있어야한다는 조금 느리지 만 날 파업) 내가 다음에 무슨 짓입니까? meanShiftSegmentation이이 정보를 제공하는 것이 논리적 인 것으로 보입니다. (색상 값 벡터 또는 각 레이블에 대한 마스크 벡터)

감사합니다.

답변

0

다음은 meanShiftSegmentation 결과에서 색상 정보를 제거하지 않고도이를 수행하는 또 다른 방법입니다. 나는 성능을 위해이 둘을 비교하지 않았다.

// Loop through whole image, pixel and pixel and then use the colour to index an array of bools indicating presence. 

vector<Scalar> colours; 
vector<Scalar>::iterator colourIter; 
vector< vector< vector<bool> > > colourSpace; 
vector< vector< vector<bool> > >::iterator colourSpaceBIter; 
vector< vector<bool> >::iterator colourSpaceGIter; 
vector<bool>::iterator colourSpaceRIter; 

// Initialize 3D Vector 
colourSpace.resize(256); 
for (int i = 0; i < 256; i++) { 
    colourSpace[i].resize(256); 
    for (int j = 0; j < 256; j++) { 
     colourSpace[i][j].resize(256); 
    } 
} 

// Loop through pixels in the image (should be fastish, look into LUT for faster) 
uchar r, g, b; 
for (int i = 0; i < segments.rows; i++) 
{ 
    Vec3b* pixel = segments.ptr<Vec3b>(i); // point to first pixel in row 
    for (int j = 0; j < segments.cols; j++) 
    { 
     b = pixel[j][0]; 
     g = pixel[j][1]; 
     r = pixel[j][2]; 

     colourSpace[b][g][r] = true; // this colour is in the image. 
     //cout << "BGR: " << int(b) << " " << int(g) << " " << int(r) << endl; 
    } 
} 

// Get all the unique colours from colourSpace 
// loop through colourSpace 
int bi=0; 
for (colourSpaceBIter = colourSpace.begin(); colourSpaceBIter != colourSpace.end(); colourSpaceBIter++) { 
    int gi=0; 
    for (colourSpaceGIter = colourSpaceBIter->begin(); colourSpaceGIter != colourSpaceBIter->end(); colourSpaceGIter++) { 
     int ri=0; 
     for (colourSpaceRIter = colourSpaceGIter->begin(); colourSpaceRIter != colourSpaceGIter->end(); colourSpaceRIter++) { 
      if (*colourSpaceRIter) 
       colours.push_back(Scalar(bi,gi,ri)); 
      ri++; 
     } 
     gi++; 
    } 
    bi++; 
} 

// For each colour 
int segmentCount = 0; 
for (colourIter = colours.begin(); colourIter != colours.end(); colourIter++) { 

    Mat label = Mat(segments.rows, segments.cols, CV_8UC3, *colourIter); // image filled with label colour. 
    Mat boolImage = Mat(segments.rows, segments.cols, CV_8UC3); 
    inRange(segments, *colourIter, *colourIter, boolImage); // which pixels in labeled image are identical to this label? 

    vector<vector<Point> > labelContours; 
    findContours(boolImage, labelContours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE); 

    // Loop through contours. 
    for (int idx = 0; idx < labelContours.size(); idx++) { 
     // get bounds for this contour. 
     Rect bounds = boundingRect(labelContours[idx]); 
     float area = contourArea(labelContours[idx]); 

     // Draw this contour on a new blank image 
     Mat maskImage = Mat::zeros(boolImage.rows, boolImage.cols, boolImage.type()); 
     drawContours(maskImage, labelContours, idx, Scalar(255,255,255), CV_FILLED); 

     Mat patchROI = frame(bounds); 
     Mat maskROI = maskImage(bounds); 
    } 
    segmentCount++; 
} 
관련 문제