//----------------------------------------------------------------- // ipcommon.cpp: // 画像処理一般 // Last Update: <2006/10/24 12:05:46 A.Murakami> //----------------------------------------------------------------- #include #include #include #include #include "wingui.h" #include "ipcommon.h" //----------------------------------------------------------------- // ユークリッドの互除法による最小公倍数 //----------------------------------------------------------------- // ユークリッドの互除法による最小公倍数 int lcm(int a,int b) { int x=a,y=b,c; if(a<=0||b<=0) return 1; if(a 0) maxv = a[i]; if(a[i]-minv < 0) minv = a[i]; } // 正規化 for(i=0;iiWHITE) gray=iWHITE; return gray; } //----------------------------------------------------------------- // RGB から YUV 色調への計算 //----------------------------------------------------------------- void rgb2yuv(BYTE r,BYTE g,BYTE b,BYTE &y,BYTE &u,BYTE &v) { double yv,uv,vv; yv = (0.2989 *(r+175.45)+0.5871*(g-132.40)+0.1140*(b+221.74)); uv = (0.5115 *(r+175.45)-0.4283*(g-132.40)-0.0832*(b+221.74)); vv = (-0.1726*(r+175.45)-0.3389*(g-132.40)+0.5114*(b+221.74)); if(yv>iWHITE) yv=iWHITE; if(yv<0) yv=0; if(uv>iWHITE) uv=iWHITE; if(uv<0) uv=0; if(vv>iWHITE) vv=iWHITE; if(vv<0) vv=0; y = (BYTE)yv; u = (BYTE)uv; v = (BYTE)vv; } BYTE rgb2y(BYTE r,BYTE g,BYTE b) { double yv; yv = (0.2989 *(r+175.45)+0.5871*(g-132.40)+0.1140*(b+221.74)); if(yv>iWHITE) yv=iWHITE; if(yv<0) yv=0; return (BYTE)yv; } BYTE rgb2u(BYTE r,BYTE g,BYTE b) { double uv; uv = (0.5115 *(r+175.45)-0.4283*(g-132.40)-0.0832*(b+221.74)); if(uv>iWHITE) uv=iWHITE; if(uv<0) uv=0; return (BYTE)uv; } BYTE rgb2v(BYTE r,BYTE g,BYTE b) { double vv; vv = (-0.1726*(r+175.45)-0.3389*(g-132.40)+0.5114*(b+221.74)); if(vv>iWHITE) vv=iWHITE; if(vv<0) vv=0; return (BYTE)vv; } //----------------------------------------------------------------- // RGB から ρ/θ の計算 //----------------------------------------------------------------- void rgb2rth(BYTE r,BYTE g,BYTE b,BYTE &rho,BYTE &th) { // YUV 色調への変換 BYTE y,u,v; rgb2yuv(r,g,b,y,u,v); // 色彩距離(ρ),色相(θ) の計算 double tmp1,tmp2,rhov,thv; tmp1=u-128.; tmp2=v-128.; rhov = sqrt(tmp1*tmp1+tmp2*tmp2); thv = rad2deg(atan2(tmp1,tmp2)); if(rhov<0) rhov=0; if(rhov>180) rhov=180; if(thv<0) thv+=360; if(thv>360) thv-=360; rhov = (double)iWHITE*(rhov)/(180.); thv = (double)iWHITE*(thv) /(360.); rho = (BYTE)rhov; th = (BYTE)thv; } BYTE rgb2rho(BYTE r,BYTE g,BYTE b) { // YUV 色調への変換 BYTE y,u,v; rgb2yuv(r,g,b,y,u,v); // 色彩距離(ρ)の計算 double tmp1,tmp2,rhov; tmp1=u-128.; tmp2=v-128.; rhov = sqrt(tmp1*tmp1+tmp2*tmp2); if(rhov<0) rhov=0; if(rhov>180) rhov=180; rhov = (double)iWHITE*(rhov)/(180.); return (BYTE)rhov; } BYTE rgb2theta(BYTE r,BYTE g,BYTE b) { // YUV 色調への変換 BYTE y,u,v; rgb2yuv(r,g,b,y,u,v); // 色相(θ) の計算 double tmp1,tmp2,thv; tmp1=u-128.; tmp2=v-128.; thv = rad2deg(atan2(tmp1,tmp2)); if(thv<0) thv+=360; if(thv>360) thv-=360; thv = (double)iWHITE*(thv) /(360.); return (BYTE)thv; } //----------------------------------------------------------------- // 描画関数 //----------------------------------------------------------------- // 中心:p(x,y),半径:r の円を描く void draw_circle(LPBYTE oBuf,POINT cp,int radius) { int xs,ys,th,th_max; double cirstep; // 1ピクセル毎の計算となるように th_max = rint(2*M_PI*radius); cirstep = 360./th_max; for(th=0;th=xw1 && dx1<=xw2 && dy1>=yw1 && dy1<=yw2){ *x1 = dx1; *y1 = dy1; mkp1 = 1; } if(dx2>=xw1 && dx2<=xw2 && dy2>=yw1 && dy2<=yw2){ *x2 = dx2; *y2 = dy2; mkp2 = 1; } //-------------------------------------------------- // ウィンドウ内であれば終了 //-------------------------------------------------- if(mkp1 == 1 && mkp2 == 1) return 1; ip = 0; //-------------------------------------------------- // 直線とウィンドウの上下の枠と交差する点を求める //-------------------------------------------------- for(i=0;i<2;i++){ wk=gr_wnx[i]; is=croslnxc(dx1,dy1,dx2,dy2,wk,&yc); if(is == 1 && yc>=yw1 && yc<=yw2){ xx[ip] = wk; yy[ip] = yc; ip++; } } //-------------------------------------------------- // 直線とウィンドウの左右の枠と交差する点を求める //-------------------------------------------------- if(ip<2){ for(i=0;i<2;i++){ wk=gr_wny[i]; is=croslnyc(dx1,dy1,dx2,dy2,wk,&xc); if(is == 1 && xc>=xw1 && xc<=xw2){ xx[ip] = xc; yy[ip] = wk; ip++; } } } //-------------------------------------------------- // 描く直線が枠と交差しない場合は直線の全てが // 枠の外側にあるので、描く必要がないことをしめす //-------------------------------------------------- if(ip==0) return 0; //-------------------------------------------------- // 枠と交差する点を描く直線の対応する端点として代入 //-------------------------------------------------- for(i=0;i<2;i++){ ds1[i] = ((xx[i]-dx1)*(xx[i]-dx1)+(yy[i]-dy1)*(yy[i]-dy1)); ds2[i] = ((xx[i]-dx2)*(xx[i]-dx2)+(yy[i]-dy2)*(yy[i]-dy2)); } if(mkp1 == 0){ if(ds1[0]ds1[1]){ *x1 = xx[1]; *y1 = yy[1]; } } if(mkp2 == 0){ if(ds2[0]ds2[1]){ *x2 = xx[1]; *y2 = yy[1]; } } return 1; } //----------------------------------------------------------------- // テンプレート位置の描画[網掛け] //----------------------------------------------------------------- void mark_template_area(LPBYTE inBuf,POINT tp,int txsize,int tysize) { int x,y,xstep=5,ystep=5; for(y=tp.y;yiGHistへ //----------------------------------------------------------------- void make_histogram(LPBYTE inBuf) { int x,y; FillMemory(iGHist,sizeof(UINT)*iMAX_GRAY,0); for(y=0;yiWHITE) gray=iWHITE; iGHist[gray]++; iGray[j+i*iWidth] = gray; } return iGray; } LPBYTE GetColor(int csel) { int i,j; BYTE r,g,b,gray; LPBYTE iColor=(LPBYTE)GlobalAlloc(GPTR,sizeof(BYTE)*iSize); FillMemory(iGHist,sizeof(UINT)*512,0); for(i=0;iINTP_NN){ if(y>0) m=(int)y; else m=(int)(y-1); if(x>0) n=(int)x; else n=(int)(x-1); } else { m = rint(y); n = rint(x); } // out of area if(!ip_safe(n+xc,m+yc,iWidth,iHeight)) return 0; // interpolation switch(intp_opt){ case INTP_NN: // nearest neighbour gray = ib[XY2PI(n+xc,m+yc,iWidth)]; break; case INTP_LN: // linear if(!ip_safe(n+xc+1,m+yc+1,iWidth,iHeight)) return 0; // 線形補間 q = y-m; p = x-n; p1 = ib[XY2PI(n+xc ,m+yc ,iWidth)]; p2 = ib[XY2PI(n+xc+1,m+yc ,iWidth)]; p3 = ib[XY2PI(n+xc ,m+yc+1,iWidth)]; p4 = ib[XY2PI(n+xc+1,m+yc+1,iWidth)]; gray = rint((1.0-q)*((1.0-p)*p1+p*p2) + q*((1.0-p)*p3+p*p4)); break; case INTP_BCC: // bicubic if(!ip_safe(n+xc+2,m+yc+2,iWidth,iHeight) || !ip_safe(n+xc-1,m+yc-1,iWidth,iHeight)) return 0; // 16個の格子点を用いた補間(3次補間) c[0]=(m-1)-y; c[1]=m-y; c[2]=(m+1)-y; c[3]=(m+2)-y; c[4]=(n-1)-x; c[5]=n-x; c[6]=(n+1)-x; c[7]=(n+2)-x; // 補間関数 for(i=0;i<8;i++){ if(c[i]<0) c[i]=-c[i]; if(0<=c[i] && c[i]<1) c[i]=1-2*c[i]*c[i]+c[i]*c[i]*c[i]; else if(1<=c[i] && c[i]<2) c[i]=4-8*c[i]+5*c[i]*c[i]-c[i]*c[i]*c[i]; else if(2<=c[i]) c[i]=0; } // 補間濃度 sum = 0; sum += c[0]*c[4]*ib[XY2PI(n+xc-1,m+yc-1,iWidth)]; sum += c[0]*c[5]*ib[XY2PI(n+xc ,m+yc-1,iWidth)]; sum += c[0]*c[6]*ib[XY2PI(n+xc+1,m+yc-1,iWidth)]; sum += c[0]*c[7]*ib[XY2PI(n+xc+2,m+yc-1,iWidth)]; sum += c[1]*c[4]*ib[XY2PI(n+xc-1,m+yc ,iWidth)]; sum += c[1]*c[5]*ib[XY2PI(n+xc ,m+yc ,iWidth)]; sum += c[1]*c[6]*ib[XY2PI(n+xc+1,m+yc ,iWidth)]; sum += c[1]*c[7]*ib[XY2PI(n+xc+2,m+yc ,iWidth)]; sum += c[2]*c[4]*ib[XY2PI(n+xc-1,m+yc+1,iWidth)]; sum += c[2]*c[5]*ib[XY2PI(n+xc ,m+yc+1,iWidth)]; sum += c[2]*c[6]*ib[XY2PI(n+xc+1,m+yc+1,iWidth)]; sum += c[2]*c[7]*ib[XY2PI(n+xc+2,m+yc+1,iWidth)]; sum += c[3]*c[4]*ib[XY2PI(n+xc-1,m+yc+2,iWidth)]; sum += c[3]*c[5]*ib[XY2PI(n+xc ,m+yc+2,iWidth)]; sum += c[3]*c[6]*ib[XY2PI(n+xc+1,m+yc+2,iWidth)]; sum += c[3]*c[7]*ib[XY2PI(n+xc+2,m+yc+2,iWidth)]; if(sum<0) sum = 0; if(sum>iWHITE) sum = iWHITE; gray = rint(sum); break; } if(gray<0) gray=0; if(gray>iWHITE) gray=iWHITE; return (BYTE)gray; } CPIXEL c_image_interpolation(LPBYTE icb,int intp_opt, double x,double y,int xc,int yc) { CPIXEL rgb={0,0,0}; int i,m,n,gray,r,g,b; // for linear BYTE p1,p2,p3,p4; double p,q; // for bicubic double c[8],sum; // point of interpolation if(intp_opt>INTP_NN){ if(y>0) m=(int)y; else m=(int)(y-1); if(x>0) n=(int)x; else n=(int)(x-1); } else { m = rint(y); n = rint(x); } // out of area if(!ip_safe(n+xc,m+yc,iWidth,iHeight)) return rgb; // interpolation switch(intp_opt){ case INTP_NN: // nearest neighbour r = icb[XY2PI((n+xc)*3,m+yc,iLength)+2]; g = icb[XY2PI((n+xc)*3,m+yc,iLength)+1]; b = icb[XY2PI((n+xc)*3,m+yc,iLength)+0]; break; case INTP_LN: // linear if(!ip_safe(n+xc+1,m+yc+1,iWidth,iHeight)) return rgb; // 線形補間 for(i=0;i<3;i++){ q = y-m; p = x-n; p1 = icb[XY2PI((n+xc )*3,m+yc ,iLength)+i]; p2 = icb[XY2PI((n+xc+1)*3,m+yc ,iLength)+i]; p3 = icb[XY2PI((n+xc )*3,m+yc+1,iLength)+i]; p4 = icb[XY2PI((n+xc+1)*3,m+yc+1,iLength)+i]; gray = rint((1.0-q)*((1.0-p)*p1+p*p2) + q*((1.0-p)*p3+p*p4)); switch(i){ case 0: b = gray; break; case 1: g = gray; break; case 2: r = gray; break; } } break; case INTP_BCC: // bicubic if(!ip_safe(n+xc+2,m+yc+2,iWidth,iHeight) || !ip_safe(n+xc-1,m+yc-1,iWidth,iHeight)) return rgb; // 16個の格子点を用いた補間(3次補間) c[0]=(m-1)-y; c[1]=m-y; c[2]=(m+1)-y; c[3]=(m+2)-y; c[4]=(n-1)-x; c[5]=n-x; c[6]=(n+1)-x; c[7]=(n+2)-x; // 補間関数 for(i=0;i<8;i++){ if(c[i]<0) c[i]=-c[i]; if(0<=c[i] && c[i]<1) c[i]=1-2*c[i]*c[i]+c[i]*c[i]*c[i]; else if(1<=c[i] && c[i]<2) c[i]=4-8*c[i]+5*c[i]*c[i]-c[i]*c[i]*c[i]; else if(2<=c[i]) c[i]=0; } // 補間濃度 for(i=0;i<3;i++){ sum = 0; sum += c[0]*c[4]*icb[XY2PI((n+xc-1)*3,m+yc-1,iLength)+i]; sum += c[0]*c[5]*icb[XY2PI((n+xc )*3,m+yc-1,iLength)+i]; sum += c[0]*c[6]*icb[XY2PI((n+xc+1)*3,m+yc-1,iLength)+i]; sum += c[0]*c[7]*icb[XY2PI((n+xc+2)*3,m+yc-1,iLength)+i]; sum += c[1]*c[4]*icb[XY2PI((n+xc-1)*3,m+yc ,iLength)+i]; sum += c[1]*c[5]*icb[XY2PI((n+xc )*3,m+yc ,iLength)+i]; sum += c[1]*c[6]*icb[XY2PI((n+xc+1)*3,m+yc ,iLength)+i]; sum += c[1]*c[7]*icb[XY2PI((n+xc+2)*3,m+yc ,iLength)+i]; sum += c[2]*c[4]*icb[XY2PI((n+xc-1)*3,m+yc+1,iLength)+i]; sum += c[2]*c[5]*icb[XY2PI((n+xc )*3,m+yc+1,iLength)+i]; sum += c[2]*c[6]*icb[XY2PI((n+xc+1)*3,m+yc+1,iLength)+i]; sum += c[2]*c[7]*icb[XY2PI((n+xc+2)*3,m+yc+1,iLength)+i]; sum += c[3]*c[4]*icb[XY2PI((n+xc-1)*3,m+yc+2,iLength)+i]; sum += c[3]*c[5]*icb[XY2PI((n+xc )*3,m+yc+2,iLength)+i]; sum += c[3]*c[6]*icb[XY2PI((n+xc+1)*3,m+yc+2,iLength)+i]; sum += c[3]*c[7]*icb[XY2PI((n+xc+2)*3,m+yc+2,iLength)+i]; if(sum<0) sum = 0; if(sum>iWHITE) sum = iWHITE; gray = rint(sum); switch(i){ case 0: b = gray; break; case 1: g = gray; break; case 2: r = gray; break; } } break; } if(r<0) r=0; if(r>iWHITE) r=iWHITE; if(g<0) g=0; if(g>iWHITE) g=iWHITE; if(b<0) b=0; if(b>iWHITE) b=iWHITE; rgb.r = r; rgb.g = g; rgb.b = b; return rgb; } //----------------------------------------------------------------- // 最近傍法による画像サイズの縮小・拡大[nearest neighbour] //----------------------------------------------------------------- void nn_scale(LPBYTE inBuf,double zx,double zy) { int i,j,m,n; int xsize=(zx>1.0)?iWidth : rint(iWidth*zx); LPBYTE ib; // 画像確保 ib=(LPBYTE)GlobalAlloc(GPTR,sizeof(BYTE)*iSize); CopyMemory(ib,inBuf,sizeof(BYTE)*iSize); FillMemory(inBuf,sizeof(BYTE)*iSize,0); // 変換 for(i=0;i1.0)?iWidth:rint(iWidth*zx); double x,y,p,q; LPBYTE ib; // 画像確保 ib=(LPBYTE)GlobalAlloc(GPTR,sizeof(BYTE)*iSize); CopyMemory(ib,inBuf,sizeof(BYTE)*iSize); FillMemory(inBuf,sizeof(BYTE)*iSize,0); // 変換 for(i=0;iiWHITE) d=iWHITE; } else d = 0; inBuf[XY2PI(j,i,xsize)] = d; } GlobalFree(ib); } //----------------------------------------------------------------- // バイキュービック[3次補間]法による画像の拡大・縮小 //----------------------------------------------------------------- void bcc_scale(LPBYTE inBuf,double zx,double zy) { int i,j,k,m,n,d; int xsize=(zx>1.0)?iWidth : rint(iWidth*zx); double x,y,c[8],sum; LPBYTE ib; // 画像確保 ib=(LPBYTE)GlobalAlloc(GPTR,sizeof(BYTE)*iSize); CopyMemory(ib,inBuf,sizeof(BYTE)*iSize); FillMemory(inBuf,sizeof(BYTE)*iSize,0); // 変換 for(i=0;iiWHITE) sum = iWHITE; d = rint(sum); } else d=0; inBuf[XY2PI(j,i,xsize)] = d; } } //----------------------------------------------------------------- // 平均画素法による画像サイズの縮小 // [兼ローパスフィルタ] //----------------------------------------------------------------- void sqm_scale(LPBYTE inBuf,double zx,double zy) { int i,x,y,x1,x2,y1,y2; int lcm_x,lcm_y,p_count,meanp; int xsize,ysize,oxsize,oysize; LPBYTE oneline; // 画像サイズ[偶数に調節] xsize = oxsize = rint(iWidth*zx); ysize = oysize = rint(iHeight*zy); if(xsize%2) xsize--; if(ysize%2) ysize--; // 最小公倍数の計算 lcm_x = lcm(iWidth ,xsize); lcm_y = lcm(iHeight,ysize); x1 = lcm_x / iWidth; y1 = lcm_y / iHeight; x2 = lcm_x / xsize; y2 = lcm_y / ysize; // 描画サイズは元のまま if(xsize>iWidth ) xsize = oxsize = iWidth; if(ysize>iHeight) ysize = oysize = iHeight; //-------------------------------------------------- // x 方向 //-------------------------------------------------- oneline=(LPBYTE)GlobalAlloc(GPTR,sizeof(BYTE)*iWidth*x1); for(y=0;yiWidth ) xsize = oxsize = iWidth; if(ysize>iHeight) ysize = oysize = iHeight; // ビットマップ用サイズ if((oxsize*3)%4==0) bxsize = oxsize*3; else bxsize = oxsize*3+(4-(oxsize*3)%4); //-------------------------------------------------- // x 方向 //-------------------------------------------------- oneline=(LPBYTE)GlobalAlloc(GPTR,sizeof(BYTE)*iLength*x1); for(y=0;y DITHER_NL-1) new_gray = DITHER_NL-1; inBuf[XY2PI(x,y,iWidth)] = new_gray; } //-------------------------------------------------- // ディザ画像の作成 //-------------------------------------------------- x_block=iWidth / DITHER_BSZ; // 横のブロック数 y_block=iHeight / DITHER_BSZ; // 縦のブロック数 if(iWidth % DITHER_BSZ) x_block++; if(iHeight % DITHER_BSZ) y_block++; for(i=0;imaxv) maxv=inBuf[XY2PI(x,y,iWidth)]; } // 階調を線形変換して image2[y][x] に代入 for(y=0;y=iLevel) gray=iLevel-1; } trans_table[i] = gray; trhist[gray] += iGHist[i]; } // 平滑化した画像の作成 gray_step = (double)(iWHITE+1) / iLevel; for(y=0;y maxv) maxv = new_value; } // フィルタリングを行う for(y=1;y max_frequency) max_frequency = iGHist[i]; // ヒストグラム画像の作成 FillMemory(inBuf,sizeof(BYTE)*iSize,0); for(i=0;i