图像分割

来源:互联网 发布:容我喝一杯82年的java 编辑:程序博客网 时间:2024/06/05 19:43
根据不同领域的不同需要,往往只对原始图像的某一部分进行处理,这些部分一般来说具有特定的灰度 纹理等特征,图像分割就是根据图像在各个区域的不同特性,而对齐进行边界或区域的分割,并从中提取所关心的目标。
图像分割算法可划分为4类:并行边界分割算法,串行边界分割算法,并行区域分割算法,串行区域分割算法。

并行边界分割算法:
图像边缘:图像局部区域亮度变化最显著的部分,该区域的灰度剖面一般可看作是一个阶跃。
梯度算子:


1.罗布特交叉算子:
2个2*2的模版:
1  0      0 1                
0 -1     -1 0   
代码:
  1. /*************************************************************************
  2. * 函数名称:
  3. * SplitRoberts()
  4. * 参数:
  5. * BYTE* bmp,LONG width,LONG height ------图像参数
  6. * 返回值:
  7. * BOOL - 成功返回TRUE,否则返回FALSE。
  8. * 说明:该函数对图象进行罗伯特交叉算子的边缘检测。采用2*2算子,所以只能对具有
  9. *陡峭的低噪声图像才有很好的效果
  10. ************************************************************************/
  11. voidSplitRoberts(BYTE *bmp,LONG width,LONG height);
  12. voidMyProcess::SplitRoberts(BYTE *bmp,LONG width,LONG height)
  13. {
  14. LONG i,j;
  15. BYTE *temp_bmp =new BYTE [(width+6)*(height+2)];
  16. //填充temp_bmp
  17. BmpFilter(temp_bmp,bmp,width,height);
  18. //2*2模版
  19. for(i=1;i<height+1;i++)
  20. for(j=3;j<width+3;j++)
  21. {
  22. int a = temp_bmp[i*(width+6)+j];
  23. int b = temp_bmp[(i+1)*(width+6)+j+1];
  24. int c = temp_bmp[i*(width+6)+j+1];
  25. int d = temp_bmp[(i+1)*(width+6)+j];
  26. /*a = sqrt(a);
  27. b = sqrt(b);
  28. c = sqrt(c);
  29. d = sqrt(d);*/
  30. bmp[(i-1)*width+j-3]= sqrt((a-b)*(a-b)+(c-d)*(c-d));
  31. }
  32. delete[]temp_bmp;
  33. }
薄瑞维特边缘算子(运算同上):
-1  0  1          1 1 1       
-1  0  1          0 0 0
-1  0  1          1 1 1
  1. if(type==0)//罗伯特交叉算子
  2. {
  3. int a = temp_bmp[i*(width+6)+j];
  4. int b = temp_bmp[(i+1)*(width+6)+j+1];
  5. int c = temp_bmp[i*(width+6)+j+1];
  6. int d = temp_bmp[(i+1)*(width+6)+j];
  7. bmp[(i-1)*width+j-3]= sqrt((a-b)*(a-b)+(c-d)*(c-d));
  8. }
  9. elseif(type==1)//薄瑞维特边缘算子
  10. {
  11. int a = temp_bmp[i*(width+6)+j]*-1;
  12. a+= temp_bmp[i*(width+6)+j+2];
  13. a+= temp_bmp[(i+1)*(width+6)+j]*-1;
  14. a+= temp_bmp[(i+1)*(width+6)+j+2];
  15. if(i<height)
  16. {
  17. a+= temp_bmp[(i+2)*(width+6)+j]*-1;
  18. a+= temp_bmp[(i+2)*(width+6)+j+2];
  19. }
  20. int b = temp_bmp[i*(width+6)+j];
  21. b+= temp_bmp[i*(width+6)+j+1];
  22. b+= temp_bmp[i*(width+6)+j+2];
  23. if(i<height)
  24. {
  25. b+= temp_bmp[(i+2)*(width+6)+j]*-1;
  26. b+= temp_bmp[(i+2)*(width+6)+j+1]*-1;
  27. b+= temp_bmp[(i+2)*(width+6)+j+2]*-1;
  28. }
  29. bmp[(i-1)*width+j-3]= sqrt((a)*(a)+(b)*(b));
  30. }
  31. }
