前两节我们系统学习了什么是颜色空间以及如何在Halcon环境下如何进行颜色检测,今天我们将学习如何在OPenCV环境下进行颜色检测,同样检查上一节中的保险丝。在教程中针对Halcon和OpenCV做了简单对比。
例程分析主要步骤如下:
1.将图像由RGB格式转换至HSV格式,并将其分离至HSV三个通道。
2.根据饱和度通道讲保险丝区域分割出来,即ROI区域。
3.利用ROI区域将保险丝的强度通道分离出来,即使保险丝与背景分离。
4.不同颜色所对应的的色彩通道的灰度值不同,根据相应色彩的灰度范围 即可区分出不同颜色的保险丝。
本例程的收获主要由以下几点:
1.针对不同颜色物体的分离、统计、检测等要求可以利用其HSV空间。
2.在分离ROI区域时,得到Mask区域后可以采用的方法为 A.copyTo(B,Mask)。
该方法等同于Halcon中的reduce_domain (A, Mask, B)。
3.在进行阈值分割时OpenCv中没有分割出两个阈值之间区域的算子,因此我采用了以下两种算子来达到相应结果,
threshold(A, B, min, 255, THRESH_TOZERO)
threshold(B, B, max, 255, THRESH_TOZERO_INV)
该方法等同于Halcon中的 threshold(A,B,min,max)
4.将分割出来的区域的连接的部分分割开,以便进行面积、中心、形状的选择及统计。Halcon中采用的方法为Connection
OpenCv中采用findContours亦可达到相应的效果。
#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
for (int i = 0; i < 5; i++)
{
cv::Mat imagecolor, imagehsv, imageh, images, imagev, ROI, HROI, HTarget, cour, Hsg;
vector<Mat> hsvchannels;
string file;
string s;
char t[256];
sprintf_s(t, "%02d", i);
s = t;//int 转化为String
file = "../data/color/color_fuses_" + s + ".png";
imagecolor = imread(file);
if (imagecolor.empty())
break;
cvtColor(imagecolor, imagehsv, CV_RGB2HSV);//将图像转换至HSV空间
split(imagehsv, hsvchannels);
imageh = hsvchannels.at(0);
images = hsvchannels.at(1);
imagev = hsvchannels.at(2);//将HSV通道分离
threshold(images, ROI, 60, 255, THRESH_BINARY);//利用饱和度通道讲保险丝区域分离,选定ROI区域
imageh.copyTo(HROI, ROI);//采用色彩通道来区分颜色,因此在H通道分割出ROI区域
threshold(HROI, HTarget, 110, 255, THRESH_TOZERO);//利用强度通道区分颜色红色110~230、橘黄97~110、黄80~95、绿30~60l、蓝色0~10
threshold(HTarget, HTarget, 230, 255, THRESH_TOZERO_INV);//分割出两个阈值之间的区域
blur(HTarget, HTarget, Size(2, 2));//对图像进行平滑去除部分噪声
threshold(HTarget, HTarget, 110, 255, THRESH_BINARY);
cv::Mat element25(25, 25, CV_8U, cv::Scalar(1));
cv::Mat close;
cv::morphologyEx(HTarget, close, cv::MORPH_CLOSE, element25);
cv::Mat element15(25, 25, CV_8U, cv::Scalar(1));
cv::Mat open;
cv::morphologyEx(close, open, cv::MORPH_OPEN, element15);//分割出目标区域
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
/// 找到轮廓
findContours(open, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));
/// 圆形边界框
vector<vector<Point> > contours_poly(contours.size());
vector<Point2f>center(contours.size());
vector<float>radius(contours.size());
for (int i = 0; i < contours.size(); i++)
{
minEnclosingCircle(contours[i], center[i], radius[i]);
}
/// 画包围的 圆形框
Mat drawing = Mat::zeros(imagecolor.size(), CV_8UC3);
for (int i = 0; i < contours.size(); i++)
{
Scalar color = Scalar(0, 0, 255);
circle(drawing, center[i], (int)radius[i], color, 4, 8, 0);
}
Mat drawingroi;//在白色图片上绘制图形不可以简单的相加
cvtColor(drawing, drawingroi, CV_RGB2GRAY);
threshold(drawingroi, drawingroi, 20, 255, THRESH_BINARY);
drawing.copyTo(imagecolor, drawingroi);
sprintf_s(t,"%01d", contours.size());
s = t;
string txt ="Red Fuse : "+ s;
putText(imagecolor, txt, Point(100, 100), CV_FONT_HERSHEY_COMPLEX, 1,
Scalar(0, 0, 255), 2, 8);
imshow("Image", imagecolor);
waitKey();
}
return 0;
}
教程持续更新,欢迎转载!