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

📄 medianfilter.cpp

📁 visual c++数字图像与图形处理中的光盘内容
💻 CPP
字号:
/////////////////////////////////////////////////////////////////////////////////
//
// MedianFilter.cpp: implementation of the CMedianFilter class.
//
////////////////////////////////////////////////////////////////////////////////
// 版权所有(2002)
// Copyright(2002)
// 编写者: 向世明
// Author: Xiang Shiming

#include "stdafx.h"
#include "MedianFilter.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
IMPLEMENT_DYNAMIC(CMedianFilter, CImageAreaProcess)
CMedianFilter::CMedianFilter()
{
	m_dwOperation = IMAGE_BLUR_MEDIAN_FILTER;
	m_pnMask = NULL;
	m_nMaskBit = 0;
}

CMedianFilter::~CMedianFilter()
{
	if(m_pnMask)delete[] m_pnMask;
	m_pnMask = NULL;
}

#ifdef _DEBUG
void CMedianFilter::Dump(CDumpContext& dc) const
{
	CImageAreaProcess::Dump(dc);
}

void CMedianFilter::AssertValid() const
{
	CImageAreaProcess::AssertValid();
}
#endif

//设置蒙板
void CMedianFilter::SetMask(const int *pnMask,  int nRows,  int nCols)
{
	//保证为奇数
	m_nRows = 2 * (nRows / 2) + 1;
	m_nCols = 2 * (nCols / 2) + 1;

	if(m_pnMask)delete[] m_pnMask;
	m_pnMask = new int[m_nRows * m_nCols];
	int i;
	m_nMaskBit = 0;
	for( i = 0;i < m_nRows * m_nCols;i++)m_pnMask[i] = 0;
	
	for(i = 0;i < nRows;i++)
	{
		for(int j = 0; j < nCols;j++)
		{
			int index = m_nCols * i + j;
			m_pnMask[index] = pnMask[nCols * i + j];
			if(m_pnMask[index] != 0) m_nMaskBit++;
		}
	}

}


//快速分类方法, 递归调用
//nFirst, nLast表示数组序号
void CMedianFilter::QuickSort(BYTE* pbyArray,  int nFirst,  int nLast)
{
	int nLeft = nFirst;
	int nRight = nLast;
	if(nFirst >= nLast) return;

	BYTE byMiddle = pbyArray[(nFirst + nLast) / 2];
	do
	{
		while(pbyArray[nLeft] < byMiddle)nLeft++;
		while(pbyArray[nRight] > byMiddle)nRight--;
		if(nLeft <= nRight)
		{
			int nTemp = pbyArray[nLeft];
			pbyArray[nLeft++] = pbyArray[nRight];
			pbyArray[nRight--] = nTemp;
		}
	
	}while(nLeft <= nRight);

	QuickSort(pbyArray, nFirst, nRight);
	QuickSort(pbyArray, nLeft, nLast);
}

//处理边界
PIXELCOLORRGB CMedianFilter::FilterPixelOnBorder(LPBYTE lpbyBitsSrc32,  int x,  int y,  int nScanWidth,  int nScanHeight)
{
	//行字节数
	DWORD dwWidthBytes = (DWORD)nScanWidth * 4;

	//存储一个像素邻域的RGB三分量
	BYTE* pbyRed = new BYTE[m_nMaskBit];
	BYTE* pbyGreen = new BYTE[m_nMaskBit];
	BYTE* pbyBlue = new BYTE[m_nMaskBit];

	//邻域中的左上角点.
	int xx = x - ((m_nCols - 1) / 2);
	int yy = y - ((m_nRows - 1) / 2);

	//三个数组pnRed, pnGreen, pnBlue的索引值
	int index = 0;

	//用于在蒙板中寻找非0数, 逐个进行
	int nOneByOne = 0;


	//用嵌套循环获取小邻域数据.
	
	for(int i = 0;i < m_nRows;i++)
	{
		//y坐标
		int nY = yy + i;

		//复制边界
		nY = (nY < 0) ? 0 : ((nY > (nScanHeight - 1)) ? (nScanHeight - 1) : nY);

		//指针, 指向行数据
		BYTE* pbySrc = lpbyBitsSrc32 + ((DWORD)nY) * dwWidthBytes; 

		for(int j = 0;j < m_nCols;j++)
		{
			if(m_pnMask[nOneByOne] != 0)
			{
				//x坐标	
				int nX = xx + j;

				//复制边界
				nX = (nX < 0) ? 0 : ((nX > (nScanWidth - 1)) ? (nScanWidth - 1) : nX);
				
				BYTE* pbyRaw = pbySrc + 4 * nX;
				
				//记录颜色分量
				pbyBlue[index] = *pbyRaw++; 
				pbyGreen[index] = *pbyRaw++;
				pbyRed[index] = *pbyRaw++;
				index++;
			}
			nOneByOne++;
		}//end j
	}//end i

	QuickSort(pbyRed, 0, (m_nMaskBit - 1));
	QuickSort(pbyGreen, 0, (m_nMaskBit - 1));
	QuickSort(pbyBlue, 0, (m_nMaskBit - 1));

	//RGB颜色结构, 在 IMG.H 中定义
	PIXELCOLORRGB rgb;

	rgb.red = pbyRed[m_nMaskBit / 2];
	rgb.green = pbyGreen[m_nMaskBit / 2];
	rgb.blue = pbyBlue[m_nMaskBit / 2];



	delete[] pbyBlue;
	delete[] pbyGreen;
	delete[] pbyRed;
	return rgb;

}

