mathmorphology.cpp

来自「visual c++数字图像与图形处理中的光盘内容」· C++ 代码 · 共 1,035 行 · 第 1/2 页

CPP
1,035
字号
/////////////////////////////////////////////////////////////////////////////////
//
// MathMorphology.cpp: implementation of the CMathMorphology class.
//
////////////////////////////////////////////////////////////////////////////////
// 版权所有(2002)
// Copyright(2002)
// 编写者: 向世明
// Author: Xiang Shiming


#include "stdafx.h"
#include "MathMorphology.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
IMPLEMENT_DYNAMIC(CMathMorphology, CImageProcess)
CMathMorphology::CMathMorphology()
{
	m_dwOperation = IMAGE_MATH_MORPHOLOGY_DILATE;
	m_nElementUsed = 1;
	m_pME = NULL;
}

CMathMorphology::~CMathMorphology()
{
	if(m_pME)delete[] m_pME;
	m_pME = NULL;
}

#ifdef _DEBUG
void CMathMorphology::Dump(CDumpContext& dc) const
{
	CImageProcess::Dump(dc);
}

void CMathMorphology::AssertValid() const
{
	CImageProcess::AssertValid();
}
#endif

//nEUsed----pME数组的大小
void CMathMorphology::SetMorphologyElement(const MORPHOLOGYELEMENT* pME, int nEUsed)
{
	ASSERT(pME);
	m_nElementUsed = nEUsed;
	if(m_pME) delete[] m_pME;
	m_pME = new MORPHOLOGYELEMENT[nEUsed];
	for(int i = 0;i < m_nElementUsed;i++) m_pME[i] = pME[i];
}

//数学形态学--膨胀

//lpbyBits32----源像素值, 带回结果值
//x, y, nWidth,  int nHeight, 定义区域的宽度
//nScanWidth,  int nScanHeight, 扫描宽度和扫描高度


BOOL CMathMorphology::Dilate(LPBYTE lpbyBits32,  int x,  int y,  int nWidth,  int nHeight,  int nScanWidth,  int nScanHeight)
{
	
	//第一步, 进行参数合法性检测
	ASSERT(lpbyBits32);
	ASSERT(m_pME);

	
	if((x > (nScanWidth - 1)) || (y > (nScanHeight - 1))) return FALSE;
	m_dwOperation = IMAGE_MATH_MORPHOLOGY_DILATE;

	//有效区域的宽度和高度
	int w = min(nWidth, nScanWidth - x);
	int h = min(nHeight, nScanHeight - y);

	//第二步, 分配内存空间, 最后结果只可能在(-255, +255)之间, 
	//存储蓝色、绿色、红色
	int nSize = w * h;

	//注:避免分配大的存储空间的办法是引入结构元素的分解算法
	//我们这里采用分配大的内存来实现,从而使算法很直观
	//比如, 对于800 * 600的图像
	//2 = sizeof(short);
	//800 * 600 * 2 * 3 + 800 * 600 * 2 * 3 = 5760000 bytes

	//存储源
	short* pcxDataSrc =  new short[(nSize * 3)];
	if (pcxDataSrc == NULL)	return FALSE;

	//存储目标
	short* pcxDataDst = new short[(nSize * 3)];
	if (pcxDataDst == NULL)	return FALSE;


	//第三步, 获取输入图像的数据
	
	//行字节数
	DWORD dwWidthBytes = (DWORD)nScanWidth * 4;

	//开始数据基索引
	DWORD dwBaseIndex = y * dwWidthBytes + 4 * x;
	
	//指向内存源数据
	short* pcxDataFore = pcxDataSrc;
	
	int i, j;
	for(i = 0;i < h;i++)
	{
		//指向一行的开始数据
		BYTE* pbySrc = lpbyBits32 + dwBaseIndex;
		for(j = 0;j < w;j++)
		{
			//blue
			*pcxDataFore++ = *pbySrc++;
			//green
			*pcxDataFore++ = *pbySrc++;
			//red
			*pcxDataFore++ = *pbySrc++;
			pbySrc++;
		}
		dwBaseIndex += dwWidthBytes;
	}


	//第四步, 进行膨胀, 这是主要的计算工作
	Dilate(pcxDataSrc, w, h, pcxDataDst);

	//第五步, 回带数据
	//指向内存目标数据
	pcxDataFore = pcxDataDst;

	dwBaseIndex = y * dwWidthBytes + 4 * x;
	for(i = 0;i < h;i++)
	{
		//指向一行的开始数据
		BYTE* pbyDst = lpbyBits32 + dwBaseIndex;
		for(j = 0;j < w;j++)
		{
			short cxBlue = *pcxDataFore++;
			short cxGreen = *pcxDataFore++;
			short cxRed = *pcxDataFore++;
			
			*pbyDst++ = (BYTE)BOUND(cxBlue, 0, 255);
			*pbyDst++ = (BYTE)BOUND(cxGreen, 0, 255);
			*pbyDst++ = (BYTE)BOUND(cxRed, 0, 255);
			pbyDst++;
		}
		dwBaseIndex += dwWidthBytes;
	}

	delete[] pcxDataSrc;
	delete[] pcxDataDst;
	return TRUE;
}

