数字图像处理相关实验总结(图像滤波,分割,旋转、编码等)

本文总结了数字图像处理的相关实验,重点介绍了Huffman编码的过程,包括统计像素概率、构建Huffman树以及编码写入文件的实现。同时,提到了解码程序的编程思路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

hufman编码是一种无损最优编码

编程思路是:先 统计像素概率,再构建hufman树,遍历树,取出全部像素和对应编码,在构建缓冲区,以八位二进制数据写入文件。

预先定义的一些结构体和函数:

struct TreeNode {
	float pval;
	short pixval;
	TreeNode *left;
	TreeNode *right;
	TreeNode(float x1,int x2) : pval(x1),pixval(x2), left(NULL), right(NULL) {}
	TreeNode(float x1) : pval(x1), pixval(-1), left(NULL), right(NULL) {}
	TreeNode(TreeNode* x1) : pval(x1->pval), pixval(x1->pixval), left(x1->left), right(x1->right) {}
};
TreeNode* CreatHuffman(float *a, int n) {
	int i, j;
	struct TreeNode **b, *q;
	int size=0;              //图像存在的像素值的个数(可能小于256)
	for (i = 0;i < n;++i) {
		if (a[i] != 0)
			size++;
	}
	b = (TreeNode**)malloc(size * sizeof(TreeNode));
	for (i = 0,j = 0; i < n; i++) //初始化b指针数组,使每个指针元素指向a数组中对应的元素结点  
		if(a[i]!=0){
			b[j] = new TreeNode(a[i],i);
			b[j]->left = b[j]->right = NULL;
			j++;
		}
	for (i = 1; i < size; i++)//进行 n-1 次循环建立哈夫曼树  
	{
		//k1表示森林中具有最小权值的树根结点的下标,k2为次最小的下标  
		int k1 = -1, k2;
		for (j = 0; j < size; j++)//让k1初始指向森林中第一棵树,k2指向第二棵  
		{
			if (b[j] != NULL && k1 == -1)
			{
				k1 = j;
				continue;
			}
			if (b[j] != NULL)
			{
				k2 = j;
				break;
			}
		}
		for (j = k2; j < size; j++)//从当前森林中求出最小权值树和次最小  
		{
			if (b[j] != NULL)
			{
				if (b[j]->pval < b[k1]->pval)
				{
					k2 = k1;
					k1 = j;
				}
				else if (b[j]->pval < b[k2]->pval)
					k2 = j;
			}
		}
		//由最小权值树和次最小权值树建立一棵新树,q指向树根结点  
		q = (TreeNode* )malloc(sizeof(struct TreeNode));
		q->pval = b[k1]->pval + b[k2]->pval;
		q->pixval = -1;
		q->left = b[k1];
		q->right = b[k2];

		b[k1] = q;//将指向新树的指针赋给b指针数组中k1位置  
		b[k2] = NULL;//k2位置为空  
	}
	free(b); //删除动态建立的数组b  
	return q;
}
map<unsigned char, string> pixencode;
vector<int> inorderTraversal(TreeNode* root,string x) {
	vector<int> val;
	if (!root)
		return val;

	vector<int> tmp = inorderTraversal(root->left,x+'0');
	if (!tmp.empty())
		for (int i = 0;i < tmp.size();i++)
			val.push_back(tmp[i]);
	if (root->pixval != -1) {
		pixencode.insert(pair<unsigned char, string>(root->pixval, x));
	}
	val.push_back(root->pval);
	vector<int> tmp1 = inorderTraversal(root->right,x+'1');
	if (!tmp1.empty())
		for (int i = 0;i < tmp1.size();i++)
			val.push_back(tmp1[i]);
	return val;
}

pair<unsigned char, unsigned int> StringBin2Int(string tmp) {
	unsigned char size=0;
	unsigned int num=0;
	while (tmp[0] == '0') {
		size++;
		tmp = string(tmp.begin() + 1, tmp.end());
	}
	while (tmp.size()) {
		if (tmp[0] == '1') {
			num = num * 2;
			num++;
		}
		else {
			num = num * 2;
		}
		tmp = string(tmp.begin() + 1, tmp.end());
	}
	pair<unsigned char, unsigned int> data;
	data.first = size;
	data.second = num;
	return data;

}
string intnum2string(unsigned char zeronum, unsigned int  intnum) {
	string tmp = "";
	while (intnum) {
		if (intnum % 2 == 0) {
			tmp = '0' + tmp;
		}
		else {
			tmp = '1' + tmp;
		}
		intnum = intnum / 2;
	}
	while (zeronum--) {
		tmp = '0' + tmp;
	}
	return tmp;
}

 

解码程序: 

