Я работаю над приложением WPF, которое должно позволить пользователю определять любую четырехстороннюю форму, которая будет служить средой для рамки камеры. Это достигается путем наложения видеопотока с четырьмя точками, связанными с линиями, для визуализации, какая область должна использоваться в выходном изображении.растягивать четырехугольник, чтобы соответствовать прямоугольнику
Как второй шаг, который вызывает у меня проблемы, я хотел бы показать результат преобразования выбранного четырехугольника в прямоугольник. Мне удалось это сделать, используя opencv's warpPerspective, но это оказалось медленным (процессор тяжелый).
Я считаю, что это также можно сделать с помощью WPF (ускорение GPU) с использованием Viewport3D
и 3D-трансформаций. Я нашел очень полезный article, который привел меня к следующему коду
<Viewport3D x:Name="canvasViewPort">
<Viewport3D.Camera>
<OrthographicCamera Position="0.5 0.5 1" LookDirection="0 0 -1" UpDirection="0 1 0" Width="1" />
</Viewport3D.Camera>
<ModelVisual3D>
<ModelVisual3D.Content>
<DirectionalLight Color="White" Direction="0,0,-1"/>
</ModelVisual3D.Content>
</ModelVisual3D>
<Viewport2DVisual3D>
<Viewport2DVisual3D.Transform>
<MatrixTransform3D x:Name="canvas3dTransform" />
</Viewport2DVisual3D.Transform>
<Viewport2DVisual3D.Geometry>
<MeshGeometry3D Positions="0 0 0, 0 1 0, 1 0 0, 1 1 0" TextureCoordinates="0 1, 0 0, 1 1, 1 0" TriangleIndices="0 2 1, 2 3 1"/>
</Viewport2DVisual3D.Geometry>
<Viewport2DVisual3D.Material>
<DiffuseMaterial Brush="White" Viewport2DVisual3D.IsVisualHostMaterial="True"/>
</Viewport2DVisual3D.Material>
<Canvas x:Name="mainCanvas" Margin="0" Width="{Binding ResolutionX}" Height="{Binding ResolutionY}">
<Canvas.Background>
<ImageBrush ImageSource="{Binding BackgroundImg}" />
</Canvas.Background>
</Canvas>
</Viewport2DVisual3D>
</Viewport3D>
И
protected void Transform()
{
double targetWidth = canvasViewPort.ActualWidth, xScale = targetWidth/ResolutionX,
targetHeight = canvasViewPort.ActualHeight, yScale = targetHeight/ResolutionY;
var points3d = new Point3D[4];
if (EditorMode || Corners == null || Corners.Count < 4)
{ //fit canvas in parent container without warping to allow Corners edition
points3d[0] = Point2dTo3d(canvasViewPort, new Point(0, 0));
points3d[1] = Point2dTo3d(canvasViewPort, new Point(0, targetHeight));
points3d[2] = Point2dTo3d(canvasViewPort, new Point(targetWidth, 0));
points3d[3] = Point2dTo3d(canvasViewPort, new Point(targetWidth, targetHeight));
}
else
{ //get warped points, Corners indices order is to reflect convention used in the linked blog post
points3d[0] = Point2dTo3d(canvasViewPort, new Point(Corners[0].X * xScale, Corners[0].Y * yScale));
points3d[1] = Point2dTo3d(canvasViewPort, new Point(Corners[3].X * xScale, Corners[3].Y * yScale));
points3d[2] = Point2dTo3d(canvasViewPort, new Point(Corners[1].X * xScale, Corners[1].Y * yScale));
points3d[3] = Point2dTo3d(canvasViewPort, new Point(Corners[2].X * xScale, Corners[2].Y * yScale));
}
var A = new Matrix3D();
A.M11 = points3d[2].X - points3d[0].X;
A.M12 = points3d[2].Y - points3d[0].Y;
A.M21 = points3d[1].X - points3d[0].X;
A.M22 = points3d[1].Y - points3d[0].Y;
A.OffsetX = points3d[0].X;
A.OffsetY = points3d[0].Y;
double den = A.M11 * A.M22 - A.M12 * A.M21;
double a = (A.M22 * points3d[3].X - A.M21 * points3d[3].Y +
A.M21 * A.OffsetY - A.M22 * A.OffsetX)/den;
double b = (A.M11 * points3d[3].Y - A.M12 * points3d[3].X +
A.M12 * A.OffsetX - A.M11 * A.OffsetY)/den;
var B = new Matrix3D();
B.M11 = a/(a + b - 1);
B.M22 = b/(a + b - 1);
B.M14 = B.M11 - 1;
B.M24 = B.M22 - 1;
canvas3dTransform.Matrix = B * A;
}
Point3D Point2dTo3d(Viewport3D vp, Point pt)
{
var cam = (OrthographicCamera)canvasViewPort.Camera;
double x = cam.Width/vp.ActualWidth * (pt.X - vp.ActualWidth/2) + cam.Position.X;
double y = cam.Width/vp.ActualWidth * (pt.Y - vp.ActualHeight/2) + cam.Position.Y;
return new Point3D(x, y, 0);
}
К сожалению, это делает противоположное тому, что мне нужно - это перемещает углы рамки для точек, определенных в Corners
в то время как мне нужно разместить определенные точки в углах Canvas
.
На изображении ниже область между прямоугольником и внутренним четырехугольником должна быть обрезана, а содержимое четырехугольника должно быть растянуто, чтобы соответствовать внешнему прямоугольнику.
Есть ли еще одна трансформация, которую я должен применить для достижения этой цели? Возможно, есть простая трансформация, которую я могу применить к координатам углов рамки для перемещения определенных точек там?
любого прогресса до сих пор? – Nissim