顏色矩原理及C++實現
1 顏色矩原理
顏色矩(color moments)是由Stricker和Orengo[1]所提出的一種非常簡單而有效的顏色特徵。這種方法的數學基礎在於影象中任何的顏色分佈均可以用它的矩來表示。此外,由於顏色分佈資訊主要集中在低階矩中,因此僅採用顏色的一階矩(mean)、二階矩(variance)和三階矩(skewness)就足以表達影象的顏色分佈。與顏色直方圖相比,該方法的另一個好處在於無需對特徵進行向量化。因此,影象的顏色矩一共只需要9個分量(3個顏色分量,每個分量上3個低階矩),與其他的顏色特徵相比是非常簡潔的。在實際應用中為避免低次矩較弱的分辨能力,顏色矩常和其它特徵結合使用,而且一般在使用其它特徵前起到過濾縮小範圍(narrow down)的作用。
三種顏色矩的數學定義:
其中,
- 一階矩表示第i個顏色通道上所有畫素的均值
- 二階矩表示第i 顏色通道上所有畫素的標準差
- 三階矩表示第i個通道上所有畫素的斜度(skewness)的三次方根。
影象的三個分量的前三階顏色矩組成一個9維顏色特徵向量。
2 顏色矩的C++實現
在網上找了很久也沒有找到公開的用C++實現的顏色矩程式碼,OpenCV裡面也沒有現成的函式可以呼叫。因為專案需要,只能參考公式和其他版本(Matlab、Python)的顏色矩實現程式碼自己用C++寫一個。但由於很久沒用OpenCV了,寫出來並調通還花了不少時間。本人水平有限,如有更好的C++實現程式碼希望交流學習。廢話不多說,下面是顏色矩的C++實現(軟體環境Windows10+VS2013+OpenCV2.4.9):
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
double calc3orderMom(Mat &channel) //計算三階矩
{
uchar *p;
double mom=0;
double m = mean(channel)[0]; //計算單通道影象的均值
int nRows = channel.rows;
int nCols = channel.cols;
if (channel.isContinuous()) //連續儲存有助於提升影象掃描速度
{
nCols *= nRows;
nRows = 1;
}
for (int i = 0; i < nRows; i++) //計算立方和
{
p = channel.ptr<uchar>(i);
for (int j = 0; j < nCols; j++)
mom += pow((p[j] - m) ,3);
}
float temp;
temp = cvCbrt((float)(mom / (nRows*nCols))); //求均值的立方根
mom = (double)temp;
return mom;
}
//計算9個顏色矩:3個通道的1、2、3階矩
double *colorMom(Mat &img)
{
double *Mom = new double[9]; //存放9個顏色矩
Mat hsvimg;
if (img.channels() != 3)
cout << "Error,input image must be a color image" << endl;
Mat r(img.rows, img.cols, CV_8U);
Mat g(img.rows, img.cols, CV_8U);
Mat b(img.rows, img.cols, CV_8U);
Mat channels[] = { b, g, r };
split(img, channels);
Mat tmp_m, tmp_sd;
//計算b通道的顏色矩
meanStdDev(b, tmp_m, tmp_sd);
Mom[0] = tmp_m.at<double>(0, 0);
Mom[3] = tmp_sd.at<double>(0, 0);
Mom[6] = calc3orderMom(b);
// cout << Mom[0] << " " << Mom[1] << " " << Mom[2] << " " << endl;
//計算g通道的顏色矩
meanStdDev(g, tmp_m, tmp_sd);
Mom[1] = tmp_m.at<double>(0, 0);
Mom[4] = tmp_sd.at<double>(0, 0);
Mom[7] = calc3orderMom(g);
// cout << Mom[3] << " " << Mom[4] << " " << Mom[5] << " " << endl;
//計算r通道的顏色矩
meanStdDev(r, tmp_m, tmp_sd);
Mom[2] = tmp_m.at<double>(0, 0);
Mom[5] = tmp_sd.at<double>(0, 0);
Mom[8] = calc3orderMom(r);
// cout << Mom[6] << " " << Mom[7] << " " << Mom[8] << " " << endl;
return Mom;//返回顏色矩陣列
}
//測試程式碼
int main()
{
Mat src = imread("purple.jpg");
if (src.data == NULL)
cout << "image load failed!";
double *Mom ;
Mom = colorMom(src);
cout << "Color moments:";
for (int i = 0; i < 9; i++)//輸出顏色矩
cout << Mom[i] << " ";
cout << endl;
waitKey();
}
執行結果:
參考文獻
1.stricker M ,Orengo M.similarity of col0rimages[J].Proc.SPIE St0rage and Retrieval f0r Image and Video Dtabases,1995,242O:381—392
2. 顏色特徵提取(二)——顏色矩
3. 顏色矩原理及Python實現