⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 coding.cpp

📁 电子书《数字图像处理学》Visual C++实现 郎锐编写 所附源码
💻 CPP
📖 第 1 页 / 共 5 页
字号:
					if (iMap[k] == j)
					{
						// 映射到节点j+1
						iMap[k] = j + 1;
					}
					else if (iMap[k] == j + 1)
					{
						// 映射到节点j
						iMap[k] = j;
					}
				}
			}
			else
			{
				// 退出循环
				break;
			}
		}
	}

	//////////////////////////////////////////////////////////
	// 对DIB进行编码压缩
	
	// 位掩码
	unsigned char Mask[8] = {128, 64, 32, 16, 8, 4, 2, 1};
	CString strTemp = "";

	// 打开文件
	CFile file;
	file.Open(strPath, CFile::modeCreate | CFile::modeReadWrite);

	// 对各像素进行编码
	for (i = 0; i < lHeight; i ++)
	{
		for (j = 0; j < lLineBytes; j ++)
		{
			unsigned char V = *((unsigned char *)lpDIBBits + lLineBytes * i + j);
			strTemp += m_strCode[V];
			int len = strTemp.GetLength();
			int loop = 0;
			
			// 保存编码后的数据 
			do{
				unsigned char T = 0;
				for (k = 0; k < min(8, strTemp.GetLength()); k++)
				{
					if (strTemp.Mid(k, 1) == "1")
						T |= Mask[k];
				}
				file.Write(&T, 1);
				loop++;
				len -= 8;
				if (strTemp.GetLength() < 8)
					break;
				else
					strTemp = strTemp.Right(strTemp.GetLength() - 8);
			}while (len >= 8);
		}
	}
	
	// 关闭文件
	file.Close();

	// 解除锁定
	::GlobalUnlock((HGLOBAL) hDIB);

	// 恢复光标
	EndWaitCursor();

	// 返回TRUE
	return TRUE;
}


/*************************************************************************
 *
 * 函数名称:
 *   Shannon_Fannon()
 *
 * 参数:
 *	 HDIB	 hDIB			- 待编码DIB句柄
 *   CString strPath	    - 要装载的文件路径
 *
 * 返回值:
 *   BOOL               - 成功返回True,否则返回False。
 *
 * 说明:
 *   该函数对指定DIB位图进行仙农-弗诺编码 
 *	 
 *************************************************************************/

