解説
3行3列のパラメータを利用したコンボリュート法による画像処理例。この方法を使うとぼかし、シャープ、エンボス、輪郭検出...さまざまな 処理を行える。とは言うものの単純にコンボリュートを施しただけでは暗すぎ て(コントラストがなさすぎて)思ったように結果が見えなかったりもする。 そのため実際にこれらの方法を使って画像処理をする場合は、ほかの画像処理 法と組み合わせて使った方がいい。
ここに挙げたパラメータはほんの一例にすぎないが、それでも単に行列を回 転させただけのものも多い(つまり重複しているものも多い)。
実行例
次に挙げる画像は上から順に以下のパラメータ指定による実行結果。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全方向 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: //エンボス処理パラメータ7垂直方向 pnOperate[0] = 0; //[ 0 ][ -1 ][ 0 ] pnOperate[1] = -1; //[ 0 ][ 2 ][ 0 ] pnOperate[2] = 0; //[ 0 ][ -1 ][ 0 ] pnOperate[3] = 0; pnOperate[4] = 0; pnOperate[5] = 0; pnOperate[6] = 0; pnOperate[7] = -1; pnOperate[8] = 0; break; case CONV_EMBOSS08: //エンボス処理パラメータ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_EMBOSS09: //エンボス処理パラメータ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_EMBOSS10: //エンボス処理パラメータ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_SOBEL02: //Sobel処理パラメータ垂直 pnOperate[0] = 1; //[ 1 ][ 0 ][ -1 ] pnOperate[1] = 0; //[ 2 ][ 0 ][ -2 ] pnOperate[2] = -1; //[ 1 ][ 0 ][ -1 ] pnOperate[3] = 2; pnOperate[4] = 0; pnOperate[5] = -2; pnOperate[6] = 1; pnOperate[7] = 0; 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_PREWITT02: //Prewitt処理パラメータ垂直 pnOperate[0] = 1; //[ 1 ][ 0 ][ -1 ] pnOperate[1] = 0; //[ 1 ][ 0 ][ -1 ] pnOperate[2] = -1; //[ 1 ][ 0 ][ -1 ] pnOperate[3] = 1; pnOperate[4] = 0; pnOperate[5] = -1; pnOperate[6] = 1; pnOperate[7] = 0; 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_KIRSH02: //Kirsh処理パラメータ垂直 pnOperate[0] = 5; //[ 5 ][ -3 ][ -3 ] pnOperate[1] = -3; //[ 5 ][ -3 ][ -3 ] pnOperate[2] = -3; //[ 5 ][ -3 ][ -3 ] pnOperate[3] = 5; pnOperate[4] = -3; pnOperate[5] = -3; pnOperate[6] = 5; 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 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;

次に挙げる画像は上から順に以下のパラメータ指定による実行結果。
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;

