第5章 画像変形 【リスト5-1】 型紙によるトリミング #include "myWin.h" #include "math.h" #define XST 420 #define YST 10 #define GWIDTH 400 #define GHIGHT 400 #define RED(X) (X & 0xFF) #define GREEN(X) ((X>>8) & 0xFF) #define BLUE(X) ((X>>16) & 0xFF) static HBITMAP hBM[2];static HDC hBuff[2]; static BITMAP bM[2]; void clearBitmap(int i){//ビットマップのクリア SelectObject(hBuff[i], GetStockObject(NULL_PEN)); PatBlt(hBuff[i], 0,0,GWIDTH,GHIGHT,WHITENESS);//黒塗り } void createBitmap(HWND hw){//ビットマップの設定 HDC hdc=GetDC(hw); for(int i=0;i<2;i++){ hBM[i]=CreateCompatibleBitmap(hdc,GWIDTH,GHIGHT); hBuff[i]=CreateCompatibleDC(hdc); SelectObject(hBuff[i], hBM[i]); clearBitmap(i); } } int pixel(int i, int j){//画像1からピクセルを取り出す return GetPixel(hBuff[1], i,j); } void setPixel(int i, int j, COLORREF C){//画像0にピクセルを設定する SetPixel(hBuff[0], i,j, C); } void procPolygon(){ int NUMPOLY=5; POINT poly[]={{200,10},{390,150},{300,350}, {100,350},{19,150}}; PatBlt(hBuff[0], 0,0,GWIDTH,GHIGHT,BLACKNESS);//黒塗り HPEN hpen=CreatePen(PS_NULL,1,0xFFFFFF);SelectObject(hBuff[0], hpen); HBRUSH brush=CreateSolidBrush(0xFFFFFF); SelectObject(hBuff[0], brush); Polygon(hBuff[0],poly,NUMPOLY);//型紙の描画 BitBlt(hBuff[0],0,0,GWIDTH, GHIGHT, hBuff[1], 0,0,SRCAND); DeleteObject(hpen);DeleteObject(hpen); } void procLButtonDown(HWND hw, WPARAM wp,LPARAM lp){ procPolygon(); InvalidateRect(hw,NULL,TRUE); } void procRButtonDown(HWND hw, WPARAM wp,LPARAM lp){ clearBitmap(0);//画像0をクリア InvalidateRect(hw,NULL,TRUE); } void procCreate(HWND hw, WPARAM wp,LPARAM lp){//初期処理 createBitmap(hw);MoveWindow(hw,0,0,850,460,TRUE); hBM[1]=LoadBitmap(hInstance, TEXT("suzume"));//画像1に表示 GetObject(hBM[1],sizeof(BITMAP), &bM[1]); InvalidateRect(hw,NULL,TRUE); } void procPaint(HWND hw, WPARAM wp,LPARAM lp){//画面表示 PAINTSTRUCT ps; HDC hdc = BeginPaint(hw,&ps); SelectObject(hBuff[0],hBM[0]);SelectObject(hBuff[1],hBM[1]); BitBlt(hdc,10,YST,GWIDTH, GHIGHT, hBuff[0], 0,0,SRCCOPY); BitBlt(hdc,XST,YST,GWIDTH, GHIGHT, hBuff[1], 0,0,SRCCOPY); EndPaint(hw,&ps); } LRESULT CALLBACK WndProc(HWND hw, UINT msg, WPARAM wp,LPARAM lp){ switch(msg){ case WM_DESTROY : PostQuitMessage(0) ; return 0; case WM_CREATE : procCreate(hw,wp,lp); return 0; case WM_LBUTTONDOWN : procLButtonDown(hw,wp,lp); return 0; case WM_RBUTTONDOWN : procRButtonDown(hw,wp,lp); return 0; case WM_PAINT : procPaint (hw,wp,lp); return 0; } return DefWindowProc(hw,msg,wp,lp); } (ANDによる描画ができない言語の場合) ---(前略)--- Polygon(hBuff[0],poly,NUMPOLY); for(int i=0;i=GWIDTH || IY<0 || IY>=GHIGHT) C=0; else C=pixel(IX,IY); setPixel(i,j,C); } } void procLButtonDown(HWND hw, WPARAM wp,LPARAM lp){ affineTransformation(); InvalidateRect(hw,NULL,TRUE); } 【リスト5-5】 バイリニア補間法 COLORREF mixColor(int C1, int C2,double Alfa){ return (COLORREF) ((double)C1*(1-Alfa)+(double)C2*Alfa); } COLORREF mixColor24(COLORREF C1,COLORREF C2, double DX){ COLORREF R1,G1,B1, R2,G2,B2; R1=RED(C1);G1=GREEN(C1); B1=BLUE(C1); R2=RED(C2);G2=GREEN(C2); B2=BLUE(C2); R1=mixColor(R1,R2,DX);G1=mixColor(G1,G2,DX);B1=mixColor(B1,B2,DX); return RGB(R1,G1, B1); } COLORREF bilinear(double X,double Y){ int IX,IY, JX, JY;double DX1, DY1; IX=(int)X; IY=(int)Y; if(IX<0 || IX>=GWIDTH || IY<0 || IY>=GHIGHT) return 0; if(IX==(GWIDTH-1) && IY>=(GHIGHT-1))return pixel(GWIDTH-1, GHIGHT-1); if(IX==(GWIDTH-1))return pixel(GWIDTH-1, IY); if(IY>=(GHIGHT-1))return pixel(IX, GHIGHT-1); JX=IX+1; JY=IY+1; DX1=X-(double)IX; DY1=Y-(double)IY; COLORREF C1=mixColor24(pixel(IX,IY),pixel(JX,IY), DX1); COLORREF C2=mixColor24(pixel(IX,JY),pixel(JX,JY), DX1); return mixColor24(C1, C2, DY1); } 【リスト5-6】 バイキュービック補間法 #define BIQA -1.0 double biParam[] = {BIQA+3.0, BIQA+2.0, - (BIQA*4.0), BIQA*8.0, BIQA*5.0}; COLORREF bicubic(double X,double Y){ int IX,IY;double Eps=0.001;IX=(int)X; IY=(int)Y; if(IX<0 || IX>=GWIDTH || IY<0 || IY>=GHIGHT) return 0; if(IX==(GWIDTH-1) && IY>=(GHIGHT-1))return pixel(GWIDTH-1, GHIGHT-1); if(IX==(GWIDTH-1))return pixel(GWIDTH-1, IY); if(IY>=(GHIGHT-1))return pixel(IX, GHIGHT-1); if(IX==0 || IY==0 || IX>(GWIDTH-3) || IY>(GHIGHT-3)){ IX=(int)(X+0.5); IY=(int)(Y+0.5); return pixel(IX,IY); } double CL[3]; CL[0]=CL[1]=CL[2]=0; for(int i=-1;i<3;i++)for(int j=-1;j<3;j++){ int XC=IX+i, YC=IY+j; double DX=abs(XC-X), DY=abs(YC-Y), WGT=0.0; int iflag=true; if(DX<=1.0)WGT=1.0-biParam[0]*DX*DX+biParam[1]*DX*DX*DX; else if(DX<=2.0) WGT=biParam[2]+biParam[3]*DX-biParam[4]*DX*DX+BIQA*DX*DX*DX; else iflag=false; if(iflag){ if(DY<=1.0)WGT*=1.0-biParam[0]*DY*DY+biParam[1]*DY*DY*DY; else if(DY<=2.0) WGT*=biParam[2]+biParam[3]*DY-biParam[4]*DY*DY+BIQA*DY*DY*DY; else iflag=false; } if(iflag){ int C=pixel(XC,YC); CL[0]+= RED(C)*WGT;CL[1]+= GREEN(C)*WGT;CL[2]+= BLUE(C)*WGT; } } if(CL[0]>255) CL[0]=255;if(CL[0]<0)CL[0]=0; if(CL[1]>255) CL[1]=255;if(CL[1]<0)CL[1]=0; if(CL[2]>255) CL[2]=255;if(CL[2]<0)CL[2]=0; return RGB((int)CL[0],(int)CL[1],(int)CL[2]); } 【リスト5-7】 アフィン変換以外の変換(その1) void otherTrans(){ double X, Y;COLORREF C; for(int i=0;i=GWIDTH || IY<0 || IY>=GHIGHT) C=0; else C=pixel(IX,IY); setPixel(i,j,C); } } void procLButtonDown(HWND hw, WPARAM wp,LPARAM lp){ otherTrans(); InvalidateRect(hw,NULL,TRUE); } 【リスト5-8】 アフィン変換以外の変換(その2) void otherTrans(){ double X, Y;COLORREF C; for(int i=0;i=GWIDTH || IY<0 || IY>=GHIGHT) C=0; else C=pixel(IX,IY); setPixel(i,j,C); } } 【リスト5-9】 アフィン変換以外の変換(その3) void otherTrans(){ double X, Y;COLORREF C; for(int i=0;i=GWIDTH || IY<0 || IY>=GHIGHT) C=0; else C=pixel(IX,IY); setPixel(i,j,C); } } 【リスト5-10】 歪んだ四角形 void drawImage(double X1, double Y1, double X2, double Y2, double X3, double Y3, double X4, double Y4){ int iw=GWIDTH, ih=GHIGHT; double w=(double)iw, h=(double)ih; double sDY1=Y3-Y1, sDY2=Y4-Y2, sDX1=X3-X1, sDX2=X4-X2, ST=abs(sDY1); if(abs(sDY2)>ST)ST=abs(sDY2); if(abs(sDX1)>ST)ST=abs(sDX1); if(abs(sDX2)>ST)ST=abs(sDX2); ST*=2;sDY1/=ST; sDY2/=ST; sDX1/=ST; sDX2/=ST; double YY1=Y1, YY2=Y2, XX1=X1, XX2=X2; int jed=(int)(ST+0.5); for(int j=0; jST2)ST2=abs(DY); ST2*=2; DX/=ST2; DY/=ST2; int ked=(int)(ST2+0.5); double X=XX1,Y=YY1; for(int k=0; kLLX)break; double c=(double)j/(double)i;if(i=LX)ii=LX-1; int jj=(int)((double)j*D+0.5);//if(jj>=LY)jj=LY-1; if(iiLLX)break; double r=(double)j/(LY-1); r=sqrt(1-r*r); int ii=(int)((double)i/r+0.5);if(ii>=LX)ii=LX-1; int jj=j; setPixel(LX+i,LY+j,pixel(LX+ii,LY+jj)); setPixel(LX-i,LY-j,pixel(LX-ii,LY-jj)); setPixel(LX-i,LY+j,pixel(LX-ii,LY+jj)); setPixel(LX+i,LY-j,pixel(LX+ii,LY-jj)); } } } 【リスト5-13】 XY座標の対応表作成 int xTab[GWIDTH][GHIGHT], yTab[GWIDTH][GHIGHT]; void genXTab(){ for(int j=0;j=0) setPixel(i,j, pixel(xTab[i][j],yTab[i][j])) ; } 【リスト5-15】 一般図形への画像詰込み void drawPolygon(){ int NUMPOLY=5; POINT poly[]={{200,10},{390,150},{300,350}, {100,350},{19,150}}; PatBlt(hBuff[0], 0,0,GWIDTH,GHIGHT,BLACKNESS);//黒塗り HPEN hpen=CreatePen(PS_NULL,1,0xFFFFFF);SelectObject(hBuff[0], hpen); HBRUSH brush=CreateSolidBrush(0xFF00FF);SelectObject(hBuff[0], brush); Ellipse(hBuff[0],0,0,400,300); Polygon(hBuff[0],poly,NUMPOLY); DeleteObject(hpen);DeleteObject(hpen); } 【リスト5-16】 最大・最小で比例配分 void genXTab2(){ int maxX=0,minX=GWIDTH; for(int i=0;imaxX)maxX=i; if(imaxY)maxY=j; if(j