效果展示:
思路是将图片转化为hsv格式,然后用inRange函数变为黑白二值化图像,二值化图像有噪点时用开操作闭操作去除,用canny算子检测边缘,findContours函数寻找轮廓,再计算轮廓矩 和中心,再绘制轮廓和形心
图片转化为hsv格式
图为各种颜色的hsv值对应表
cvtColor(src, hsv, CV_BGR2HSV); //直接转换为hsv
贴上详细介绍hsv的博文
HSV效果图
inRange函数
//inRange函数可以将指定颜色转化为白色,其他颜色转化为黑色
inRange(hsv, Scalar(26, 43, 46), Scalar(34, 255, 255), temp);
第一个变量为输入的hsv图片,第二个是某颜色对应的hsv_min值,第三个是某颜色对应的hsv_max值,第四个是输出的图像
效果图
Canny函数
//对得到的二值化图像进行边缘检测
Canny(temp, temp, 20, 80, 3, false);
效果图
寻找轮廓
findContours(temp, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));
计算轮廓矩 和轮廓中心
//计算轮廓矩
vector<Moments> mu(contours.size());
for (int i = 0; i < contours.size(); i++)
{
mu[i] = moments(contours[i], false);
}
//计算轮廓中心
vector<Point2f> mc(contours.size());
for (int i = 0; i < contours.size(); i++)
{
mc[i] = Point2d(mu[i].m10 / mu[i].m00, mu[i].m01 / mu[i].m00);
}
绘制轮廓标和标定形心
Mat drawing = Mat::zeros(temp.size(), CV_8UC3);
for (int i = 0; i < contours.size(); i++)
{
Scalar color = Scalar(0, 0, 0);
//第一个变量用初始图像可以将轮廓绘制到原图上
drawContours(src, contours, i, color, 2, 8, hierarchy, 0, Point(0, 0));
//指的是标定形心,第一个变量用初始图像可以将形心绘制到原图上
circle(src, mc[i], 1, Scalar(0, 0, 0), -1, 6, 0); //画中心圆
}
代码少了降噪部分,图是自己画的比较清晰没有噪点等问题就没有写。
除此之外还出现了一些问题
问题
指点蓝色时没达到效果。
标定紫色时星星的形心不在中间。
以上两个问题还想不到解决方法。。。
最后
贴上findContours和drawContours使用介绍
完整代码如下:
#include <opencv2/opencv.hpp>
#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include<iostream>
#include <opencv2\imgproc\types_c.h>
using namespace std;
using namespace cv;
Mat hsv;
Mat temp;
string colour;
//声明Choose函数。
void Choose();
//主函数
int main()
{
//输入想要的颜色
cout << "请输入颜色:" << endl;
cin >> colour;
//载入并显示图像
Mat src = imread("1.jpg");
imshow("原图", src);
//RGB转化为hsv图像,方便下一步提取指定颜色
cvtColor(src, hsv, CV_BGR2HSV); //直接转换
imshow("1", hsv);
//定义一个选择函数,一种颜色对应一个hsv范围
Choose();
imshow("2", temp);
//对得到的二值化图像进行边缘检测
Canny(temp, temp, 20, 80, 3, false);
imshow("3", temp);
//变量声明
std::vector<std::vector<Point>> contours;
std::vector<Vec4i> hierarchy;
//寻找轮廓
findContours(temp, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));
//计算轮廓矩
vector<Moments> mu(contours.size());
for (int i = 0; i < contours.size(); i++)
{
mu[i] = moments(contours[i], false);
}
//计算轮廓中心
vector<Point2f> mc(contours.size());
for (int i = 0; i < contours.size(); i++)
{
mc[i] = Point2d(mu[i].m10 / mu[i].m00, mu[i].m01 / mu[i].m00);
}
//绘制轮廓标定形心
Mat drawing = Mat::zeros(temp.size(), CV_8UC3);
for (int i = 0; i < contours.size(); i++)
{
Scalar color = Scalar(0, 0, 0);
//第一个变量用初始图像可以将轮廓绘制到原图上
drawContours(src, contours, i, color, 2, 8, hierarchy, 0, Point(0, 0));
//指的是标定形心
circle(src, mc[i], 1, Scalar(0, 0, 0), -1, 6, 0); //画中心圆
}
imshow("output", src);
waitKey(0);
return(0);
}
//选择函数
void Choose()
{
if (colour == "黄")
//inRange函数可以将指定颜色转化为白色,其他颜色转化为黑色
inRange(hsv, Scalar(26, 43, 46), Scalar(34, 255, 255), temp);
else if (colour == "红")
inRange(hsv, Scalar(156, 43, 46), Scalar(180, 255, 255), temp);
else if (colour == "绿")
inRange(hsv, Scalar(35, 43, 46), Scalar(77, 255, 255), temp);
else if (colour == "蓝")
inRange(hsv, Scalar(100, 43, 46), Scalar(124, 255, 255), temp);
else if (colour == "黑")
inRange(hsv, Scalar(0, 0, 0), Scalar(180, 255, 46), temp);
else if (colour == "紫")
inRange(hsv, Scalar(125, 43, 46), Scalar(155, 255, 255), temp);
else if (colour == "橙")
inRange(hsv, Scalar(11, 43, 46), Scalar(25, 255, 255), temp);
else
cout << "找不到颜色" << endl;
}