void CDemoView::Onhufencode()
{
	// TODO: 在此添加命令处理程序代码
	CDemoDoc *pDoc = GetDocument();
	HDIB dib = pDoc->GetHDIB();

	LPSTR	lpDIB = (LPSTR) ::GlobalLock((HGLOBAL)dib);
	int width = ::DIBWidth(lpDIB);
	int height = ::DIBHeight(lpDIB);
	LPBITMAPINFOHEADER phead = (LPBITMAPINFOHEADER)lpDIB;
	int biBitCount = phead->biBitCount / 8;
	int lineByte = (width *biBitCount + 3) / 4 * 4;
	unsigned char *lpDIBBits = (unsigned char *)::FindDIBBits(lpDIB);
	int palSize = ::PaletteSize((LPSTR)lpDIB);      //调色板尺寸
	float pixnum[256];
	for (int i = 0;i < 256;++i) {
		pixnum[i] = 0;
	}
	for (int i = 0;i < height;++i) {
		for (int j = 0;j < width;++j) {
			for (int z = 0;z < biBitCount;++z) {
				pixnum[*(lpDIBBits + i * lineByte + j * biBitCount + z)]++;
			}
		}
	}
	int pixsum = width * height * biBitCount;

	for (int i = 0;i < 256;++i) {
		pixnum[i] = pixnum[i] / pixsum;	
	}
	TreeNode *Node = CreatHuffman(pixnum, 256); //构建huffman二叉树
	string binst;
	inorderTraversal(Node, binst);
	int sumByte = 0;  //原图像Byte大小
	int EncodeByte = 0; //压缩后图像Byte大小
	sumByte += 40 + palSize;
	sumByte += height * lineByte;
	ofstream imagefile("D:\\Courseware\\数字图像处理\\图象编程\\图象编程\\image.bin", ios::binary);
	if (!imagefile) {
		cerr << "open error" << endl;
		abort();//退出程序

	}
	short tablesize = (short)pixencode.size();
	imagefile.write((char*)&height,sizeof(int));
	imagefile.write((char*)&width, sizeof(int));
	imagefile.write((char*)&biBitCount, sizeof(int));
	imagefile.write((char*)&tablesize, sizeof(short)); //huffman树数据大小
	EncodeByte += 14; //加上写入数据大小
	map<unsigned char, string>::iterator iter;
	//存储huffman数数据 数据格式: 像素数据   字符串前零的数量 后面字符串对应的int
	for (iter = pixencode.begin();iter != pixencode.end();++iter) {
		pair<unsigned char, unsigned int> data;
		data = StringBin2Int(iter->second);
		unsigned char size = data.first;
		unsigned int num = data.second;
		imagefile.write((char*)&iter->first, sizeof(unsigned char));
		imagefile.write((char*)&size, sizeof(unsigned char));
		imagefile.write((char*)&num, sizeof(unsigned int));
		EncodeByte += 6;//加上写入数据大小
	}
	int i = 0, j = 0, z = 0;
	int a = *(lpDIBBits + i * lineByte + j * biBitCount + z);
	string datastring= pixencode[*(lpDIBBits + i * lineByte + j * biBitCount + z)];
	z++;
	if (biBitCount == 1) {
		z = 0;
		j++;
	}
	int size;    //bit数,需凑齐八位写入文件
	while (1) {
		a= *(lpDIBBits + i * lineByte + j * biBitCount + z);
		datastring = datastring + pixencode[*(lpDIBBits + i * lineByte + j * biBitCount + z)];//像素1。。2。。
		size = datastring.size();
		while (size >= 8) {
			string tmpdata(datastring.begin() , datastring.begin() + 8);
			char todata = 0;
			for (int k = 0;k < 8;++k) {
				if (tmpdata[k] == '1') {
					todata *=2;
					todata++;
				}
				else {
					todata *= 2;
				}
					
			}
			imagefile.write((char*)&todata, sizeof(char));
			EncodeByte++;
			datastring = string(datastring.begin() + 8, datastring.end());
			size = datastring.size();
		}
		z++;
		if (z == biBitCount) {
			z = 0;
			j++;
			if (j == width) {
				j = 0;
				i++;
				if (i == height) {
					break;
				}
			}
		}
	}
	imagefile.close();
	CString string;
	float ratio = (float)sumByte / EncodeByte;
	string.Format("图像压缩率:%3f%%", ratio * 100);
	::MessageBox(0, string, "dataMessage", MB_OKCANCEL);
}

解码程序:

