解説
画像をシャープにする処理としてよく使われるアンシャープマスク。その原理は非常に簡単。 ぼかしを入れた画像と元画像との"差"を元の画像に加えるだけ。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;
}
。。。。省略。。。。
};
