워핑과 모핑 C# 소스 코드
워핑과 모핑 부분 소스 코드
- 메뉴를 다음과 같이 추가한다.
- [기하_워핑] 메뉴를 더블클릭한 후 private void 기하워핑ToolStripMenuItem_Click() 함수 위쪽에 f_Warping 함수를 추가한다.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293private byte[] f_Warping(int width, int height, control_line[] source_lines, control_line[] dest_lines, byte[] data){int depth = data.Length / width / height;byte[] newdata = new byte[data.Length];double u; // 수직 교차점의 위치double h; // 제어선으로부터 픽셀의 수직 변위double d; // 제어선과 픽셀 사이의 거리double tx, ty; // 결과영상 픽셀에 대응되는 입력 영상 픽셀 사이의 변위의 합double xp, yp; // 각 제어선에 대해 계산된 입력 영상의 대응되는 픽셀 위치double weight; // 각 제어선의 가중치double totalWeight; // 가중치의 합double a = 0.001;double b = 2.0;double p = 0.75;int x1, x2, y1, y2;int src_x1, src_y1, src_x2, src_y2;double src_line_length, dest_line_length;int num_lines = 23; // 제어선의 수int line;int x, y;int source_x, source_y;int last_row, last_col;last_row = height - 1;last_col = width - 1;// 출력 영상의 각 픽셀에 대하여for (y = 0; y < height; y++){for (x = 0; x < width; x++){totalWeight = 0.0;tx = 0.0;ty = 0.0;// 각 제어선에 대하여for (line = 0; line < num_lines; line++){x1 = dest_lines[line].Px;y1 = dest_lines[line].Py;x2 = dest_lines[line].Qx;y2 = dest_lines[line].Qy;dest_line_length = Math.Sqrt((float)(x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));// 수직교차점의 위치 및 픽셀의 수직 변위 계산u = (double)((x - x1) * (x2 - x1) + (y - y1) * (y2 - y1)) /(double)((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));h = (double)((y - y1) * (x2 - x1) - (x - x1) * (y2 - y1)) / dest_line_length;// 제어선과 픽셀 사이의 거리 계산if (u < 0) d = Math.Sqrt((float)(x - x1) * (x - x1) + (y - y1) * (y - y1));else if (u > 1) d = Math.Sqrt((float)(x - x2) * (x - x2) + (y - y2) * (y - y2));else d = Math.Abs(h);src_x1 = source_lines[line].Px;src_y1 = source_lines[line].Py;src_x2 = source_lines[line].Qx;src_y2 = source_lines[line].Qy;src_line_length = Math.Sqrt((float)(src_x2 - src_x1) * (src_x2 - src_x1) +(src_y2 - src_y1) * (src_y2 - src_y1));// 입력 영상에서의 대응 픽셀 위치 계산xp = src_x1 + u * (src_x2 - src_x1) -h * (src_y2 - src_y1) / src_line_length;yp = src_y1 + u * (src_y2 - src_y1) +h * (src_x2 - src_x1) / src_line_length;// 제어선에 대한 가중치 계산weight = Math.Pow((Math.Pow((double)(dest_line_length), p) / (a + d)), b);// 대응 픽셀과의 변위 계산tx += (xp - x) * weight;ty += (yp - y) * weight;totalWeight += weight;}source_x = x + (int)(tx / totalWeight + 0.5);source_y = y + (int)(ty / totalWeight + 0.5);// 영상의 경계를 벗어나는지 검사if (source_x < 0) source_x = 0;if (source_x > last_col) source_x = last_col;if (source_y < 0) source_y = 0;if (source_y > last_row) source_y = last_row;for (int dt = 0; dt < depth; dt++){newdata[(y * width + x) * depth + dt] = data[(source_y * width + source_x) * depth + dt];}}}return newdata;}
- control_line 클래스를 추가한다.
123456789101112131415class control_line{public int Px;public int Py;public int Qx;public int Qy;public control_line(int px, int py, int qx, int qy){this.Px = px;this.Py = py;this.Qx = qx;this.Qy = qy;}}
- [기하_워핑] 메뉴를 더블클릭한 후 다음코드를 완성한다.
12345678910111213141516171819202122232425///////// Start Image Processing ////////////////int[] source_init = new int[]{116,7,207,5, 34,109,90,21, 55,249,30,128, 118,320,65,261,123,321,171,321, 179,319,240,264, 247,251,282,135, 281,114,228,8,78,106,123,109, 187,115,235,114, 72,142,99,128, 74,150,122,154,108,127,123,146, 182,152,213,132, 183,159,229,157, 219,131,240,154,80,246,117,212, 127,222,146,223, 154,227,174,221, 228,252,183,213,114,255,186,257, 109,258,143,277, 152,278,190,262};int[] dest_init = new int[] {120,8,200,6, 12,93,96,16, 74,271,16,110, 126,336,96,290,142,337,181,335, 192,335,232,280, 244,259,288,108, 285,92,212,13,96,135,136,118, 194,119,223,125, 105,145,124,134, 110,146,138,151,131,133,139,146, 188,146,198,134, 189,153,218,146, 204,133,221,140,91,268,122,202, 149,206,159,209, 170,209,181,204, 235,265,208,199,121,280,205,284, 112,286,160,301, 166,301,214,287};control_line[] source_lines = new control_line[23];control_line[] dest_lines = new control_line[23];for (int i = 0; i < source_lines.Length; i++){source_lines[i] = new control_line(source_init[i * 4], source_init[i * 4 + 1], source_init[i * 4 + 2], source_init[i * 4 + 3]);dest_lines[i] = new control_line(dest_init[i * 4], dest_init[i * 4 + 1], dest_init[i * 4 + 2], dest_init[i * 4 + 3]);}byte[] newdata = f_Warping(bmp.Width, bmp.Height, source_lines, dest_lines, data);///////// End Image Processing ////////////////
- [기하_모핑] 메뉴를 더블클릭한 후 다음 코드를 완성한다.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576private void 기하모핑ToolStripMenuItem_Click(object sender, EventArgs e){Bitmap bmp = f_OpenBitmapFile();if (bmp == null) return;PixelFormat pixelFormat = bmp.PixelFormat;byte[] data = f_getDataFromImage(bmp);Bitmap bmp2 = f_OpenBitmapFile();if (bmp2 == null) return;byte[] data2 = f_getDataFromImage(bmp2);///////// Start Image Processing ////////////////int[] source_init = new int[]{116,7,207,5, 34,109,90,21, 55,249,30,128, 118,320,65,261,123,321,171,321, 179,319,240,264, 247,251,282,135, 281,114,228,8,78,106,123,109, 187,115,235,114, 72,142,99,128, 74,150,122,154,108,127,123,146, 182,152,213,132, 183,159,229,157, 219,131,240,154,80,246,117,212, 127,222,146,223, 154,227,174,221, 228,252,183,213,114,255,186,257, 109,258,143,277, 152,278,190,262};int[] dest_init = new int[] {120,8,200,6, 12,93,96,16, 74,271,16,110, 126,336,96,290,142,337,181,335, 192,335,232,280, 244,259,288,108, 285,92,212,13,96,135,136,118, 194,119,223,125, 105,145,124,134, 110,146,138,151,131,133,139,146, 188,146,198,134, 189,153,218,146, 204,133,221,140,91,268,122,202, 149,206,159,209, 170,209,181,204, 235,265,208,199,121,280,205,284, 112,286,160,301, 166,301,214,287};control_line[] source_lines = new control_line[23];control_line[] dest_lines = new control_line[23];for (int i = 0; i < source_lines.Length; i++){source_lines[i] = new control_line(source_init[i * 4], source_init[i * 4 + 1], source_init[i * 4 + 2], source_init[i * 4 + 3]);dest_lines[i] = new control_line(dest_init[i * 4], dest_init[i * 4 + 1], dest_init[i * 4 + 2], dest_init[i * 4 + 3]);}int NUM_FRAMES = 10;control_line[] warp_lines = new control_line[23];for (int i = 0; i < warp_lines.Length; i++){warp_lines[i] = new control_line(0, 0, 0, 0);}Bitmap[] bmpResult = new Bitmap[NUM_FRAMES + 1];for (int frame = 0; frame <= NUM_FRAMES; frame++){double fweight = (double)frame / NUM_FRAMES;for (int i = 0; i < warp_lines.Length; i++){warp_lines[i].Px = (int)(source_lines[i].Px + (dest_lines[i].Px - source_lines[i].Px) * fweight);warp_lines[i].Py = (int)(source_lines[i].Py + (dest_lines[i].Py - source_lines[i].Py) * fweight);warp_lines[i].Qx = (int)(source_lines[i].Qx + (dest_lines[i].Qx - source_lines[i].Qx) * fweight);warp_lines[i].Qy = (int)(source_lines[i].Qy + (dest_lines[i].Qy - source_lines[i].Qy) * fweight);}byte[] newdata = f_Warping(bmp.Width, bmp.Height, source_lines, warp_lines, data);byte[] newdata2 = f_Warping(bmp.Width, bmp.Height, dest_lines, warp_lines, data2);for (int i = 0; i < newdata.Length; i++){int val = (int)((1 - fweight) * newdata[i] + fweight * newdata2[i]);if (val > 255) val = 255;if (val < 0) val = 0;newdata[i] = (byte)val;}bmpResult[frame] = f_makeImageFromData(bmp.Width, bmp.Height, pixelFormat, newdata);}///////// End Image Processing ////////////////for (int frame = 0; frame <= NUM_FRAMES; frame++){f_drawImage(bmp, bmp2, bmpResult[frame]);System.Threading.Thread.Sleep(1000);}}