//膨胀----保护成员函数
void CMathMorphology::Dilate(short* pcxDataSrc,  int nWidth,  int nHeight, short* pcxDataDst)
{
	//指向返回数据区
	short* pcxDst = pcxDataDst;
	
	//行数据
	int nRowScan = 3 * nWidth;	

	for(int i = 0;i < nHeight;i++)
	{

		for(int j = 0;j < nWidth;j++)
		{
			//移动结构元素至(i, j)点
			short cxMaxRed, cxMaxGreen, cxMaxBlue;
			cxMaxRed = cxMaxGreen = cxMaxBlue = -32767;
			
			for(int k = 0;k < m_nElementUsed;k++)
			{
				//基于结构元素的相对坐标
				int xr = m_pME[k].x;
				int yr = m_pME[k].y;

				//绝对地址
				int x = j - xr;
				int y = i - yr;

				//注意形态学膨胀运算的原始定义是, 只要有一个相交即可
				//但是, 为了避免边界处可能没有进行处理, 而使结果看起来有些缺陷, 
				//我们简单地将边界进行复制
				x = (x < 0) ? 0 : ((x > (nWidth - 1)) ? (nWidth - 1) : x);
				y = (y < 0) ? 0 : ((y > (nHeight - 1)) ? (nHeight - 1) : y);

				//获取数据
				short cxBlue = pcxDataSrc[(y * nRowScan + 3 * x)];
				short cxGreen = pcxDataSrc[(y * nRowScan + 3 * x + 1)];
				short cxRed = pcxDataSrc[(y * nRowScan + 3 * x + 2)];

				short cxB = cxBlue + m_pME[k].blue;
				short cxG = cxGreen + m_pME[k].green;
				short cxR = cxRed + m_pME[k].red;

				if(cxB > cxMaxBlue)cxMaxBlue = cxB;
				if(cxG > cxMaxGreen)cxMaxGreen = cxG;
				if(cxR > cxMaxRed)cxMaxRed = cxR;

			}

			//由于我们将边界扩大, 因而总是可以重叠的

			/*
			cxMaxBlue = BOUND(cxMaxBlue, 0, 255);
			cxMaxGreen = BOUND(cxMaxGreen, 0, 255);
			cxMaxRed = BOUND(cxMaxRed, 0, 255);
			*/

			pcxDataDst[(i * nRowScan + 3 * j)] = cxMaxBlue;
			pcxDataDst[(i * nRowScan + 3 * j + 1)] = cxMaxGreen;
			pcxDataDst[(i * nRowScan + 3 * j + 2)] = cxMaxRed;
		}
	}

}

