智能系统专业实验(二):MRF图像分割实验

  • 实验目的

掌握马尔科夫随机场(MRF)的算法原理,通过 Markov 随机场(MRF)实现图像的分割。

  • 实验基本原理及步骤(或方案设计及理论计算)

(1)基本原理

LD是两个符号集:\large L=\left \{ 1,2,\cdots ,L \right \}\large D=\left \{ 1,2,\cdots ,D \right \}\large S=\left \{ 1,2,\cdots ,N \right \}是下标集合,令X和Y是两个随机场,他们的状态空间分别是LD,这样对于\large \forall i\in S\large X_{i}\in L,Y_{i}\in D。令x表示X的一组配置,\large \chi是所有可能配置的集合,即\large \chi =\left \{ x=\left ( x_{1},\cdots ,x_{N} \right )|x_{i}\in L,i\in S \right \};同样,令y是Y的一组配置,y是所有可能配置的集合,则可得\large y=\left \{ y=\left ( t_{1},\cdots ,y_{N} \right |y_{i}\in D,i\in S) \right \}。用X表示图像类别标识,Y表示图像灰度。

     MRF理论

MRF理论提供了建模上下文依赖实体的一种方式,实体包括图像像素和相关特征等。在MRF中,S中的位置通过邻域系统相互关联,邻域系统定义为\large N=\left \{ N_{i},i\in S \right \},这里\large N_{i}是位置 i 的邻域集,\large i\notin N_{i}。如果满足以下条件:

