图像的局部特征研究--Hu不变矩
2016-03-25 00:00
239 查看
研究问题:最近需要对九宫格里面的九幅图像做出识别,判断哪一个格子里面的图片才是最特殊的,而其他图片是相似的,即其他八个格子里的图可以看作是一图作旋转,增添,缩放,镜像等操作,就像下面这样:
图1.右下角的小人是要找的目标图像,其他的小车可看作有其中一幅旋转平移等操作得到
我的思路是先对这个图片进行分割,分割成9幅小图,再对每一幅图片求特征表示及描述,根据这些图的特点,选择了一个比较简单的衡量图像特征的区域描述子--Hu矩。
在黎曼积分意义下,将二维(p+q)阶矩定义为:
(1)
可以看作是一个密度分布函数,在这里我们研究的对象是一幅图,其分布函数区间为
[
0, 255]。
相应的(p+q)阶中心矩则定义如下:
(2)
其中
(3)
将积分符号换成求和符号会比较助于理解,但是为了保持证明的完整性,仍然保留积分符号考虑整个实数域。
①中心距对于
的平移具有不变性:
假如新的坐标
为:
,其中α,β是常数
(4)
易知
和
的中心距是相同的。
②矩对于缩放具有不变性:
,α是个常数 (5)
可以看作是(x,
y)分别乘于系数α得到,对于每一个α系数由公式(2),有:
(6)
因为α是个常数,那么变换前后的中心距有这样的关系:
(7)
最后可以得到:
(8)
这也可以称为相似矩不变性。
③矩对于旋转具有不变性:
(9)
旋转矩阵的模为1。
(10)
将(9)和(10)跟公式(2)结合,也可以得到
和
的关系,这可以称为正交不变性。
上述这些只是数学上的简单说明,论证的是图像矩的不变性,对于实际的应用,更常用的是用二阶矩和三阶矩构造出的7个不变矩组:
首先,对中心矩进行归一化:
, 其中
,p+q
= 2,3......。 (11)
那么,存在7个不变矩组为:
(12)
这些矩组对于平移、尺度变化、镜像(内部为负号)和旋转是不变的。
为了解决一开始提出的问题,就简单地写了一个程序:
完整的程序如下:
总结:Hu不变矩是一个比较简单而且有效的特征描述子,需要注意的是,要计算的图片最好是处理过的边缘图或者轮廓图,这能提高鲁棒性,但是,相比其他匹配算法如SURF来说,Hu矩的局限也很大,它受图片的质量影响比较大,可以说,Hu矩作为特征描述子的用途比较大,但是其他地方不考虑直接用这一算法。
图1.右下角的小人是要找的目标图像,其他的小车可看作有其中一幅旋转平移等操作得到
我的思路是先对这个图片进行分割,分割成9幅小图,再对每一幅图片求特征表示及描述,根据这些图的特点,选择了一个比较简单的衡量图像特征的区域描述子--Hu矩。
下面详细叙述Hu矩的不变性:
在黎曼积分意义下,将二维(p+q)阶矩定义为:(1)
可以看作是一个密度分布函数,在这里我们研究的对象是一幅图,其分布函数区间为
[
0, 255]。
相应的(p+q)阶中心矩则定义如下:
(2)
其中
(3)
将积分符号换成求和符号会比较助于理解,但是为了保持证明的完整性,仍然保留积分符号考虑整个实数域。
①中心距对于
的平移具有不变性:
假如新的坐标
为:
,其中α,β是常数
(4)
易知
和
的中心距是相同的。
②矩对于缩放具有不变性:
,α是个常数 (5)
可以看作是(x,
y)分别乘于系数α得到,对于每一个α系数由公式(2),有:
(6)
因为α是个常数,那么变换前后的中心距有这样的关系:
(7)
最后可以得到:
(8)
这也可以称为相似矩不变性。
③矩对于旋转具有不变性:
(9)
旋转矩阵的模为1。
(10)
将(9)和(10)跟公式(2)结合,也可以得到
和
的关系,这可以称为正交不变性。
上述这些只是数学上的简单说明,论证的是图像矩的不变性,对于实际的应用,更常用的是用二阶矩和三阶矩构造出的7个不变矩组:
首先,对中心矩进行归一化:
, 其中
,p+q
= 2,3......。 (11)
那么,存在7个不变矩组为:
(12)
这些矩组对于平移、尺度变化、镜像(内部为负号)和旋转是不变的。
为了解决一开始提出的问题,就简单地写了一个程序:
<pre name="code" class="cpp">void calcHu(Mat image) { int bmpWidth = image.cols; int bmpHeight = image.rows; int bmpStep = image.step; int bmpChannels = image.channels(); uchar* pBmpBuf = image.data; double m00=0,m11=0,m20=0,m02=0,m30=0,m03=0,m12=0,m21=0; //中心矩 double x0=0,y0=0; //计算中心距时所使用的临时变量(x-x') double u20=0,u02=0,u11=0,u30=0,u03=0,u12=0,u21=0; //规范化后的中心矩 double t1=0,t2=0,t3=0,t4=0,t5=0;//临时变量 int Center_x=0,Center_y=0;//重心 int i,j; //循环变量 // 获得图像的区域重心(普通矩) double s10=0,s01=0,s00=0; //0阶矩和1阶矩 for(j=0;j<bmpHeight;j++)//y { for(i=0;i<bmpWidth;i++)//x { s10+=i*pBmpBuf[j*bmpStep+i]; s01+=j*pBmpBuf[j*bmpStep+i]; s00+=pBmpBuf[j*bmpStep+i]; } } Center_x=(int)(s10/s00+0.5); Center_y=(int)(s01/s00+0.5); // 计算二阶、三阶矩(中心矩) m00=s00; for(j=0;j<bmpHeight;j++) { for(i=0;i<bmpWidth;i++)//x { x0=(i-Center_x); y0=(j-Center_y); m11+=x0*y0*pBmpBuf[j*bmpStep+i]; m20+=x0*x0*pBmpBuf[j*bmpStep+i]; m02+=y0*y0*pBmpBuf[j*bmpStep+i]; m03+=y0*y0*y0*pBmpBuf[j*bmpStep+i]; m30+=x0*x0*x0*pBmpBuf[j*bmpStep+i]; m12+=x0*y0*y0*pBmpBuf[j*bmpStep+i]; m21+=x0*x0*y0*pBmpBuf[j*bmpStep+i]; } } // 计算规范化后的中心矩: mij/pow(m00,((i+j+2)/2) u20=m20/pow(m00,2); u02=m02/pow(m00,2); u11=m11/pow(m00,2); u30=m30/pow(m00,2.5); u03=m03/pow(m00,2.5); u12=m12/pow(m00,2.5); u21=m21/pow(m00,2.5); // 计算中间变量 t1=(u20-u02); t2=(u30-3*u12); t3=(3*u21-u03); t4=(u30+u12); t5=(u21+u03); // 计算不变矩 M[0]=u20+u02; M[1]=t1*t1+4*u11*u11; M[2]=t2*t2+t3*t3; M[3]=t4*t4+t5*t5; M[4]=t2*t4*(t4*t4-3*t5*t5)+t3*t5*(3*t4*t4-t5*t5); M[5]=t1*(t4*t4-t5*t5)+4*u11*t4*t5; M[6]=t3*t4*(t4*t4-3*t5*t5)-t2*t5*(3*t4*t4-t5*t5); }
完整的程序如下:
#include <opencv2/opencv.hpp> #include <ctime> using namespace std; using namespace cv; double M[7] = {0}; vector<Mat> cutImage(Mat image) { vector<Mat> roi; int rwidth = image.cols/3; int rheight = image.rows/3; for (int y = 0;y < image.rows-10;y +=rheight) { for (int x = 0;x < image.cols-10;x += rwidth) { Rect rect(x, y, rwidth, rheight); rect &= Rect(0, 0, image.cols, image.rows);; roi.push_back(image(rect)); } } return roi; } void calcHu(Mat image) { int bmpWidth = image.cols; int bmpHeight = image.rows; int bmpStep = image.step; int bmpChannels = image.channels(); uchar* pBmpBuf = image.data; double m00=0,m11=0,m20=0,m02=0,m30=0,m03=0,m12=0,m21=0; //中心矩 double x0=0,y0=0; //计算中心距时所使用的临时变量(x-x') double u20=0,u02=0,u11=0,u30=0,u03=0,u12=0,u21=0; //规范化后的中心矩 double t1=0,t2=0,t3=0,t4=0,t5=0;//临时变量 int Center_x=0,Center_y=0;//重心 int i,j; //循环变量 // 获得图像的区域重心(普通矩) double s10=0,s01=0,s00=0; //0阶矩和1阶矩 for(j=0;j<bmpHeight;j++)//y { for(i=0;i<bmpWidth;i++)//x { s10+=i*pBmpBuf[j*bmpStep+i]; s01+=j*pBmpBuf[j*bmpStep+i]; s00+=pBmpBuf[j*bmpStep+i]; } } Center_x=(int)(s10/s00+0.5); Center_y=(int)(s01/s00+0.5); // 计算二阶、三阶矩(中心矩) m00=s00; for(j=0;j<bmpHeight;j++) { for(i=0;i<bmpWidth;i++)//x { x0=(i-Center_x); y0=(j-Center_y); m11+=x0*y0*pBmpBuf[j*bmpStep+i]; m20+=x0*x0*pBmpBuf[j*bmpStep+i]; m02+=y0*y0*pBmpBuf[j*bmpStep+i]; m03+=y0*y0*y0*pBmpBuf[j*bmpStep+i]; m30+=x0*x0*x0*pBmpBuf[j*bmpStep+i]; m12+=x0*y0*y0*pBmpBuf[j*bmpStep+i]; m21+=x0*x0*y0*pBmpBuf[j*bmpStep+i]; } } // 计算规范化后的中心矩: mij/pow(m00,((i+j+2)/2) u20=m20/pow(m00,2); u02=m02/pow(m00,2); u11=m11/pow(m00,2); u30=m30/pow(m00,2.5); u03=m03/pow(m00,2.5); u12=m12/pow(m00,2.5); u21=m21/pow(m00,2.5); // 计算中间变量 t1=(u20-u02); t2=(u30-3*u12); t3=(3*u21-u03); t4=(u30+u12); t5=(u21+u03); // 计算不变矩 M[0]=u20+u02; M[1]=t1*t1+4*u11*u11; M[2]=t2*t2+t3*t3; M[3]=t4*t4+t5*t5; M[4]=t2*t4*(t4*t4-3*t5*t5)+t3*t5*(3*t4*t4-t5*t5); M[5]=t1*(t4*t4-t5*t5)+4*u11*t4*t5; M[6]=t3*t4*(t4*t4-3*t5*t5)-t2*t5*(3*t4*t4-t5*t5); } int compareHu(double mo[9][7]) { int no = 0; double sum = 0, min = 100, max = 0; for (int i = 0;i<9;i++) { sum += mo[i][0]; if(mo[i][0]>max) max = mo[i][0]; if(mo[i][0]<min) min = mo[i][0]; } sum /= 9; if(sum - min > max - sum) max = min; for (int i = 0;i<9;i++) if (mo[i][0]==max){ no = i;break;} //cout<<max<<endl<<no<<endl; return no; } void drawCross(int n, Mat image) { int centerx = 0, centery = 0, widstep = 0, heistep = 0; widstep = image.cols/6; heistep = image.rows/6; centerx = n%3 * widstep * 2 + widstep; centery = n/3 * heistep * 2 + heistep; Scalar color(0, 0, 255); line(image, Point(centerx-20, centery), Point(centerx+20, centery), color, 2); line(image, Point(centerx, centery-10), Point(centerx, centery+10), color, 2); } int main() { Mat src, binary; vector <Mat> srcRoi; int count = 12; double moment[9][7] = {0}; while (--count) { char imageName[10]; sprintf_s(imageName, "%d.jpg", count); src = imread(imageName, 1); Canny(src, binary, 50, 100); srcRoi = cutImage(binary); for (int i = 0;i < 9;i++) { calcHu(srcRoi[i]); for (int j = 0;j<7;j++) moment[i][j] = M[j]; } int no = compareHu(moment); drawCross(no, src); imshow(imageName, src); waitKey(0); } return 0; }
总结:Hu不变矩是一个比较简单而且有效的特征描述子,需要注意的是,要计算的图片最好是处理过的边缘图或者轮廓图,这能提高鲁棒性,但是,相比其他匹配算法如SURF来说,Hu矩的局限也很大,它受图片的质量影响比较大,可以说,Hu矩作为特征描述子的用途比较大,但是其他地方不考虑直接用这一算法。
相关文章推荐
- 自动化安装
- 进程与线程。js是什么运行机制?node.js是什么运行机制?
- eclipse中导出Runnable JAR的问题
- Oracle语句记录
- ORACLE导出
- Navicat如何隐藏网格
- C语言 算法与数据结构 栈
- 百度地图---之---行政区域划分
- Android中如何判断APP是否联网
- C语言_基本数据类型范围、类型之间的转换规则、打印某个内存连续的内存值
- Codeforces 637D 模拟
- Nginx学习笔记——启动、停止
- DataMining(1)_Know Your Data
- Spring中@Transactional事务回滚
- 二叉查找树的数据结构以及实现(JAVA)
- java连接mysql插入数据出现中文乱码
- java爬取动态加载/js返回数据的网页的源代码
- 蜂窝iOS培训:这两个阶段你坚持下来了吗?
- HDU 1016 Prime Ring Problem(深度优先搜索)
- mysqladmin命令用法