1. Image 결합
#include <opencv2/opencv.hpp>
#include <iostream>
#include <vector>
#include <array>
using namespace std;
int main() {
// cv namespace는 설명을 위해 사용하지 않음
cv::Mat img = cv::imread("img1.png");
cv::Mat gray_img;
cv::cvtColor(img, gray_img, cv::COLOR_BGR2GRAY); // gray.로 변환
cout << gray_img.size() << " channel : " << gray_img.channels() << endl; // 225x225x1
cout << img.size() << " channel : " << img.channels() << endl; // 225x225x3
array<cv::Mat, 3> arr = { gray_img, gray_img, gray_img };
cv::Mat merge_img;
cv::merge(arr, merge_img); // ArrayOfArray를 합침
cout << merge_img.size() << " channel : " << merge_img.channels() << endl; //225x225x3
cv::Mat concat_img;
cv::hconcat(merge_img, img, concat_img); // 수평으로 결합 - 차원이 같아야함
//cv::vconcat(merge_img, img, concat_img); // 수직으로 결합 - 차원이 같아야함
cout << concat_img.size() << " channel : " << concat_img.channels() << endl; // 450x225x3
cv::imshow("qwe", concat_img);
cv::waitKey(0);
return 0;
}
- Opencv에서 제공하는 concat 함수를 사용하여 이미지를 수직 또는 수평으로 결합할 수 있다
- vconcat, hconcat - 흑백이미지와 color 이미지를 결합하기 위해서는 흑백이미지의 경우 채널이 1이기 때문에 먼저 3채널로 만든 뒤 결합하여야 한다. 그때 cv::merge 함수를 사용하여 생성하였다
- merge를 사용할 때 흑백 이미지에 대해서 array를 생성한 후 merge 하였는데, vertor를 사용하지 않고 array를 사용한 이유는 우리가 원하는 차원의 개수(3)를 알고있기 때문에 원소의 개수를 지정할 수 있는 array를 사용했다
2. 외곽선 검출 (https://docs.opencv.org/3.4/df/d0d/tutorial_find_contours.html)
#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())
'Machine Learning > Computer Vision' 카테고리의 다른 글
(12) Opencv Python - 자동차 번호판에 대하여 (0) | 2023.09.14 |
---|---|
(1) OpenCV C++ - 기초 ( imread, imshow, cvtColor, resize) (0) | 2023.09.08 |
(11) OpenCV python - 원근(투영) 변환 - perspective (projection) transform (0) | 2022.06.07 |
(에러를 딛고 깨달은) opencv perspective transform 후 선 그린 후 원본에서 해당 선의 위치 구하기 - 역변환 하기, 점 변환 (0) | 2022.03.10 |
(10) OpenCV python - 색상 범위 추출 - inRange (0) | 2021.11.27 |