// ■C言語で画像処理 #include "myWin.h" #include "math.h" #define LB_1 3001 #define LB_2 3002 #define LB_3 3003 #define BT_1 1001 #define BT_2 1002 #define BT_3 1003 #define BT_4 1004 #define BT_5 1005 #define BT_6 1006 #define BT_7 1007 #define BT_8 1008 #define BT_9 1009 #define BT_10 1010 #define BT_11 1011 #define BT_13 1013 #define XST 310 #define YST 150 #define RED(X) (X & 0xFF) #define GREEN(X) ((X>> 8) & 0xFF) #define BLUE(X) ((X>>16) & 0xFF) #define swap(type, X, Y) do{type T; T=X; X=Y; Y=T;} while(0) static HDC hBuff[3]; //ビットマップ描画用 static HBITMAP hBM[3];//ビットマップ描画用 static BITMAP bM[3];//ビットマップ描画用 static HCURSOR hc; int Xstart=310, DX=-1; int filter[3][3]={{1,1,1},{1,1,1},{1,1,1}}; static SCROLLINFO scr[3]; static HWND scroll[3],scrLbl[3]; static int drawMode=0, XR1, YR1, XR2, YR2, XT, YT; void drawEdge(HWND hw){ COLORREF C1, C2, C3, R1, R2, G1, G2, B1, B2; for(int i=0;i<300;i++)for(int j=0;j<300;j++){ int i1= (i==299)?298: i, j1=(j==299)? 298: j, i2=i1+1, j2=j1+1; C1=GetPixel(hBuff[1],i1, j1); C2=GetPixel(hBuff[1],i2, j1); C3=GetPixel(hBuff[1],i1, j2); R1=abs((int)(RED (C1)-RED (C2))); G1=abs((int)(GREEN(C1)-GREEN(C2))); B1=abs((int)(BLUE (C1)-BLUE (C2))); R2=abs((int)(RED (C1)-RED (C3))); G2=abs((int)(GREEN(C1)-GREEN(C3))); B2=abs((int)(BLUE (C1)-BLUE (C3))); SetPixel(hBuff[0],i,j,RGB((R1+R2)/2,(G1+G2)/2,(G1+G2)/2)); } InvalidateRect(hw,NULL,TRUE); } int mixColor(int C1, int C2, double Alfa){ return (int)((double)C1*(1-Alfa)+(double)C2*Alfa); } void drawRGB(HWND hw){ COLORREF C,R,G,B; for(int i=0;i<300;i++)for(int j=0;j<300;j++){ int i1= (i==299)?298: i, j1=(j==299)? 298: j, i2=i1+1, j2=j1+1; C=GetPixel(hBuff[1],i1, j1); R=(int)((double)RED (C)*(double)scr[0].nPos/100); G=(int)((double)GREEN(C)*(double)scr[1].nPos/100); B=(int)((double)BLUE (C)*(double)scr[2].nPos/100); SetPixel(hBuff[0],i,j,RGB(R,G,B)); } InvalidateRect(hw,NULL,TRUE); } void setCoff(int i, COLORREF *CC, double *D){ if(scr[i].nPos>=50) {*CC = 0xFF; *D=(scr[i].nPos-50.0)/50.0;} else { *CC = 0x0; *D=(50.0-scr[i].nPos)/50.0;} } void drawRGB2(HWND hw){ COLORREF C,R,G,B, CC; double D; for(int i=0;i<300;i++)for(int j=0;j<300;j++){ int i1= (i==299)?298: i, j1=(j==299)? 298: j, i2=i1+1, j2=j1+1; C=GetPixel(hBuff[1],i1, j1); setCoff(0, &CC, &D); R= mixColor(RED (C), CC,D); setCoff(1, &CC, &D); G= mixColor(GREEN(C), CC,D); setCoff(2, &CC, &D); B= mixColor(BLUE (C), CC,D); SetPixel(hBuff[0],i,j,RGB(R,G,B)); } InvalidateRect(hw,NULL,TRUE); } void drawDistinct(HWND hw){ int C0, C1, C2, C3,C4, R1, R2, G1, G2, B1, B2, R,G,B; double AR, AG, AB, Alfa=0.5;//Alfa:鮮明化の度合い。0〜1 for(int i=1;i<299;i++)for(int j=0;j<300;j++){ int i1=i+1, j1=j+1,i2=i-1, j2=j-1; C0=GetPixel(hBuff[1], i , j );//該当ピクセルの色と C1=GetPixel(hBuff[1], i1, j );//周辺ピクセルの色 C2=GetPixel(hBuff[1], i , j1); C3=GetPixel(hBuff[1], i2, j ); C4=GetPixel(hBuff[1], i , j2); R=RED(C0); G=GREEN(C0); B=BLUE(C0);//周辺の明るさとの差 R1= R*4 - RED (C1)- RED (C2)- RED (C3) - RED (C4); G1= G*4 - GREEN(C1)- GREEN(C2)- GREEN(C3) - GREEN(C4); B1= B*4 - BLUE (C1)- BLUE (C2)- BLUE (C3) - BLUE (C4); AR=abs((double)R1/255)*Alfa;//強調度合い AG=abs((double)G1/255)*Alfa; AB=abs((double)B1/255)*Alfa; R2=0xFF;if(R1<0) R2=0; //周辺が暗い場合は明るく G2=0xFF;if(G1<0) G2=0; //周辺が明るい場合は暗く B2=0xFF;if(B1<0) B2=0; //周辺色との差で明暗強調 R1=mixColor(R, R2, AR);if(R1>255) R1=255; G1=mixColor(G, G2, AG);if(G1>255) G1=255; B1=mixColor(B, B2, AB);if(B1>255) B1=255; SetPixel(hBuff[0],i,j,RGB(R1,G1,B1)); } InvalidateRect(hw,NULL,TRUE); } double setValue(double X,double tCurve[]){//カラートーンによる明るさ double A=0; for(int i=4;i>=0;i--)A = A*X+tCurve[i]; if(A<0) A=0; if(A>255)A=255; return A; } void drawContrast(HWND hw){ double tCurve[5]={ 0.0, 4.0, -0.003, 0.0001, 0.0}; int C0, R1, G1, B1, R,G,B; //double AR, AG, AB, Alfa=0.5;//Alfa:鮮明化の度合い。0〜1 for(int i=1;i<299;i++)for(int j=0;j<300;j++){ int i1=i+1, j1=j+1,i2=i-1, j2=j-1; C0=GetPixel(hBuff[1], i , j );//該当ピクセルの色と R=RED(C0); G=GREEN(C0); B=BLUE(C0);//周辺の明るさとの差 double Z=setValue(((double)R+(double)G+(double)B)/3,tCurve)/255; R1= (int)(Z*R); G1= (int)(Z*G); B1= (int)(Z*B); SetPixel(hBuff[0],i,j,RGB(R1,G1,B1)); } InvalidateRect(hw,NULL,TRUE); } void procFilter(int filter[3][3]){//フィルタ処理 for(int i=1;i<299;i++)for(int j=0;j<300;j++){ COLORREF C; int R=0,G=0,B=0, T=0; for(int k1=0;k1<=2; k1++)for(int k2=0;k2<=2; k2++){ C=GetPixel(hBuff[1],i+k1-1,j+k2-1); T+= filter[k1][k2]; R+=RED(C)*filter[k1][k2]; G+=GREEN(C)*filter[k1][k2]; B+=BLUE(C)*filter[k1][k2]; } R/=T; G/=T; B/=T; if(R>255)R=255; if(G>255)G=255; if(B>255)B=255; SetPixel(hBuff[0],i,j,RGB(R,G,B)); } } void drawShade(HWND hw){//平滑化フィルタ int filter[3][3]={{1,1,1},{1,1,1},{1,1,1}}; procFilter(filter); InvalidateRect(hw,NULL,TRUE); } void drawAverage(HWND hw){//加重平均フィルタ int filter[3][3]={{1,2,1},{2,4,2},{1,2,1}}; procFilter(filter); InvalidateRect(hw,NULL,TRUE); } void drawMedian(HWND hw){//メディアンフィルタ for(int i=1;i<299;i++)for(int j=0;j<300;j++){ int R=0,G=0,B=0, T=0, filter[9], k=0; for(int k1=0;k1<=2; k1++)for(int k2=0;k2<=2; k2++,k++) filter[k]=GetPixel(hBuff[1], i+k1-1, j+k2-1); for(int k1=0;k1<8;k1++)for(int k2=8;k2>k1; k2--) if(filter[k2-1]>filter[k2]) swap(int,filter[k2-1],filter[k2]); SetPixel(hBuff[0],i,j,filter[4]); } InvalidateRect(hw,NULL,TRUE); } void drawGamma(HWND hw){//ガンマ補正 トーンカーブは、 double DP=0.8; //255*pow(色/255,DP)の式で近似。DP<1のとき強調。 for(int i=1;i<299;i++)for(int j=0;j<300;j++){ COLORREF C=GetPixel(hBuff[1], i, j); double R=255*pow((double)RED (C)/255, DP); double G=255*pow((double)GREEN(C)/255, DP); double B=255*pow((double)BLUE (C)/255, DP); SetPixel(hBuff[0],i,j,RGB((int)R,(int)G,(int)B)); } InvalidateRect(hw,NULL,TRUE); } void drawMosaic(HWND hw){//モザイク処理(位置は固定)、 BitBlt(hBuff[0],0,0,bM[1].bmWidth,bM[1].bmHeight,hBuff[1],0,0,SRCCOPY); for(int i=60;i<140; i+=8)for(int j=40;j<120;j+=8){ int N=0, R=0, G=0, B=0, C=0; for(int k1=0;k1<8; k1++)for(int k2=0;k2<8; k2++){ N++; COLORREF C=GetPixel(hBuff[1], i+k1, j+k2); R+=RED(C); G+=GREEN(C); B+=BLUE(C); } C=RGB(R/N, G/N, B/N); for(int k1=0;k1<8; k1++)for(int k2=0;k2<8; k2++){ SetPixel(hBuff[0],i+k1,j+k2,C); } } InvalidateRect(hw,NULL,TRUE); } void drawMono(HWND hw){//モノクロ画像化 COLORREF C; for(int i=0;i<300;i++)for(int j=0;j<300;j++){ C=GetPixel(hBuff[1],i,j); C=(RED(C)+GREEN(C)+BLUE(C))/3; SetPixel(hBuff[0],i,j,RGB(C,C,C)); } InvalidateRect(hw,NULL,TRUE); } void drawMove(HWND hw){//結果反映 BitBlt(hBuff[1],0,0,bM[1].bmWidth,bM[1].bmHeight,hBuff[0],0,0,SRCCOPY); InvalidateRect(hw,NULL,TRUE); } void createButton(HWND hw, TCHAR name[], int X,int Y, int w, int h, int No){ CreateWindow(TEXT("BUTTON"),name,WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON, X,Y,w,h, hw, (HMENU)No,hInstance,NULL); } HWND createLabel(HWND hw, TCHAR name[], int X,int Y, int w, int h, int No){ return CreateWindow(TEXT("STATIC"),name,WS_CHILD|WS_VISIBLE|SS_LEFT, X,Y,w,h, hw, (HMENU)No,hInstance,NULL); } void createScroll(HWND hw){ for(int i=0;i<3;i++){ scroll[i]= CreateWindow(TEXT("SCROLLBAR"),TEXT(""), WS_CHILD | WS_VISIBLE | SBS_HORZ, 30, i*20+70, 200, 20, hw, (HMENU)(2000+i), hInstance,NULL); scrLbl[i]=createLabel(hw,TEXT(" 100%"), 240, i*20+70, 60,20, 2100+i); scr[i].cbSize = sizeof(SCROLLINFO); scr[i].fMask=SIF_PAGE | SIF_RANGE; scr[i].nMin = 0; scr[i].nMax=100; scr[i].nPage=10; SetScrollInfo(scroll[i],SB_CTL, & scr[i],TRUE); scr[i].fMask=SIF_POS;scr[i].nPos=100; SetScrollInfo(scroll[i],SB_CTL, & scr[i],TRUE); } } void procCreate(HWND hw, WPARAM wp, LPARAM lp){ MoveWindow(hw, 0,0,700, 500,TRUE); SetWindowText(hw,TEXT("C言語で画像処理")); createButton(hw,TEXT("白黒化" ), 10, 2,90,30,BT_1); createButton(hw,TEXT("エッジ抽出" ),100, 2,90,30,BT_2); createButton(hw,TEXT("ぼかし" ),190, 2,90,30,BT_3); createButton(hw,TEXT("荷重平均" ),280, 2,90,30,BT_4); createButton(hw,TEXT("メディアン" ),370, 2,90,30,BT_5); createButton(hw,TEXT("ガンマ補正" ),460, 2,90,30,BT_6); createButton(hw,TEXT("モザイク" ), 10,32,90,30,BT_7); createButton(hw,TEXT("鮮明化" ),100,32,90,30,BT_8); createButton(hw,TEXT("明暗強調" ),190,32,90,30,BT_9); createButton(hw,TEXT("RGB比率" ),280,32,90,30,BT_10); createButton(hw,TEXT("RGB明暗" ),370,32,90,30,BT_11); createButton(hw,TEXT("結果反映" ),460,32,90,30,BT_13); createScroll(hw); createLabel(hw,TEXT("R"),10, 70,20,20,LB_1); createLabel(hw,TEXT("G"),10, 90,20,20,LB_2); createLabel(hw,TEXT("B"),10,110,20,20,LB_3); createLabel(hw,TEXT("左図で左ボタンドラッギングで複写範囲指定。"),300,70,400,20,LB_3); createLabel(hw,TEXT("続く左クリックで複写。右クリックで複写中止。"),300,90,400,20,LB_3); createLabel(hw,TEXT("右図の左右ボタンクリックでゴミピクセル混入。"),300,110,400,20,LB_3); HDC hdc=GetDC(hw); hBM[0]=CreateCompatibleBitmap(hdc,300,300); hBM[1]=LoadBitmap(hInstance,TEXT("pict1")); hBM[2]=CreateCompatibleBitmap(hdc,300,300); for(int i=0;i<3;i++){ hBuff[i]=CreateCompatibleDC(hdc);SelectObject(hBuff[i],hBM[i]); } SelectObject(hBuff[0], GetStockObject(NULL_PEN)); PatBlt(hBuff[0], 0,0,300,300,WHITENESS); SelectObject(hBuff[2], GetStockObject(NULL_PEN)); PatBlt(hBuff[2], 0,0,300,300,WHITENESS); for(int i=0;i<2;i++)GetObject(hBM[i],sizeof(BITMAP),&bM[i]); BitBlt(hBuff[0],0,0,bM[1].bmWidth,bM[1].bmHeight,hBuff[1],0,0,SRCCOPY); ReleaseDC(hw, hdc); hc=LoadCursor(NULL, IDC_ARROW);SetCursor(hc); InvalidateRect(hw,NULL,TRUE); } void drawFrame(HWND hw){//選択範囲指定時の枠組み表示 HPEN pen=CreatePen(PS_SOLID,1,0xFFFFFF); SelectObject(hBuff[0],pen); HBRUSH brush=CreateSolidBrush(0x00); SelectObject(hBuff[0],brush); SetROP2(hBuff[0],R2_XORPEN); Rectangle(hBuff[0],XR1,YR1, XR2,YR2); SetROP2(hBuff[0],R2_COPYPEN); DeleteObject(brush);DeleteObject(pen); InvalidateRect(hw,NULL,TRUE); } void moveImage(){//イメージの移動 int XT1=XT,YT1=YT, XT2=XT-(XR2-XR1),YT2=YT-(YR2-YR1); if(XT1>XT2)swap(int, XT1,XT2); if(YT1>YT2)swap(int, YT1,YT2); BitBlt(hBuff[0], XT1,YT1,XT2-XT1,YT2-YT1,hBuff[0],XR1,YR1,SRCCOPY); } void drawFrame2(HWND hw){//複写指定直前の枠組み表示 BitBlt(hBuff[0],0,0,bM[1].bmWidth,bM[1].bmHeight,hBuff[2],0,0,SRCCOPY); moveImage(); InvalidateRect(hw,NULL,TRUE); } void procLButtonDown(HWND hw, WPARAM wp, LPARAM lp){ int X=LOWORD(lp)-XST, Y=HIWORD(lp)-YST, X2=LOWORD(lp)-10; if (Y>0 && Y0 && X0 && X20 && Y0 && X0 && X2XR2) swap(int, XR1, XR2); if(YR1>YR2) swap(int, YR1, YR2); BitBlt(hBuff[2],0,0,bM[1].bmWidth,bM[1].bmHeight,hBuff[0],0,0,SRCCOPY); XT=X2; YT=Y; drawFrame2(hw); InvalidateRect(hw,NULL,TRUE); } } } } void procMouseMove(HWND hw, WPARAM wp, LPARAM lp){ //if(GetKeyState(VK_LBUTTON)>=0) return; int Y=HIWORD(lp)-YST, X2=LOWORD(lp)-10; if (Y>0 && Y0 && X20 && Y0 && X0 && X20) scr[i].nPos--;break; case SB_LINERIGHT:if(scr[i].nPos<(scr[i].nMax)) scr[i].nPos++;break; case SB_PAGELEFT :if(scr[i].nPos>=(int)scr[i].nPage) scr[i].nPos -=scr[i].nPage;break; case SB_PAGERIGHT: if((scr[i].nPos+(int)scr[i].nPage)<(scr[i].nMax-1)) scr[i].nPos +=scr[i].nPage;break; case SB_THUMBPOSITION:scr[i].nPos=HIWORD(wp); } SetScrollInfo(scroll[i],SB_CTL, & scr[i],TRUE); TCHAR str[256]; wsprintf(str,TEXT(" %3d%%"),scr[i].nPos); SetWindowText(scrLbl[i], str); } void procCommand(HWND hw, WPARAM wp, LPARAM lp){//ボタンイベント hc=LoadCursor(NULL, IDC_WAIT);SetCursor(hc); switch(LOWORD(wp)){ case BT_1:drawMono (hw);break; case BT_2:drawEdge (hw);break; case BT_3:drawShade (hw);break; case BT_4:drawAverage (hw);break; case BT_5:drawMedian (hw);break; case BT_6:drawGamma (hw);break; case BT_7:drawMosaic (hw);break; case BT_8:drawDistinct(hw);break; case BT_9:drawContrast(hw);break; case BT_10:drawRGB (hw);break; case BT_11:drawRGB2 (hw);break; case BT_13:drawMove (hw);break; } hc=LoadCursor(NULL, IDC_ARROW);SetCursor(hc); } LRESULT CALLBACK WndProc(HWND hw, UINT msg, WPARAM wp, LPARAM lp){ switch(msg){ case WM_DESTROY : for(int i=0;i<2;i++){DeleteDC(hBuff[i]); DeleteObject(hBM[i]);} PostQuitMessage(0) ; return 0; case WM_CREATE : procCreate (hw, wp, lp); return 0; case WM_LBUTTONDOWN : procLButtonDown (hw, wp, lp); return 0; case WM_LBUTTONUP : procLButtonUp (hw, wp, lp); return 0; case WM_RBUTTONDOWN : procRButtonDown (hw, wp, lp); return 0; case WM_MOUSEMOVE : procMouseMove (hw, wp, lp); return 0; case WM_COMMAND : procCommand (hw, wp, lp); return 0; case WM_PAINT : procPaint (hw, wp, lp); return 0; case WM_HSCROLL : procHScroll (hw, wp, lp); return 0; case WM_SETCURSOR : SetCursor(hc); return 0; } return DefWindowProc(hw, msg, wp, lp); }