图片识别方法之一:颜色分步法
每张图片都可以生成颜色分布的直方图(color histogram)。如果两张图片的直方图很接近,就可以认为它们很相似。
任何一种颜色都是由红绿蓝三原色(RGB)构成的,所以上图共有4张直方图(三原色直方图 + 最后合成的直方图)。
如果每种原色都可以取256个值,那么整个颜色空间共有1600万种颜色(256的三次方)。针对这1600万种颜色比较直方图,计算量实在太大了,因此需要采用简化方法。可以将0~255分成四个区:0~63为第0区,64~127为第1区,128~191为第2区,192~255为第3区。这意味着红绿蓝分别有4个区,总共可以构成64种组合(4的3次方)。
任何一种颜色必然属于这64种组合中的一种,这样就可以统计每一种组合包含的像素数量。
上图是某张图片的颜色分布表,将表中最后一栏提取出来,组成一个64维向量(7414, 230, 0, 0, 8, ..., 109, 0, 0, 3415, 53929)。这个向量就是这张图片的特征值或者叫"指纹"。
于是,寻找相似图片就变成了找出与其最相似的向量。这可以用皮尔逊相关系数或者余弦相似度算出。
皮尔逊相关系数回顾:
皮尔逊相关也称为积差相关(或积矩相关)是英国统计学家皮尔逊于20世纪提出的一种计算直线相关的方法。
假设有两个变量X、Y,那么两变量间的皮尔逊相关系数可通过以下公式计算:
公式一:
#include <cv.h>
#include <highgui.h>
#include <stdio.h>
#include <iostream>
#include <math.h>
using namespace std;
void histogram(IplImage* src, int color_histogram[], int N)
{
int index;
int width=src->width;
int height=src->height;
for (int w=0;w<width;w++)
{
for (int h=0;h<height;h++)
{
int Blue = ((uchar *)(src->imageData + h*src->widthStep))[w*src->nChannels +0];
int Green = ((uchar *)(src->imageData + h*src->widthStep))[w*src->nChannels +1];
int Red = ((uchar *)(src->imageData + h*src->widthStep))[w*src->nChannels +2];
index = (Blue/64)*16+(Green/64)*4+(Red/64)*1;
++color_histogram[index];
}
}
}
double math_coefficient(int a[], int b[], int N)
{
double Sum_xy = 0;
double Sum_x =0;
double Sum_y = 0;
double Sum_x2 = 0;
double Sum_y2 = 0;
for(int i=0; i<N; i++)
{
Sum_xy += a[i]*b[i];
Sum_x += a[i];
Sum_y += b[i];
Sum_x2 += a[i]*a[i];
Sum_y2 += b[i]*b[i];
}
return (Sum_xy*N-Sum_x*Sum_y)/sqrt((N*Sum_x2-pow(Sum_x,2))*(N*Sum_y2-pow(Sum_y,2)));
}
double image_coefficient(IplImage* src1, IplImage* src2)
{
int H1[64] = {0};
int H2[64] = {0};
histogram(src1, H1,64);
histogram(src2, H2,64);
return math_coefficient(H1,H2,64);
}
int main()
{
IplImage* src1 = cvLoadImage("D:\\opencv.JPG",1);
IplImage* src2 = cvLoadImage("D:\\opencv_meitu_1.jpg",1);
cout<<image_coefficient(src1,src2)<<endl;
getchar();
return 0;
}