画像のコンボリュート処理

 前に作成したコンボリューション関連関数を手直しして前回作成したGDI+用クラスから使えるように した。
 コンボリューションはソースコードが(パラメータの一覧があるおかげでで)無駄に長いので別クラス として宣言してそこから派生させる形で実装している。


解説



実行例

 画像処理として以下のコードでシャープ化を行った。

		_cImage2.Convolution(CDnpImageConvolution::CONV_SHARP01);





ソースコード

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


 以下のソースコードを「DnpImageConvolution.h」のファイル名で保存する。


#pragma	once

class	CDnpImageConvolution
{
public:

	enum	CONVOLUTION_TYPE
	{
		CONV_DUMMY = 0,

		CONV_EMBOSS01,
		CONV_EMBOSS02,
		CONV_EMBOSS03,
		CONV_EMBOSS04,
		CONV_EMBOSS05,
		CONV_EMBOSS06,
		CONV_EMBOSS07,
		CONV_EMBOSS08,
		CONV_EMBOSS09,
		CONV_SOBEL01,
		CONV_PREWITT01,
		CONV_KIRSH01,
		CONV_EDGE01,
		CONV_EDGE02,
		CONV_EDGE03,
		CONV_EDGE04,
		CONV_EDGE05,
		CONV_EDGE06,
		CONV_EDGE07,
		CONV_EDGEENHANCE01,
		CONV_AVRREMOVE01,
		CONV_SHARP01,
		CONV_SHARP02,
		CONV_SHARP03,
		CONV_SHARP04,
		CONV_SOFT01,
		CONV_SOFT02,
		CONV_SOFT03,
		CONV_SOFT04,
		CONV_SOFT05,
		CONV_SOFT06,
		CONV_SOFT07,
		CONV_SOFT08,
		CONV_LAPLACIAN01,
		CONV_LAPLACIAN02,

		CONV_DUMMY_END
	};


	//
	//	コンボリューション処理パラメータの対称度チェック
	//
	//例えば下の2つのパラメータは"同じ処理を角度を変えて行うもの"
	//と考えることができる(左を45度回転したものが右になるため)。
	//この行列の場合、45度回転を8回繰り返すと元と同じ形になる。
	//この関数はこの8回から1つ引いた"7"という値を返す。
	//
	//	[  1 ][  1 ][  1 ]		[  0 ][  1 ][  1 ]
	//	[  0 ][  0 ][  0 ]		[  0 ][  0 ][  1 ]
	//	[  0 ][  0 ][  0 ]		[  0 ][  0 ][  0 ]
	//
	UINT	GetConvolutionRotateCount(int pnOperate[9])
	{
		int		i;
		int		pnOperateCopy[9];
		int		nTmp;

		memcpy(pnOperateCopy,pnOperate,sizeof(int) * 9);

		for(i = 0; i < 8; i++)
		{
			nTmp = pnOperateCopy[8];
			pnOperateCopy[8] = pnOperateCopy[7];
			pnOperateCopy[7] = pnOperateCopy[6];
			pnOperateCopy[6] = pnOperateCopy[5];
			pnOperateCopy[5] = pnOperateCopy[3];
			pnOperateCopy[3] = pnOperateCopy[2];
			pnOperateCopy[2] = pnOperateCopy[1];
			pnOperateCopy[1] = pnOperateCopy[0];
			pnOperateCopy[0] = nTmp;

			if(memcmp(pnOperate,pnOperateCopy,sizeof(int) * 9) == 0)
				return	i;
		}

		ATLASSERT(0);
		return	8;
	}


	//
	//	コンボリューション処理パラメータの回転
	//
	//
	//例えば下の2つのパラメータは"同じ処理を角度を変えて行うもの"
	//と考えることができる(左を45度回転したものが右になるため)。
	//この行列の場合、45度回転を8回繰り返すと元と同じ形になる。
	//この関数は指定した回数だけ45度回転をする
	//
	//	[  1 ][  1 ][  1 ]		[  0 ][  1 ][  1 ]
	//	[  0 ][  0 ][  0 ]		[  0 ][  0 ][  1 ]
	//	[  0 ][  0 ][  0 ]		[  0 ][  0 ][  0 ]
	//
	bool	GetConvolutionRotate(UINT nCount,int pnOperate[])
	{
		UINT	i;
		int		nTmp;

		nCount = nCount % 8;
		for(i = 0; i < nCount; i++)
		{
			//forで何度も回転するのは効率が悪いが最大7回なので大したことはない
			nTmp = pnOperate[8];
			pnOperate[8] = pnOperate[7];
			pnOperate[7] = pnOperate[6];
			pnOperate[6] = pnOperate[5];
			pnOperate[5] = pnOperate[3];
			pnOperate[3] = pnOperate[2];
			pnOperate[2] = pnOperate[1];
			pnOperate[1] = pnOperate[0];
			pnOperate[0] = nTmp;
		}

		return	true;
	}