索贝尔边缘算子
-1  0  1          1 2 1       
-2  0  2          0 0 0
-1  0  1          1 2 1
  1. elseif(type==2)//索贝尔边缘算子
  2. {
  3. int a = temp_bmp[i*(width+6)+j]*-1;
  4. a+= temp_bmp[i*(width+6)+j+2];
  5. a+= temp_bmp[(i+1)*(width+6)+j]*-2;
  6. a+= temp_bmp[(i+1)*(width+6)+j+2]*2;
  7. if(i<height)
  8. {
  9. a+= temp_bmp[(i+2)*(width+6)+j]*-1;
  10. a+= temp_bmp[(i+2)*(width+6)+j+2];
  11. }
  12. int b = temp_bmp[i*(width+6)+j];
  13. b+= temp_bmp[i*(width+6)+j+1]*2;
  14. b+= temp_bmp[i*(width+6)+j+2];
  15. if(i<height)
  16. {
  17. b+= temp_bmp[(i+2)*(width+6)+j]*-1;
  18. b+= temp_bmp[(i+2)*(width+6)+j+1]*-2;
  19. b+= temp_bmp[(i+2)*(width+6)+j+2]*-1;
  20. }
  21. bmp[(i-1)*width+j-3]= sqrt((a)*(a)+(b)*(b));
  22. }
拉普拉斯算子:
在模版滤波中实现,速度优于方向导数滤波。适合无噪声图像,是无方向性算子

Kirsch方向算子:
    采用一组模版分别计算不同方向上的差值,取其最大值作为最终输出的边缘强度
  1. {5,5,5,
  2. -3,0,-3,
  3. -3,-3,-3,
  4. 1,3},
  5. {-3,5,5,
  6. -3,0,5,
  7. -3,-3,-3,
  8. 1,3},
  9. {-3,-3,5,
  10. -3,0,5,
  11. -3,-3,5,
  12. 1,3},
  13. {-3,-3,-3,
  14. -3,0,5,
  15. -3,5,5,
  16. 1,3}
  1. /*************************************************************************
  2. * 函数名称:SplitKirsch()
  3. * 参数:BYTE* bmp,LONG width,LONG height ------图像参数
  4. * 返回值:无
  5. * 说明:该函数进行Kirsch方向算子边缘检测。
  6. ************************************************************************/
  7. voidSplitKirsch(BYTE *bmp,LONG width,LONG height);
  8. LONG i,j;
  9. //申请一个临时空间,由1包围bmp图像,方便进行模版处理
  10. BYTE *temp_bmp =new BYTE[(width+6)*(height+2)];
  11. BmpFilter(temp_bmp,bmp,width,height);
  12. //模版滤波
  13. for(i=1;i<height+1;i++)
  14. for(j=3;j<width+3;j++)
  15. {
  16. LONG g,max=-99999;
  17. for(g=0;g<4;g++)
  18. {
  19. LONG k,m,temp=0;
  20. for(k=-1;k<kernel_kirsch[g].Dimention-1;k++)
  21. for(m=-1;m<kernel_kirsch[g].Dimention-1;m++)
  22. {
  23. int a = temp_bmp[(i+k)*(width+6)+j+m*3];
  24. int b = kernel_kirsch[g].Element[k+1][m+1];
  25. temp+=a*b;
  26. }
  27. //temp/=kernel.Divisor;
  28. //////////////////////////////////////////////////////////////////////////
  29. //此处注意,不应将值给待处理对象,而应传给未处理的原图像
  30. //temp_bmp[i*(width+6)+j] = (BYTE)temp;
  31. if(temp>max) max = temp;
  32. }
  33. bmp[(i-1)*width+j-3]= max;
  34. }
  35. delete[] temp_bmp;
