思路
由于每种颜色都有一个阈值,单纯的计算RGB百分比的效果并不好,对于这点,网上已经有很多结论。于是,我想到采用hsv空间下每个像素点分量,获取某种颜色所占百分比(我这里采用的是蓝色)。因为,在hsv空间下,相近颜色都会被归于一个范围。所以,我们可以比较相近颜色,在图片中,所占百分比。C++与C#代码有些许不同。具体如下:
代码
C++
#include <iostream>
#include <opencv2/opencv.hpp>
#include <iomanip>
#include <cmath>
#include <string>
#include <opencv2/highgui/highgui_c.h>
#include <unordered_map>
#include <vector>
using namespace std;
using namespace cv;
//struct Triple
//{
// char col[_MAX_PATH];
// int h_min;
// int s_min;
// int v_min;
// int h_max;
// int s_max;
// int v_max;
//};
/*
区分不同颜色,在图片中所占百分比
*/
unordered_map<string,float> hsv_percentage(Mat hsv_image) {
int num_black = 0;
int num_grey = 0;
int num_white = 0;
int num_red = 0;
int num_orange = 0;
int num_yellow = 0;
int num_green = 0;
int num_blue = 0;
int num_purple = 0;
//vector<float> record(9,0);
unordered_map<string, float> record;
float area = (float)(hsv_image.rows * hsv_image.cols);
for (int i = 0; i < hsv_image.rows; i++) //行数
{
for (int j = 0; j < hsv_image.cols; j++) //列数
{
//在这里操作具体元素
//{"black", 0, 0, 0, 180, 255, 46}
if ((hsv_image.at<Vec3b>(i, j)[0] >= 0 && hsv_image.at<Vec3b>(i, j)[0] <= 180)
&& (hsv_image.at<Vec3b>(i, j)[1] >= 0 && hsv_image.at<Vec3b>(i, j)[1] <= 255)
&& (hsv_image.at<Vec3b>(i, j)[2] >= 0 && hsv_image.at<Vec3b>(i, j)[2] <= 46)) {
num_black++;
}
//{ "grey",0,0,46,180,43,220 }
else if ((hsv_image.at<Vec3b>(i, j)[0] >= 0 && hsv_image.at<Vec3b>(i, j)[0] <= 180)
&& (hsv_image.at<Vec3b>(i, j)[1] >= 0 && hsv_image.at<Vec3b>(i, j)[1] <= 43)
&& (hsv_image.at<Vec3b>(i, j)[2] >= 46 && hsv_image.at<Vec3b>(i, j)[2] <= 220)) {
num_grey++;
}
// { "white",0,0,221,180,30,255 }
else if ((hsv_image.at<Vec3b>(i, j)[0] >= 0 && hsv_image.at<Vec3b>(i, j)[0] <= 180)
&& (hsv_image.at<Vec3b>(i, j)[1] >= 0 && hsv_image.at<Vec3b>(i, j)[1] <= 30)
&& (hsv_image.at<Vec3b>(i, j)[2] >= 221 && hsv_image.at<Vec3b>(i, j)[2] <= 255)) {
num_white++;
}
//{ "red", 156, 43, 46, 180, 255, 255 }
else if ((hsv_image.at<Vec3b>(i, j)[0] >= 156 && hsv_image.at<Vec3b>(i, j)[0] <= 180)
&& (hsv_image.at<Vec3b>(i, j)[1] >= 43 && hsv_image.at<Vec3b>(i, j)[1] <= 255)
&& (hsv_image.at<Vec3b>(i, j)[2] >= 46 && hsv_image.at<Vec3b>(i, j)[2] <= 255)) {
num_red++;
}
else if ((hsv_image.at<Vec3b>(i, j)[0] >= 0&& hsv_image.at<Vec3b>(i, j)[0] <= 10)
&& (hsv_image.at<Vec3b>(i, j)[1] >= 43 && hsv_image.at<Vec3b>(i, j)[1] <= 255)
&& (hsv_image.at<Vec3b>(i, j)[2] >= 46 && hsv_image.at<Vec3b>(i, j)[2] <= 255)) {
num_red++;
}
//{ "orange",11,43,46,25,255,255 }
else if ((hsv_image.at<Vec3b>(i, j)[0] >= 11 && hsv_image.at<Vec3b>(i, j)[0] <= 25)
&& (hsv_image.at<Vec3b>(i, j)[1] >= 43 && hsv_image.at<Vec3b>(i, j)[1] <= 255)
&& (hsv_image.at<Vec3b>(i, j)[2] >= 46 && hsv_image.at<Vec3b>(i, j)[2] <= 255)) {
num_orange++;
}
// { "yellow", 26, 43, 46, 34, 255, 255 }
else if ((hsv_image.at<Vec3b>(i, j)[0] >= 26 && hsv_image.at<Vec3b>(i, j)[0] <= 34)
&& (hsv_image.at<Vec3b>(i, j)[1] >= 43 && hsv_image.at<Vec3b>(i, j)[1] <= 255)
&& (hsv_image.at<Vec3b>(i, j)[2] >= 46 && hsv_image.at<Vec3b>(i, j)[2] <= 255)) {
num_yellow++;
}
//{ "green",35,43,46,99,255,255 },
else if ((hsv_image.at<Vec3b>(i, j)[0] >= 35 && hsv_image.at<Vec3b>(i, j)[0] <= 99)
&& (hsv_image.at<Vec3b>(i, j)[1] >= 43 && hsv_image.at<Vec3b>(i, j)[1] <= 255)
&& (hsv_image.at<Vec3b>(i, j)[2] >= 46 && hsv_image.at<Vec3b>(i, j)[2] <= 255)) {
num_green++;
}
//{ "blue",100,43,46,124,255,255 },
else if ((hsv_image.at<Vec3b>(i, j)[0] >= 100 && hsv_image.at<Vec3b>(i, j)[0] <= 124)
&& (hsv_image.at<Vec3b>(i, j)[1] >= 43 && hsv_image.at<Vec3b>(i, j)[1] <= 255)
&& (hsv_image.at<Vec3b>(i, j)[2] >= 46 && hsv_image.at<Vec3b>(i, j)[2] <= 255)) {
num_blue++;
}
// { "purple",125,43,46,155,255,255 }
else if ((hsv_image.at<Vec3b>(i, j)[0] >= 125 && hsv_image.at<Vec3b>(i, j)[0] <= 155)
&& (hsv_image.at<Vec3b>(i, j)[1] >= 43 && hsv_image.at<Vec3b>(i, j)[1] <= 255)
&& (hsv_image.at<Vec3b>(i, j)[2] >= 46 && hsv_image.at<Vec3b>(i, j)[2] <= 255)) {
num_purple++;
}
}
}
record.insert(make_pair("black", (float)num_black / area));
record.insert(make_pair("grey", (float)num_grey / area));
record.insert(make_pair("white", (float)num_white / area));
record.insert(make_pair("red", (float)num_red / area));
record.insert(make_pair("orange", (float)num_orange / area));
record.insert(make_pair("yellow", (float)num_yellow / area));
record.insert(make_pair("green", (float)num_green / area));
record.insert(make_pair("blue", (float)num_blue / area));
record.insert(make_pair("purple", (float)num_purple / area));
//(float)num / (float)(hsv_image.rows * hsv_image.cols);
return record;
}
/*
在图片里查找指定颜色的比例
*/
void Mat_color_Find(string qimage)
{
Mat image = imread(qimage);//将图片加载进来
if (image.empty())
{
cout << "could not load image...\n" << endl;
return;
}
Mat hsv_image;
cvtColor(image, hsv_image, CV_BGR2HSV);
unordered_map<string, float> temp = hsv_percentage(hsv_image);
//rat = (float)num / (float)(hsv_image.rows * hsv_image.cols);
for (auto it = temp.begin(); it != temp.end();it++) {
cout << it->first << " " <<it->second << endl;
}
return;
}
int main(){
/*struct Triple colour[9] =
{
{"black",0,0,0,180,255,46},
{"grey",0,0,46,180,43,220},
{"white",0,0,221,180,30,255},
{"red",156,43,46,180,255,255},
{"orange",11,43,46,25,255,255},
{"yellow",26,43,46,34,255,255},
{"green",35,43,46,99,255,255},
{"blue",100,43,46,124,255,255},
{"purple",125,43,46,155,255,255}
};*/
string s = "C:/Users/wenhaofu/Desktop/picture/2021-07-01.png";
Mat_color_Find(s);
//cout << blue_temp << endl;
}
C#
public void Checkcolourgreaterthan(string colour, float percentage,string path)
{
Mat mat = new Mat(path, ImreadModes.AnyColor);
Mat imgHSV = new Mat();
Dictionary<string, float> temp = new Dictionary<string, float>();
Cv2.CvtColor(mat, imgHSV, ColorConversionCodes.BGR2HSV);
temp = Hsv_percentage(imgHSV);
foreach (var item in temp)
{
Console.WriteLine($"key={item.Key},value={item.Value}");
if (item.Key == colour) {
Assert.IsTrue(item.Value>=percentage, item.Value+" < "+ percentage);
}
}
}
private static Dictionary<string, float> Hsv_percentage(Mat hsv_image)
{
int num_black = 0;
int num_grey = 0;
int num_white = 0;
int num_red = 0;
int num_orange = 0;
int num_yellow = 0;
int num_green = 0;
int num_blue = 0;
int num_purple = 0;
//vector<float> record(9,0);
Dictionary<string, float> record = new Dictionary<string, float>();
float area = (float)(hsv_image.Rows * hsv_image.Cols);
Console.WriteLine("area: " + area);
for (int i = 0; i < hsv_image.Rows; i++) //行数
{
for (int j = 0; j < hsv_image.Cols; j++) //列数
{
//在这里操作具体元素
//{"black", 0, 0, 0, 180, 255, 46}
if ((hsv_image.Get<Vec3b>(i, j).Item0 >= 0 && hsv_image.Get<Vec3b>(i, j).Item0 <= 180)
&& (hsv_image.Get<Vec3b>(i, j).Item1 >= 0 && hsv_image.Get<Vec3b>(i, j).Item1 <= 255)
&& (hsv_image.Get<Vec3b>(i, j).Item2 >= 0 && hsv_image.Get<Vec3b>(i, j).Item2 <= 46))
{
num_black++;
}
//{ "grey",0,0,46,180,43,220 }
else if ((hsv_image.Get<Vec3b>(i, j).Item0 >= 0 && hsv_image.Get<Vec3b>(i, j).Item0 <= 180)
&& (hsv_image.Get<Vec3b>(i, j).Item1 >= 0 && hsv_image.Get<Vec3b>(i, j).Item1 <= 43)
&& (hsv_image.Get<Vec3b>(i, j).Item2 >= 46 && hsv_image.Get<Vec3b>(i, j).Item2 <= 220))
{
num_grey++;
}
// { "white",0,0,221,180,30,255 }
else if ((hsv_image.Get<Vec3b>(i, j).Item0 >= 0 && hsv_image.Get<Vec3b>(i, j).Item0 <= 180)
&& (hsv_image.Get<Vec3b>(i, j).Item1 >= 0 && hsv_image.Get<Vec3b>(i, j).Item1 <= 30)
&& (hsv_image.Get<Vec3b>(i, j).Item2 >= 221 && hsv_image.Get<Vec3b>(i, j).Item2 <= 255))
{
num_white++;
}
//{ "red", 156, 43, 46, 180, 255, 255 }
else if ((hsv_image.Get<Vec3b>(i, j).Item0 >= 156 && hsv_image.Get<Vec3b>(i, j).Item0 <= 180)
&& (hsv_image.Get<Vec3b>(i, j).Item1 >= 43 && hsv_image.Get<Vec3b>(i, j).Item1 <= 255)
&& (hsv_image.Get<Vec3b>(i, j).Item2 >= 46 && hsv_image.Get<Vec3b>(i, j).Item2 <= 255))
{
num_red++;
}
else if ((hsv_image.Get<Vec3b>(i, j).Item0 >= 0 && hsv_image.Get<Vec3b>(i, j).Item0 <= 10)
&& (hsv_image.Get<Vec3b>(i, j).Item1 >= 43 && hsv_image.Get<Vec3b>(i, j).Item1 <= 255)
&& (hsv_image.Get<Vec3b>(i, j).Item2 >= 46 && hsv_image.Get<Vec3b>(i, j).Item2 <= 255))
{
num_red++;
}
//{ "orange",11,43,46,25,255,255 }
else if ((hsv_image.Get<Vec3b>(i, j).Item0 >= 11 && hsv_image.Get<Vec3b>(i, j).Item0 <= 25)
&& (hsv_image.Get<Vec3b>(i, j).Item1 >= 43 && hsv_image.Get<Vec3b>(i, j).Item1 <= 255)
&& (hsv_image.Get<Vec3b>(i, j).Item2 >= 46 && hsv_image.Get<Vec3b>(i, j).Item2 <= 255))
{
num_orange++;
}
// { "yellow", 26, 43, 46, 34, 255, 255 }
else if ((hsv_image.Get<Vec3b>(i, j).Item0 >= 26 && hsv_image.Get<Vec3b>(i, j).Item0 <= 34)
&& (hsv_image.Get<Vec3b>(i, j).Item1 >= 43 && hsv_image.Get<Vec3b>(i, j).Item1 <= 255)
&& (hsv_image.Get<Vec3b>(i, j).Item2 >= 46 && hsv_image.Get<Vec3b>(i, j).Item2 <= 255))
{
num_yellow++;
}
//{ "green",35,43,46,99,255,255 },
else if ((hsv_image.Get<Vec3b>(i, j).Item0 >= 35 && hsv_image.Get<Vec3b>(i, j).Item0 <= 99)
&& (hsv_image.Get<Vec3b>(i, j).Item1 >= 43 && hsv_image.Get<Vec3b>(i, j).Item1 <= 255)
&& (hsv_image.Get<Vec3b>(i, j).Item2 >= 46 && hsv_image.Get<Vec3b>(i, j).Item2 <= 255))
{
num_green++;
}
//{ "blue",100,43,46,124,255,255 },
else if ((hsv_image.Get<Vec3b>(i, j).Item0 >= 100 && hsv_image.Get<Vec3b>(i, j).Item0 <= 124)
&& (hsv_image.Get<Vec3b>(i, j).Item1 >= 43 && hsv_image.Get<Vec3b>(i, j).Item1 <= 255)
&& (hsv_image.Get<Vec3b>(i, j).Item2 >= 46 && hsv_image.Get<Vec3b>(i, j).Item2 <= 255))
{
num_blue++;
}
// { "purple",125,43,46,155,255,255 }
else if ((hsv_image.Get<Vec3b>(i, j).Item0 >= 125 && hsv_image.Get<Vec3b>(i, j).Item0 <= 155)
&& (hsv_image.Get<Vec3b>(i, j).Item1 >= 43 && hsv_image.Get<Vec3b>(i, j).Item1 <= 255)
&& (hsv_image.Get<Vec3b>(i, j).Item2 >= 46 && hsv_image.Get<Vec3b>(i, j).Item2 <= 255))
{
num_purple++;
}
}
}
//Console.WriteLine("num_blue: " + num_blue);
record.Add("black", (float)num_black / area);
record.Add("grey", (float)num_grey / area);
record.Add("white", (float)num_white / area);
record.Add("red", (float)num_red / area);
record.Add("orange", (float)num_orange / area);
record.Add("yellow", (float)num_yellow / area);
record.Add("green", (float)num_green / area);
record.Add("blue", (float)num_blue / area);
record.Add("purple", (float)num_purple / area);
//(float)num / (float)(hsv_image.rows * hsv_image.cols);
return record;
}
运行结果
测试图片
获取其中各种颜色所占百分比