ソースコード
WTLのプロジェクトウイザードを使ってSDI Apllicationプロジェクトを作成し、View用の ヘッダーファイルを以下のように変える。ここではプロジェクト名を「ImageEffect110」と しています。// ImageEffect110View.h : interface of the CImageEffect110View class // ///////////////////////////////////////////////////////////////////////////// #pragma once #include※ソースコード中に既知のバグというかミスコーディングがあります。画像にどんな 変化が加わるかを見るだけのテスト用途のため修正はしていません。#pragma comment(lib,"Gdiplus.lib") class CImageEffect110View : public CWindowImpl { public: DECLARE_WND_CLASS(NULL) BOOL PreTranslateMessage(MSG* pMsg) { pMsg; return FALSE; } BEGIN_MSG_MAP(CImageEffect110View) MESSAGE_HANDLER(WM_PAINT, OnPaint) END_MSG_MAP() // Handler prototypes (uncomment arguments if needed): // LRESULT MessageHandler(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) // LRESULT CommandHandler(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) // LRESULT NotifyHandler(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/) // //コンボリューション処理 // //nWidthは画像の幅(単位ピクセル) //nHeightは画像の高さ(単位ピクセル) //nStrideBytesは画像の幅一列あたりのサイズ(単位bytes) //pRgbDataは画像データ(RGBTRIPLEの並び) //pnOperateは処理行列(3行3列) //bNotDivideは積算後に除算を行わないか、行うかの指定(falseなら除算する) // bool Convolution(ULONG nWidth,ULONG nHeight,long nStrideBytes,BYTE* pRgbData,int pnOperate[9],bool bNotDivide=false) { int i; ULONG x; ULONG y; long nTmpR; long nTmpG; long nTmpB; int nDiv; //計算結果を除算する値 = pnOperate[]の合計値 long nPosBytes; BYTE* pNew; //新しい色値の画像を入れるバイト配列 RGBTRIPLE* pRgbUp; //左上の元値のピクセル(+1で上、+2で右上) RGBTRIPLE* pRgbCur; //左の元値のピクセル(+1で中心、+2で右) RGBTRIPLE* pRgbDown; //左下の元値のピクセル(+1で下、+2で右下) RGBTRIPLE* pRgbNew; //新しい色値を代入するピクセル RGBTRIPLE* ppRefPos[9]; //元値の上下左右斜め全9ピクセル位置 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]; for(y = 1; y < nHeight - 1; y++) { nPosBytes = (y - 1) * nStrideBytes; pRgbUp = (RGBTRIPLE*)&(pRgbData[nPosBytes]); nPosBytes += nStrideBytes; pRgbCur = (RGBTRIPLE*)&(pRgbData[nPosBytes]); pRgbNew = (RGBTRIPLE*)&(pNew[nPosBytes]); nPosBytes += nStrideBytes; pRgbDown = (RGBTRIPLE*)&(pRgbData[nPosBytes]); 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->rgbtBlue = (BYTE)nTmpB; pRgbNew->rgbtGreen = (BYTE)nTmpG; pRgbNew->rgbtRed = (BYTE)nTmpR; pRgbUp++; pRgbCur++; pRgbDown++; pRgbNew++; } } memcpy(pRgbData,pNew,nStrideBytes * nHeight); delete pNew; return true; } 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_EMBOSS10, CONV_SOBEL01, CONV_SOBEL02, CONV_PREWITT01, CONV_PREWITT02, CONV_KIRSH01, CONV_KIRSH02, 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 }; bool Convolution(ULONG nWidth,ULONG nHeight,long nStrideBytes,BYTE* pRgbData,CONVOLUTION_TYPE enumType,bool bNotDivide=false) { 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: //エンボス処理パラメータ7垂直方向 pnOperate[0] = 0; //[ 0 ][ -1 ][ 0 ] pnOperate[1] = -1; //[ 0 ][ 2 ][ 0 ] pnOperate[2] = 0; //[ 0 ][ -1 ][ 0 ] pnOperate[3] = 0; pnOperate[4] = 0; pnOperate[5] = 0; pnOperate[6] = 0; pnOperate[7] = -1; pnOperate[8] = 0; break; case CONV_EMBOSS08: //エンボス処理パラメータ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_EMBOSS09: //エンボス処理パラメータ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_EMBOSS10: //エンボス処理パラメータ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_SOBEL02: //Sobel処理パラメータ垂直 pnOperate[0] = 1; //[ 1 ][ 0 ][ -1 ] pnOperate[1] = 0; //[ 2 ][ 0 ][ -2 ] pnOperate[2] = -1; //[ 1 ][ 0 ][ -1 ] pnOperate[3] = 2; pnOperate[4] = 0; pnOperate[5] = -2; pnOperate[6] = 1; pnOperate[7] = 0; 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_PREWITT02: //Prewitt処理パラメータ垂直 pnOperate[0] = 1; //[ 1 ][ 0 ][ -1 ] pnOperate[1] = 0; //[ 1 ][ 0 ][ -1 ] pnOperate[2] = -1; //[ 1 ][ 0 ][ -1 ] pnOperate[3] = 1; pnOperate[4] = 0; pnOperate[5] = -1; pnOperate[6] = 1; pnOperate[7] = 0; 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_KIRSH02: //Kirsh処理パラメータ垂直 pnOperate[0] = 5; //[ 5 ][ -3 ][ -3 ] pnOperate[1] = -3; //[ 5 ][ -3 ][ -3 ] pnOperate[2] = -3; //[ 5 ][ -3 ][ -3 ] pnOperate[3] = 5; pnOperate[4] = -3; pnOperate[5] = -3; pnOperate[6] = 5; 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 Convolution(nWidth,nHeight,nStrideBytes,pRgbData,pnOperate,bNotDivide); } bool OnPaint(HDC hDC,int nX,int nY,CONVOLUTION_TYPE enumType) { //////////////////////////// //GDI+初期化 //本当はアプリケーションの初期化時に行うべきだがソースコードの簡易化のためOnPaintに配置 ULONG_PTR _nToken; Gdiplus::GdiplusStartupInput _sGdiplusStartupInput; Gdiplus::GdiplusStartup(&_nToken,&_sGdiplusStartupInput,NULL); //////////////////////////// //画像読み込み //ソースコード簡易化のため描画毎に読み出す Gdiplus::Bitmap* pImage; Gdiplus::Graphics cGraphics(hDC); pImage = Gdiplus::Bitmap::FromFile(L"c:\\test.jpg",TRUE); //////////////////////////// //画像表示(画像処理前) cGraphics.DrawImage(pImage,(Gdiplus::REAL)nX,(Gdiplus::REAL)nY ,(Gdiplus::REAL)pImage->GetWidth(),(Gdiplus::REAL)pImage->GetHeight()); //////////////////////////// //画像処理 // 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; Convolution(pImage->GetWidth(),pImage->GetHeight(),bitmapData.Stride,(BYTE*)pTmp,enumType); pImage->UnlockBits(&bitmapData); //////////////////////////// //画像表示(画像処理後) cGraphics.DrawImage(pImage,(Gdiplus::REAL)pImage->GetWidth() + 2 + nX,(Gdiplus::REAL)nY ,(Gdiplus::REAL)pImage->GetWidth(),(Gdiplus::REAL)pImage->GetHeight()); //////////////////////////// //画像開放 delete pImage; //////////////////////////// //GDI+開放処理 //本当はアプリケーションの終了時に行うべきだがソースコードの簡易化のため行わない //Gdiplus::GdiplusShutdown(_nToken); return true; } LRESULT OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { int i; int nY; CPaintDC dc(m_hWnd); nY = 0; for(i = 0; i < 5; i++) { OnPaint(dc.m_hDC,0,nY,(CONVOLUTION_TYPE)(i + 1 + 5*7)); nY += 202; } return 0; } };