轮廓提取:
方法:如果当前8领域的值中间值的差相等(或在一定范围内),则认为是非轮廓,将值设为白色。 /*************************************************************************
  1. * 函数名称:SplitContour()
  2. * 参数:BYTE* bmp,LONG width,LONG height ------图像参数
  3. * 返回值:无
  4. * 说明:轮廓提取
  5. ************************************************************************/
  6. voidSplitContour(BYTE *bmp,LONG width,LONG height);
  7. voidMyProcess::SplitContour(BYTE *bmp,LONG width,LONG height)
  8. {
  9. LONG i,j;
  10. BYTE *temp_bmp =new BYTE[width*height];
  11. memcpy(temp_bmp,bmp,width*height);
  12. for(i=0;i<height;i++)
  13. for(j=0;j<width/3;j++)
  14. {
  15. int I=0,temp_r,temp_g,temp_b;
  16. temp_r = temp_bmp[i*width+j*3];
  17. temp_g = temp_bmp[i*width+j*3+1];
  18. temp_b = temp_bmp[i*width+j*3+2];
  19. for(int k=i-1;k<i+2;k++)
  20. for(int l=j-1;l<j+2;l++)
  21. {
  22. if(k>=0&& l>=0&& l<width && k<height)
  23. {
  24. if(abs(temp_bmp[k*width+l*3]-temp_r)<10&&
  25. abs(temp_bmp[k*width+l*3+1]-temp_g)<10&&
  26. abs(temp_bmp[k*width+l*3+2]-temp_b)<10)
  27. {
  28. I++;
  29. }
  30. }
  31. }
  32. if(I==9)
  33. {
  34. bmp[i*width+j*3]=255;
  35. bmp[i*width+j*3+1]=255;
  36. bmp[i*width+j*3+2]=255;
  37. }
  38. }
  39. delete[] temp_bmp;
  40. }
Hough变换直线检测
检测直线,直线可写成p=xcos(angle)+ysin(angle);
p为原点到直线距离,angle为斜率角
再找出最大的num[angle][p],即可确定一条直线,因为同一直线上的点,当angle一样时,p只有等于原直线斜率时才相等
  1. /*************************************************************************
  2. * 函数名称:HoufuLine()
  3. * 参数:BYTE* bmp,LONG width,LONG height ------图像参数
  4. * 返回值:无
  5. * 说明:Houfu直线检测
  6. ************************************************************************/
  7. voidHoufuLine(BYTE *bmp,LONG width,LONG height);
  8. voidMyProcess::HoufuLine(BYTE *bmp,LONG width,LONG height)
  9. {
  10. LONG i,j,angle,p;
  11. BYTE *temp_bmp =new BYTE[width*height];
  12. //图像二值化
  13. for(i=0;i<height;i++)
  14. for(j=0;j<width;j++)
  15. {
  16. if(bmp[i*width+j]>128) temp_bmp[i*width+j]=255;
  17. else temp_bmp[i*width+j]=0;
  18. }
  19. //存储累计变量的数组
  20. //最大距离
  21. int maxDis = sqrt(width*width+height*height);
  22. int*num =newint[360*maxDis];
  23. //初始化数组
  24. memset(num,0,(360*maxDis)*sizeof(int));
  25. //检测直线,p=xcos(angle)+ysin(angle);
  26. //再找出最大的num[angle][p],即可确定一条直线
  27. int max=0,maxa,maxp;
  28. for(i=0;i<height;i++)
  29. for(j=0;j<width;j++)
  30. {
  31. if(temp_bmp[i*width+j]==0)
  32. for(angle=0;angle<360;angle++)
  33. {
  34. p=abs(i*sin(angle/360.0*6.28)+j*cos(angle/360.0*6.28));
  35. num[p*360+angle]++;
  36. if(max < num[p*360+angle])
  37. {
  38. max=num[p*360+angle];
  39. maxa=angle;
  40. maxp=p;
  41. }
  42. }
  43. }
  44. //找出直线的策略---数目大于一个值即认为是直线
  45. int line = width/10;
  46. //for(i=0;i<360;i++)
  47. //for(j=0;j<width+height;j++)
  48. {
  49. //if(num[i*maxDis+j]>line)
  50. {
  51. /*double k=tan(i/360.0*6.28);
  52. double b=j/sin(i/360.0*6.28);
  53. for(int m=0;m<width;m++)
  54. {
  55. int y = k*m+b;
  56. bmp[y*width+m]=0;
  57. }*/
  58. int k,m;
  59. for(k=0;k<height;k++)
  60. for(m=0;m<width;m++)
  61. {
  62. //if(temp_bmp[k*width+m]==0)
  63. {
  64. if(maxp==abs(m*cos(maxa/360.0*6.28)+k*sin(maxa/360.0*6.28)))
  65. {
  66. bmp[k*width+m]=0;
  67. }
  68. }
  69. }
  70. }
  71. }
  72. }
