#include <opencv2/opencv.hpp>
#include <opencv2/imgproc.hpp>
#include <vector>
#include <array>
#include <iostream>
using namespace std;
cv::Mat gray_img;
const int max_thresh = 255; // threshold 최댓값
int thresh = 100;
cv::RNG rng(54321); // Random Number Generator - 랜덤값 생성
void thresh_callback(int, void*);
int main() {
const char* img_path = "milk.jpg";
cv::Mat img = cv::imread(img_path); // 이미지 읽어오기
cv::cvtColor(img, gray_img, cv::COLOR_BGR2GRAY); // gray scale로 변환
cv::blur(gray_img, gray_img, cv::Size(3, 3)); // 이미지에 블러 적용 3x3 커널사용
const char* window_name = "origin"; // 보여줄 윈도우 이름
cv::namedWindow(window_name); // 이미지를 보여줄 윈도우 생성
cv::imshow(window_name, img); // 이미지 표현
cv::createTrackbar("Canny thresh:", window_name, &thresh, max_thresh, thresh_callback); // 이미지에 수평으로 컨트롤 할 수 있는 바 생성 ( 마지막 파라미터는 onChange 함수로 파라미터를 (int, void*) 형태로 가지고 있어야함
thresh_callback(0,0); // trackbar에 따라 외곽선 검출 결과를 보여주는 함수
cv::waitKey(0);
return 0;
}
void thresh_callback(int, void*)
{
cv::Mat canny_output;
cv::Canny(gray_img, canny_output, thresh, thresh * 2); // Canny 알고리즘을 이용해서 물체의 엣지(edge)를 검출
vector<vector<cv::Point> > contours; // Point = {int, int} = vector int가 2개 있는
vector<cv::Vec4i> hierarchy; // Vec4i = {int, int, int, int} = vector int가 4개있는
cv::findContours(canny_output, contours, hierarchy, cv::RETR_TREE, cv::CHAIN_APPROX_SIMPLE); // binary 이미지에서 외곽선을 찾는다
cv::Mat drawing = cv::Mat::zeros(canny_output.size(), CV_8UC3);
for (size_t i = 0; i < contours.size(); i++)
{
cv::Scalar color = cv::Scalar(rng.uniform(0, 256), rng.uniform(0, 256), rng.uniform(0, 256));
cv::drawContours(drawing, contours, (int)i, color, 2, cv::LINE_8, hierarchy, 0);
}
imshow("Contours", drawing);
}
opencv docs에서 새로운 함수를 알게되었다 createTrackbar - 설정한 윈도우에 설정한 변수의 값을 변경할 수 있는 바가 생성된다
Edge 추출시 blur를 활용하여 불필요한 edge가 덜 나오게 할 수 있다.
cv::findContours - 외곽선을 검출한다
(input image, output image, contours, hierarchy, int mode, int method, cv::Point offset=cv::Points())
mode 의 종류 cv2::RETR_EXTERNAL : 외곽선중 가장 바깥쪽 선만 리턴한다 cv2::RETR_LIST : 모든 외곽선을 찾지만 계층관계는 구성하지 않는다 cv2::RETR_CCOMP : 모든 외곽선을 찾으며 2단계의 계층관계를 구성한다 cv2::RETR_TREE : 모든 외곽선을 찾으며 모든 계층관계를 구성한다 여기서 계층이란 검출된 외곽선 안에 있는 또다른 외곽선을 뜻한다
method 의 종류 cv2::CHAIN_APPROX_NONE : 모든 point를 저장 cv2::CHAIN_APPROX_SIMPLE : 4개의 point만을 저장하여 메모리를 절약 cv2::CHAIN_APPROX_TC89_L1 : Teh_Chin 연결 근사 알고리즘 L1버전을 적용하여 point 개수를 줄임 cv2::CHAIN_APPROX_TC89_KCOS : Teh_Chin 연결 근사 알고리즘 KCOS 버전을 적용하여 point 개수를 줄임 return 값으로 오는 contours의 shape를 찍어보면 각각 method마다 shape이 다른것을 볼 수 있다.
cv::Scalar 를 이용하여 외곽선을 그릴 때마다 다른 색상을 적용
cv::drawContours
(InputOutputArray image, InputArrayOfArrays contours, int contourIdx, const cv:Scalar &color, int thickness=1, int lineType=8, cv::InputArray hierarchy=noArray(), int maxLevel = 2147483657, cv::Point offset = cv::Point())