解説
画像をグレースケール変換して指定されたしきい値を境に2つの色に変える。そのとき 新しい画像と元画像との誤差を右、左下、下、右下の各ピクセルに反映させる誤差拡散法 を採用した。実行例
以下のコードで処理を施した。RGBTRIPLE rgbHigh; RGBTRIPLE rgbLow; rgbHigh.rgbtBlue = 100; rgbHigh.rgbtGreen = 255; rgbHigh.rgbtRed = 255; rgbLow.rgbtBlue = 0; rgbLow.rgbtGreen = 0; rgbLow.rgbtRed = 0; _cImage2.BicolorErrorVariance2(120,rgbHigh,rgbLow);

前回作成した処理関数BicolorErrorVarianceよりも誤差適用範囲が広いため、生成で きる画像はきめ細かくなるはずだが...BicolorErrorVarianceよりも劣っている。
ソースコード
GDI+を利用した画像処理テストのスケルトン2を 元に拡張する。前に作成した「DnpImage.h」に2階調化関数を追加する。
class CDnpImage : public CDnpImageBase
,public CDnpImageConvolution
,public CDnpColorSpaceHLS
,public CDnpColorSpaceHSV
{
public:
//
// 画像の誤差拡散法による2階調化
//
//グレースケール変換したときの色値がcbThresholdを超えていればrgbHighに、
//下回ればrgbLowに変えて2階調化する。新しい値の誤差を右、左下、下、右下
//など右、左下、下、右下方向2列までの各ピクセルに割り振る誤差拡散法による。
//
bool BicolorErrorVariance2(BYTE cbThreshold,RGBTRIPLE rgbHigh,RGBTRIPLE rgbLow)
{
if(IsValidImage() == false)
return false;
int nStrideBytes;
bool ret;
UINT x;
UINT y;
UINT nWidth;
UINT nHeight;
BYTE* pData;
RGBTRIPLE* pRGB;
BYTE cbHigh;
BYTE cbLow;
int nError;
cbHigh = (BYTE)((77 * rgbHigh.rgbtRed + 150 * rgbHigh.rgbtGreen + 29 * rgbHigh.rgbtBlue) >> 8);
cbLow = (BYTE)((77 * rgbLow .rgbtRed + 150 * rgbLow .rgbtGreen + 29 * rgbLow .rgbtBlue) >> 8);
nWidth = GetWidth();
nHeight = GetHeight();
//グレースケール変換
ret = GrayScale();
if(ret == false)
return false;
ret = LockBits(&pData,&nStrideBytes);
if(ret == false)
return false;
for(y = 0; y < nHeight; y++)
{
pRGB = (RGBTRIPLE*)pData;
for(x = 0; x < nWidth; x++)
{
RGBTRIPLE* pRGBDown1;
RGBTRIPLE* pRGBDown2;
pRGBDown1 = (RGBTRIPLE*)((BYTE*)pRGB + nStrideBytes);
pRGBDown2 = (RGBTRIPLE*)((BYTE*)pRGB + nStrideBytes * 2);
//pRGB[x] //現
//pRGB[x+1] //右
//pRGB[x+2] //右2つ目
//pRGBDown1[x-1] //左下
//pRGBDown1[x] //真下
//pRGBDown1[x+1] //右下
//pRGBDown2[x-1] //左下2つ目
//pRGBDown2[x] //真下2つ目
//pRGBDown2[x+1] //右下2つ目
//....
if(pRGB[x].rgbtRed > cbThreshold)
{
pRGB[x] = rgbHigh;
nError = (int)cbHigh - (int)pRGB[x].rgbtRed;
}
else
{
pRGB[x] = rgbLow;
nError = (int)cbLow - (int)pRGB[x].rgbtRed;
}
#define ERROR_VARIANCE(rgb,nWeight) \
{ \
rgb.rgbtRed += nError * nWeight / 48; \
if(rgb.rgbtRed > 255) \
rgb.rgbtRed = 255; \
if(rgb.rgbtRed < 0) \
rgb.rgbtRed = 0; \
}
//右1
if(x < nWidth - 1)
ERROR_VARIANCE(pRGB[x + 1],7);
//右2
if(x < nWidth - 2)
ERROR_VARIANCE(pRGB[x + 2],5);
if(y < nHeight - 1)
{
//下1左2
if(x >= 2)
ERROR_VARIANCE(pRGBDown1[x - 2],3);
//下1左1
if(x >= 1)
ERROR_VARIANCE(pRGBDown1[x - 1],5);
//下1
ERROR_VARIANCE(pRGBDown1[x],7);
//下1右1
if(x < nWidth - 1)
ERROR_VARIANCE(pRGBDown1[x + 1],5);
//下1右2
if(x < nWidth - 2)
ERROR_VARIANCE(pRGBDown1[x + 2],3);
}
if(y < nHeight - 2)
{
//下2左2
if(x >= 2)
ERROR_VARIANCE(pRGBDown2[x - 2],1);
//下2左1
if(x >= 1)
ERROR_VARIANCE(pRGBDown2[x - 1],3);
//下2
ERROR_VARIANCE(pRGBDown2[x],5);
//下2右1
if(x < nWidth - 1)
ERROR_VARIANCE(pRGBDown2[x + 1],3);
//下2右2
if(x < nWidth - 2)
ERROR_VARIANCE(pRGBDown2[x + 2],1);
}
}
pData += nStrideBytes;
}
UnlockBits();
return true;
}
。。。。省略。。。。
};