//腐蚀----公有成员函数
BOOL CMathMorphology::Erode(LPBYTE lpbyBits32,  int x,  int y,  int nWidth,  int nHeight,  int nScanWidth,  int nScanHeight)
{
	//第一步, 进行参数合法性检测
	ASSERT(lpbyBits32);
	ASSERT(m_pME);
	
	if((x > (nScanWidth - 1)) || (y > (nScanHeight - 1))) return FALSE;
	
	m_dwOperation = IMAGE_MATH_MORPHOLOGY_ERODE;
	//有效区域的宽度和高度
	int w = min(nWidth, nScanWidth - x);
	int h = min(nHeight, nScanHeight - y);

	//第二步, 分配内存空间, 结果只可能在(-255, +255)之间, 
	//存储蓝色、绿色、红色
	int nSize = w * h;

	//存储源
	short* pcxDataSrc =  new short[(nSize * 3)];
	if (pcxDataSrc == NULL)	return FALSE;

	//存储目标
	short* pcxDataDst = new short[(nSize * 3)];
	if (pcxDataDst == NULL)	return FALSE;


	//第三步, 获取输入图像的数据
	
	//行字节数
	DWORD dwWidthBytes = (DWORD)nScanWidth * 4;
	
	//开始数据基索引
	DWORD dwBaseIndex = y * dwWidthBytes + 4 * x;
	
	//指向内存源数据
	short* pcxDataFore = pcxDataSrc;
	
	int i, j;
	for(i = 0;i < h;i++)
	{
		//指向一行的开始数据
		BYTE* pbySrc = lpbyBits32 + dwBaseIndex;
		for(j = 0;j < w;j++)
		{
			//blue
			*pcxDataFore++ = *pbySrc++;
			//green
			*pcxDataFore++ = *pbySrc++;
			//red
			*pcxDataFore++ = *pbySrc++;
			pbySrc++;
		}
		dwBaseIndex += dwWidthBytes;
	}

	//第四步
	//进行腐蚀, 这是主要的计算工作
	Erode(pcxDataSrc, w, h, pcxDataDst);

	//第五步
	//指向内存目标数据
	pcxDataFore = pcxDataDst;

	dwBaseIndex = y * dwWidthBytes + 4 * x;
	for(i = 0;i < h;i++)
	{
		//指向一行的开始数据
		BYTE* pbyDst = lpbyBits32 + dwBaseIndex;
		for(j = 0;j < w;j++)
		{
			short cxBlue = *pcxDataFore++;
			short cxGreen = *pcxDataFore++;
			short cxRed = *pcxDataFore++;
			
			*pbyDst++ = (BYTE)BOUND(cxBlue, 0, 255);
			*pbyDst++ = (BYTE)BOUND(cxGreen, 0, 255);
			*pbyDst++ = (BYTE)BOUND(cxRed, 0, 255);
			pbyDst++;
		}
		dwBaseIndex += dwWidthBytes;
	}

	delete[] pcxDataSrc;
	delete[] pcxDataDst;
	return TRUE;

}

//腐蚀----保护成员函数
void CMathMorphology::Erode(short *pcxDataSrc,  int nWidth,  int nHeight,  short *pcxDataDst)
{
	//指向返回数据区
	short* pcxDst = pcxDataDst;
	
	//行数据
	int nRowScan = 3 * nWidth;	

	for(int i = 0;i < nHeight;i++)
	{

		for(int j = 0;j < nWidth;j++)
		{
			//移动结构元素至(i, j)点
			short cxMinRed, cxMinGreen, cxMinBlue;
			cxMinRed = cxMinGreen = cxMinBlue = 32767;
			
			
			for(int k = 0;k < m_nElementUsed;k++)
			{
				//基于结构元素的相对坐标
				int xr = m_pME[k].x;
				int yr = m_pME[k].y;

				//绝对地址
				int x = j + xr;
				int y = i + yr;

				//注意形态学腐蚀运算的原始定义是, 所有相交才进行腐蚀, 
				//但是, 为了避免边界处可能没有进行处理, 而使结果看起来有些缺陷, 
				//我们简单地将边界进行复制
				x = (x < 0) ? 0 : ((x > (nWidth - 1)) ? (nWidth - 1) : x);
				y = (y < 0) ? 0 : ((y > (nHeight - 1)) ? (nHeight - 1) : y);

				
				//获取数据
				short cxBlue = pcxDataSrc[(y * nRowScan + 3 * x)];
				short cxGreen = pcxDataSrc[(y * nRowScan + 3 * x + 1)];
				short cxRed = pcxDataSrc[(y * nRowScan + 3 * x + 2)];

				short cxB = cxBlue - m_pME[k].blue;
				short cxG = cxGreen - m_pME[k].green;
				short cxR = cxRed - m_pME[k].red;

				if(cxB < cxMinBlue)cxMinBlue = cxB;
				if(cxG < cxMinGreen)cxMinGreen = cxG;
				if(cxR < cxMinRed)cxMinRed = cxR;
			}//end 

			/*
			cxMinBlue = BOUND(cxMinBlue, 0, 255);
			cxMinGreen = BOUND(cxMinGreen, 0, 255);
			cxMinRed = BOUND(cxMinRed, 0, 255);
			*/

			pcxDataDst[(i * nRowScan + 3 * j)] = cxMinBlue;
			pcxDataDst[(i * nRowScan + 3 * j + 1)] = cxMinGreen;
			pcxDataDst[(i * nRowScan + 3 * j + 2)] = cxMinRed;

		}//end j
	}//end i

}