BOOL CCoding::Shannon_Fannon(HDIB hDIB, CString strPath)
{
	// 字符串变量
	CString	str;
	
	// 中间变量
	LONG	iTemp;
	
	// 当前编码区间的频率和
	FLOAT	fTotal = 0;	
	
	// 计数(编码完成的个数)
	LONG	iCount = 0;
	
	// 频率和
	FLOAT	fSum;
	
	// 起始位置
	LONG	iStart;
	
	// 指向布尔型数组的指针
	BOOL	bFinished[256];
	
	// 循环变量		
	LONG i;
	LONG j;
	LONG k;
	
	// 灰度计数
	int nNs[256];

	// 灰度概率分布
	float fPs[256];

	// 映射关系
	int iMap[256];
	
	// Huffman编码
	CString m_strCode [256];

	// 变量初始化
	memset(nNs, 0, sizeof(nNs));

	// 指向DIB的指针
	LPBYTE lpDIB;
	
	// 指向DIB象素指针
	LPBYTE lpDIBBits;
	
	// 锁定DIB
	lpDIB = (LPBYTE) ::GlobalLock((HGLOBAL) hDIB);

	// 找到DIB图像象素起始位置
	lpDIBBits = m_clsDIB.FindDIBBits(lpDIB);
	
	// 判断是否是24-bpp位图
	if (m_clsDIB.DIBBitCount(lpDIB) != 24)
	{
		// 提示用户
		MessageBox("请先将其转换为24位色位图,再进行处理!", "系统提示" , MB_ICONINFORMATION | MB_OK);
		
		// 解除锁定
		::GlobalUnlock((HGLOBAL) hDIB);
		
		// 返回
		return FALSE;
	}
	
	// 更改光标形状
	BeginWaitCursor();

	//////////////////////////////////////////////////////////
	// 计算灰度概率分布
	
	// DIB的宽度
	LONG lWidth = m_clsDIB.DIBWidth(lpDIB);
	
	// DIB的高度
	LONG lHeight = m_clsDIB.DIBHeight(lpDIB);

	// 计算图像每行的字节数
	LONG lLineBytes = WIDTHBYTES(lWidth * 24);

	// 对各像素进行灰度分布统计
	for (i = 0; i < lHeight; i ++)
	{
		for (j = 0; j < lLineBytes; j ++)
		{
			// 对各像素进行灰度统计
			unsigned char V = *((unsigned char *)lpDIBBits + lLineBytes * i + j);
			nNs[V]++;		
		}
	}

	// 计算灰度分布密度
	for(i = 0; i < 256; i++)
		fPs[i] = nNs[i] / (lHeight * lLineBytes * 1.0f);

	// 初始化
	for (i = 0; i < 256; i ++)
	{
		// 初始化映射关系
		iMap[i] = i;
		
		// 初始化为FALSE
		bFinished[i] = FALSE;
		
		// 计算fTotal
		fTotal += fPs[i];
	}

	// 用冒泡法对fPs[]进行排序
	for (j = 0; j < 256 - 1; j ++)
	{
		for (i = 0; i < 256 - j - 1; i ++)
		{
			if (fPs[i] > fPs[i + 1])
			{
				// 互换
				float fTemp = fPs[i];
				fPs[i] = fPs[i + 1];
				fPs[i + 1] = fTemp;
				
				// 更新映射关系
				iTemp = iMap[i];
				iMap[i] = iMap[i+1];
				iMap[i+1] = iTemp;
			}
		}
	}

	//////////////////////////////////////////////////////////
	// 计算仙农-弗诺编码表
	
	// 寻找第一个不为0的概率灰度级
	for (iStart = 0; iStart < 256 - 1; iStart++)
	{
		// 判断概率是否大于0
		if (fPs[iStart] > 0)
			break;
	}
	
	// 初始化变量
	fSum = 0;
	str = "1";
		
	// 开始编码
	while(iCount < 256)
	{
		// 初始化iCount为iStart
		iCount = iStart;
		
		// 循环编码
		for (i = iStart; i < 256; i ++)
		{
			// 判断是否编码完成
			if (bFinished[i] == FALSE)
			{
				// 编码没有完成,继续编码
				
				// fSum加当前出现的频率
				fSum += fPs[i];
				
				// 判断是否超出总和的一半
				if (fSum > fTotal/2.0)
				{
					// 超出,追加的字符改为0
					str = "0";
				}
				
				// 编码追加字符1或0
				m_strCode[iMap[i]] += str;
				
				// 判断是否编码完一段
				if (fSum == fTotal)
				{
					// 完成一部分编码,重新计算fTotal
					
					// 初始化fSum为0
					fSum = 0;
					
					// 判断是否是最后一个元素
					if (i == 256 - 1)
					{
						// 是最后,设置从起始点开始
						j = iStart;
					}
					else
					{
						// 不是最后,设置从下一个点开始
						j = i + 1;
					}
					
					// 保存j值
					iTemp = j;
					str = m_strCode[iMap[j]];
					
					// 计算下一段的fTotal
					fTotal = 0;
					for (; j < 256; j++)
					{
						// 判断是否是同一段编码
						if ((m_strCode[iMap[j]].Right(1) != str.Right(1)) 
							|| (m_strCode[iMap[j]].GetLength() != str.GetLength()))
							break;
						
						// 累加
						fTotal += fPs[j];
					}
					
					// 初始化str为1
					str = "1";
					
					// 判断是否该段长度为1
					if (iTemp + 1 == j)
					{
						// 是,表示该段编码已经完成
						bFinished[iTemp] = TRUE;
					}
				}
			}
			else
			{
				// iCount加1
				iCount ++;
				
				// 计算下一次循环的fTotal
				
				// 初始化fSum为0
				fSum = 0;
				
				// 判断是否是最后一个元素
				if (i == 256 - 1)
				{
					// 是最后,设置从起始点开始
					j = iStart;
				}
				else
				{
					// 不是最后,设置从下一个点开始
					j = i + 1;
				}
				
				// 保存j值
				iTemp = j;
				str = m_strCode[iMap[j]];
				
				// 计算下一段的fTotal
				fTotal = 0;
				for (; j < 256; j++)
				{
					// 判断是否是同一段编码
					if ((m_strCode[iMap[j]].Right(1) != str.Right(1)) 
						|| (m_strCode[iMap[j]].GetLength() != str.GetLength()))
						break;
					
					// 累加
					fTotal += fPs[j];
				}
				
				// 初始化str为1
				str = "1";
				
				// 判断是否该段长度为1
				if (iTemp + 1 == j)
				{
					// 是,表示该段编码已经完成
					bFinished[iTemp] = TRUE;
				}
			}
		}
	}

	//////////////////////////////////////////////////////////
	// 对DIB进行编码压缩
	
	// 位掩码
	unsigned char Mask[8] = {128, 64, 32, 16, 8, 4, 2, 1};
	CString strTemp = "";

	// 打开文件
	CFile file;
	file.Open(strPath, CFile::modeCreate | CFile::modeReadWrite);

	// 对各像素进行编码
	for (i = 0; i < lHeight; i ++)
	{
		for (j = 0; j < lLineBytes; j ++)
		{
			unsigned char V = *((unsigned char *)lpDIBBits + lLineBytes * i + j);
			strTemp += m_strCode[V];
			int len = strTemp.GetLength();
			int loop = 0;
			
			// 保存编码后的数据 
			do{
				unsigned char T = 0;
				for (k = 0; k < min(8, strTemp.GetLength()); k++)
				{
					if (strTemp.Mid(k, 1) == "1")
						T |= Mask[k];
				}
				file.Write(&T, 1);
				loop++;
				len -= 8;
				if (strTemp.GetLength() < 8)
					break;
				else
					strTemp = strTemp.Right(strTemp.GetLength() - 8);
			}while (len >= 8);
		}
	}
	
	// 关闭文件
	file.Close();

	// 解除锁定
	::GlobalUnlock((HGLOBAL) hDIB);

	// 恢复光标
	EndWaitCursor();

	// 返回TRUE
	return TRUE;
}


