图像分割实验
Lab4
一、 实验目的
实验目标 设计图像分割算法完成实验图像的分割,分割结果“米粒”像素标记为 255,“背 景”像素标记为 0。
具体要求:
(1)程序使用 C++语言编写,集成开发环境可以选择 vs 或 Qt,核心代码不允许直接调 用库函数实现,不允许使用 opencv 等第天天;
(2)独立完成实验,自由设计处理流程和选择算法;
(3)分割结果以 BMP 格式文件保存,完成实验报告。
提示 此实验图像存在背景光照不均匀的现象,在设计分割算法时应该加以考虑。
二、 处理流程和算法设计
处理流程:
算法设计:
先通过均值滤波,消除图像噪声,该图像没有特别明显的会产生干扰的噪声,但尝试后发现平滑可以起到一定效果。具体说明见结果分析。
对图像进行分块。由于图像存在背景光照不均匀现象,图像下方的背景色比上方的小,所以将图像进行分块,不同的块使用不同的阈值。考虑到图像大小为474×474像素,将整个图像分为79×79的36个小块。
对每一小块使用大津阈值法,计算出阈值后直接对该块进行分类。
三、 实验及结果分析
实验结果:
结果分析:
- 使用均值滤波:图像中看似会对图像分割产生影响的噪声不多,但实验发现滤波还是能产生很大效果。我只尝试了3×3卷积核的均值滤波,感觉可以使用更大的卷积核。
左侧为未滤波的分割结果,可以看出存在少量噪声的干扰。而经过滤波后这些干扰消失了。
- 使用分块后计算阈值:该图像存在背景光照不均匀现象,图像下方的背景色比上方的小,如果对整个图像计算阈值,会让上方和下方像素对阈值比较敏感。
左侧为未分块计算阈值后的分割结果,可以看出对于图像下方的影响较大,但对于上方产生的影响不大,由此 可以得出分成36块其实有点多,分为上中下三个部分可能就可以达到类似效果。
- 总体而言,该算法没有明显不足,可以很好地实现这个图像的分割。
四、 具体实现
均值滤波
均值滤波的实现比较简单,即使用一个全为1的核进行卷积。其他的模板运算也可以使用这段代码,只需要改变模板即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| void CSegmentation::smoothing() { int core[9] = { 1, 1, 1, 1, 1, 1, 1, 1, 1}; LPBYTE ptr; int p = CSegImg->GetPitch(); ptr = (LPBYTE)CSegImg->GetBits(); int height = CSegImg->GetHeight(); int width = CSegImg->GetWidth(); for (int j=1;j<height-1;j++) { for (int i=1;i<width-1;i++) { int sum = 0; int pr = 0; for ( int m=j-1; m<j+2; m++) { for (int n=i-1; n<i+2; n++) { sum += ptr [ m*p + n] * core[pr++] ; } } sum/=8; if (sum > 255) sum = 255; if (sum <0) sum = 0; ptr [ j*p+i ] = sum; } } for ( int m=0; m<height; m++) { for (int n=0; n<width; n++) { BYTE xx; xx = ptr [ m*p + n]; } } }
|
分块大津阈值
实现对于一个给定的块的大津阈值法操作
r、c、x表示进行操作的范围为第r到r+x行,c到c+x列
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
| void CSegmentation::otsu(int r,int c,int x) { int grayhis[256]; int thresigma[256]; memset(grayhis,0,1024); memset(thresigma,0,1024); LPBYTE ptr; int p = CSegImg->GetPitch(); ptr = (LPBYTE)CSegImg->GetBits(); for(int i=r;i<r+x;i++) { for(int j=c;j<c+x;j++) { BYTE gray = ptr[i*p+j]; grayhis[gray]++; } } int l=0,h=255; while(grayhis[l]==0) l++; while(grayhis[h]==0) h--; for(int t=l+1;t<h-1;t++) { int PA=0,PB=0; for(int i=l;i<t;i++) PA+=grayhis[i]; for(int i=t;i<=h;i++) PB+=grayhis[i]; int miua=0,miub=0; for(int i=l;i<t;i++) miua+=(i*grayhis[i]); for(int i=t;i<=h;i++) miub+=(i*grayhis[i]); miua/=PA; miub/=PB; int sigmaa=0,sigmab=0; for(int i=l;i<t;i++) sigmaa+=((i-miua)*(i-miua)*grayhis[i]); for(int i=t;i<=h;i++) sigmab+=((i-miub)*(i-miub)*grayhis[i]); sigmaa/=PA; sigmab/=PB; int sigma=PA*sigmaa+PB*sigmab; thresigma[t]=sigma; } int thre=0,mint=INT_MAX; for(int i=l+1;i<h-1;i++) { if(thresigma[i]<mint) { mint=thresigma[i]; thre=i; } } for(int i=r;i<r+x;i++) { for(int j=c;j<c+x;j++) { if(ptr[i*p+j]<thre) ptr[i*p+j]=0; else ptr[i*p+j]=255; } } }
|
对总体进行分块后使用大津阈值
1 2 3 4 5 6 7 8 9
| void CSegmentation::Seg() { smoothing(); for(int i=0;i<6;i++) { for(int j=0;j<6;j++) otsu(i*79,j*79,79); } }
|