Imaging for UWP
画像をワープ
Imaging for UWP > Bitmap for UWP > C1Bitmap の使い方 > 画像をワープ

画像をワープできると面白いです。ワープ効果の作成に必要なコードは多少複雑ですが、C1DragHelpers と多少の計算によって画像にワープ効果を適用できます。FaceWarp サンプルでは、独自の画像をロードし、完成した画像をエクスポートし、ワープ効果の見栄えが気に入らない場合は画像をリセットします。

C# コードの書き方

C#
コードのコピー
InitializeComponent();

LoadDefaultImage();
image.Source = screen.ImageSource;

var mouseHelper = new C1DragHelper(image, captureElementOnPointerPressed: true);
var line = new Line();
mouseHelper.DragStarted += (s, e) =>
{
_position = e.GetPosition(image);
line = new Line
{
X1 = _position.X,
Y1 = _position.Y,
X2 = _position.X,
Y2 = _position.Y,
Stroke = new SolidColorBrush(Colors.Blue),
StrokeThickness = 7,
StrokeEndLineCap = PenLineCap.Triangle,
StrokeStartLineCap = PenLineCap.Round
};
imageGrid.Children.Add(line);
};
mouseHelper.DragDelta += (s, e) =>
{
var pos = e.GetPosition(image);
line.X2 = pos.X;
line.Y2 = pos.Y;
};
mouseHelper.DragCompleted += (s, e) =>
{
imageGrid.Children.Remove(line);
var start = _position;
var end = new Point(_position.X + e.CumulativeTranslation.X, _position.Y + e.CumulativeTranslation.Y);

bitmap = new C1Bitmap(screen);
Warp(bitmap, screen, start, end);
};
}
void Warp(C1Bitmap src, C1Bitmap dst, Point start, Point end)
{
dst.BeginUpdate();
dst.Copy(src, false);

var dist = Distance(start, end);
var affectedDist = dist * 1.5;
var affectedDistSquared = affectedDist * affectedDist;
for (int row = 0; row < dst.Height; ++row)
{
for (int col = 0; col < dst.Width; ++col)
{
var point = new Point(col, row);
if (DistanceSq(start, point) > affectedDistSquared)
{
continue;
}
if (DistanceSq(end, point) < 0.25)
{
dst.SetPixel(col, row, src.GetPixel((int)start.X, (int)start.Y));
continue;
}
var dir = new Point(point.X - end.X, point.Y - end.Y);
var t = IntersectRayCircle(end, dir, start, affectedDist);
TryT(-end.X / dir.X, ref t);
TryT(-end.Y / dir.Y, ref t);
TryT((dst.Width - end.X) / dir.X, ref t);
TryT((dst.Height - end.X) / dir.X, ref t);
var anchor = new Point(end.X + (point.X - end.X) * t, end.Y + (point.Y - end.Y));
var x = start.X + (anchor.X - start.X) / t;
var y = start.Y + (anchor.Y - start.Y) / t;
dst.SetPixel(col, row, src.GetInterpolatedPixel(x, y));
}
}
dst.EndUpdate();
}

static double Distance(Point a, Point b)
{
return Math.Sqrt(DistanceSq(a, b));
}

static double DistanceSq(Point a, Point b)
{
var dx = a.X - b.X;
var dy = a.Y - b.Y;
return dx * dx + dy * dy;
}

static void TryT(double t2, ref double t)
{
if (t2 > 0 && t2 < t)
{
t = t2;
}
}

static double IntersectRayCircle(Point rayOri, Point rayDir, Point center, double radius)
{
var a = rayDir.X;
var b = rayOri.X;
var c = center.X;
var d = rayDir.Y;
var e = rayOri.Y;
var f = center.Y;
var g = radius * radius;

var num1 = Math.Sqrt(d * (2 * a * (b - c) * (e - f) - d * (b * b - 2 * b * c + c * c - g)) - a * a * (e * e - 2 * e * f + f * f - g));
var num2 = a * (c - b) + d * (f - e);
return (num1 + num2 > 0 ? num1 + num2 : num1 - num2) / (a * a + d * d);
}
関連トピック