效果展示:
思路是將圖片轉化爲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;
}