画像のメディアンフィルターによるノイズ除去

解説

周囲8ピクセルを含めた9ピクセルの各値をソートしてその中間の値を新しい値と する。ソートはR、G、B各色ごとに処理する。
一般的にノイズ除去処理に用いられるフィルター。完全に"点"のノイズに対し ては有効に働くがそれ以外のノイズに対してはイマイチ。



実行例

 以下のコードで処理を施した。

		_cImage2.Median();





ソースコード

 GDI+を利用した画像処理テストのスケルトン2を 元に拡張する。


 前に作成した「DnpImage.h」に処理関数を追加する。


#include "math.h"

class	CDnpImage : public CDnpImageBase
	,public CDnpImageConvolution
	,public CDnpColorSpaceHLS
	,public CDnpColorSpaceHSV
{
public:

	//
	//	メディアンフィルター
	//
	//周囲8ピクセルを含めた9ピクセルの各値をソートしてその中間の値を新しい値と
	//する。ソートはR.G.B各色ごとに処理する。
	//一般的にノイズ除去処理に用いられるフィルター。完全に"点"のノイズに対し
	//ては有効に働くがそれ以外のノイズに対してはイマイチ。
	//
	bool	Median(void)
	{
		if(IsValidImage() == false)
			return	false;

		int			nStrideBytes;
		bool		ret;
		UINT		x;
		UINT		y;
		UINT		nWidth;
		UINT		nHeight;
		BYTE*		pData;
		BYTE*		pDataOrg;
		RGBTRIPLE*	pRGB;

		nWidth	= GetWidth();
		nHeight	= GetHeight();

		ret = LockBits(&pData,&nStrideBytes);
		if(ret == false)
			return	false;
		pDataOrg = pData;

		//バブルソート用マクロ
		#define	BUBBLE_SORT(pcbData,nCount)							\
			{														\
				int		i;											\
				int		j;											\
				int		nTmp;										\
																	\
				for(i = 0; i < nCount - 1; i++)						\
				{													\
					for(j = 0; j < nCount - 1; j++)					\
					{												\
						if (pcbData[j + 1] > pcbData[j])			\
							continue;								\
						nTmp = pcbData[j];							\
						pcbData[j]		= pcbData[j + 1];			\
						pcbData[j + 1]	= nTmp;						\
					}												\
				}													\
			}


		///////////////////////////////////////
		//メディアン処理
		//
		BYTE		pnData[9];
		RGBTRIPLE	prgbData[9];
		BYTE*		pNew;
		BYTE*		pTmp;
		RGBTRIPLE*	prgbNew;
		RGBTRIPLE*	prgbDown;
		RGBTRIPLE*	prgbUp;

		pNew = new BYTE[nStrideBytes * nHeight];
		pData = pDataOrg;
		pTmp = pNew;
		for(y = 0; y < nHeight; y++)
		{
			prgbNew	= (RGBTRIPLE*)pTmp;

			pRGB	= (RGBTRIPLE*)pData;
			prgbUp	= (RGBTRIPLE*)(pData - nStrideBytes);
			prgbDown= (RGBTRIPLE*)(pData + nStrideBytes);
			for(x = 0; x < nWidth; x++)
			{
				int		nCount;

				nCount = 0;
				if(x >= 1)
					prgbData[nCount++] = pRGB[x - 1];
				prgbData[nCount++] = pRGB[x];
				if(x < nWidth - 1)
					prgbData[nCount++] = pRGB[x + 1];

				if(y >= 1)
				{
					if(x >= 1)
						prgbData[nCount++] = prgbUp[x - 1];
					prgbData[nCount++] = prgbUp[x];
					if(x < nWidth - 1)
						prgbData[nCount++] = prgbUp[x + 1];
				}

				if(y < nHeight - 1)
				{
					if(x >= 1)
						prgbData[nCount++] = prgbDown[x - 1];
					prgbData[nCount++] = prgbDown[x];
					if(x < nWidth - 1)
						prgbData[nCount++] = prgbDown[x + 1];
				}

				int		a;
				int		i;

				#define	MEDIAN(color)								\
				{													\
					BUBBLE_SORT(pnData,nCount);						\
																	\
					if(nCount % 2)									\
						color = pnData[nCount / 2];					\
					else											\
					{												\
						a = nCount / 2 - 1;							\
						color = (pnData[a] + pnData[a + 1]) / 2;	\
					}												\
				}

				//R
				for(i = 0; i < nCount; i++)
					pnData[i] = prgbData[i].rgbtRed;
				MEDIAN(prgbNew[x].rgbtRed);

				//G
				for(i = 0; i < nCount; i++)
					pnData[i] = prgbData[i].rgbtGreen;
				MEDIAN(prgbNew[x].rgbtGreen);

				//B
				for(i = 0; i < nCount; i++)
					pnData[i] = prgbData[i].rgbtBlue;
				MEDIAN(prgbNew[x].rgbtBlue);
			}
			pData	+= nStrideBytes;
			pTmp	+= nStrideBytes;
		}

		memcpy(pDataOrg,pNew,nStrideBytes * nHeight);

		delete	pNew;

		UnlockBits();

		return	true;
	}


	。。。。省略。。。。

};

カテゴリー「VC++ TIPS」 のエントリー