HSV 이용해서 객체 검출하기 2
#4 게시물과는 달리 한 색만을 검출하는 것이 아니라 넓은 범위에서 원하는 부분을 검출해보자
다음과 같은 이미지에서 Google의 글자 부분을 인식해서 사각형을 그려보고자 한다.
HSV의 범위와 opencv에서 사용하는 범위가 다르게 때문에 다음 코드를 이용해서
적절한 범위를 얻어낸다
const int max_value_H = 360 / 2;
const int max_value = 255;
const String window_capture_name = "Video Capture";
const String window_detection_name = "Object Detection";
int low_H = 0, low_S = 0, low_V = 0;
int high_H = max_value_H, high_S = max_value, high_V = max_value;
static void on_low_H_thresh_trackbar(int, void*)
{
low_H = min(high_H - 1, low_H);
setTrackbarPos("Low H", window_detection_name, low_H);
}
static void on_high_H_thresh_trackbar(int, void*)
{
high_H = max(high_H, low_H + 1);
setTrackbarPos("High H", window_detection_name, high_H);
}
static void on_low_S_thresh_trackbar(int, void*)
{
low_S = min(high_S - 1, low_S);
setTrackbarPos("Low S", window_detection_name, low_S);
}
static void on_high_S_thresh_trackbar(int, void*)
{
high_S = max(high_S, low_S + 1);
setTrackbarPos("High S", window_detection_name, high_S);
}
static void on_low_V_thresh_trackbar(int, void*)
{
low_V = min(high_V - 1, low_V);
setTrackbarPos("Low V", window_detection_name, low_V);
}
static void on_high_V_thresh_trackbar(int, void*)
{
high_V = max(high_V, low_V + 1);
setTrackbarPos("High V", window_detection_name, high_V);
}
int main(int argc, char* argv[])
{
namedWindow(window_capture_name);
namedWindow(window_detection_name);
resizeWindow(window_detection_name, Size(1024, 768));
// Trackbars to set thresholds for HSV values
createTrackbar("Low H", window_detection_name, &low_H, max_value_H, on_low_H_thresh_trackbar);
createTrackbar("High H", window_detection_name, &high_H, max_value_H, on_high_H_thresh_trackbar);
createTrackbar("Low S", window_detection_name, &low_S, max_value, on_low_S_thresh_trackbar);
createTrackbar("High S", window_detection_name, &high_S, max_value, on_high_S_thresh_trackbar);
createTrackbar("Low V", window_detection_name, &low_V, max_value, on_low_V_thresh_trackbar);
createTrackbar("High V", window_detection_name, &high_V, max_value, on_high_V_thresh_trackbar);
Mat frame, frame_HSV, frame_threshold;
string fileDir = "../thirdparty/opencv_470/sources/samples/data/";
string fileName = fileDir + "find_google_area.png";
frame = cv::imread(fileName, cv::ImreadModes::IMREAD_COLOR);
while (true) {
if (frame.empty())
{
break;
}
// Convert from BGR to HSV colorspace
cvtColor(frame, frame_HSV, COLOR_BGR2HSV);
// Detect the object based on HSV Range Values
inRange(frame_HSV, Scalar(low_H, low_S, low_V), Scalar(high_H, high_S, high_V), frame_threshold);
// Show the frames
imshow(window_capture_name, frame);
imshow(window_detection_name, frame_threshold);
char key = (char)waitKey(30);
if (key == 'q' || key == 27)
{
break;
}
}
return 0;
}
다음과 같이 트랙바를 이용해 검출하고자 하는 부분만 하얀색으로 표시되도록 조절한다
결과를 보기위한 코드는 #4 게시물과 HSV 범위가 다른 것 외엔 차이점이 거의 없다
결과 이미지를 보면 글자 외에 풀 부분과 작은 노이즈까지 검출하는 것을 볼 수 있다
이것을 해결하기 위해서
Mat im_floodfill = detect_img_R.clone();
floodFill(im_floodfill, cv::Point(0, 0), Scalar(255));
// Invert floodfilled image
Mat im_floodfill_inv;
bitwise_not(im_floodfill, im_floodfill_inv);
// Combine the two images to get the foreground.
Mat detect_img_R_fill = (detect_img_R | im_floodfill_inv);
o나 g 같이 빈 공간을 채운다
그리고 최소 면적과 둘레의 최소 길이를 설정해 필터링 하는 과정을 추가했다
double area = cv::contourArea(contours[i]);
double length = cv::arcLength(contours[i], false);
if (area < 10) continue;
if (length < length_spec) continue;
최종 결과