图像处理基本算法 形状特征

形状特征

(一)特点:各种基于形状特征的检索方法都可以比较有效地利用图像中感兴趣的目标来进行检索,但它们也有一些共同的问题,包括:①目前基于形状的检索方法还缺乏比较完善的数学模型;②如果目标有变形时检索结果往往不太可靠;③许多形状特征仅描述了目标局部的性质,要全面描述目标常对计算时间和存储量有较高的要求;④许多形状特征所反映的目标形状信息与人的直观感觉不完全一致,或者说,特征空间的相似性与人视觉系统感受到的相似性有差别。另外,从 2-D 图像中表现的 3-D 物体实际上只是物体在空间某一平面的投影,从 2-D 图像中反映出来的形状常不是 3-D 物体真实的形状,由于视点的变化,可能会产生各种失真。

(二)常用的特征提取与匹配方法

Ⅰ几种典型的形状特征描述方法

通常情况下,形状特征有两类表示方法,一类是轮廓特征,另一类是区域特征。图像的轮廓特征主要针对物体的外边界,而图像的区域特征则关系到整个形状区域。

几种典型的形状特征描述方法:

(1)边界特征法该方法通过对边界特征的描述来获取图像的形状参数。其中Hough 变换检测平行直线方法和边界方向直方图方法是经典方法。Hough 变换是利用图像全局特性而将边缘像素连接起来组成区域封闭边界的一种方法,其基本思想是点—线的对偶性;边界方向直方图法首先微分图像求得图像边缘,然后,做出关于边缘大小和方向的直方图,通常的方法是构造图像灰度梯度方向矩阵。

(2)傅里叶形状描述符法

傅里叶形状描述符(Fourier shape descriptors)基本思想是用物体边界的傅里叶变换作为形状描述,利用区域边界的封闭性和周期性,将二维问题转化为一维问题。

由边界点导出三种形状表达,分别是曲率函数、质心距离、复坐标函数。

(3)几何参数法

形状的表达和匹配采用更为简单的区域特征描述方法,例如采用有关形状定量测度(如矩、面积、周长等)的形状参数法(shape factor)。在 QBIC 系统中,便是利用圆度、偏心率、主轴方向和代数不变矩等几何参数,进行基于形状特征的图像检索。

需要说明的是,形状参数的提取,必须以图像处理及图像分割为前提,参数的准确性必然受到分割效果的影响,对分割效果很差的图像,形状参数甚至无法提取。

(4)形状不变矩法

利用目标所占区域的矩作为形状描述参数。

(5)其它方法

近年来,在形状的表示和匹配方面的工作还包括有限元法(Finite Element Method 或 FEM)、旋转函数(Turning Function)和小波描述符(Wavelet Descriptor)等方法。

实际上,只是提取物体的形状,这并不难,最难的是这些特征该怎么用!

特征嘛,自然是讲此物区分彼物的特点。

那么假如,给出了一系列不同形状物体的轮廓该如何识别出他们呢?正方形,圆形,矩形,椭圆,不规则图形,再进一步,这些图形由于受到信号的干扰,有噪声存在时,该如何去识别他们呢?

那就可以使用形状的特征了,我们定义一些参数,来描述这些形状。

1 矩形度:R = A0/A; A0为区域面积,A为区域最小外接矩形面积。

那么R = 1 时,为矩形的概率很大,R = PI/4时为圆的可能性最大

2 体态比 T = a/b;

a b 分别为区域最小外接矩形的长和宽。

T = 1 为正方形或者圆形,

T>1 为细长图形

3 球状性 S = Ri/Rc

Ri Rc分别为内切圆和外接圆半径,圆心都在中心上

4 球状性 C = Ur/Pr

Ur 为区域重心到轮廓点的平均距离

Pr 为区域重心到轮廓点的均方差

5 中心矩

这一特征,使用颇为频繁,OpenCV有专门的函数求解(p,q)次矩

6 长轴 短轴

最小外接矩形的长轴和短轴

7面积

一般会作为阈值使用,判定某个区域的面积在两个阈值之间才判定有效

