边缘检测和图像分割的联系:
边缘检测是通过图像的梯度变化将图像中梯度变化明显的地方检测出来,针对的是边缘信息。图像分割是将目标分割出来,针对的是目标对象,边缘检测是空间域图像分割的一种方法,属于包含关系
边缘检测后的图像是二值图像,对二值图像可以运用形态学操作来分割目标,所以边缘检测是图像分割的一个前提。但分割不一定非要用边缘检测。
图像分割:
概念:
图像分割是将图像划分成若干个互不相交的小区域的过程,所谓小区域是某种意义下具有共同属性的像素的连通集合。
从集合的观点看:它应该是具有如下性质的一种点集,集合R代表整个区域,对R的分割可看作将R分成N个满足以下五个条件的非空子集R1,R2,…,RN:
目的:
无论是图像处理、分析、理解与识别,其基础工作一般都建立在图像分割的基础上;
将图像中有意义的特征或者应用所需要的特征信息提取出来;
图像分割的最终结果是将图像分解成一些具有某种特征的单元,称为图像的基元;
相对于整幅图像来说,这种图像基元更容易被快速处理。
图像分割原理
图像分割的研究多年来一直受到人们的高度重视,至今提出了各种类型的分割算法。Pal把图像分割算法分成了6类:阈值分割,像素分割、深度图像分割、彩色图像分割,边缘检测和基于模糊集的方法。但是,该方法中,各个类别的内容是有重叠的。为了涵盖不断涌现的新方法,有的研究者将图像分割算法分为以下六类:并行边界分割技术、串行边界分割技术、并行区域分割技术、串行区域分割技术、结合特定理论工具的分割技术和特殊图像分割技术。
图像分割的特征:
分割出来的各区域对某种性质例如灰度,纹理而言具有相似性,区域内部是连通的的且没有过多小孔。
区域边界是明确的
相邻区域对分割所依据的性质有明显的差异
图像分割的方法:
一、基于像素灰度值的分割方法:阈值(门限)方法
二、基于区域的分割方法:通过直接确定区域间的边界来实现分割的边界方法;
三、基于边缘的分割技术:首先检测边缘像素, 再将边缘像素连接起来构成边界形成分割。
图像分割包含的内容:
边缘检测
边缘跟踪 :
从图像中一个边缘点出发,然后根据某种判别准则搜索下一个边缘点以此跟踪出目标边界。
阈值分割 :
原始图像——f(x,y)
灰度阈值——T
阈值运算得二值图像——g(x,y)
区域分割:
阈值分割法由于没有或很少考虑空间关系,使多阈值选择受到限制
于区域的分割方法可以弥补这点不足,它利用的是图像的空间性质,该方法认为分割出来的属于同一区域的像素应具有相似的性质,其概念是相当直观的。
传统的区域分割算法有区域增长法和区域分裂合并法。该类方法在没有先验知识可以利用时,对含有复杂场景或自然景物等先验知识不足的图像进行分割, 也可以取得较好的性能。但是,空间和时间开销都比较大。
区域生长法主要考虑象素及其空间邻域象素之间的关系
开始时确定一个或多个象素点作为种子,然后按某种相似性准则增长区域,逐步生成具有某种均匀性的空间区域,将相邻的具有相似性质的象素或区域归并从而逐步增长区域,直至没有可以归并的点或其它小区域为止。
区域内象素的相似性度量可以包括平均灰度值、纹理、颜色等信息。
区域生长:
主要考虑像素及其空间邻域像素之间的关系
开始时确定一个或多个像素点作为种子,然后按某种相似性准则增长区域,逐步生成具有某种均匀性的空间区域,将相邻的具有相似性质的像素或区域归并从而逐步增长区域,直至没有可以归并的点或其它小区域为止。
区域内像素的相似性度量可以包括平均灰度值、纹理、颜色等信息。
主要步骤:
选择合适的种子点
确定相似性准则(生长准则)
确定生长停止条件
区域分裂:
条件:如果区域的某些特性不满足一致性准则
开始:从图像的最大区域开始,一般情况下,是从整幅图像开始
注意:
确定分裂准则(一致性准则)
确定分裂方法,即如何分裂区域,使得分裂后的子区域的特性尽可能都满足一致性准则值
边缘检测:
在视觉计算理论框架中,抽取二维图像上的边缘、角点、纹理等基本特征,是整个系统框架中的第一步。这些特征所组成的图称为基元图。
在不同“尺度”意义下的边缘点,在一定条件下包含了原图像的全部信息。
定义:
•目前,具有对边缘的描述性定义,即两个具有不同灰度的均匀图像区域的边界,即边界反映局部的灰度变化。
•局部边缘是图像中局部灰度级以简单(即单调)的方式作极快变换的小区域。这种局部变化可用一定窗口运算的边缘检测算子来检测。
边缘的描述:
1) 边缘法线方向——在某点灰度变化最剧烈的方向,与边缘方向垂直;
2) 边缘方向——与边缘法线方向垂直,是目标边界的切线方向;
3) 边缘强度——沿边缘法线方向图像局部的变化强度的量度。
边缘检测的基本思想是通过检测每个像素和其邻域的状态,以决定该像素是否位于一个物体的边界上。如果一个像素位于一个物体的边界上,则其邻域像素的灰度值的变化就比较大。假如可以应用某种算法检测出这种变化并进行量化表示,那么就可以确定物体的边界。
边缘检测算法有如下四个步骤:
滤波:边缘检测算法主要是基于图像强度的一阶和二阶导数,但导数的计算对噪声很敏感,因此必须使用滤波器来改善与噪声有关的边缘检测器的性能.需要指出,大多数滤波器在降低噪声的同时也导致了边缘强度的损失,因此,增强边缘和降低噪声之间需要折衷.
增强:增强边缘的基础是确定图像各点邻域强度的变化值.增强算法可以将邻域(或局部)强度值有显著变化的点突显出来.边缘增强一般是通过计算梯度幅值来完成的.
检测:在图像中有许多点的梯度幅值比较大,而这些点在特定的应用领域中并不都是边缘,所以应该用某种方法来确定哪些点是边缘点.最简单的边缘检测判据是梯度幅值阈值判据.
定位:如果某一应用场合要求确定边缘位置,则边缘的位置可在子像素分辨率上来估计,边缘的方位也可以被估计出来.
在边缘检测算法中,前三个步骤用得十分普遍。这是因为大多数场合下,仅仅需要边缘检测器指出边缘出现在图像某一像素点的附近,而没有必要指出边缘的精确位置或方向.边缘检测误差通常是指边缘误分类误差,即把假边缘判别成边缘而保留,而把真边缘判别成假边缘而去掉.边缘估计误差是用概率统计模型来描述边缘的位置和方向误差的.我们将边缘检测误差和边缘估计误差区分开,是因为它们的计算方法完全不同,其误差模型也完全不同.
边缘检测的三个共性准则:
•好的检测结果,或者说对边缘的误测率尽可能低,就是在图像边缘出现的地方检测结果中不应该没有;另一方面不要出现虚假的边缘;
•对边缘的定位要准确,也就是我们标记出的边缘位置要和图像上真正边缘的中心位置充分接近;
•对同一边缘要有尽可能低的响应次数,也就是检测响应最好是单像素的。
几种常用的边缘检测算子主要有Roberts边缘检测算子,Sobel算子、Prewitt算子、Krisch边缘算子,高斯-拉普拉斯算子。
图像特征:
•图像特征是指图像中可用作标志的属性,它可以分为统计特征和视觉特征两类。
•图像的统计特征是指一些人为定义的特征,通过变换才能得到,如图像的直方图、矩、频谱等;
•图像的视觉特征是指人的视觉可直接感受到的自然特征,如区域的亮度、纹理或轮廓等
轮廓提取:
二值图像轮廓提取的算法非常简单, 就是掏空内部点: 如果原图像中有一点为黑,且它的8个邻点都是黑色时,说明该点是内部点, 将该点删除(置为白色像素值255)。对图像中所有像素点执行该操作便可完成图像轮廓的提取。
模板匹配:
模板匹配是指用一个较小的图像,即模板与源图像进行比较, 以确定在源图像中是否存在与该模板相同或相似的区域, 若该区域存在, 还可确定其位置并提取该区域。
形状匹配:
形状也是描述图像内容的一个重要特征, 利用形状进行匹配需要考虑三个问题。首先,形状常与目标联系在一起,所以相对于颜色, 形状特征可以看作是更高层次的图像特征。要获得有关目标的形状参数,常常要先对图像进行分割, 所以形状特征会受图像分割效果的影响。其次,目标形状的描述是一个非常复杂的问题,至今还没有找到能与人的感觉相一致的图像形状的确切数学定义。最后,从不同视角获取的图像中目标形状可能会有很大差别,为准确进行形状匹配,需要解决平移、 尺度、 旋转变换不变性的问题。
标的形状常常可以用目标的轮廓来表示,而轮廓是由一系列边界点所组成的。一般认为,在较大尺度下常常能较可靠地消除误检并检测到真正的边界点, 但在大尺度下对边界的定位不易准确。相反,在较小尺度下对真正边界点的定位常比较准确,但在小尺度下误检的比例会增加。所以,可考虑先在较大尺度下检测出真正的边界点,再在较小尺度下对真正边界点进行较精确的定位。小波变换和分析作为一种多尺度、 多通道分析工具,比较适合对图像进行多尺度的边界检测。
图像分割的实现
我用了Roberts算子、Sobel算子和Kirsh算子边缘检测的方法但都由于亮度不均等因素对图像分割的效果不太好:
Sobel:
void sobel (unsignedchar* des, constunsignedchar* src, int width, int height)
{
for (int y=0; y《height; y++)
for (int x=0; x《width; x++)
des[y * width + x]=255;
/* Now compute the convolution, scaling */
for (int y=1; y《height-1; y++)
for (int x=1; x《width-1; x++)
{
double n = (src[(y+1)*width+x-1]+2*src[(y+1)*width+x]+src[(y+1)*width+x+1]) -
(src[(y-1)*width+x-1]+2*src[(y-1)*width+x]+src[(y-1)*width+x+1]);
double m = (src[(y-1)*width+x+1]+2*src[y*width+x+1]+src[(y+1)*width+x+1])-
(src[(y-1)*width+x-1]+2*src[y*width+x-1]+src[(y+1)*width+x-1]);
double k = (int)( sqrt( (double)(n*n + m*m) )/4.0 );
des[y * width + x] = k;
}
thresh (des, width,height);
}
Roberts算子:
void roberts(unsignedchar* des, constunsignedchar* src, int width, int height)
{
for (int y=0; y《height; y++)
for (int x=0; x《width; x++)
des[y * width + x]=255;
/* Now compute the convolution, scaling */
for (int y=1; y《height-1; y++)
for (int x=1; x《width-1; x++)
{
double n = src[y*width+x] - src[(y+1)*width+x+1];
double m = src[(y+1)*width+x] - src[y*width+x+1];
double k = abs(m)+abs(n);
des[y * width + x] = k;
}
thresh (des, width,height);
}
Kirsch算子:
void kirsch(unsigned char* des, const unsigned char* src, int width, int height)
{
// TODO: Add your command handler code here
//显示数值
long int i,j,Ns;
static int nWeight[8][3][3];//对一个静态整型数组赋初值,模板
double dGrad[8];
int nTmp[3][3],xx,yy;//每像素点的邻域值
nWeight[0][0][0] = -1 ;
nWeight[0][0][1] = 0 ;
nWeight[0][0][2] = 1 ;
nWeight[0][1][0] = -2 ;
nWeight[0][1][1] = 0 ;
nWeight[0][1][2] = 2 ;
nWeight[0][2][0] = -1 ;
nWeight[0][2][1] = 0 ;
nWeight[0][2][2] = 1 ;
nWeight[1][0][0] = -1 ;
nWeight[1][0][1] = -2 ;
nWeight[1][0][2] = -1 ;
nWeight[1][1][0] = 0 ;
nWeight[1][1][1] = 0 ;
nWeight[1][1][2] = 0 ;
nWeight[1][2][0] = 1 ;
nWeight[1][2][1] = 2 ;
nWeight[1][2][2] = 1 ;//负号上下??? 已改成8个方向模板的值
nWeight[2][0][0] = 0 ;
nWeight[2][0][1] = -1 ;
nWeight[2][0][2] = -2 ;
nWeight[2][1][0] = 1 ;
nWeight[2][1][1] = 0 ;
nWeight[2][1][2] = -1 ;
nWeight[2][2][0] = 2 ;
nWeight[2][2][1] = 1 ;
nWeight[2][2][2] = 0 ;
nWeight[3][0][0] = 1 ;
nWeight[3][0][1] = 0 ;
nWeight[3][0][2] = -1 ;
nWeight[3][1][0] = 2 ;
nWeight[3][1][1] = 0 ;
nWeight[3][1][2] = -2 ;
nWeight[3][2][0] = 1 ;
nWeight[3][2][1] = 0 ;
nWeight[3][2][2] = -1 ;
nWeight[4][0][0] = 2 ;
nWeight[4][0][1] = 1 ;
nWeight[4][0][2] = 0 ;
nWeight[4][1][0] = 1 ;
nWeight[4][1][1] = 0 ;
nWeight[4][1][2] = -1 ;
nWeight[4][2][0] = 0 ;
nWeight[4][2][1] = -1 ;
nWeight[4][2][2] = -2 ;
nWeight[5][0][0] = 1 ;
nWeight[5][0][1] = 2 ;
nWeight[5][0][2] = 1 ;
nWeight[5][1][0] = 0 ;
nWeight[5][1][1] = 0 ;
nWeight[5][1][2] = 0 ;
nWeight[5][2][0] = -1 ;
nWeight[5][2][1] = -2 ;
nWeight[5][2][2] = -1 ;
nWeight[6][0][0] = 0 ;
nWeight[6][0][1] = 1 ;
nWeight[6][0][2] = 2 ;
nWeight[6][1][0] = -1 ;
nWeight[6][1][1] = 0 ;
nWeight[6][1][2] = 1 ;
nWeight[6][2][0] = -2 ;
nWeight[6][2][1] = -1 ;
nWeight[6][2][2] = 0 ;
nWeight[7][0][0] = -2 ;
nWeight[7][0][1] = -1 ;
nWeight[7][0][2] = 0 ;
nWeight[7][1][0] = -1 ;
nWeight[7][1][1] = 0 ;
nWeight[7][1][2] = 1 ;
nWeight[7][2][0] = 0 ;
nWeight[7][2][1] = -1 ;
nWeight[7][2][2] = 2 ;
//注意:每行的字节数必须是4的整数倍!!!先不考虑
Ns=height*width;
unsigned char* kk = new unsigned char[width * height]; //开始变换 initiion
for(i=0; i《height ; i++ )
//if(i==0)//tt change at 05.05.16
for(j=0 ; j《width ; j++ )
{
des[i*width + j]=0;//*(pdGrad+y*nWidth+x)
}
for(i=1; i《height-1 ; i++ )
{
for(j=1 ; j《width-1 ; j++ )
{
dGrad[0] = 0 ;
dGrad[1] = 0 ;
dGrad[2] = 0 ;
dGrad[3] = 0 ;
dGrad[4] = 0 ;
dGrad[5] = 0 ;
dGrad[6] = 0 ;
dGrad[7] = 0 ;
// sobel算子需要的各点象素值
// 模板第一行
nTmp[0][0] = src[(i-1)*width + j - 1 ];
nTmp[0][1] = src[(i-1)*width + j ] ;
nTmp[0][2] = src[(i-1)*width + j + 1 ] ;
// 模板第二行
nTmp[1][0] = src[i*width + j - 1 ] ;
nTmp[1][1] = src[i*width + j ] ;
nTmp[1][2] = src[i*width + j + 1 ] ;
// 模板第三行
nTmp[2][0] = src[(i+1)*width + j - 1 ] ;
nTmp[2][1] = src[(i+1)*width + j ] ;
nTmp[2][2] = src[(i+1)*width + j + 1 ] ;
// 计算梯度
for(yy=0; yy《3; yy++)
for(xx=0; xx《3; xx++)
{
dGrad[0] += nTmp[yy][xx] * nWeight[0][yy][xx] ;
dGrad[1] += nTmp[yy][xx] * nWeight[1][yy][xx] ;
dGrad[2] += nTmp[yy][xx] * nWeight[2][yy][xx] ;
dGrad[3] += nTmp[yy][xx] * nWeight[3][yy][xx] ;
dGrad[4] += nTmp[yy][xx] * nWeight[4][yy][xx] ;
dGrad[5] += nTmp[yy][xx] * nWeight[5][yy][xx] ;
dGrad[6] += nTmp[yy][xx] * nWeight[6][yy][xx] ;
dGrad[7] += nTmp[yy][xx] * nWeight[7][yy][xx] ;
}
for (xx=1;xx《8;xx++)
{
if (dGrad[xx]》dGrad[0])
dGrad[0]=dGrad[xx];
}
des[i*width + j]=dGrad[0];// 梯度值写入src[i]
}
}
//设定阈值
int th[5120],newth[5120],shuN,newN,flagyuzhi;//winframe=32,ii,jj,initpos;
double thk,kmin,mvalue[8];
shuN=0;
thk=0.5;
for (i=0;i《Ns;i++)//每层的每个点
{
if ((i》=width) && (i《(Ns-width)))//若是非边界点,则……
{
if ((i%width!=0) && ((i+1)%width!=0))
{
//每点做变换,首先求kirs(c)h算子
mvalue[0]=fabs(double(des[i+1]+des[i+width+1]+des[i+width]+
des[i+width-1]+des[i-1]-des[i-width-1]-
des[i-width]-des[i-width+1]));
mvalue[1]=fabs(double(des[i+width+1]+des[i+width]+
des[i+width-1]+des[i-1]+des[i-width-1]-
des[i-width]-des[i-width+1]-des[i+1]));
mvalue[2]=fabs(double(des[i+width]+des[i+width-1]+des[i-1]+
des[i-width-1]+des[i-width]-
des[i-width+1]-des[i+1]-des[i+width+1]));
mvalue[3]=fabs(double(des[i+width-1]+des[i-1]+
des[i-width-1]+des[i-width]+
des[i-width+1]-des[i+1]-des[i+width+1]-
des[i+width]));
mvalue[4]=fabs(double(des[i-1]+des[i-width-1]+
des[i-width]+des[i-width+1]+des[i+1]-
des[i+width+1]-des[i+width]-
des[i+width-1]));
mvalue[5]=fabs(double(des[i-width-1]+des[i-width]+
des[i-width+1]+des[i+1]+des[i+width+1]-
des[i+width]-des[i+width-1]-des[i-1]));
mvalue[6]=fabs(double(des[i-width]+des[i-width+1]+des[i+1]+
des[i+width+1]+des[i+width]-
des[i+width-1]-des[i-1]-des[i-width-1]));
mvalue[7]=fabs(double(des[i-width+1]+des[i+1]+des[i+width+1]+
des[i+width]+des[i+width-1]-
des[i-1]-des[i-width-1]-des[i-width]));
for (j=1;j《8;j++) //比较得出算子,mvalue[0]为最大
{
if (mvalue[0]《mvalue[j])
mvalue[0]=mvalue[j];
}
kk[i]=max(1,mvalue[0]/15);
if (shuN==0)
kmin=kk[i];
if (kk[i]》thk)
{
th[shuN]=i;
kmin=min(kmin,kk[i]);
shuN++;
if (shuN》=5*height)//若大于5*H个点,则重新确定
{
//AfxMessageBox(“lll”);
thk=kmin;
newN=0;
for (j=0;j《shuN;j++)
{
if (kk[th[j]]》thk)
{
if (newN==0)
kmin=kk[th[j]];
newth[newN]=th[j];
kmin=min(kmin,kk[th[j]]);
newN++;
}
//else des[th[j]]=0;
}
for (j=0;j《5120;j++)
{
th[j]=newth[j];
}
shuN=newN;
}//重新确定完
}
//非边界的每点变换结束
}
}
}//一层结束
for (i=0;i《Ns;i++)//每层的每个点
{
if (des[i]《thk)
des[i]=0;
}
thresh (des, width,height);
//菜单函数结束
}
下面三图分别为sobel、Roberts、kerish边缘检测的结果:
之后打算用霍夫变换检测直线找矩形框,但是由于光照形成的噪点效果并不是很好,因此最后用自适应直方图均衡去除光照影响加自适应中值滤波再用投影法实现矩形框和数字的检测。具体如下:
int main()
{
IplImage* src = cvLoadImage(“dm5.bmp”);
IplImage* gray = cvCreateImage(cvGetSize(src), src-》depth, 1);
cvCvtColor(src,gray,CV_BGR2GRAY); //灰度化
int width = src-》width;
int height = src-》height;
IplImage* dst = cvCreateImage(cvGetSize(src), src-》depth, gray-》nChannels);
IplImage* scr = cvCreateImage(cvGetSize(gray), gray-》depth, gray-》nChannels);
cvSmooth(gray, gray, CV_MEDIAN, 3, 0, 0, 0); //中值滤波,消除小的噪声;
cvSmooth(gray, gray, CV_GAUSSIAN, 9, gray-》nChannels);//高斯滤波
cvCvtColor(src,scr,CV_BGR2GRAY);
cvThreshold( gray, gray, 190, 255, CV_THRESH_BINARY);//二值化
int nChannels =gray-》nChannels;
cvNamedWindow(“origin”,0);
cvResizeWindow(“origin”,int(width/2),int(height/2));
cvShowImage(“origin”, src);
unsigned char* img = new unsigned char[width * height ];
unsigned char* des = new unsigned char[width * height ];
unsigned char* gra = new unsigned char[width * height];
unsigned char* grt = new unsigned char[width * height];
img_data(gray, gra,width,height, nChannels);
img_data(scr, img,width,height,nChannels);
AHE(des, img, width, height,nChannels,10);//自适应直方图均衡
Projection( grt,gra,width,height); //投影检测表盘区域
img_extract(des,grt,width,height,1); //表盘区域还原
//kirsch(des,gra, width,height);
data_img( scr, des, width, height, nChannels);
cvNamedWindow(“表盘”,0);
cvResizeWindow(“表盘”,int(width/2),int(height/2));
cvShowImage(“表盘”, scr);
cvThreshold(scr, scr, 100, 255, CV_THRESH_BINARY); //表盘区域二值化以查找数字
img_data(scr, img,width,height,nChannels);
Adaptivemedianfilter(des, img, width, height, nChannels); //自适应中值滤波去噪
ImageDilation( img, des, width, height,nChannels,1);
ImageErosion( des,img,width, height,nChannels,1); //经过一次膨胀腐蚀去噪
location(img, des, width, height); //找出数字所在区域
data_img( scr, img, width, height, nChannels);
cvNamedWindow(“数字”,0);
cvResizeWindow(“数字”,int(width/2),int(height/2));
cvSaveImage(“123.bmp”,scr);
cvShowImage(“数字”, scr);
data_img( gray,des, width, height, nChannels);
cvNamedWindow(“erzhi”,0);
cvResizeWindow(“erzhi”,int(width/2),int(height/2));
cvShowImage(“erzhi”, gray);
cvWaitKey(0);
}
/**************************************************************************
函数名:Projection
功 能:投影法找出矩形区域
输 入:目标图像des, 原图像 src,图像宽width, 高height
返回值:no
*************************************************************************/
void Projection(unsigned char* des, const unsigned char* src,int width, int height)
{
int* h_sum = new int[height];
int* w_sum = new int[width];
int up=0;
int below=height;
int left=0;
int right=width;
for(int y=0;y《height;y++)
{
for(int x=0;x《width;x++)
{
des[y*width+x]=255;
}
}
for(int y=0;y《height;y++)
{
h_sum[y]=0;
for(int x=0;x《width;x++)
{
//printf(“src %d”,src[y*width+x]);
h_sum[y]=h_sum[y]+src[y*width+x];
}
//printf(“%d行%d ”,y,h_sum[y]);
}
for(int y=height/2;y《height;y++)
{
if((h_sum[y]-h_sum[height/2])》255*60)
{
below=y;
break;
}
}
for(int y=height/2;y》0;y--)
{
if((h_sum[y]-h_sum[height/2])》255*60)
{
up=y;
break;
}
}
for(int x=0;x《width;x++)
{
w_sum[x]=0;
for(int y=up;y《below;y++)
{
w_sum[x]=w_sum[x]+src[y*width+x];
}
//printf(“%d列%d ”,x,w_sum[x]);
}
int max_r=0;
int max_l=0;
for(int x=width/2+100;x《width;x++)
{
if(w_sum[x]》max_r)
{
right=x;
max_r=w_sum[x];
}
}
for(int x=width/2-100;x》0;x--)
{
if(w_sum[x]》max_l)
{
left=x;
max_l=w_sum[x];
}
}
for(int y=up;y《below;y++)
{
for(int x=left;x《right;x++)
{
des[y*width+x]=0;
}
}
printf(“up%d below%d left%d right%d”,up, below,left, right);
}
void img_extract(unsigned char* des, const unsigned char* src,int width, int height, int nChannels)
{
for (int y=0;y《height;y++)
for(int x=0;x《width;x++)
if(src[y*width+x]!=0)
{
for(int n = 0; n 《 nChannels; n++)
{
des[y * width * nChannels + x * nChannels + n ] = 255;
}
}
}
/************************************************************************
函数名:location
功 能:投影法找出数字
输 入:目标图像des, 原图像 src,图像宽width, 高height
返回值:no
**********************************************************************/
void location(unsigned char* des, const unsigned char* src,int width, int height)
{
int* h_sum = new int[height];
int* w_sum = new int[width];
int up=0;
int below=height;
int left=0;
int right=width;
for(int y=0;y《height;y++)
{
for(int x=0;x《width;x++)
{
des[y*width+x]=255;
}
}
for(int y=0;y《height;y++)
{
h_sum[y]=0;
for(int x=0;x《width;x++)
{
//printf(“src %d”,src[y*width+x]);
h_sum[y]=h_sum[y]+src[y*width+x];
}
//printf(“%d行%d ”,y,h_sum[y]);
}
int h_mid=(h_sum[height/2]+h_sum[height/2-10]+h_sum[height/2-20]+h_sum[height/2-30]+h_sum[height/2-40]);
h_mid=h_mid/5;
for(int y=height/2;y《height;y++)
{
if((h_sum[y]-h_mid)》255*35)
{
below=y;
break;
}
}
for(int y=height/2;y》0;y--)
{
if((h_sum[y]-h_mid)》255*37)
{
up=y;
break;
}
}
for(int x=0;x《width;x++)
{
w_sum[x]=0;
for(int y=up;y《below;y++)
{
w_sum[x]=w_sum[x]+src[y*width+x];
}
//printf(“%d列%d ”,x,w_sum[x]);
}
int right_start=width-10;
for(int x=width-10;x》width/2;x--)
{
if(w_sum[x]!=(below-up)*255)
{
right_start=x;
break;
}
}
for(int x=right_start-45;x》width/2;x--)
{
if(w_sum[x]《255*(below-up-40))
{
right=x;
break;
}
}
int left_start=10;
for(int x=10;x《width;x++)
{
if(w_sum[x]!=(below-up)*255)
{
left_start=x;
break;
}
}
for(int x=left_start+100;x《width;x++)
{
if(w_sum[x]《255*(below-up-20))
{
left=x;
break;
}
}
for(int y=up;y《below;y++)
{
for(int x=left-5;x《right+5;x++)
{
des[y*width+x]=src[y*width+x];
}
}
printf(“up%d below%d left%d right%d left_start%d h_mid%d height/2%d width%d”,up, below,left, right,left_start,h_mid,height/2,width);
}
结果展示
评论
查看更多