/*************************************************************************
 *
 * 函数名称:
 *   DIBToGIF()
 *
 * 参数:
 *   HDIB hDIB	        - DIB句柄
 *   CFile& file        - 要保存的文件
 *   BOOL bInterlace	- 保存方式
 *
 * 返回值:
 *   BOOL               - 成功返回True,否则返回False。
 *
 * 说明:
 *   该函数将256色DIB位图保存为GIF文件。
 *
 *************************************************************************/

BOOL CCoding::DIBToGIF(HDIB hDIB, CFile &file, BOOL bInterlace)
{
	// 循环变量
	LONG	i;
	LONG	j;
	
	// 锁定DIB
	LPBYTE lpDIB = (LPBYTE) ::GlobalLock((HGLOBAL) hDIB);

	// 判断是否是8-bpp位图
	if (m_clsDIB.DIBBitCount(lpDIB) != 8)
	{
		// 提示用户
		MessageBox("请先将其转换为8位色位图,再进行处理!", "系统提示" , MB_ICONINFORMATION | MB_OK);
		
		// 解除锁定
		::GlobalUnlock((HGLOBAL) hDIB);
		
		// 返回
		return FALSE;
	}

	// GIF文件头
	GIFHEADER          GIFH;
	
	// GIF逻辑屏幕描述块
	GIFSCRDESC         GIFS;
	
	// GIF图像描述块
	GIFIMAGE           GIFI;
	
	// GIF编码参数
	GIFC_VAR           GIFCVar;
	
	// 调色板
	BYTE               byGIF_Pal[768];
	
	// 字节变量
	BYTE               byChar;
	
	// 指向BITMAPINFO结构的指针(Win3.0)
	LPBITMAPINFO	   lpbmi;
	
	// 指向BITMAPCOREINFO结构的指针
	LPBITMAPCOREINFO   lpbmc;
	
	// 表明是否是Win3.0 DIB的标记
	BOOL			   bWinStyleDIB;
		
	// 更改光标形状
	BeginWaitCursor();
	
	// 获取DIB高度
	LONG lHeight = m_clsDIB.DIBHeight(lpDIB);
	
	// 获取DIB宽度
	LONG lWidth  = m_clsDIB.DIBWidth(lpDIB);
	
	// 找到DIB图像象素起始位置
	LPBYTE lpDIBBits = m_clsDIB.FindDIBBits(lpDIB);

	// 计算每行字节数
	LONG lWidthBytes = DWORD_WBYTES(lWidth * 8);
	
	// 给GIFCVar结构赋值
	GIFCVar.wWidth     = (WORD)lWidth;
	GIFCVar.wDepth     = (WORD)lHeight;
	GIFCVar.wBits      = m_clsDIB.DIBBitCount(lpDIB);
	GIFCVar.wLineBytes = (WORD)BYTE_WBYTES((DWORD)GIFCVar.wWidth * (DWORD)GIFCVar.wBits);
	
	// 计算颜色数目
	LONG lColors       = 1 << GIFCVar.wBits;
	
	// 获取指向BITMAPINFO结构的指针(Win3.0)
	lpbmi = (LPBITMAPINFO)lpDIB;
	
	// 获取指向BITMAPCOREINFO结构的指针
	lpbmc = (LPBITMAPCOREINFO)lpDIB;
	
	// 判断是否是WIN3.0的DIB
	bWinStyleDIB = IS_WIN30_DIB(lpDIB);
	
	// 给调色板赋值
	if (bWinStyleDIB)
	{
		j = 0;
		for (i = 0; i < lColors; i++)
		{
			// 读取红色分量
			byGIF_Pal[j++] = lpbmi->bmiColors[i].rgbRed;
			
			// 读取绿色分量
			byGIF_Pal[j++] = lpbmi->bmiColors[i].rgbGreen;
			
			// 读取蓝色分量
			byGIF_Pal[j++] = lpbmi->bmiColors[i].rgbBlue;
		}
	}
	else
	{
		j = 0;
		for (i = 0; i < lColors; i++)
		{
			// 读取红色分量
			byGIF_Pal[j++] = lpbmc->bmciColors[i].rgbtRed;
			
			// 读取绿色分量
			byGIF_Pal[j++] = lpbmc->bmciColors[i].rgbtGreen;
			
			// 读取红色分量
			byGIF_Pal[j++] = lpbmc->bmciColors[i].rgbtBlue;
		}
	}
	
	////////////////////////////////////////////////////////////////////////////////////////
	// 开始写GIF文件
	
	// 写GIF文件头
	GIFH.bySignature[0] = 'G';
	GIFH.bySignature[1] = 'I';
	GIFH.bySignature[2] = 'F';
	GIFH.byVersion[0]='8';
	GIFH.byVersion[1]='9';
	GIFH.byVersion[2]='a';
	file.Write((LPBYTE)&GIFH, 6);
	
	// 写GIF逻辑屏幕描述块
	GIFS.wWidth               = GIFCVar.wWidth;
	GIFS.wDepth               = GIFCVar.wDepth;
	GIFS.GlobalFlag.PalBits   = GIFCVar.wBits - 1;
	GIFS.GlobalFlag.SortFlag  = 0x00;
	GIFS.GlobalFlag.ColorRes  = GIFCVar.wBits - 1;
	GIFS.GlobalFlag.GlobalPal = 0x01;
	GIFS.byBackground         = 0x00;
	GIFS.byAspect             = 0x00;
	file.Write(&GIFS, 7);
	
	// 写GIF全局调色板
	file.Write(byGIF_Pal, (lColors * 3));
	
	// 写GIF图像描述间隔符
	byChar = 0x2C;
	file.Write(&byChar, 1);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -