2013-06-17 2 views
5

입력 이미지를 사용하여 : enter image description here검출 클러스터에서 OpenCV에게

예상 출력 : I 세 (또는 몇 개의) 다각형에 맞게하려는 enter image description here

(이 경우를 들어, 사각형) 이 이미지에서 "큰"흰색 얼룩을 나타냅니다. 출력 이미지에 그려지는 직사각형은 흰색 영역에 대한 나의 지각에 따른 것입니다. 나는 알고리즘이 같은 bouding 지역을 생각해 낼 것으로 기대하지 않는다. 내가 원하는 것은 하얀 픽셀 클러스터 주위에 꽉 찬 다각형을 몇 개 끼워 넣는 것입니다.

내 초기 솔루션은이 이미지의 윤곽선을 찾고 각 윤곽선에 점의 볼록 선체를 찾아서 각 윤곽선 주위에 닫힌 볼록 다각형을 맞추는 것으로 구성되었습니다.

그러나 흰색 영역은 가장자리 주변에서 검은 영역으로 매우 잘게 조각 났으므로 cv2.findContours가 반환하는 윤곽 수는 매우 높습니다 (약 500 정도). 이 때문에 볼록한 선체를 피팅해도 흰색 영역의 모양이 개선되지 않습니다. 흰색 영역은 대부분 원래 추상 모양을 유지합니다. 내 목표는 흰색 영역의 여러 작은 윤곽을 하나의 전체 윤곽을 병합하여 볼록한 선체에 맞출 수있는 것입니다.

어떻게이 문제를 해결할 수 있습니까? 서로 가까이있는 윤곽선을 찾기 위해 처음에는 윤곽 점에서 클러스터링 알고리즘을 사용해야합니까?

+0

http://en.wikipedia.org/wiki/DBSCAN이 도움이 될 수 있습니다. 파이썬 밑에. 데모 http://scikit-learn.org/stable/auto_examples/cluster/plot_dbscan.html – baci

답변

1

각 흰 점과 세 개의 클러스터에 대한 특징으로 x y 좌표를 사용하여 kmeans 클러스터링을 사용할 수 있습니다. 그런 다음 결과로 나온 3 개의 클러스터의 볼록한 선체를 가져옵니다. 다른 출발점을 시도하고 가장 좋은 결과를 선택해야 할 수도 있습니다. http://docs.opencv.org/modules/core/doc/clustering.html#kmeans

2

윤곽선을 찾기 전에 먼저 이미지를 확장 할 수 있습니다. 발진이 일어나 밝은 영역이 커집니다. 이미지의 모든 기존 흰색 픽셀 주위에 흰색 픽셀을 추가하는 것으로 생각할 수 있습니다. 이렇게하면 인접한 밝은 모양이 합쳐집니다. http://docs.opencv.org/doc/tutorials/imgproc/erosion_dilatation/erosion_dilatation.html

블러와 임계 값을 다시 설정할 수 있지만 흐림 효과는 흐림 정도에 따라 확장보다 훨씬 비쌉니다.

3

먼저이 이미지에서 형태학 폐쇄 (확장 후 침식)를 수행해야합니다. 이렇게하면 개별 구성 요소의 모양과 크기를 보존하면서 이미지에있는 모든 작은 "구멍"을 닫을 수 있습니다. 그 반대편에, 침식 후에 팽창이 일어날 때, 그것은 이미지의 잡음이 많은 점을 제거합니다. 비슷한 이미지로 작업 중이며 내 구성 요소를 확장하기 위해 최대 10 회까지 확장 및 부식을 수행해야했습니다. 그런 다음 연결된 구성 요소를 사용하거나 등고선을 찾으십시오. 이것은 분명히 컨투어 카운트를 400에서 20-30으로 줄입니다.

두 번째로, 당신은 3 개의 클러스터가 필요하다고 언급했습니다. 비록 두 개의 작은 클러스터 (빨간 선으로 덮여 있음)가 하나로 합쳐 졌을지라도. 내가 만든 것은 클러스터의 각각이 가능한 한 경계 사각형에 꼭 맞게 들어가는 것입니다. 따라서 임계 값 효율 (예 : 80 %)을 설정하고 계층 적 클러스터링을 사용하여 연결된 각 구성 요소를 클러스터로 병합하는 것이 좋습니다. 흰 픽셀이 (클러스터의) 경계 사각형의 공간의 80 % 미만을 차지하면 클러스터링을 중지하고 클러스터를 가져옵니다.

0

필요한 모든 영역이 연결될 때까지 모양 주위에 대략적인 윤곽을 그릴 수 있습니다. 이것으로 나는 효과적으로 이미지를 부식시키고있다. 연결된 지역 주변에 선체를 그리면 빨간색 직사각형이 생깁니다.(그들은 모두 흰색 점의 99 %를 커버하는 경우, 예를 들어) 가장 큰 세 개의 선체가 일부 필수 속성이 될 때까지

그냥

#include <vector> 
using std::vector; 
#include <algorithm> 
using std::sort; 
#include <string> 
using std::string; 
using std::to_string; 
#include <iostream> 
using std::clog; 
using std::endl; 
#include <opencv2/opencv.hpp> 
using namespace cv; 

int main() 
{ 
    typedef vector<Point> Polygon; 
    typedef vector<Polygon> Polygons; 
    Mat mFrame; 
    Mat mOrig; 
    mFrame = imread("R2TsZ.png"); 
    mFrame.copyTo(mOrig); 
    Mat mOrigHull; 
    Mat mOut; 
    int fileCounter = 0; 
    while(true){ 
    clog<< "image read"<< endl; 
    cvtColor(mFrame, mOut, CV_BGR2GRAY); 
    clog<< "image grayscaled"<< endl; 
    Polygons contours; 
    Polygons aContours; 
    Polygons hulls; 
    OutputArray hierarchy = {}; 

    findContours(mOut, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE); 
    clog<< contours.size()<< " contours found"<< endl; 
    sort(contours.begin(), contours.end(), [](auto p1, auto p2){ 
     return contourArea(p1) > contourArea(p2); 
    }); 
    clog<< "contours sorted"<< endl; 
    aContours.resize(contours.size()); 
    hulls.resize(contours.size()); 
    for(size_t i = 0; i < aContours.size() - 1; ++ i){ 
     approxPolyDP(contours[i], aContours[i], 20, true); 
     drawContours(mFrame, aContours, i, Scalar(255, 255, 255), 10); 
     convexHull(aContours[i], hulls[i], true); 
    } 
    mOrig.copyTo(mOrigHull); 
    for(size_t i = 0; i < 3; ++ i){ 
     drawContours(mOrigHull, hulls, i, Scalar(0, 0, 255), 10); 
    } 
    imshow("out", mOrigHull); 
    int key = waitKey() & 0xff; 
    if(key == 27){ 
     return EXIT_SUCCESS; 
    } 
    if(key == 'p'){ 
     string file = "test_" + to_string(++ fileCounter) + ".png"; 
     imwrite(file, mOrigHull); 
     clog<< file<< " saved."<< endl; 
    } 
    } 
} 

는 OpenCV의에서이 tutorial에서 자세한 내용을 참조하십시오 반복합니다.

enter image description here