반응형

이진화시킨 이미지에서 findContours함수를 사용하여 contour를 찾은 후,  approxPolyDP 함수를 사용하여 다각형(polygon)을 검출하는 예제입니다.




OpenCV 사용해서 실시간으로 도형 검출하기(shape detection) 1 / 2 -  이미지에서 검출


OpenCV 사용해서 실시간으로 도형 검출하기(shape detection) 2 / 2 -  웹캠에서 검출

http://webnautes.tistory.com/1193



2016. 12. 29   최초 작성

2018.   6. 30 도형 판정하는 방법 변경(  내각 체크 → Convex polygon 여부 검사 )

                      webcam으로 테스트 추가




1-1. 다음 테스트용 이미지를 저장하여 OpenCV를 위한 프로젝트 폴더에 넣습니다.


사각형, 육각형, 십각형 도형에는 각각 해당 도형은 아니지만 꼭지점 갯수가 같은 도형이 같이 추가되어 있습니다.

원의 경우에는 팔각형이 추가되어 있는데 실행 결과에서 이유를 설명합니다.




Visual Studio 2017의 경우 프로젝트 이름이 OpenCV Project V 라면 이미지를 복사해놓을 위치는 다음과 같습니다.

C:\Users\로그인_사용자_이름\source\repos\OpenCV Project V\OpenCV Project V




OpenCV를 위한 프로젝트 생성 방법은 다음 포스팅을 참고하세요.


Visual Studio 2017에서 OpenCV 3.4.1를 사용하는 방법

http://webnautes.tistory.com/1132





1-2. 다음 소스코드를 프로젝트의 cpp 소스 파일에 붙여넣기 합니다.


#include "opencv2/opencv.hpp"
#include <iostream>  
#include <string>

using namespace cv;
using namespace std;



//Contour 영역 내에 텍스트 쓰기
//https://github.com/bsdnoobz/opencv-code/blob/master/shape-detect.cpp
void setLabel(Mat& image, string str, vector<Point> contour)
{
int fontface = FONT_HERSHEY_SIMPLEX;
double scale = 0.5;
int thickness = 1;
int baseline = 0;

Size text = getTextSize(str, fontface, scale, thickness, &baseline);
Rect r = boundingRect(contour);

Point pt(r.x + ((r.width - text.width) / 2), r.y + ((r.height + text.height) / 2));
rectangle(image, pt + Point(0, baseline), pt + Point(text.width, -text.height), CV_RGB(200, 200, 200), FILLED);
putText(image, str, pt, fontface, scale, CV_RGB(0, 0, 0), thickness, 8);
}



int main(int, char**)
{
Mat img_input, img_result, img_gray;

//이미지파일을 로드하여 image에 저장  
img_input = imread("test.png", IMREAD_COLOR);
if (img_input.empty())
{
cout << "Could not open or find the image" << std::endl;
return -1;
}


//그레이스케일 이미지로 변환  
cvtColor(img_input, img_gray, COLOR_BGR2GRAY);

//이진화 이미지로 변환
Mat binary_image;
threshold(img_gray, img_gray, 0, 255, THRESH_BINARY_INV | THRESH_OTSU);

//contour를 찾는다.
vector<vector<Point> > contours;
findContours(img_gray, contours, RETR_LIST, CHAIN_APPROX_SIMPLE);

//contour를 근사화한다.
vector<Point2f> approx;
img_result = img_input.clone();

for (size_t i = 0; i < contours.size(); i++)
{
approxPolyDP(Mat(contours[i]), approx, arcLength(Mat(contours[i]), true)*0.02, true);

if (fabs(contourArea(Mat(approx))) > 100)  //면적이 일정크기 이상이어야 한다.
{

int size = approx.size();

//Contour를 근사화한 직선을 그린다.
if (size % 2 == 0) {
line(img_result, approx[0], approx[approx.size() - 1], Scalar(0, 255, 0), 3);

for (int k = 0; k < size - 1; k++)
line(img_result, approx[k], approx[k + 1], Scalar(0, 255, 0), 3);

for (int k = 0; k < size; k++)
circle(img_result, approx[k], 3, Scalar(0, 0, 255));
}
else {
line(img_result, approx[0], approx[approx.size() - 1], Scalar(0, 255, 0), 3);

for (int k = 0; k < size - 1; k++)
line(img_result, approx[k], approx[k + 1], Scalar(0, 255, 0), 3);

for (int k = 0; k < size; k++)
circle(img_result, approx[k], 3, Scalar(0, 0, 255));
}



//도형을 판정한다.
if (size == 3)
setLabel(img_result, "triangle", contours[i]); //삼각형

//이하는 해당 꼭지점을 가진 convex라면 찾는 도형
else if (size == 4 && isContourConvex(Mat(approx)))
setLabel(img_result, "rectangle", contours[i]); //사각형

else if (size == 5 && isContourConvex(Mat(approx)))
setLabel(img_result, "pentagon", contours[i]); //오각형

else if (size == 6 && isContourConvex(Mat(approx)))
setLabel(img_result, "hexagon", contours[i]);  //육각형

else if (size == 10 && isContourConvex(Mat(approx)))
setLabel(img_result, "decagon", contours[i]);    //십각형

//위 조건에 해당 안되는 경우는 찾아낸 꼭지점 갯수를 표시
else setLabel(img_result, to_string(approx.size()), contours[i]);
}

}


imshow("input", img_input);
imshow("result", img_result);


waitKey(0);


return 0;
}





1-3. 실행해보면 원본 이미지를 보여주는 input 창과 도형에 인식된 이름을 출력해주는 result 창이 보여집니다.


결과 창입니다. 테스트 이미지에 주어진 모든 도형이 회전 되었는지 여부랑 상관없이 해당 도형을 검출하고 있습니다. 꼭지점 갯수를 기반으로 해당 도형인지 판단 하기 때문입니다.



해당 다각형을 위한 꼭지점 갯수를 가지고 있더라도 Convex polygon이 아니라면 제외 시켰기 때문에 파란색 2번, 녹색 2번, 노란색 2번은 검출된 이름 대신에 꼭지점 갯수만 출력하고 있습니다.


원에서 검출된 contour를 approxPolyDP 함수로 근사화하면 8개의 꼭지점을 갖습니다.

필요시 팔각형과 원 중 한쪽으로 인식이 완료되었다고 코드를 수정해도 될 듯합니다.


또는 OpenCV에서 제공하는 원을 검출하는 HoughCircles 함수를 사용해도 됩니다.

https://docs.opencv.org/3.4/d4/d70/tutorial_hough_circle.html



다음 포스팅에서는  웹캠을 사용하여 실시간으로 도형 검출하는 것을 진행해보겠습니다.



반응형

문제 발생시 지나치지 마시고 댓글 남겨주시면 가능한 빨리 답장드립니다.

도움이 되셨다면 토스아이디로 후원해주세요.
https://toss.me/momo2024


제가 쓴 책도 한번 검토해보세요 ^^

+ Recent posts