	bool	GetConvolutionOperator(CONVOLUTION_TYPE enumType,int pnOperate[])
	{
//		int		pnOperate[9];

		//パラメータ参照元
		// http://www.rebol.net/rebcode/demos/convolution-rc.r
		//など

		switch(enumType)
		{
		case	CONV_DUMMY:
		case	CONV_DUMMY_END:
			//ダミー処理パラメータ
			pnOperate[0] = 0;			//[  0 ][  0 ][  0 ]
			pnOperate[1] = 0;			//[  0 ][  1 ][  0 ]
			pnOperate[2] = 0;			//[  0 ][  0 ][  0 ]
			pnOperate[3] = 0;
			pnOperate[4] = 1;
			pnOperate[5] = 0;
			pnOperate[6] = 0;
			pnOperate[7] = 0;
			pnOperate[8] = 0;
			break;

		case	CONV_EMBOSS01:
			//エンボス処理パラメータ1
			pnOperate[0] = 0;			//[  0 ][  0 ][  0 ]
			pnOperate[1] = 0;			//[  0 ][  1 ][  0 ]
			pnOperate[2] = 0;			//[  0 ][  0 ][ -8 ]
			pnOperate[3] = 0;
			pnOperate[4] = 1;
			pnOperate[5] = 0;
			pnOperate[6] = 0;
			pnOperate[7] = 0;
			pnOperate[8] = -1;
			break;

		case	CONV_EMBOSS02:
			//エンボス処理パラメータ2
			pnOperate[0] = 2;			//[  2 ][  0 ][  0 ]
			pnOperate[1] = 0;			//[  0 ][ -1 ][  0 ]
			pnOperate[2] = 0;			//[  0 ][  0 ][ -1 ]
			pnOperate[3] = 0;
			pnOperate[4] = -1;
			pnOperate[5] = 0;
			pnOperate[6] = 0;
			pnOperate[7] = 0;
			pnOperate[8] = -1;
			break;

		case	CONV_EMBOSS03:
			//エンボス処理パラメータ3
			pnOperate[0] = -2;			//[ -2 ][ -1 ][  0 ]
			pnOperate[1] = -1;			//[ -1 ][  1 ][  1 ]
			pnOperate[2] = 0;			//[  0 ][  1 ][  2 ]
			pnOperate[3] = -1;
			pnOperate[4] = 1;
			pnOperate[5] = 1;
			pnOperate[6] = 0;
			pnOperate[7] = 1;
			pnOperate[8] = 2;
			break;

		case	CONV_EMBOSS04:
			//エンボス処理パラメータ4Laplascian
			pnOperate[0] = -1;			//[ -1 ][  0 ][ -1 ]
			pnOperate[1] = 0;			//[  0 ][  4 ][  0 ]
			pnOperate[2] = -1;			//[ -1 ][  0 ][ -1 ]
			pnOperate[3] = 0;
			pnOperate[4] = 4;
			pnOperate[5] = 0;
			pnOperate[6] = -1;
			pnOperate[7] = 0;
			pnOperate[8] = -1;
			break;

		case	CONV_EMBOSS05:
			//エンボス処理パラメータ5全方向
		case	CONV_EDGE04:
			//エッジ検出処理パラメータ4
			pnOperate[0] = -1;			//[ -1 ][ -1 ][ -1 ]
			pnOperate[1] = -1;			//[ -1 ][  8 ][ -1 ]
			pnOperate[2] = -1;			//[ -1 ][ -1 ][ -1 ]
			pnOperate[3] = -1;
			pnOperate[4] = 8;
			pnOperate[5] = -1;
			pnOperate[6] = -1;
			pnOperate[7] = -1;
			pnOperate[8] = -1;
			break;

		case	CONV_EMBOSS06:
			//エンボス処理パラメータ6水平方向
			pnOperate[0] = 0;			//[  0 ][  0 ][  0 ]
			pnOperate[1] = 0;			//[ -1 ][  2 ][ -1 ]
			pnOperate[2] = 0;			//[  0 ][  0 ][  0 ]
			pnOperate[3] = -1;
			pnOperate[4] = 2;
			pnOperate[5] = -1;
			pnOperate[6] = 0;
			pnOperate[7] = 0;
			pnOperate[8] = 0;
			break;

		case	CONV_EMBOSS07:
			//エンボス処理パラメータ8水平垂直
			pnOperate[0] = 0;			//[  0 ][ -1 ][  0 ]
			pnOperate[1] = -1;			//[ -1 ][  4 ][ -1 ]
			pnOperate[2] = 0;			//[  0 ][ -1 ][  0 ]
			pnOperate[3] = -1;
			pnOperate[4] = 4;
			pnOperate[5] = -1;
			pnOperate[6] = 0;
			pnOperate[7] = -1;
			pnOperate[8] = 0;
			break;

		case	CONV_EMBOSS08:
			//エンボス処理パラメータ9Lossy
			pnOperate[0] = 1;			//[  1 ][ -2 ][  1 ]
			pnOperate[1] = -2;			//[  1 ][ -2 ][  4 ]
			pnOperate[2] = 1;			//[ -2 ][ -1 ][ -2 ]
			pnOperate[3] = -2;
			pnOperate[4] = 4;
			pnOperate[5] = -2;
			pnOperate[6] = -2;
			pnOperate[7] = -1;
			pnOperate[8] = -2;
			break;

		case	CONV_EMBOSS09:
			//エンボス処理パラメータ10
			pnOperate[0] = -4;			//[ -4 ][ -2 ][  0 ]
			pnOperate[1] = -2;			//[ -2 ][  2 ][  2 ]
			pnOperate[2] = 0;			//[  0 ][  2 ][  4 ]
			pnOperate[3] = -2;
			pnOperate[4] = 2;
			pnOperate[5] = 2;
			pnOperate[6] = 0;
			pnOperate[7] = 2;
			pnOperate[8] = 4;
			break;

		case	CONV_SOBEL01:
			//Sobel処理パラメータ水平
			pnOperate[0] = 1;			//[  1 ][  2 ][  1 ]
			pnOperate[1] = 2;			//[  0 ][  0 ][  0 ]
			pnOperate[2] = 1;			//[ -1 ][ -2 ][ -1 ]
			pnOperate[3] = 0;
			pnOperate[4] = 0;
			pnOperate[5] = 0;
			pnOperate[6] = -1;
			pnOperate[7] = -2;
			pnOperate[8] = -1;
			break;

		case	CONV_PREWITT01:
			//Prewitt処理パラメータ水平
			pnOperate[0] = 1;			//[  1 ][  1 ][  1 ]
			pnOperate[1] = 1;			//[  0 ][  0 ][  0 ]
			pnOperate[2] = 1;			//[ -1 ][ -1 ][ -1 ]
			pnOperate[3] = 0;
			pnOperate[4] = 0;
			pnOperate[5] = 0;
			pnOperate[6] = -1;
			pnOperate[7] = -1;
			pnOperate[8] = -1;
			break;

		case	CONV_KIRSH01:
			//Kirsh処理パラメータ水平
			pnOperate[0] = 5;			//[  5 ][  5 ][  5 ]
			pnOperate[1] = 5;			//[ -3 ][ -3 ][ -3 ]
			pnOperate[2] = 5;			//[ -3 ][ -3 ][ -3 ]
			pnOperate[3] = -3;
			pnOperate[4] = -3;
			pnOperate[5] = -3;
			pnOperate[6] = -3;
			pnOperate[7] = -3;
			pnOperate[8] = -3;
			break;

		case	CONV_EDGE01:
			//エッジ検出処理パラメータ1
			pnOperate[0] = 0;			//[  0 ][  1 ][  0 ]
			pnOperate[1] = 1;			//[  1 ][ -4 ][  1 ]
			pnOperate[2] = 0;			//[  0 ][  1 ][  0 ]
			pnOperate[3] = 1;
			pnOperate[4] = -4;
			pnOperate[5] = 1;
			pnOperate[6] = 0;
			pnOperate[7] = 1;
			pnOperate[8] = 0;
			break;

		case	CONV_EDGE02:
			//エッジ検出処理パラメータ2
			pnOperate[0] = -5;			//[ -5 ][  0 ][  0 ]
			pnOperate[1] = 0;			//[  0 ][  0 ][  0 ]
			pnOperate[2] = 0;			//[  0 ][  0 ][ -5 ]
			pnOperate[3] = 0;
			pnOperate[4] = 0;
			pnOperate[5] = 0;
			pnOperate[6] = 0;
			pnOperate[7] = 0;
			pnOperate[8] = -5;
			break;

		case	CONV_EDGE03:
			//エッジ検出処理パラメータ3
			pnOperate[0] = -125;		//[ -125 ][ -125 ][ -125 ]
			pnOperate[1] = -125;		//[ -125 ][ 1000 ][ -125 ]
			pnOperate[2] = -125;		//[ -125 ][ -125 ][ -125 ]
			pnOperate[3] = -125;
			pnOperate[4] = 1000;
			pnOperate[5] = -125;
			pnOperate[6] = -125;
			pnOperate[7] = -125;
			pnOperate[8] = -125;
			break;

		//case	CONV_EDGE04:
		//	//エッジ検出処理パラメータ4
		//	break;

		case	CONV_EDGE05:
			//エッジ検出処理パラメータ5
			pnOperate[0] = -1;			//[ -1 ][ -1 ][ -1 ]
			pnOperate[1] = -1;			//[  2 ][  2 ][  2 ]
			pnOperate[2] = -1;			//[ -1 ][ -1 ][ -1 ]
			pnOperate[3] = 2;
			pnOperate[4] = 2;
			pnOperate[5] = 2;
			pnOperate[6] = -1;
			pnOperate[7] = -1;
			pnOperate[8] = -1;
			break;

		case	CONV_EDGE06:
			//エッジ検出処理パラメータ6
			pnOperate[0] = -5;			//[ -5 ][ -5 ][ -5 ]
			pnOperate[1] = -5;			//[ -5 ][ 39 ][ -5 ]
			pnOperate[2] = -5;			//[ -5 ][ -5 ][ -5 ]
			pnOperate[3] = -5;
			pnOperate[4] = 39;
			pnOperate[5] = -5;
			pnOperate[6] = -5;
			pnOperate[7] = -5;
			pnOperate[8] = -5;
			break;

		case	CONV_EDGE07:
			//エッジ検出処理パラメータ7
			pnOperate[0] = 0;			//[  0 ][  2 ][  0 ]
			pnOperate[1] = 0;			//[  2 ][ -8 ][  2 ]
			pnOperate[2] = 0;			//[  0 ][  2 ][  0 ]
			pnOperate[3] = -1;
			pnOperate[4] = 1;
			pnOperate[5] = 0;
			pnOperate[6] = 0;
			pnOperate[7] = 0;
			pnOperate[8] = 0;
			break;

		case	CONV_EDGEENHANCE01:
			//エッジ強調処理パラメータ
			pnOperate[0] = 0;			//[  0 ][  0 ][  0 ]
			pnOperate[1] = 0;			//[ -1 ][  1 ][  0 ]
			pnOperate[2] = 0;			//[  0 ][  0 ][  0 ]
			pnOperate[3] = -1;
			pnOperate[4] = 1;
			pnOperate[5] = 0;
			pnOperate[6] = 0;
			pnOperate[7] = 0;
			pnOperate[8] = 0;
			break;

		case	CONV_AVRREMOVE01:
			//平均削除処理パラメータ
			pnOperate[0] = -1;			//[ -1 ][ -1 ][ -1 ]
			pnOperate[1] = -1;			//[ -1 ][  9 ][ -1 ]
			pnOperate[2] = -1;			//[ -1 ][ -1 ][ -1 ]
			pnOperate[3] = -1;
			pnOperate[4] = 9;
			pnOperate[5] = -1;
			pnOperate[6] = -1;
			pnOperate[7] = -1;
			pnOperate[8] = -1;
			break;

		case	CONV_SHARP01:
			//シャープ処理パラメータ1
			pnOperate[0] = -1;			//[ -1 ][ -1 ][ -1 ]
			pnOperate[1] = -1;			//[ -1 ][ 16 ][ -1 ]
			pnOperate[2] = -1;			//[ -1 ][ -1 ][ -1 ]
			pnOperate[3] = -1;
			pnOperate[4] = 16;
			pnOperate[5] = -1;
			pnOperate[6] = -1;
			pnOperate[7] = -1;
			pnOperate[8] = -1;
			break;

		case	CONV_SHARP02:
			//シャープ処理パラメータ2
			pnOperate[0] = 0;			//[  0 ][ -2 ][  0 ]
			pnOperate[1] = -2;			//[ -2 ][ 11 ][ -2 ]
			pnOperate[2] = 0;			//[  0 ][ -2 ][  0 ]
			pnOperate[3] = -2;
			pnOperate[4] = 11;
			pnOperate[5] = -2;
			pnOperate[6] = 0;
			pnOperate[7] = -2;
			pnOperate[8] = 0;
			break;

		case	CONV_SHARP03:
			//シャープ処理パラメータ3
			pnOperate[0] = 0;			//[  0 ][ -1 ][  0 ]
			pnOperate[1] = -1;			//[ -1 ][  5 ][ -1 ]
			pnOperate[2] = 0;			//[  0 ][ -1 ][  0 ]
			pnOperate[3] = -1;
			pnOperate[4] = 5;
			pnOperate[5] = -1;
			pnOperate[6] = 0;
			pnOperate[7] = -1;
			pnOperate[8] = 0;
			break;

		case	CONV_SHARP04:
			//シャープ処理パラメータ4
			pnOperate[0] = 0;			//[  0 ][ -3 ][  0 ]
			pnOperate[1] = -3;			//[ -3 ][ 24 ][ -3 ]
			pnOperate[2] = 0;			//[  0 ][ -3 ][  0 ]
			pnOperate[3] = -3;
			pnOperate[4] = 24;
			pnOperate[5] = -3;
			pnOperate[6] = 0;
			pnOperate[7] = -3;
			pnOperate[8] = 0;
			break;

		case	CONV_SOFT01:
			//Gaussian blur処理パラメータ
			pnOperate[0] = 1;			//[  1 ][  2 ][  1 ]
			pnOperate[1] = 2;			//[  2 ][  4 ][  2 ]
			pnOperate[2] = 1;			//[  1 ][  2 ][  1 ]
			pnOperate[3] = 2;
			pnOperate[4] = 4;
			pnOperate[5] = 2;
			pnOperate[6] = 1;
			pnOperate[7] = 2;
			pnOperate[8] = 1;
			break;

		case	CONV_SOFT02:
			//Gaussian blur処理パラメータ
			pnOperate[0] = 45;			//[  45 ][ 122 ][  45 ]
			pnOperate[1] = 122;			//[ 122 ][ 322 ][ 122 ]
			pnOperate[2] = 45;			//[  45 ][ 122 ][  45 ]
			pnOperate[3] = 122;
			pnOperate[4] = 322;
			pnOperate[5] = 122;
			pnOperate[6] = 45;
			pnOperate[7] = 122;
			pnOperate[8] = 45;
			break;

		case	CONV_SOFT03:
			//Gaussian blur処理パラメータ
			pnOperate[0] = 0;			//[  0 ][  1 ][  0 ]
			pnOperate[1] = 1;			//[  1 ][  1 ][  1 ]
			pnOperate[2] = 0;			//[  0 ][  1 ][  0 ]
			pnOperate[3] = 1;
			pnOperate[4] = 1;
			pnOperate[5] = 1;
			pnOperate[6] = 0;
			pnOperate[7] = 1;
			pnOperate[8] = 0;
			break;

		case	CONV_SOFT04:
			//ぼかし処理パラメータ
			pnOperate[0] = 1;			//[  1 ][  2 ][  1 ]
			pnOperate[1] = 2;			//[  2 ][  3 ][  2 ]
			pnOperate[2] = 1;			//[  1 ][  2 ][  1 ]
			pnOperate[3] = 2;
			pnOperate[4] = 3;
			pnOperate[5] = 2;
			pnOperate[6] = 1;
			pnOperate[7] = 2;
			pnOperate[8] = 1;
			break;

		case	CONV_SOFT05:
			//ぼかし処理パラメータ
			pnOperate[0] = 625;			//[  625 ][ 1250 ][  625 ]
			pnOperate[1] = 1250;		//[ 1250 ][ 2500 ][ 1250 ]
			pnOperate[2] = 625;			//[  625 ][ 1250 ][  625 ]
			pnOperate[3] = 1250;
			pnOperate[4] = 2500;
			pnOperate[5] = 1250;
			pnOperate[6] = 625;
			pnOperate[7] = 1250;
			pnOperate[8] = 625;
			break;

		case	CONV_SOFT06:
			//ぼかし処理パラメータ
			pnOperate[0] = 1;			//[  1 ][  1 ][  1 ]
			pnOperate[1] = 1;			//[  1 ][  1 ][  1 ]
			pnOperate[2] = 1;			//[  1 ][  1 ][  1 ]
			pnOperate[3] = 1;
			pnOperate[4] = 1;
			pnOperate[5] = 1;
			pnOperate[6] = 1;
			pnOperate[7] = 1;
			pnOperate[8] = 1;
			break;

		case	CONV_SOFT07:
			//ぼかし処理パラメータ
			pnOperate[0] = 0;			//[  0 ][  1 ][  0 ]
			pnOperate[1] = 1;			//[  1 ][  0 ][  1 ]
			pnOperate[2] = 0;			//[  0 ][  1 ][  0 ]
			pnOperate[3] = 1;
			pnOperate[4] = 0;
			pnOperate[5] = 1;
			pnOperate[6] = 0;
			pnOperate[7] = 1;
			pnOperate[8] = 0;
			break;

		case	CONV_SOFT08:
			//ぼかし処理パラメータ
			pnOperate[0] = 2;			//[  2 ][  2 ][  2 ]
			pnOperate[1] = 2;			//[  2 ][  1 ][  2 ]
			pnOperate[2] = 2;			//[  2 ][  2 ][  2 ]
			pnOperate[3] = 2;
			pnOperate[4] = 1;
			pnOperate[5] = 2;
			pnOperate[6] = 2;
			pnOperate[7] = 2;
			pnOperate[8] = 2;
			break;

		case	CONV_LAPLACIAN01:
			//ラプラシアン処理パラメータ全方向
			pnOperate[0] = 1;			//[  1 ][  1 ][  1 ]
			pnOperate[1] = 1;			//[  1 ][ -8 ][  1 ]
			pnOperate[2] = 1;			//[  1 ][  1 ][  1 ]
			pnOperate[3] = 1;
			pnOperate[4] = -8;
			pnOperate[5] = 1;
			pnOperate[6] = 1;
			pnOperate[7] = 1;
			pnOperate[8] = 1;
			break;

		case	CONV_LAPLACIAN02:
			//ラプラシアン処理パラメータ上下左右
			pnOperate[0] = 0;			//[  0 ][  1 ][  0 ]
			pnOperate[1] = 1;			//[  1 ][ -4 ][  1 ]
			pnOperate[2] = 0;			//[  0 ][  1 ][  0 ]
			pnOperate[3] = 1;
			pnOperate[4] = -4;
			pnOperate[5] = 1;
			pnOperate[6] = 0;
			pnOperate[7] = 1;
			pnOperate[8] = 0;
			break;

		default:
			ATLASSERT(0);
			return	false;
		}

		return	true;
	}




