画像のコンボリュート法によるブラー処理

解説

 コンボリュート法によるブラー処理。あるピクセルに3、その斜め方向のピクセルに1、 上下左右のピクセルに2を乗算した値を15で除算した結果を新しい色値とする。

 ここでは下のような3行3列の処理パラメータのテーブルを用意してブラー処理を実行してい る。このパラメータの値を変えればブラー以外にもぼかし処理やエッジ検出処理などさまざま な画像処理を行える。
121
232
121

実行例



ソースコード

 GDI+を利用した画像処理テストのスケルトンの 画像処理部分を以下のように変更する。



		////////////////////////////
		//画像処理
		//
		UINT		x;
		UINT		y;
		UINT		nPos;
		RGBTRIPLE*	pTmp;
		Gdiplus::BitmapData		bitmapData;

		pImage->LockBits(&Gdiplus::Rect(0,0,pImage->GetWidth(),pImage->GetHeight())
			,Gdiplus::ImageLockModeRead | Gdiplus::ImageLockModeWrite,PixelFormat24bppRGB,&bitmapData);

		pTmp = (RGBTRIPLE*)bitmapData.Scan0;

		int		pnOperate[9];

		//ブラー処理パラメータ
		pnOperate[0] = 1;
		pnOperate[1] = 2;
		pnOperate[2] = 1;
		pnOperate[3] = 2;
		pnOperate[4] = 3;
		pnOperate[5] = 2;
		pnOperate[6] = 1;
		pnOperate[7] = 2;
		pnOperate[8] = 1;

		{
			int			i;
			long		pnRefPos[9];
			int			nTmpR;
			int			nTmpG;
			int			nTmpB;
			int			nDiv;
			int			nStride;
			int			nPixelCount;
			RGBTRIPLE*	prgbTmp;

			nDiv = 0;
			for(i = 0; i < 9; i++)
				nDiv += pnOperate[i];
			if(nDiv < 0)
				nDiv *= -1;

			nStride = bitmapData.Stride / sizeof(RGBTRIPLE);
			nPixelCount = nStride * pImage->GetHeight();

			prgbTmp = new RGBTRIPLE[nPixelCount];
			for(y = 1; y < pImage->GetHeight() - 1; y++)
			{
				nPos = y * nStride;

				for(x = 1; x < pImage->GetWidth() - 1; x++, nPos++)
				{
					//あるピクセルの上下左右のピクセルオフセット計算
					//いちいち計算するのは効率が悪いがソースコードは見やすい?
					pnRefPos[0] = nPos - nStride - 1;
					pnRefPos[1] = pnRefPos[0] + 1;
					pnRefPos[2] = pnRefPos[0] + 2;
					pnRefPos[3] = nPos - 1;
					pnRefPos[4] = nPos;
					pnRefPos[5] = nPos + 1;
					pnRefPos[6] = nPos + nStride - 1;
					pnRefPos[7] = pnRefPos[6] + 1;
					pnRefPos[8] = pnRefPos[6] + 2;

					//テーブルの値を使って計算
					nTmpR = 0;
					nTmpG = 0;
					nTmpB = 0;
					for(i = 0; i < 9; i++)
					{
						if(pnRefPos[i] < 0 || pnRefPos[i] >= nPixelCount)
							continue;

						nTmpR += pTmp[pnRefPos[i]].rgbtRed	* pnOperate[i];
						nTmpG += pTmp[pnRefPos[i]].rgbtGreen* pnOperate[i];
						nTmpB += pTmp[pnRefPos[i]].rgbtBlue	* pnOperate[i];
					}
					
					//平均値を求めるために除算
					if(nDiv != 1 && nDiv != 0)
					{
						nTmpR /= nDiv;
						nTmpG /= nDiv;
						nTmpB /= nDiv;
					}

					//色ビット数を超えないように制限
					nTmpR = (nTmpR < 0) ? 0 : nTmpR;
					nTmpR = (nTmpR > 255) ? 255 : nTmpR;
					nTmpG = (nTmpG < 0) ? 0 : nTmpG;
					nTmpG = (nTmpG > 255) ? 255 : nTmpG;
					nTmpB = (nTmpB < 0) ? 0 : nTmpB;
					nTmpB = (nTmpB > 255) ? 255 : nTmpB;

					prgbTmp[nPos].rgbtBlue	= (BYTE)nTmpB;
					prgbTmp[nPos].rgbtGreen	= (BYTE)nTmpG;
					prgbTmp[nPos].rgbtRed	= (BYTE)nTmpR;
				}
			}

			memcpy(pTmp,prgbTmp,sizeof(RGBTRIPLE) * nPixelCount);
			delete	prgbTmp;
		}
		pImage->UnlockBits(&bitmapData);

※ソースコード中に既知のバグというかミスコーディングがあります。nStrideを用意 していますがこれが諸悪の原因です。画像にどんな変化が加わるかを見るだけのテスト用途のため修正 はしていません。

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