Table of Contents
Color Detecting using OpenCV
Author: Myong Geon Kim Email: m.geon.kim@gmail.com
Date: Last modified on <06/20/19>
Keywords: Tutorial, how to, step-by-step, opencv
This tutorial is for whom will continue DASL Intern Gantry project. Visual studio and OpenCV library are required for this tutorial.
Motivation and Audience
Readers of this tutorial assumes the reader has the following background and interests:
* Basic background of CPP
* Basic background of using OpenCV library : How to Use OpenCV library.
The rest of this tutorial is presented as follows:
- Final Words
Code
#include <opencv2/opencv.hpp> #include <iostream> using namespace cv; using namespace std; int main() { int range_count = 0; Scalar red(0, 0, 255); Scalar blue(255, 0, 0); Scalar yellow(0, 255, 255); Scalar magenta(255, 0, 255); Mat rgb_color = Mat(1, 1, CV_8UC3, red); Mat hsv_color; cvtColor(rgb_color, hsv_color, COLOR_BGR2HSV); int hue = (int)hsv_color.at<Vec3b>(0, 0)[0]; int saturation = (int)hsv_color.at<Vec3b>(0, 0)[1]; int value = (int)hsv_color.at<Vec3b>(0, 0)[2]; cout << "hue = " << hue << endl; cout << "saturation = " << saturation << endl; cout << "value = " << value << endl; int low_hue = hue - 10; int high_hue = hue + 10; int low_hue1 = 0, low_hue2 = 0; int high_hue1 = 0, high_hue2 = 0; if (low_hue < 10) { range_count = 2; high_hue1 = 180; low_hue1 = low_hue + 180; high_hue2 = high_hue; low_hue2 = 0; } else if (high_hue > 170) { range_count = 2; high_hue1 = low_hue; low_hue1 = 180; high_hue2 = high_hue - 180; low_hue2 = 0; } else { range_count = 1; low_hue1 = low_hue; high_hue1 = high_hue; } cout << low_hue1 << " " << high_hue1 << endl; cout << low_hue2 << " " << high_hue2 << endl; VideoCapture cap(1); Mat img_frame, img_hsv; if (!cap.isOpened()) { cerr << "ERROR! Unable to open camera\n"; return -1; } for (;;) { // wait for a new frame from camera and store it into 'frame' cap.read(img_frame); // check if we succeeded if (img_frame.empty()) { cerr << "ERROR! blank frame grabbed\n"; break; } //HSV로 변환 cvtColor(img_frame, img_hsv, COLOR_BGR2HSV); //지정한 HSV 범위를 이용하여 영상을 이진화 Mat img_mask1, img_mask2; inRange(img_hsv, Scalar(low_hue1, 50, 50), Scalar(high_hue1, 255, 255), img_mask1); if (range_count == 2) { inRange(img_hsv, Scalar(low_hue2, 50, 50), Scalar(high_hue2, 255, 255), img_mask2); img_mask1 |= img_mask2; } //morphological opening 작은 점들을 제거 erode(img_mask1, img_mask1, getStructuringElement(MORPH_ELLIPSE, Size(5, 5))); dilate(img_mask1, img_mask1, getStructuringElement(MORPH_ELLIPSE, Size(5, 5))); //morphological closing 영역의 구멍 메우기 dilate(img_mask1, img_mask1, getStructuringElement(MORPH_ELLIPSE, Size(5, 5))); erode(img_mask1, img_mask1, getStructuringElement(MORPH_ELLIPSE, Size(5, 5))); //라벨링 Mat img_labels, stats, centroids; int numOfLables = connectedComponentsWithStats(img_mask1, img_labels, stats, centroids, 8, CV_32S); //영역박스 그리기 int max = -1, idx = 0; for (int j = 1; j < numOfLables; j++) { int area = stats.at<int>(j, CC_STAT_AREA); if (max < area) { max = area; idx = j; } } int left = stats.at<int>(idx, CC_STAT_LEFT); int top = stats.at<int>(idx, CC_STAT_TOP); int width = stats.at<int>(idx, CC_STAT_WIDTH); int height = stats.at<int>(idx, CC_STAT_HEIGHT); int x = left + width / 2; int y = top + height / 2; int original_x = centroids.at<double>(0, 0); //중심좌표 int original_y = centroids.at<double>(0, 1); circle(img_frame, Point(x, y), width / 2, Scalar(0, 0, 255), 1); //make a circle around object cout << "Ball position X = " << x // x position of center point of circle << ",\tY = " << y // y position of center point of circle << ",\tRadius = " << width/2 <<"center x =" << original_x <<"center y=" << original_y << "\n"; imshow("이진화 영상", img_mask1); imshow("원본 영상", img_frame); if (waitKey(5) >= 0) break; } return 0; }
Explanation
Above project is made by three big parts.
First, detect color by setting up curtain hue value.
Second, clarify detected color by change the image to binary image.
Last, labeling that color.
Detecting and clarifying was hard for me to understand how it works.
In this tutorial, I will focus on drawing a circle around the color and finding its position.
In this part,
int left = stats.at<int>(idx, CC_STAT_LEFT); int top = stats.at<int>(idx, CC_STAT_TOP); int width = stats.at<int>(idx, CC_STAT_WIDTH); int height = stats.at<int>(idx, CC_STAT_HEIGHT);
“stats.at” function helps to find left,top,width,height of color
which means we can find radius and center of circle.
int original_x = centroids.at<double>(0, 0); int original_y = centroids.at<double>(0, 1);
This function let us know the origin point of images.
circle(img_frame, Point(x, y), width / 2, Scalar(0, 0, 255), 1); //make a circle around object
This function draw a circle around the color.
cout << "Ball position X = " << x // x position of center point of circle << ",\tY = " << y // y position of center point of circle << ",\tRadius = " << width/2 <<"center x =" << original_x <<"center y=" << original_y << "\n";
This will show current position and radius of circle constantly in the cmd window.
Final Words
For questions, clarifications, etc, Email: m.geon.kim@gmail.com