설명

마우스로 상자를 만들면, 그 상자에 있는 도형을 Detection해준다.
아직까지는 삼각형, 사각형, 오각형, 육각형, 원만 Detection해준다.

코드

#include "opencv2/opencv.hpp"  

#include <iostream>  

#include <string.h>


using namespace cv;

using namespace std;



bool ldown = false, lup = false;

Mat img_input, img_gray;

Point corner1, corner2;

Rect box;


char * name = "polygons";


Point2f weightCenter(vector<Point> contour);

float distance(Point2f a, Point2f b);

int GetAngle(Point a, Point b, Point c);

void detection(String name, int size, Mat img_result, vector<Point2f> approx, vector<vector<Point>> contours, int index);

void polygonDetection(Mat img_input);

static void mouse_callback(int event, int x, int y, int, void* param);



//무게중심

Point2f weightCenter(vector<Point> contour) {

Point2f result;


for (int i = 0; i < contour.size(); i++) {

result.x += contour[i].x;

result.y += contour[i].y;

}

result.x /= contour.size();

result.y /= contour.size();


return result;

}



//거리구하기

float distance(Point2f a, Point2f b) {

return sqrt(pow(abs(a.x - b.x), 2) + pow(abs(a.y - b.y), 2));

}


//세 점이 주어질 때 사이 각도 구하기

int GetAngle(Point a, Point b, Point c)

{

Point ab = { b.x - a.x, b.y - a.y };

Point cb = { b.x - c.x, b.y - c.y };


float dot = (ab.x * cb.x + ab.y * cb.y); // dot product

float cross = (ab.x * cb.y - ab.y * cb.x); // cross product


float alpha = atan2(cross, dot);


return (int)floor(alpha * 180.0 / CV_PI + 0.5);

}


//변의 길이

void detection(String name, int size, Mat img_result, vector<Point2f> approx, vector<vector<Point>> contours, int index) {

cout << name << endl;

int last = 0;

for (int k = 0; k < size - 1; k++) {

line(img_result, approx[k], approx[k + 1], Scalar(0, 255, 0), 3);

cout << "lenght : [" << k << "] : " << distance(approx[k], approx[k + 1]) << endl;

last = k;

}


line(img_result, approx[0], approx[approx.size() - 1], Scalar(0, 255, 0), 3);

cout << "lenght : [" << size - 1 << "]" << " : " << distance(approx[0], approx[approx.size() - 1]) << endl;

cout << "weight Center : " << weightCenter(contours[index]) << endl;

}


//도형 Detection

void polygonDetection(Mat img_input) {


cvtColor(img_input, img_gray, COLOR_BGR2GRAY);

threshold(img_gray, img_gray, 125, 255, THRESH_BINARY_INV | THRESH_OTSU);

vector<vector<Point>> contours;

findContours(img_gray, contours, RETR_LIST, CHAIN_APPROX_SIMPLE);


//contour를 근사화한다.

Mat img_result;

img_result = img_input.clone();


vector<Point2f> approx;

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))) > 10) {

int size = approx.size();


vector<int> angle;


for (int k = 0; k < size; k++) {

int ang = GetAngle(approx[k], approx[(k + 1) % size], approx[(k + 2) % size]);

angle.push_back(ang);

}


sort(angle.begin(), angle.end());


int minAngle = angle.front();

int maxAngle = angle.back();

int threshold = 50;


//도형을 판정

if (size == 3 && (minAngle >= 0 - threshold && maxAngle <= 90 + threshold)) {

detection("traingle", size, img_result, approx, contours, i);

}

else if (size == 4 && minAngle >= 90 - threshold && maxAngle <= 90 + threshold) {


detection("rectangle", size, img_result, approx, contours, i);

}

else if (size == 5 && minAngle >= 108 - threshold && maxAngle <= 108 + threshold) {

detection("pentagon", size, img_result, approx, contours, i);


}

else if (size >= 6 && minAngle >= 120 - threshold && maxAngle <= 120 + threshold) {

cout << "circle" << endl;

cout << "Center : " << weightCenter(contours[i]) << endl;

cout << "radius : " << distance(weightCenter(contours[i]), approx[0]) << endl;

circle(img_result, weightCenter(contours[i]), distance(weightCenter(contours[i]), approx[0]),                                                                                                                                  Scalar(0, 255, 0), 3);

}

printf("\n");

}

}

destroyWindow("Detection Polygons");

namedWindow("Detection Polygons", WINDOW_AUTOSIZE);

imshow("Detection Polygons", img_result);

}


static void mouse_callback(int event, int x, int y, int, void* param) {

if (event == EVENT_LBUTTONDOWN) {

ldown = true;

corner1.x = x;

corner1.y = y;

}

if (event == EVENT_LBUTTONUP) {

if (abs(x - corner1.x) > 20 && abs(y - corner1.y) > 20) {

lup = true;

corner2.x = x;

corner2.y = y;

}

else {

ldown = false;

}

}

if (ldown == true && lup == false) {

Point pt;

pt.x = x;

pt.y = y;


Mat locale_img = img_input.clone();


rectangle(locale_img, corner1, pt, Scalar(255, 0, 0));

imshow(name, locale_img);

}


if (ldown == true && lup == true) {

box.width = abs(corner1.x - corner2.x);

box.height = abs(corner1.y - corner2.y);


box.x = min(corner1.x, corner2.x);

box.y = min(corner1.y, corner2.y);


Mat crop(img_input, box);

polygonDetection(crop);



ldown = false; lup = false;

}

}



int main(int args, char *argv[]){

img_input = imread("polygons/all_pologon.png", CV_LOAD_IMAGE_COLOR);

if (img_input.empty())

{

cout << "Could not open or find the image" << std::endl;

return -1;

}

namedWindow(name, WINDOW_AUTOSIZE);

imshow(name, img_input);

setMouseCallback(name, mouse_callback);

waitKey(0);


return 0;

}


결과영상




'Programming > openCV' 카테고리의 다른 글

사진 인식  (0) 2017.04.22
open cv 요약  (0) 2017.04.18
BGR별 히스토그램 구하기  (0) 2017.04.11
vector에 접근하는 두가지 방법  (0) 2017.04.11
13. Hough Circles  (0) 2017.04.04

+ Recent posts