并行区域分割算法:
迭代求阈值
  1. /*************************************************************************
  2. * 函数名称:Threshold()
  3. * 参数:BYTE* bmp,LONG width,LONG height ------图像参数
  4. * 返回值:int 阈值,返回迭代的阈值
  5. * 说明:并行区域分割,迭代求阈值,先取一阈值,分割图像,分别积分并平均,反复迭代,直到阈值不变
  6. 积分即离散值加权和
  7. ************************************************************************/
  8. intThreshold(BYTE *bmp,LONG width,LONG height);
  9. intMyProcess::Threshold(BYTE *bmp,LONG width,LONG height)
  10. {
  11. //得到灰度分布直方图数值
  12. int*grayInt =newint[256];
  13. memset(grayInt,0,256*sizeof(int));
  14. this->GetGrayIntensity(bmp,grayInt,width,height);
  15. //定义阈值
  16. long T1=127,T2=0;
  17. long i,j;
  18. //迭代阈值选取
  19. long temp0=0,temp1=0,temp2=0,temp3=0;
  20. while(1)
  21. {
  22. //定义临时变量
  23. for(i=0;i<T1+1;i++)
  24. {
  25. temp0+=grayInt[i]*i;
  26. temp1+=grayInt[i];
  27. }
  28. for(;i<256;i++)
  29. {
  30. temp2+=grayInt[i]*i;
  31. temp3+=grayInt[i];
  32. }
  33. T2 =(temp0/temp1+temp2/temp3)/2;
  34. //迭代是否结束
  35. if(T1==T2)break;
  36. else T1=T2;
  37. }
  38. //对bmp进行转换
  39. for(i=0;i<height;i++)
  40. for(j=0;j<width;j++)
  41. {
  42. if(bmp[i*width+j]<T1) bmp[i*width+j]=0;
  43. else bmp[i*width+j]=255;
  44. }
  45. delete[] grayInt;
  46. return T1;
  47. }
串行区域分割
区域生长:选取多个种子,将图像像素与其比较,将像素点设为最接近的点
  1. /*************************************************************************
  2. * 函数名称:RgnGrow()
  3. * 参数:BYTE* bmp,LONG width,LONG height ------图像参数
  4. BYTE c1,BYTE c2 种子1和种子二的值
  5. * 返回值:无
  6. * 说明:串行区域分割,区域生长 对灰度图进行处理
  7. ************************************************************************/
  8. voidRgnGrow(BYTE *bmp,LONG width,LONG height,BYTE c1,BYTE c2);
  9. voidMyProcess::RgnGrow(BYTE *bmp,LONG width,LONG height,BYTE c1,BYTE c2)
  10. {
  11. LONG i,j;
  12. for(i=0;i<height;i++)
  13. for(j=0;j<width;j++)
  14. {
  15. BYTE temp=bmp[i*width+j];
  16. if(abs(temp-c1)<abs(temp-c2))
  17. {
  18. bmp[i*width+j]=c1;
  19. }
  20. else
  21. {
  22. bmp[i*width+j]=c2;
  23. }
  24. }
  25. }



0 0
原创粉丝点击