	//
	//	コンボリューション処理
	//
	//pnOperateは処理行列(3行3列)
	//bNotDivideは積算後に除算を行わないか、行うかの指定(falseなら除算する)
	//
	bool	Convolution(UINT nWidth,UINT nHeight,BYTE* pData,int nStrideBytes,int pnOperate[9],bool bNotDivide=false)
	{
		int			i;
		ULONG		x;
		ULONG		y;
		long		nTmpR;
		long		nTmpG;
		long		nTmpB;
		int			nDiv;			//計算結果を除算する値 = pnOperate[]の合計値
		BYTE*		pNew;			//新しい色値の画像を入れるバイト配列
		BYTE*		pNewTmp;
		BYTE*		pDataTmp;
		RGBTRIPLE*	pRgbUp;			//左上の元値のピクセル(+1で上、+2で右上)
		RGBTRIPLE*	pRgbCur;		//左の元値のピクセル(+1で中心、+2で右)
		RGBTRIPLE*	pRgbDown;		//左下の元値のピクセル(+1で下、+2で右下)
		RGBTRIPLE*	pRgbNew;		//新しい色値を代入するピクセル
		RGBTRIPLE*	ppRefPos[9];	//元値の上下左右斜め全9ピクセル位置

		pDataTmp = pData;

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

		pNew = new BYTE[nStrideBytes * nHeight];
		pNewTmp = pNew;

		for(y = 1; y < nHeight - 1; y++)
		{
			pRgbUp	= (RGBTRIPLE*)pData;
			pRgbCur	= (RGBTRIPLE*)((BYTE*)pRgbUp  + nStrideBytes);
			pRgbDown= (RGBTRIPLE*)((BYTE*)pRgbCur + nStrideBytes);

			pRgbNew = (RGBTRIPLE*)(pNew + nStrideBytes);

			for(x = 1; x < nWidth - 1; x++)
			{
				//あるピクセルの上下左右のピクセルポインタ
				ppRefPos[0] = pRgbUp;
				ppRefPos[1] = pRgbUp + 1;
				ppRefPos[2] = pRgbUp + 2;
				ppRefPos[3] = pRgbCur;
				ppRefPos[4] = pRgbCur + 1;
				ppRefPos[5] = pRgbCur + 2;
				ppRefPos[6] = pRgbDown;
				ppRefPos[7] = pRgbDown + 1;
				ppRefPos[8] = pRgbDown + 2;

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

					nTmpR += ppRefPos[i]->rgbtRed	* pnOperate[i];
					nTmpG += ppRefPos[i]->rgbtGreen	* pnOperate[i];
					nTmpB += ppRefPos[i]->rgbtBlue	* pnOperate[i];
				}
				//平均値を求めるために除算
				if(nDiv != 1)
				{
					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;

				pRgbNew[x].rgbtBlue	= (BYTE)nTmpB;
				pRgbNew[x].rgbtGreen	= (BYTE)nTmpG;
				pRgbNew[x].rgbtRed	= (BYTE)nTmpR;

				pRgbUp++;
				pRgbCur++;
				pRgbDown++;
			}

			//左端のピクセルは1つ右のピクセルと同じものを採用
			pRgbNew[0] = *(pRgbCur - nWidth + 1);

			//右端のピクセルは1つ左のピクセルと同じものを採用
			pRgbNew[nWidth - 1] = *(pRgbCur - 1);

			pData	+= nStrideBytes;
			pNew	+= nStrideBytes;
		}

		//上端のピクセル列は処理後の2列目と同じものを採用
		memcpy(pNewTmp,pDataTmp + nStrideBytes,nStrideBytes);

		//下端のピクセル列は処理の最終列と同じものを採用
		memcpy(pNew,pData - nStrideBytes,nStrideBytes);


		//処理後の画像を適用
		memcpy(pDataTmp,pNewTmp,nStrideBytes * nHeight);
		delete	pNewTmp;

		return	true;
	}
};




 前に作成した「DnpImage.h」に変更を加える。派生元クラスとしてCDnpImageConvolutionを入れ、 コンボリューション処理関連関数を追加する。。