//过滤内部
PIXELCOLORRGB CMedianFilter::FilterPixelInner(LPBYTE lpbyBitsSrc32,  int x,  int y,  int nScanWidth,  int nScanHeight)
{
	
	//行字节数
	DWORD dwWidthBytes = (DWORD)nScanWidth * 4;

	//存储一个像素邻域的RGB三分量
	BYTE* pbyRed = new BYTE[m_nMaskBit];
	BYTE* pbyGreen = new BYTE[m_nMaskBit];
	BYTE* pbyBlue = new BYTE[m_nMaskBit];

	//邻域中的左上角点.
	int xx = x - ((m_nCols - 1) / 2);
	int yy = y - ((m_nRows - 1) / 2);

	//三个数组pnRed, pnGreen, pnBlue的索引值
	int index = 0;

	//用于在蒙板中寻找非0数, 逐个进行
	int nOneByOne = 0;


	//用嵌套循环获取小邻域数据.
	
	for(int i = 0;i < m_nRows;i++)
	{
		//y坐标
		int nY = yy + i;

		//指针, 指向行数据
		BYTE* pbySrc = lpbyBitsSrc32 + ((DWORD)nY) * dwWidthBytes; 

		for(int j = 0;j < m_nCols;j++)
		{
			if(m_pnMask[nOneByOne] != 0)
			{
				//x坐标	
				int nX = xx + j;

				BYTE* pbyRaw = pbySrc + 4 * nX;
				
				//记录颜色分量
				pbyBlue[index] = *pbyRaw++; 
				pbyGreen[index] = *pbyRaw++;
				pbyRed[index] = *pbyRaw++;
				index++;
			}
			nOneByOne++;
		}//end j
	}//end i

	QuickSort(pbyRed, 0, (m_nMaskBit - 1));
	QuickSort(pbyGreen, 0, (m_nMaskBit - 1));
	QuickSort(pbyBlue, 0, (m_nMaskBit - 1));

	//RGB颜色结构, 在 IMG.H 中定义
	PIXELCOLORRGB rgb;
	rgb.red = pbyRed[m_nMaskBit / 2];
	rgb.green = pbyGreen[m_nMaskBit / 2];
	rgb.blue = pbyBlue[m_nMaskBit / 2];

	delete[] pbyBlue;
	delete[] pbyGreen;
	delete[] pbyRed;
	return rgb;

}