下面给出各个形状特征的求法:

  1 //图像的形状特征分析
  2 #include <cv.h>
  3 #include <cxcore.h>
  4 #include <highgui.h>
  5 #include <iostream>
  6 using namespace std;
  7
  8 int main()
  9 {
 10     IplImage *src = cvLoadImage("E:\\image\\mapleleaf.tif",0);
 11     IplImage *image = cvCreateImage(cvGetSize(src),8,3);
 12     image = cvCloneImage(src);
 13     cvNamedWindow("src",1);
 14     cvNamedWindow("dst",1);
 15     cvShowImage("src",src);
 16
 17     CvMemStorage *storage = cvCreateMemStorage(0);
 18     CvSeq * seq = cvCreateSeq(CV_SEQ_ELTYPE_POINT, sizeof(CvSeq), sizeof(CvPoint), storage);
 19     CvSeq * tempSeq = cvCreateSeq(CV_SEQ_ELTYPE_POINT, sizeof(CvSeq), sizeof(CvPoint), storage);
 20     //新图,将轮廓绘制到dst
 21     IplImage *dst = cvCreateImage(cvGetSize(src),8,3);
 22     cvZero(dst);//赋值为0
 23     double length,area;
 24
 25     //获取轮廓
 26     int cnt = cvFindContours(src,storage,&seq);//返回轮廓的数目
 27     cout<<"number of contours   "<<cnt<<endl;
 28
 29     //计算边界序列的参数 长度 面积 矩形 最小矩形
 30     //并输出每个边界的参数
 31     CvRect rect;
 32     CvBox2D box;
 33     double axislong,axisShort;//长轴和短轴
 34     double temp1= 0.0,temp2 = 0.0;
 35     double Rectangle_degree;//矩形度
 36     double long2short;//体态比
 37     double x0,y0;
 38     long sumX  = 0 ,sumY = 0;
 39     double sum =0.0;
 40     int i,j,m,n;
 41     unsigned char* ptr;
 42
 43     double UR;//区域重心到轮廓的平均距离
 44     double PR;//区域重心到轮廓点的均方差
 45     CvPoint * contourPoint;
 46     int count = 0;
 47     double CDegree;//圆形性
 48
 49     CvPoint *A,*B,*C;
 50     double AB,BC,AC;
 51     double cosA,sinA;
 52     double tempR,inscribedR;
 53
 54     for (tempSeq = seq;tempSeq != NULL; tempSeq = tempSeq->h_next)
 55     {
 56         //tempSeq = seq->h_next;
 57         length = cvArcLength(tempSeq);
 58         area = cvContourArea(tempSeq);
 59         cout<<"Length = "<<length<<endl;
 60         cout<<"Area = "<<area<<endl;
 61         cout<<"num of point "<<tempSeq->total<<endl;
 62         //外接矩形
 63         rect = cvBoundingRect(tempSeq,1);
 64
 65
 66         //绘制轮廓和外接矩形
 67         cvDrawContours(dst,tempSeq,CV_RGB(255,0,0),CV_RGB(255,0,0),0);
 68         cvRectangleR(dst,rect,CV_RGB(0,255,0));
 69         cvShowImage("dst",dst);
 70         //cvWaitKey();
 71
 72         //绘制轮廓的最小外接圆
 73         CvPoint2D32f center;//亚像素精度 因此需要使用浮点数
 74         float radius;
 75         cvMinEnclosingCircle(tempSeq,¢er,&radius);
 76         cvCircle(dst,cvPointFrom32f(center),cvRound(radius),CV_RGB(100,100,100));
 77         cvShowImage("dst",dst);
 78         //cvWaitKey();
 79
 80         //寻找近似的拟合椭圆 可以使斜椭圆
 81         CvBox2D ellipse = cvFitEllipse2(tempSeq);
 82         cvEllipseBox(dst,ellipse,CV_RGB(255,255,0));
 83         cvShowImage("dst",dst);
 84         //cvWaitKey();
 85
 86
 87         //绘制外接最小矩形
 88         CvPoint2D32f pt[4];
 89         box = cvMinAreaRect2(tempSeq,0);
 90         cvBoxPoints(box,pt);
 91         for(int i = 0;i<4;++i){
 92             cvLine(dst,cvPointFrom32f(pt[i]),cvPointFrom32f(pt[((i+1)%4)?(i+1):0]),CV_RGB(0,0,255));
 93         }
 94         cvShowImage("dst",dst);
 95         //cvWaitKey();
 96
 97
 98         //下面开始分析图形的形状特征
 99         //长轴 短轴
100         temp1 = sqrt(pow(pt[1].x -pt[0].x,2) + pow(pt[1].y -pt[0].y,2));
101         temp2 = sqrt(pow(pt[2].x -pt[1].x,2) + pow(pt[2].y -pt[1].y,2));
102
103         if (temp1 > temp2)
104         {
105             axislong = temp1;
106             axisShort=temp2;
107         }
108         else
109         {
110             axislong = temp2;
111             axisShort=temp1;
112         }
113
114         cout<<"long axis: "<<axislong<<endl;
115         cout<<"short axis: "<<axisShort<<endl;
116         //矩形度 轮廓面积和最小外接矩形面积(可以是斜矩形)之比
117         Rectangle_degree = (double)area/(axisShort*axislong);
118
119         cout<<"Rectangle degree :"<<Rectangle_degree<<endl;
120         //体态比or长宽比 最下外接矩形的长轴和短轴的比值
121         long2short = axislong/axisShort;
122         cout<<"ratio of long axis to short axis: "<<long2short<<endl;
123         //球状性 由于轮廓的内切圆暂时无法求出先搁置
124         //先求内切圆半径 枚举任意轮廓上的三个点,半径最小的就是内切圆的半径
125         //以下的最大内切圆半径求法有误 待改进
126
127         /*
128         for (int i = 0 ; i< tempSeq->total -2;i++)
129         {
130             for (int j= i+1; j<tempSeq->total-1;j++)
131             {
132                 for (int m = j+1; m< tempSeq->total; m++)
133                 {
134                     //已知圆上三点,求半径
135                     A = (CvPoint*)cvGetSeqElem(tempSeq ,i);
136                     B = (CvPoint*)cvGetSeqElem(tempSeq ,j);
137                     C = (CvPoint*)cvGetSeqElem(tempSeq,m);
138                     AB = sqrt(pow((double)A->x - B->x,2)+ pow((double)A->y - B->y,2));
139                     AC =sqrt(pow((double)A->x - C->x,2) + pow((double)A->y - C->y,2));
140                     BC = sqrt(pow((double)B->x - C->x,2)+ pow((double)B->y - C->y,2));
141
142                     cosA = ((B->x - A->x)*(C->x - A->x) + (B->y - A->y)*(C->y - A->y))/(AB*AC);
143                     sinA = sqrt(1 - pow(cosA,2));
144                     tempR = BC/(2*sinA);
145
146                     if (m == 2)
147                     {
148                         inscribedR = tempR;
149                     }
150                     else
151                     {
152                         if (tempR < inscribedR)
153                         {
154                             inscribedR = tempR;
155                         }
156                     }
157
158
159                 }
160             }
161         }
162
163         //输出最大内切圆半径
164         cout<<"radius of max inscribed circle  "<<inscribedR<<endl;
165         */
166         //圆形性 假设轮廓内是实心的
167         //球区域中心x0 y0
168         sumX = 0;
169         sumY = 0;
170         src = cvCloneImage(image);
171         for (int i = 0 ; i< src->height;i++)
172         {
173             for (int j = 0; j< src->width;j++)
174             {
175                 ptr = (unsigned char *)src->imageData + i*src->widthStep + j;
176                 if ((*ptr) > 128)
177                 {
178                     sumX += (long)j;
179                     sumY += (long)i;
180                 }
181
182             }
183         }
184         x0 = sumX/area;
185         y0 = sumY/area;
186         cout<<"center of gravity "<<x0<<"   "<<y0<<endl;
187      //求区域到重心的平均距离
188         sum = 0;
189         count = 0;
190         for (m = 0 ; m< tempSeq->total;m++)
191         {
192             contourPoint = (CvPoint*)cvGetSeqElem(tempSeq,m);
193             sum += sqrt(pow(contourPoint->x - x0,2)+ pow(contourPoint->y - y0,2));
194             count++;
195         }
196         UR = sum/count;
197         cout<<"mean distance to center of gravity"<<UR<<endl;
198         //求区域重心到轮廓点的均方差
199         sum = 0;
200         for (m = 0 ; m< tempSeq->total;m++)
201         {
202             contourPoint = (CvPoint*)cvGetSeqElem(tempSeq,m);
203             temp1 = sqrt(pow(contourPoint->x - x0,2)+ pow(contourPoint->y - y0,2));
204             sum += pow(temp1 - UR,2);
205         }
206         PR = sum/count;
207         cout<<"mean square error of distance to center of gravity"<<PR<<endl;
208         //圆形性
209         CDegree= UR/PR;
210         cout<<"degree of circle "<<CDegree<<endl;
211         //中心距
212
213         cvWaitKey(0);
214     }
215
216
217     cvReleaseImage(&src);
218     cvReleaseImage(&dst);
219     cvReleaseMemStorage(&storage);
220
221     return 0;
222 }