map<string, unsigned char> pixdecode;
void CDemoView::Onhuffmandecode()
{
	// TODO: 在此添加命令处理程序代码

	CDemoDoc *pDoc = GetDocument();
	HDIB dib = pDoc->GetHDIB();
	LPSTR	lpDIB = (LPSTR) ::GlobalLock((HGLOBAL)dib);

	LPBITMAPINFOHEADER phead = (LPBITMAPINFOHEADER)lpDIB;
	ifstream imagefile("D:\\Courseware\\数字图像处理\\图象编程\\图象编程\\image.bin", ios::binary);
	int height, width, biBitcount;
	/*读入长,高,像素字节数*/
	imagefile.read((char*)&height, sizeof(int));
	imagefile.read((char*)&width, sizeof(int));
	imagefile.read((char*)&biBitcount, sizeof(int));
	
	int palSize = 0;
	if (biBitcount == 1) //灰度图像调色板尺寸1024
		palSize = 1024;
	int lineByte = (width * biBitcount + 3) / 4 * 4;

	unsigned char *lpDIBBits = (unsigned char *)::FindDIBBits(lpDIB);
	HANDLE dibNew = ::GlobalAlloc(GHND, sizeof(BITMAPINFOHEADER) + palSize + height * lineByte);
	LPSTR lpDIBNew = (LPSTR) ::GlobalLock(dibNew);
	::memcpy((unsigned char*)lpDIBNew, (unsigned char*)lpDIB, sizeof(BITMAPINFOHEADER) );
	LPBITMAPINFOHEADER pheadNew = (LPBITMAPINFOHEADER)lpDIBNew;
	/*修改信息头数据*/
	pheadNew->biWidth = width;
	pheadNew->biHeight = height;
	pheadNew->biSizeImage = height * lineByte;
	unsigned char *lpDIBBitsNew = (unsigned char *)::FindDIBBits(lpDIBNew);
	if (biBitcount == 1) {          //如果是灰度图像,加入调色板
		unsigned char palette[1024];//定义调色板
		for (int i = 0;i < 256;i++)
		{
			*(palette + i * 4 + 0) = i;
			*(palette + i * 4 + 1) = i;
			*(palette + i * 4 + 2) = i;
			*(palette + i * 4 + 3) = 0;
		}
		::memcpy((unsigned char*)lpDIBNew + sizeof(BITMAPINFOHEADER), (unsigned char*)palette, 1024);
	}
	/*读取huffman数据*/
	unsigned short tablesize;
	imagefile.read((char*)&tablesize, sizeof(short));
	unsigned char pixnum, zeronum;
	unsigned int intnum;
	string tmpdata;
	for (int i = 0;i < tablesize;++i) {
		imagefile.read((char*)&pixnum, sizeof(unsigned char));
		imagefile.read((char*)&zeronum, sizeof(unsigned char));
		imagefile.read((char*)&intnum, sizeof(unsigned int));
		tmpdata = intnum2string(zeronum, intnum);
		pixdecode.insert(pair<string, unsigned char>(tmpdata, pixnum));
	}
	//读文件赋值//
	char data;
	int i = 0, j = 0, z = 0;
	int num = 0;
	string strdata;
	string pixstring; //存储字节编码对应的字符串
	string tmp;         //读取的八位数据对应的string值
	while (1) {
		imagefile.read((char*)&data, sizeof(char));
		unsigned char dataint = (unsigned char)data;
		tmp = "";
		for (int i = 0;i < 8;++i) {	//转化为string,并加到strdata中
			if (dataint % 2 == 0) {
				tmp = '0' + tmp;
			}
			else {
				tmp = '1' + tmp;
			}
			dataint /= 2;
		}
		strdata = strdata + tmp;

		int size = strdata.size();
		while (1) {

			pixstring = pixstring + strdata[num];           //从最后一位向前扩充
			num++;
			if (pixdecode.count(pixstring)) {             //解码成功,赋值
				int a = pixdecode[pixstring];
				*(lpDIBBitsNew + i * lineByte + j * biBitcount + z) = pixdecode[pixstring];

				z++;
				if (z == biBitcount) {
					z = 0;
					j++;
					if (j == width) {
						j = 0;
						i++;
						if (i == height)
							break;
					}
				}
				strdata = string(strdata.begin() + pixstring.size(), strdata.end()); //更新pixstring和num、size
				pixstring = "";
				size = strdata.size();
				num = 0;
			}
			if (num == size) //搜索到最高位时,退出循环
				break;
		}
		if (i == height)
			break;
	}

	imagefile.close();



	
	::GlobalUnlock(dib);
	::GlobalUnlock(dibNew);

	CMainFrame* pFrame = (CMainFrame *)(AfxGetApp()->m_pMainWnd);
	pFrame->SendMessage(WM_COMMAND, ID_FILE_NEW);

	CDemoView* pView = (CDemoView*)pFrame->MDIGetActive()->GetActiveView();
	CDemoDoc* pDocNew = pView->GetDocument();

	pDocNew->ReplaceHDIB((HDIB)dibNew);
	pDocNew->InitDIBData();
	pDocNew->UpdateAllViews(pView);
	Invalidate();
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值