//中值过滤
BOOL CMedianFilter::Medianize(LPBYTE lpbyBits32,  int x,  int y,  int nWidth,  int nHeight,  int nScanWidth,  int nScanHeight)
{
	//第一步, 参数合法性检测
	ASSERT(lpbyBits32);
	ASSERT(m_pnMask);
	if(m_nMaskBit == 0) return FALSE;

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

	//行字节数
	DWORD dwWidthBytes = (DWORD)nScanWidth * 4;

	//建立一份拷贝
	BYTE* pbySrcCopy =  new BYTE[ (dwWidthBytes * nScanHeight) ];
	if(pbySrcCopy == NULL) return FALSE;
	::CopyMemory(pbySrcCopy, lpbyBits32, dwWidthBytes * nScanHeight);

	int i, j;

	//处理上下边界
	//上下边界的高度:
	int nBorderH = (m_nRows - 1) / 2;
	for(i = 0;i < nBorderH;i++)
	{
		//当前像素y坐标
		int yy = y + i;

		//指向目的地址
		BYTE* pbyDst = lpbyBits32 + yy * dwWidthBytes + 4 * x;
		for(j = 0;j < w;j++)
		{
			//当前像素x坐标
			int xx = x + j;

			//进行卷积操作
			PIXELCOLORRGB rgb = FilterPixelOnBorder(pbySrcCopy, xx, yy, nScanWidth, nScanHeight);
	
			//写向目的数据缓冲区
			*pbyDst++ = rgb.blue;
			*pbyDst++ = rgb.green;
			*pbyDst++ = rgb.red;
			pbyDst++;
		}
	}
	
	//下边界Y坐标
	int nYBottom = (y + h - 1);
	//处理下边界
	for(i = 0;i < nBorderH;i++)
	{
		//当前像素y坐标
		int yy = nYBottom - i;

		//指向目的地址
		BYTE* pbyDst = lpbyBits32 + yy * dwWidthBytes + 4 * x;
		for(j = 0;j < w;j++)
		{
			//当前像素x坐标
			int xx = x + j;

			//进行卷积操作
			PIXELCOLORRGB rgb = FilterPixelOnBorder(pbySrcCopy, xx, yy, nScanWidth, nScanHeight);
	
			//写向目的数据缓冲区
			*pbyDst++ = rgb.blue;
			*pbyDst++ = rgb.green;
			*pbyDst++ = rgb.red;
			pbyDst++;
		}
	}

	//垂直边界宽度
	int nBorderW = (m_nCols - 1) / 2;

	
	//剩余高度 + 1 + nBorderH: 
	int nRemnantH = (h - nBorderH);
	
	//处理左边界
	for(i = nBorderH; i < nRemnantH;i++)
	{
		//当前像素y坐标
		int yy = y + i;
		//指向目的地址
		BYTE* pbyDst = lpbyBits32 + yy * dwWidthBytes + 4 * x;

		for(j = 0;j < nBorderW;j++)
		{
			//当前像素x坐标
			int xx = x + j;
			//进行卷积操作
			PIXELCOLORRGB rgb = FilterPixelOnBorder(pbySrcCopy, xx, yy, nScanWidth, nScanHeight);
	
			//写向目的数据缓冲区
			*pbyDst++ = rgb.blue;
			*pbyDst++ = rgb.green;
			*pbyDst++ = rgb.red;
			pbyDst++;
		}
	}

	//右边界x坐标起点
	int nXRight = x + w - nBorderW; 

	//处理右边界
	for(i = nBorderH; i < nRemnantH;i++)
	{
		//当前像素y坐标
		int yy = y + i;
		//指向目的地址
		BYTE* pbyDst = lpbyBits32 + yy * dwWidthBytes + 4 * nXRight;

		for(j = 0;j < nBorderW;j++)
		{
			//当前像素x坐标
			int xx = nXRight + j;
			//进行卷积操作
			PIXELCOLORRGB rgb = FilterPixelOnBorder(pbySrcCopy, xx, yy, nScanWidth, nScanHeight);
	
			//写向目的数据缓冲区
			*pbyDst++ = rgb.blue;
			*pbyDst++ = rgb.green;
			*pbyDst++ = rgb.red;
			pbyDst++;
		}
	}

	//内部宽度 - nBorderW + 1
	int nInnerW = w - nBorderW;
	
	//处理内部
	for(i = nBorderH; i < nRemnantH;i++)
	{
		//当前像素y坐标
		int yy = y + i;
		//指向目的地址
		BYTE* pbyDst = lpbyBits32 + yy * dwWidthBytes + 4 * x;

		for(j = 0;j < nInnerW;j++)
		{
			//当前像素x坐标
			int xx = x + j;
			//进行卷积操作
			PIXELCOLORRGB rgb = FilterPixelInner(pbySrcCopy, xx, yy, nScanWidth, nScanHeight);
	
			//写向目的数据缓冲区
			*pbyDst++ = rgb.blue;
			*pbyDst++ = rgb.green;
			*pbyDst++ = rgb.red;
			pbyDst++;
		}
	}

	delete[] pbySrcCopy;
	return TRUE;

}

⌨️ 快捷键说明

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