画像の簡易アンシャープマスク処理

解説

 画像をシャープにする処理としてよく使われるアンシャープマスク。その原理は非常に簡単。 ぼかしを入れた画像と元画像との"差"を元の画像に加えるだけ。
 Photoshopではアンシャープマスク処理で"量"、"半径"、"しきい値"の3つを指定できる。今回 作成したアンシャープマスク処理ではこのうち"半径"を除いた量(nAmount)と"しきい値"(nThreshold) を指定できるようにした。


実行例




 Photoshopのアンシャープマスクでは"量"は1~500%までの指定で負の値は入力できない。 しかし今回の処理コードでは特にそのような制限は設けていない。マイナスの数を指定すると 輪郭周辺が大きくぼける処理になる。



ソースコード

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


 前に作成した「DnpImage.h」に簡易アンシャープマスク処理関数を追加する。。


class	CDnpImage : public CDnpImageBase, public CDnpImageConvolution
{
public:

	//
	//	簡易アンシャープマスク処理
	//
	//新値 = 元値 + (元値-ぼけ)×nAmount/100
	//
	//処理半径は1ピクセル固定。これは3行3列コンボリュート法によるぼかし処理を
	//利用しているため。
	//
	bool	UnsharpMaskEasy(int nAmount,int nThreshold)
	{
		if(IsValidImage() == false)
			return	false;
		if(nAmount == 0 || nThreshold > 255)
			return	true;

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

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

		//////////////////////////////////
		//元画像の一時保存
		//
		BYTE*	pOrgData;

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

		//メモリを確保してコピーしておく
		pOrgData = new BYTE[nStrideBytes * nHeight];
		memcpy(pOrgData,pData,nStrideBytes * nHeight);

		UnlockBits();


		//////////////////////////////////
		//画像のぼかし処理
		//
		ret = Convolution(CONV_SOFT01);
		if(ret == false)
		{
			delete	pOrgData;
			return	false;
		}

		//////////////////////////////////
		//画像のアンシャープマスク処理
		//
		BYTE*		pOrg;
		RGBTRIPLE*	pRGBOrg;

		ret = LockBits(&pData,&nStrideBytes);
		if(ret == false)
		{
			delete	pOrgData;
			return	false;
		}

		pOrg = pOrgData;
		for(y = 0; y < nHeight; y++)
		{
			pRGB	= (RGBTRIPLE*)pData;
			pRGBOrg	= (RGBTRIPLE*)pOrg;
			for(x = 0; x < nWidth; x++)
			{
				int		nTmp;

				//REDの処理
				nTmp = pRGBOrg[x].rgbtRed	- pRGB[x].rgbtRed;
				if((nTmp > 0 && nTmp < nThreshold) || (nTmp < 0 && -1 * nTmp < nThreshold))		//nThresholdを超えていないかチェック
					nTmp = 0;
				nTmp = pRGBOrg[x].rgbtRed	+ (nTmp * nAmount) / 100;			//アンシャープマスク処理
				if(nTmp > 255)
					nTmp = 255;
				if(nTmp < 0)
					nTmp = 0;
				pRGB[x].rgbtRed		= (BYTE)nTmp;

				//GREENの処理
				nTmp = pRGBOrg[x].rgbtGreen	- pRGB[x].rgbtGreen;
				if((nTmp > 0 && nTmp < nThreshold) || (nTmp < 0 && -1 * nTmp < nThreshold))		//nThresholdを超えていないかチェック
					nTmp = 0;
				nTmp = pRGBOrg[x].rgbtGreen	+ (nTmp * nAmount) / 100;			//アンシャープマスク処理
				if(nTmp > 255)
					nTmp = 255;
				if(nTmp < 0)
					nTmp = 0;
				pRGB[x].rgbtGreen		= (BYTE)nTmp;

				//BLUEの処理
				nTmp = pRGBOrg[x].rgbtBlue	- pRGB[x].rgbtBlue;
				if((nTmp > 0 && nTmp < nThreshold) || (nTmp < 0 && -1 * nTmp < nThreshold))		//nThresholdを超えていないかチェック
					nTmp = 0;
				nTmp = pRGBOrg[x].rgbtBlue	+ (nTmp * nAmount) / 100;			//アンシャープマスク処理
				if(nTmp > 255)
					nTmp = 255;
				if(nTmp < 0)
					nTmp = 0;
				pRGB[x].rgbtBlue		= (BYTE)nTmp;
			}
			pData	+= nStrideBytes;
			pOrg	+= nStrideBytes;
		}

		UnlockBits();
		delete	pOrgData;

		return	true;
	}

	。。。。省略。。。。

};

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