/// <summary> /// 補完した値を求める /// </summary> /// <param name="bmpByte">BitmapDataのバイト配列</param> /// <param name="x">変形後の位置 x</param> /// <param name="y">変形後の位置 y</param> /// <param name="pxCol">求めた色情報</param> /// <returns>true:補完成功, false:対象座標は形状外部</returns> private static bool Interpolate(BitmapByte bmpByte, double x, double y, ref Color pxCol) { int x0 = (int)(x + 0.5); int y0 = (int)(y + 0.5); if (x0 < 0 || bmpByte.Width <= x0 || y0 < 0 || bmpByte.Height <= y0) { return(false); // 対象座標は形状外部 } pxCol = GetPixelByte(bmpByte, x0, y0); return(true); }
/// <summary> /// BitmapDataのバイト配列対象のピクセルに色情報を設定 /// </summary> /// <param name="bmpByte">BitmapDataのバイト配列情報</param> /// <param name="x">対象のx座標</param> /// <param name="y">対象のy座標</param> /// <param name="col">設定する色情報</param> private static void SetPixelByte(BitmapByte bmpByte, int x, int y, Color col) { int pos = x * bmpByte.DepthByte + bmpByte.Stride * y; bmpByte.PixelBytes[pos + 0] = col.B; bmpByte.PixelBytes[pos + 1] = col.G; bmpByte.PixelBytes[pos + 2] = col.R; if (bmpByte.DepthByte == 4) { bmpByte.PixelBytes[pos + 3] = col.A; } }
/// <summary> /// BitmapDataのバイト配列よりピクセル情報を取得 /// </summary> /// <param name="bmpByte">BitmapDataのバイト配列情報</param> /// <param name="x">対象のx座標</param> /// <param name="y">対象のy座標</param> /// <returns>対象ピクセルの色情報</returns> private static Color GetPixelByte(BitmapByte bmpByte, int x, int y) { int pos = x * bmpByte.DepthByte + bmpByte.Stride * y; byte b = bmpByte.PixelBytes[pos + 0]; byte g = bmpByte.PixelBytes[pos + 1]; byte r = bmpByte.PixelBytes[pos + 2]; byte a = 255; if (bmpByte.DepthByte == 4) { a = bmpByte.PixelBytes[pos + 3]; } return(Color.FromArgb(a, r, g, b)); }
/// <summary> /// 変形処理 /// </summary> /// <param name="srcImg">元画像</param> /// <param name="destImg">[out] 変形後画像</param> /// <param name="pt">変形後画像の頂点情報</param> /// <returns>true:成功, false:失敗</returns> public static bool Transform(Bitmap srcImg, out Bitmap destImg, List <Point> pt) { System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch(); sw.Reset(); sw.Start(); destImg = null; BitmapByte srcByte = new BitmapByte(); BitmapByte destByte = new BitmapByte(); Color pxCol = Color.FromArgb(0, 0, 0, 0); Color bgCol = Color.FromArgb(0, 0, 0, 0); TfParam p = new TfParam(); int calcWidth, calcHeight; int destWidth, destHeight; double xa, ya, xb, yb, xc, yc, xd, yd; double s, t; // 対象画素の元画像に対する比率 (0 <= s,t <=1) double tx, ty; // 変形後の座標 try { destWidth = pt[0].X; destHeight = pt[0].Y;; for (int i = 1; i < pt.Count; i++) { if (destWidth < pt[i].X) { destWidth = pt[i].X; } if (destHeight < pt[i].Y) { destHeight = pt[i].Y; } } destWidth++; destHeight++; destImg = new Bitmap(destWidth, destHeight); destByte.LockBitmap(destImg, ImageLockMode.WriteOnly); srcByte.LockBitmap(srcImg, ImageLockMode.ReadOnly); calcWidth = srcByte.Width - 1; calcHeight = srcByte.Height - 1; // 頂点データは反時計回りだが、パラメータには時計回りでセットする xa = pt[0].X; ya = pt[0].Y; xb = pt[3].X; yb = pt[3].Y; xc = pt[2].X; yc = pt[2].Y; xd = pt[1].X; yd = pt[1].Y; p.a = (xc - xd - xb + xa); p.b = (xb - xa); p.c = (xd - xa); p.f = (yc - yd - yb + ya); p.g = (yb - ya); p.h = (yd - ya); for (int y = 0; y < destHeight; y++) { for (int x = 0; x < destWidth; x++) { p.d = (x - xa); p.e = (y - ya); if (ResolveEqu(p, out s, out t) == false) { SetPixelByte(destByte, x, y, bgCol); continue; } //if ((0 <= s && s <= 1.0) && (0 <= t && t <= 1.0)) //{ tx = s * calcWidth; ty = t * calcHeight; //} if (Interpolate(srcByte, tx, ty, ref pxCol)) { SetPixelByte(destByte, x, y, pxCol); } else { SetPixelByte(destByte, x, y, bgCol); } } } destByte.MarshalCopy(); } catch (Exception ex) { return(false); } finally { try { if (srcByte != null) { srcByte.UnlockBitmap(); } } finally { if (destByte != null) { destByte.UnlockBitmap(); } } sw.Stop(); Console.WriteLine("Transform time: {0}", sw.ElapsedMilliseconds); } return(true); }