数字图像处理实验——图像分割

图像分割实验

Lab4

一、 实验目的

  1. 实验目标 设计图像分割算法完成实验图像的分割,分割结果“米粒”像素标记为 255,“背 景”像素标记为 0。

  2. 具体要求:

    (1)程序使用 C++语言编写,集成开发环境可以选择 vs 或 Qt,核心代码不允许直接调 用库函数实现,不允许使用 opencv 等第天天;

    (2)独立完成实验,自由设计处理流程和选择算法;

    (3)分割结果以 BMP 格式文件保存,完成实验报告。

  3. 提示 此实验图像存在背景光照不均匀的现象,在设计分割算法时应该加以考虑。

二、 处理流程和算法设计

处理流程

算法设计:

  1. 先通过均值滤波,消除图像噪声,该图像没有特别明显的会产生干扰的噪声,但尝试后发现平滑可以起到一定效果。具体说明见结果分析。

  2. 对图像进行分块。由于图像存在背景光照不均匀现象,图像下方的背景色比上方的小,所以将图像进行分块,不同的块使用不同的阈值。考虑到图像大小为474×474像素,将整个图像分为79×79的36个小块。

  3. 对每一小块使用大津阈值法,计算出阈值后直接对该块进行分类。

三、 实验及结果分析

实验结果:

结果分析:

  1. 使用均值滤波:图像中看似会对图像分割产生影响的噪声不多,但实验发现滤波还是能产生很大效果。我只尝试了3×3卷积核的均值滤波,感觉可以使用更大的卷积核。

​ 左侧为未滤波的分割结果,可以看出存在少量噪声的干扰。而经过滤波后这些干扰消失了。

  1. 使用分块后计算阈值:该图像存在背景光照不均匀现象,图像下方的背景色比上方的小,如果对整个图像计算阈值,会让上方和下方像素对阈值比较敏感。

​ 左侧为未分块计算阈值后的分割结果,可以看出对于图像下方的影响较大,但对于上方产生的影响不大,由此 可以得出分成36块其实有点多,分为上中下三个部分可能就可以达到类似效果。

  1. 总体而言,该算法没有明显不足,可以很好地实现这个图像的分割。

四、 具体实现

均值滤波

均值滤波的实现比较简单,即使用一个全为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*width + n] * core[pr++] ;*/
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);
}
}