#pragma once

#include "DnpImageBase.h"

#include "DnpImageConvolution.h"


class	CDnpImage : public CDnpImageBase, public CDnpImageConvolution
{
public:

	//
	//	コンボリューション処理
	//
	bool	Convolution(int pnOperate[9],bool bNotDivide=false)
	{
		bool	ret;
		int		nStrideBytes;
		BYTE*	pData;

		if(IsValidImage() == false)
			return	false;

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

		ret = CDnpImageConvolution::Convolution(GetWidth(),GetHeight(),pData,nStrideBytes,pnOperate,bNotDivide);

		UnlockBits();

		return	ret;
	}


	//
	//	コンボリューション処理
	//
	//指定したコンボリューション処理を行う。nRotateは処理パラメータ行列の右45度回転
	//を何度行うかの指定。エンボスなどの非対称パラメータの場合は結果が変わる。
	//パラメータが非対称かどうか(nRotateにいくつまでの値を指定できるか)は
	//CDnpImageConvolution::GetConvolutionRotateCount()で調べる
	//
	bool	Convolution(CDnpImageConvolution::CONVOLUTION_TYPE enumType,UINT nRotate=0)
	{
		int		pnOperate[9];
		bool	ret;

		if(IsValidImage() == false)
			return	false;

		ret = GetConvolutionOperator(enumType,pnOperate);
		if(ret == false)
			return	false;
		GetConvolutionRotate(nRotate,pnOperate);

		return	Convolution(pnOperate);
	}


	。。。。省略。。。。

};

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