//形态学开启
BOOL CMathMorphology::Open(LPBYTE lpbyBits32,  int x,  int y,  int nWidth,  int nHeight,  int nScanWidth,  int nScanHeight)
{
	//第一步, 进行参数合法性检测
	ASSERT(lpbyBits32);
	ASSERT(m_pME);
	if((x > (nScanWidth - 1)) || (y > (nScanHeight - 1))) return FALSE;
	
	m_dwOperation = IMAGE_MATH_MORPHOLOGY_OPEN;
	//有效区域的宽度和高度
	int w = min(nWidth, nScanWidth - x);
	int h = min(nHeight, nScanHeight - y);

	//第二步, 分配内存空间, 结果只可能在(-255, +255)之间, 
	//存储蓝色、绿色、红色
	int nSize = w * h;

	//存储源
	short* pcxDataSrc =  new short[(nSize * 3)];
	if (pcxDataSrc == NULL)	return FALSE;

	//存储目标
	short* pcxDataDst = new short[(nSize * 3)];
	if (pcxDataDst == NULL)	return FALSE;


	//第三步, 获取输入图像的数据
	
	//行字节数
	DWORD dwWidthBytes = (DWORD)nScanWidth * 4;
	
	//开始数据基索引
	DWORD dwBaseIndex = y * dwWidthBytes + 4 * x;
	
	//指向内存源数据
	short* pcxDataFore = pcxDataSrc;
	
	int i, j;
	for(i = 0;i < h;i++)
	{
		//指向一行的开始数据
		BYTE* pbySrc = lpbyBits32 + dwBaseIndex;
		for(j = 0;j < w;j++)
		{
			//blue
			*pcxDataFore++ = *pbySrc++;
			//green
			*pcxDataFore++ = *pbySrc++;
			//red
			*pcxDataFore++ = *pbySrc++;
			pbySrc++;
		}
		dwBaseIndex += dwWidthBytes;
	}

	//第四步
	//先进行腐蚀, 然后进行膨胀
	Erode(pcxDataSrc, w, h, pcxDataDst);
	Dilate(pcxDataDst, w, h, pcxDataSrc);

	//第五步
	//指向内存目标数据
	pcxDataFore = pcxDataSrc;

	dwBaseIndex = y * dwWidthBytes + 4 * x;
	for(i = 0;i < h;i++)
	{
		//指向一行的开始数据
		BYTE* pbyDst = lpbyBits32 + dwBaseIndex;
		for(j = 0;j < w;j++)
		{
			short cxBlue = *pcxDataFore++;
			short cxGreen = *pcxDataFore++;
			short cxRed = *pcxDataFore++;
			
			*pbyDst++ = (BYTE)BOUND(cxBlue, 0, 255);
			*pbyDst++ = (BYTE)BOUND(cxGreen, 0, 255);
			*pbyDst++ = (BYTE)BOUND(cxRed, 0, 255);
			pbyDst++;
		}
		dwBaseIndex += dwWidthBytes;
	}

	delete[] pcxDataSrc;
	delete[] pcxDataDst;

	return TRUE;

}

//关闭
BOOL CMathMorphology::Close(LPBYTE lpbyBits32,  int x,  int y,  int nWidth,  int nHeight,  int nScanWidth,  int nScanHeight)
{
	//第一步, 进行参数合法性检测
	ASSERT(lpbyBits32);
	ASSERT(m_pME);
	
	if((x > (nScanWidth - 1)) || (y > (nScanHeight - 1))) return FALSE;
	
	m_dwOperation = IMAGE_MATH_MORPHOLOGY_CLOSE;
	//有效区域的宽度和高度
	int w = min(nWidth, nScanWidth - x);
	int h = min(nHeight, nScanHeight - y);

	//第二步, 分配内存空间, 结果只可能在(-255, +255)之间, 
	//存储蓝色、绿色、红色
	int nSize = w * h;

	//存储源
	short* pcxDataSrc =  new short[(nSize * 3)];
	if (pcxDataSrc == NULL)	return FALSE;

	//存储目标
	short* pcxDataDst = new short[(nSize * 3)];
	if (pcxDataDst == NULL)	return FALSE;

	//第三步, 获取输入图像的数据
	
	//行字节数
	DWORD dwWidthBytes = (DWORD)nScanWidth * 4;
	
	//开始数据基索引
	DWORD dwBaseIndex = y * dwWidthBytes + 4 * x;
	
	//指向内存源数据
	short* pcxDataFore = pcxDataSrc;
	
	int i, j;
	for(i = 0;i < h;i++)
	{
		//指向一行的开始数据
		BYTE* pbySrc = lpbyBits32 + dwBaseIndex;
		for(j = 0;j < w;j++)
		{
			//blue
			*pcxDataFore++ = *pbySrc++;
			//green
			*pcxDataFore++ = *pbySrc++;
			//red
			*pcxDataFore++ = *pbySrc++;
			pbySrc++;
		}
		dwBaseIndex += dwWidthBytes;
	}

⌨️ 快捷键说明

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