时间: 2024-10-13 00:22:15

图像处理基本算法 形状特征的相关文章

图像处理-拉普拉斯算法

一.引言 图像锐化处理的作用是使灰度反差增强,从而使模糊图像变得更加清晰.图像模糊的实质就是图像受到平均运算或积分运算,因此可以对图像进行逆运算,如微分运算能够突出图像细节,使图像变得更为清晰.由于拉普拉斯是一种微分算子,它的应用可增强图像中灰度突变的区域,减弱灰度的缓慢变化区域. 二.卷积算法 2.1卷积原理 因此,锐化处理可选择拉普拉斯算子对原图像进行处理,产生描述灰度突变的图像,再将拉普拉斯图像与原始图像叠加而产生锐化图像.此原理实际为卷积操作,也可以理解为一种图像变换,最常见的图像变换(

图像处理卷积算法实现

今天心血来潮,想把传统的卷积算法实现一份不采用各种加速方式,仅优化算法逻辑的纯净版本. 写完发现性能还可以,特发出来分享之,若有博友在此基础上,进行了再次优化,那就更赞了. 算法很简单: inline unsigned char Clamp2Byte(int n) { return (((255 - n) >> 31) | (n & ~(n >> 31))); } void Convolution2D(unsigned char * data, unsigned int w

图像处理基本算法(整理)

转自:http://www.cnblogs.com/drizzlecrj/archive/2008/02/25/1077494.html

图像处理基本算法-卷积和相关

在执行线性空间滤波时,经常会遇到两个概念相关和卷积二者基本相似,在进行图像匹配是一个非常重要的方法.相关是滤波器模板移过图像并计算计算每个位置乘积之和的处理卷积的机理相似,但滤波器首先要旋转180度相关的计算步骤:(1)移动相关核的中心元素,使它位于输入图像待处理像素的正上方(2)将输入图像的像素值作为权重,乘以相关核(3)将上面各步得到的结果相加做为输出卷积的计算步骤:(1)卷积核绕自己的核心元素顺时针旋转180度(2)移动卷积核的中心元素,使它位于输入图像待处理像素的正上方(3)在旋转后的卷

Floyd-Warshall算法及其并行化实现(基于MPI)

Floyd-Warshall算法(或称Floyd算法)是用于寻找加权图中非固定起止点间最短路径的经典算法,它是基于动态规划思想设计的.当前我们所认识的Floyd算法之形式由计算机科学家(同时也是图灵奖得主) Robert Floyd 于 1962 年提出并发表.但在此之前,Bernard Roy(1959)和 Stephen Warshall(1962)也分别独立地提出了类似的算法.本文将主要讨论基于MPI的并行化Floyd算法实现. 欢迎关注白马负金羁的博客 http://blog.csdn.

图像处理资料分享

资料汇总:链接: http://pan.baidu.com/s/1c1bcDdY 密码: kn4w 资料精选: 1.冈萨雷斯,图像处理(Matlab版) 链接: http://pan.baidu.com/s/1hrzWXRA 密码: t3xw 2.数字图像处理与机器视觉Visual C++与Matlab实现[张铮] 链接: http://pan.baidu.com/s/1jHnbIa6 密码: 6ave 3.[MATLAB数字图像处理].张德丰.扫描版 链接: http://pan.baidu.

【算法导论】学习笔记——第6章 堆排序

堆这个数据结构应用非常广泛,数字图像处理的算法里也见过.似乎记得以前老师上课说需要用树结构实现堆排序,看了一下算法导论才明白其精髓.堆虽然是一棵树,但显然没必要非得用树结构实现堆排序.堆排序的性质很好,算法时间复杂度为O(nlgn). 1. 堆排序的简要说明.二叉堆可以分为两种形式:最大堆和最小堆.在最大堆中,最大堆性质是指除了根以外的所有结点i都要满足: A[PARENT(i)] >= A[i]:在最小堆中,最小堆性质是指除了根以外的所有结点i都要满足: A[PARENT(i)] <= A[

Android 图像处理软件

在机器视觉实验室呆了有一年半时间了,但由于自己"任性".一直以来学习的内容都是自己来安排,我还是坚持认为没有最好和最简单的技术,只有自己喜欢的技术.不过说起来还是会觉得惭愧,经常听到师兄们谈论图像处理各种算法,可是一直到此软件诞生之前对机器视觉的知识可以说一概不知.自己研究的主要是Android系统的东西,从上层到下层都有所涉及.一直以来都想把自身所长和实验室主题联系上,这样可以多和实验室牛人沟通,也顺便刷刷存在感~由此向师兄师弟们请教一二,学了一点图像处理技术,做了一款Android

基于FPGA的均值滤波算法实现

我们为了实现动态图像的滤波算法,用串口发送图像数据到FPGA开发板,经FPGA进行图像处理算法后,动态显示到VGA显示屏上,前面我们把硬件平台已经搭建完成了,后面我们将利用这个硬件基础平台上来实现基于FPGA的一系列图像处理基础算法. 椒盐噪声(salt & pepper noise)是数字图像的一个常见噪声,所谓椒盐,椒就是黑,盐就是白,椒盐噪声就是在图像上随机出现黑色白色的像素.椒盐噪声是一种因为信号脉冲强度引起的噪声,产生清楚该噪声的算法也比较简单. 均值滤波的方法将数据存储成3x3的矩阵