\large \left\{\begin{matrix} p\left ( x \right )> 0,\forall x\in \chi \\ p\left ( x_{i}|x_{S-\left \{ i \right \}} \right )=p\left ( x_{i}|x_{N_{i}} \right ) \end{matrix}\right.          (1)

则随机场X是S上关于邻域系统N的一个马尔科夫随机场(MRF)。由Hammersley-Clifford定理,MRF能够等价描述为Gibbs分布,则有

\large p\left ( x \right )=Z^{-1}exp\left ( -U\left ( x \right ) \right )          (2)

这里Z是归一化常数;U\left ( x \right )为能量函数,U\left ( x \right )=-\beta \sum _{c\in C}V_{C}\left ( x \right )为所有可能基团C的基团势能V_C\left ( x \right )之和,一个基团C被定义为S中位置的子集,V_{C}\left ( x \right )的值依赖于基团C的局部配置。

MRF-MAP估计

\widehat{x}是图像真实标号的估计,由最大后验概率(MAP)准则有

\widehat{x}=\underset{x\in \chi }{argmax}\left \{ P\left ( y|x \right ) P\left ( x \right )\right \}          (3)

由式(3)可知,要得到\widehat{x},需要首先计算类别的先验概率和观测量的似然概率。

由于x被认为是MRF的一个实现,则他的先验概率表示为式(2)。又由准似然估计,式(2)可近似表示为

\large p\left ( x_{i} \right )=\frac{exp\left ( -u\left ( x_{i} \right ) \right )}{\sum _{x_{i}\in L}exp\left ( -u\left ( x_{i} \right ) \right )}          (4)

由Potts模型有:\large V_{C}\left ( x_{i} \right )=\delta \left ( x_{i},x_{j} \right )-1     \large j\in N_{i},则

\large u\left ( x_{i} \right )=-\beta _{i}\sum _{c\in C}V_{c}\left ( x_{i} \right )=-\beta _{i}\sum _{j\in N_{i}}\left [ \delta \left ( x_{i},x_{j} \right )-1 \right ]          (5)

其中,\large \delta \left ( x_{i},x_{j} \right )=\left\{\begin{matrix} 1,x_{i}=x_{j}\\ 0 ,x_{i}\neq x_{j} \end{matrix}\right.

在给定类别标号x_{i}=l时,通常认为像素强度值y_{i}服从参数为\theta _{i}=\left \{ u_{l},\sigma _{l} \right \}高斯分布,

y_{i}=\frac{1}{\sqrt{2\pi }\sigma _{l}}exp\left ( \frac{\left ( y_{i}-u_{l} \right )^{2}}{2\sigma _{l}^{2}} \right )

基于最大后验概率(MAP)准则的图像分割,就是求标记集X,使得关于X的后验概率分布最大。考虑计算效率问题,采用条件迭代模式(ICM)方法。ICM算法是一个迭代算法,通过逐元的最大化条件概率实现像元值更新,即:

\widehat{x}_{i}=arg\underset{x_{i}\in \left \{ 1,2,\cdots ,C \right \}}{max}\left \{ f\left ( y_{i}|x_{i} \right ) *f\left ( x_{i}|x_{x_{N_{i}}} \right )\right \},i\in S          (7)

(2)算法步骤

  1. 变量说明

 x_{i}像素点 i 的类别标号;

 y_{i}像素点 i 的像素值;

 L  最大类别数;

 D  像素最大取值(灰度图像为255);

 u_{l }第l类区域的均值;

 \sigma _{l }第l类区域的标准方差;

  \beta平滑参数(取值通常在0.8 – 1.4);

 N_{i} 像素点 的邻域。

迭代过程

Step1:给定图像初始分割(通过阈值法或聚类方法);

Step2:由当前分割更新\theta _{_{i}}=\left \{ u_{l },\sigma _{l }\right \}u_{l}\sigma _{l }分别是当前第 l 类区域的均值和标准方差;

Step3:由当前图像参数和上次迭代的分割结果,并根据式(7)计算每一点最大可能的类别;

Step4:判断是否收敛或达到了最高迭代次数,如果满足则退出;否则返回Step2,进行下一次迭代。

  • 实验结果分析及回答问题(或测试环境及测试结果)
  1. 原图

智能系统专业实验(二):MRF图像分割实验_第1张图片智能系统专业实验(二):MRF图像分割实验_第2张图片

 

  1. 聚类结果图

智能系统专业实验(二):MRF图像分割实验_第3张图片智能系统专业实验(二):MRF图像分割实验_第4张图片

 

如上图最终聚类结果图,本次实验一共设置了三个聚类中心。初始分割由阈值法确定,所以最大迭代次数需要设置的更大一些。

  • 实验代码
#include
#include
#include
#include
#include 
#define max_pixel 99999999
#define max_k 50

#define imageW 320
#define imageH 240
unsigned char L[3] = {0, 1, 2};
unsigned char classes[imageH][imageW];
float p_w[imageW*imageH][3];
float p_s_w[imageW*imageH][3];
int ave[3];
float sig[3];
int num[3];

int bmpHeight, bmpWidth, biBitCount, k_num;
int label[max_pixel],rec[max_k];
int center[max_k][3];
unsigned char *pBmpBuf;
RGBQUAD *pColorTable;

void mrf(int image[],int h,int w,int itr){

	unsigned int i, j, k, l;
	unsigned maxiter = 20; 
	for(i = 0; i < w*h; i++){
		unsigned int r = i / w;
		unsigned int c = i % w;
		classes[r][c] = image[i] / 86;
	}
	for(i = 0; i < maxiter; i++){
		//计算P(w)
		for(j = 0; j < w*h; j++){
			unsigned int r = j / w;
			unsigned int c = j % w;
			for(l = 0; l < 3; l++){
				p_w[j][l] = 0;
				if(r >= 1 && c >= 1){
					if(classes[r][c] != classes[r-1][c-1]){
						p_w[j][l] -= 1;
					}	
				}
				if(r >= 1){
					if(classes[r][c] != classes[r-1][c]){
						p_w[j][l] -= 1;
					}
				}
				if(r >= 1 && c + 1 < w){
					if(classes[r][c] != classes[r-1][c+1]){
						p_w[j][l] -= 1;
					}	
				} 
				if(c + 1 < w){
					if(classes[r][c] != classes[r][c+1]){
						p_w[j][l] -= 1;
					}
					
				}
				if(r + 1 < h && c + 1 < w){
					if(classes[r][c] != classes[r+1][c+1]){
						p_w[j][l] -= 1;
					}
				}
				if(r + 1 < h){
					if(classes[r][c] != classes[r+1][c]){
						p_w[j][l] -= 1;
					}
				}
				if(r + 1 < h && c >= 1){
					if(classes[r][c] != classes[r+1][c-1]){
						p_w[j][l] -= 1;
					}
				}
				if(c >= 1){
					if(classes[r][c] != classes[r][c-1]){
						p_w[j][l] -= 1;
					}
				}
				p_w[j][l] = 0 - 0.99 * p_w[j][l];
				p_w[j][l] = exp(p_w[j][l]);
			}
			for(l = 0; l < 3; l++){
				float sum = p_w[j][0] + p_w[j][1] + p_w[j][2];
				p_w[j][l] = p_w[j][l] / sum;
			}
		}
		
		//计算p_s_w
		for(l = 0; l < 3; l++){
			ave[l] = 0;
			sig[0] = 0;
			num[l] = 0;
		}
		for(j = 0; j < h; j++){
			for(k = 0; k < w; k++){
				for(l = 0; l < 3; l++){
					if(l == classes[j][k]){
						ave[l] += image[j * imageW + k];
						num[l] += 1;
					}
				}
			}
		}
		for(l = 0; l < 3; l++){
			ave[l] /= num[l];
		}
		for(j = 0; j < h; j++){
			for(k = 0; k < w; k++){
				for(l = 0; l < 3; l++){
					if(l == classes[j][k]){
						sig[l] += pow((image[j * w + k] - ave[l]), 2);;
					}
				}
			}
		}
		for(l = 0; l < 3; l++){
			sig[l] /= num[l];
		}
		for(j = 0; j < w*h; j++){
			for(l = 0; l < 3; l++){
				p_s_w[j][l] = 0;
				p_s_w[j][l] = 1 / (sqrt(2*3.14) * sqrt(sig[l]));
				p_s_w[j][l] = p_s_w[j][l] * exp(-pow(image[j] - ave[l], 2) / sig[l]);
			}
		}
		for(j = 0; j < w*h; j++){
			for(l = 0; l < 3; l++){
				p_w[j][l] = p_w[j][l] * p_s_w[j][l];

			}
		}
		float maxVal = 0;
		for(j = 0; j < w*h; j++){
			unsigned int r = j / w;
			unsigned int c = j % w;
			for(l = 0; l < 3; l++){
				if(maxVal < p_w[j][l]){
					classes[r][c] = l;
					maxVal = p_w[j][l];
				}
			}
		}
	}
	ave[0]=62;ave[1]=157;ave[2]=228;
	for(i = 0; i < h; i++){
		for(j = 0; j < w; j++){
			for(l = 0; l < 3; l++){
				if(classes[i][j] == l){
					image[i * w + j] = ave[l];
					break;
				}
			} 
		}
	}	
}

int main(){
	const char src[] = "lena.bmp";
	const char dst[] = "segResultTest.bmp";
	k_num = 3;
	memset(label, 0, sizeof(label));
	memset(center, 0, sizeof(center));
	memset(rec, 0, sizeof(rec));
	
	//读取 bmp 文件
	FILE *fp = fopen(src, "rb");	
	if (fp == 0)
		return 0;
	fseek(fp, sizeof(BITMAPFILEHEADER), 0);
	
	BITMAPINFOHEADER head;
	fread(&head, 40, 1, fp);
	bmpHeight = head.biHeight;
	bmpWidth = head.biWidth;
	biBitCount = head.biBitCount;
	
	fseek(fp, sizeof(RGBQUAD), 1);
	
	int LineByte = (bmpWidth*biBitCount / 8 + 3) / 4 * 4;
	pBmpBuf = new unsigned char[LineByte*bmpHeight];
	fread(pBmpBuf, LineByte*bmpHeight, 1, fp);
	fclose(fp);
	//将 24 位真彩图灰度化并保存
	FILE *fp1 = fopen(dst, "wb");
	if (fp1 == 0)
	return 0;
	int LineByte1 = (bmpWidth * 8 / 8 + 3) / 4 * 4;
	//修改文件头,其中有两项需要修改,分别为 bfSize 和 bfOffBits
	BITMAPFILEHEADER bfhead;
	bfhead.bfType = 0x4D42;
	bfhead.bfSize = 14 + 40 + 256 * sizeof(RGBQUAD)+LineByte1*bmpHeight;
	bfhead.bfReserved1 = 0;
	bfhead.bfReserved2 = 0;
	bfhead.bfOffBits = 14 + 40 + 256 * sizeof(RGBQUAD);//修改偏移字节数
	fwrite(&bfhead, 14, 1, fp1); //将修改后的文件头存入 fp1;
	BITMAPINFOHEADER head1;
	head1.biBitCount = 8; //将每像素的位数改为 8
	head1.biClrImportant = 0;
	head1.biCompression = 0;
	head1.biClrUsed = 0;
	head1.biHeight = bmpHeight;
	head1.biWidth = bmpWidth;
	head1.biPlanes = 1;
	head1.biSize = 40;
	head1.biSizeImage = LineByte1*bmpHeight;//修改位图数据的大小
	head1.biXPelsPerMeter = 0;
	head1.biYPelsPerMeter = 0;
	fwrite(&head1, 40, 1, fp1); //将修改后的信息头存入 fp1;
	pColorTable = new RGBQUAD[256];
	for (int i = 0; i < 256; i++){	
		pColorTable[i].rgbRed = i;
		pColorTable[i].rgbGreen = i;
		pColorTable[i].rgbBlue = i; //是颜色表里的 B、G、R 分量都相等,且等于索引值
	}
	fwrite(pColorTable, sizeof(RGBQUAD), 256, fp1); //将颜色表写入 fp1
	//写位图数据
	unsigned char *newBmp;
	newBmp = new unsigned char[LineByte1*bmpHeight];
	int c = 0;
	for (int i = 0; i < bmpHeight * bmpWidth;i++,c++)
		label[i] = -1;
	int rgbMap[bmpHeight * bmpWidth][3];
	for (int i = 0; i < bmpHeight;i++){ //取位图 rgb 三通道数据
		for (int j = 0; j < bmpWidth;j++){
			unsigned char *tmp;
			tmp = pBmpBuf + i * LineByte + j * 3;
			rgbMap[i * bmpWidth + j][0] = int(*(tmp));
			rgbMap[i * bmpWidth + j][1] = int(*(tmp+1));
			rgbMap[i * bmpWidth + j][2] = int(*(tmp+2));
		}
	}
	
	int image[bmpHeight*bmpWidth];
	for (int i = 0; i < bmpHeight * bmpWidth;i++){
		image[i] = rgbMap[i][0]*0.299 + rgbMap[i][1]*0.587 + rgbMap[i][2]*0.114;
	}
	mrf(image, bmpHeight, bmpWidth,30);
	
	for (int i = 0; i < bmpHeight; i++){
		for (int j = 0; j < bmpWidth; j++){
			unsigned char *pb;
			pb = newBmp + i * LineByte1 + j;
			*pb = image[i * bmpWidth + j];
		}
	}
	fwrite(newBmp, LineByte1*bmpHeight, 1, fp1);
	fclose(fp1);
	system("pause");
	return 0;
}	

 

你可能感兴趣的:(大作业)