首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >拉伸四边形以拟合矩形

拉伸四边形以拟合矩形
EN

Stack Overflow用户
提问于 2016-07-22 18:56:21
回答 1查看 778关注 0票数 2

我正在开发一个WPF应用程序,它必须允许用户定义任何四边形的形状作为相机帧的裁剪区域。这是通过将视频流与由线连接的四个点叠加来实现的,以可视化输出图像中应使用的区域。

作为第二步,这给我带来了麻烦,我想展示将选定的四边形转换为矩形的结果。我已经使用opencv的warpPerspective函数做到了这一点,但这被证明是很慢的(处理器繁重)。

我相信这也可以通过使用Viewport3D和3D转换的WPF (图形处理器加速)完成。我发现了一个非常有用的article,它将我带到了以下代码

代码语言:javascript
复制
<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>

代码语言:javascript
复制
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的角点中。

在下面的图像中,矩形和内部四边形之间的区域将被裁剪,而四边形的内容应该被拉伸以适合外部矩形。

要实现这一点,我还需要应用另一种转换吗?也许有一个简单的转换,我可以应用于框架角点坐标,以移动定义的点在那里?

EN

回答 1

Stack Overflow用户

发布于 2017-08-16 21:03:28

使用Accord.NET (以nuget包的形式提供),您可以使用以下内容:

代码语言:javascript
复制
Bitmap origin = // this is your quadrilateral bitmap
var corners = new List<IntPoint>(new IntPoint[]
{
    new IntPoint(topLeftPoint), new IntPoint(topRightPoint), new IntPoint(bottomRightPoint), new IntPoint(bottomLeftPoint)
});
var filter = new QuadrilateralTransformation(corners, rect.Width, rect.Height); // rect = your target rectangle size
Bitmap result = filter.Apply(origin); // voila!
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38524712

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档