1.算法原理
(1)RGB颜色模型
我们通过在镜头前放置红(R),绿(G),蓝(B)三种颜色的滤光镜,得到R、G、B的三颜色通道。将三种滤光镜所生成的图像的灰度值以三基色原理组合在一起表示目标图像颜色的方式,就是我们最常见到的RGB颜色模型。
(2)模式分类——最近中心分类
对于图像上的每一个像素,我们都可以用一个含有R、G、B三色分量的三维向量表示。即:V(R,G,B)。
图像中的每一个物体区域都对应于向量空间(颜色空间)中的一个聚类(聚焦在一起的一些点)。对于图像中某一未知点,我们需要将其进行分类,即该点属于图像上哪一个物体区域问题。
对向量进行分类的一种办法是:测量该向量到每一个区域的表示向量距离。那么我们如何用向量表示每一个区域?我们使用每一个聚类的中心来表示该物体区域( 最近中心分类),这样大大节约了计算量和存储空间。
(3)“鸡生蛋,蛋生鸡”问题
在很多情况下,只有在提取出关于被成像物体的大量信息后,可靠的分割才是有可能实现的。不幸的是,提取出这些信息方法通常“暗含”一个假设条件,即:图像已经被分割好了(摘录于《机器视觉》一书)。
2.算法流程
算法说明:在分割前并不知道该分割的图像的物体颜色,所以只是粗略的将空间分为简单的八种颜色,给他们提供一种思路。以下是流程:
(1)初始化颜色空间:将颜色空间分为八个区域,分别是黑,蓝,绿,青,红,洋红,黄,白。
(2)计算图像上每一点到八个区域的距离,将该点的像素设为距离最短的区域颜色。
3.算法代码实现
#include<opencv2\core\core.hpp>
#include<opencv2\highgui\highgui.hpp>
#include<iostream>
#include<math.h>
using namespace std;
using namespace cv;
//全局变量
Vec3b *g_ColorVectorSpace; //颜色空间向量
//函数声明
void color_CNN(Mat srcImage, Mat &drawImage); //基于颜色空间的最近中心模式分类法(Center Nearest Neighbor, CNN)
int Calculation_CNN(Vec3b src, Vec3b vectorSpace); //计算距离并返回最小距离的空间向量坐标
void InitColorVectorSpace(); //初始化颜色空间向量
int main()
{
Mat srcImage = imread("H:/opencv/image/6.jpg");
Mat drawImage(srcImage.size(), CV_8UC3, Scalar(255, 255, 255));
color_CNN(srcImage, drawImage);
imshow("原始图", srcImage);
imshow("效果图", drawImage);
waitKey(0);
return 0;
}
void InitColorVectorSpace()
{
g_ColorVectorSpace = new Vec3b[8];
//BGR模型(不是RGB)
g_ColorVectorSpace[0] = Vec3b(0, 0, 0); //黑色
g_ColorVectorSpace[1] = Vec3b(255, 0, 0); //蓝色
g_ColorVectorSpace[2] = Vec3b(0, 255, 0); //绿色
g_ColorVectorSpace[3] = Vec3b(255, 255, 0); //青色
g_ColorVectorSpace[4] = Vec3b(0, 0, 255); //红色
g_ColorVectorSpace[5] = Vec3b(255, 0, 255); //洋红色
g_ColorVectorSpace[6] = Vec3b(0, 255, 255); //黄色
g_ColorVectorSpace[7] = Vec3b(255, 255, 255); //白色
}
void color_CNN(Mat srcImage, Mat &drawImage)
{
//初始化颜色空间
InitColorVectorSpace();
//访问图像像素
int nearestPosition = 0;
for(int y = 0; y < srcImage.rows; y++)
{
for(int x = 0; x < srcImage.cols; x++)
{
nearestPosition = Calculation_CNN(srcImage.at<Vec3b>(y,x), g_ColorVectorSpace);
drawImage.at<Vec3b>(y,x) = g_ColorVectorSpace[nearestPosition];
}
}
}
int Calculation_CNN(Vec3b src, Vec3b *vectorSpace)
{
int nearestPosition = 0;
double distance;
distance = sqrt(pow(double(src[0]-vectorSpace[0][0]),2)+pow(double(src[1]-vectorSpace[0][1]),2)+pow(double(src[2]-vectorSpace[0][2]),2));
for(int i = 1; i < 8; i++)
{
if(distance > sqrt(pow(double(src[0]-vectorSpace[i][0]),2)+pow(double(src[1]-vectorSpace[i][1]),2)+pow(double(src[2]-vectorSpace[i][2]),2)))
{
distance = sqrtl(pow(double(src[0]-vectorSpace[i][0]),2)+pow(double(src[1]-vectorSpace[i][1]),2)+pow(double(src[2]-vectorSpace[i][2]),2));
nearestPosition = i;
}
}
return nearestPosition;
}
4. 实验结果
5.一些想法
有些人会问为什么不使用HSV模型进行颜色分割,还容易不受光照影响?
首先我做这个主要是验证心里的一些想法,其次我觉得毕竟是从三维转化为一维进行分割,在光照条件比较理想的条件下我觉得还是RGB的好,虽然我没做过实验呀,有研究兴趣的同学可以实现一下。感谢您的阅读,希望可以对您的开发起到一些小小的作用。
注:本文的算法思路是参考《机器视觉》一书的第五章 区域与图像分割,第十四章 模式分类