4-point transform images

后端 未结 4 817
误落风尘
误落风尘 2021-01-05 16:10

I need to transform bitmap images with their 4 corner points moved from one location to another.

Any code that can run on Windows, C#/VB.NET preferably, even help ho

相关标签:
4条回答
  • 2021-01-05 16:11

    The keyword here is homography. Manolis Lourakis has written a GPL'ed homography implementation in C that is available here; however, this will not be able to be ported very easily because it relies on some external libraries such as LAPACK.

    0 讨论(0)
  • 2021-01-05 16:13

    Disclaimer: I work at Atalasoft

    If you are willing to go commercial, DotImage Photo can do this with the QuadrilateralWarpCommand. Sample C# Code

    // Load an image.
    AtalaImage image = new AtalaImage("test-image.jpg");
    
    // Prepare the warp positions.
    Point bottomLeft = new Point(100, image.Height - 80);
    Point topLeft = new Point(130, 45);
    Point topRight = new Point(image.Width - 60, 140);
    Point bottomRight = new Point(image.Width - 20, image.Height);
    
    // Warp the image.
    QuadrilateralWarpCommand cmd = new QuadrilateralWarpCommand(bottomLeft,
       topLeft, topRight, bottomRight, InterpolationMode.BiLinear, Color.White);
    AtalaImage result = cmd.Apply(image).Image;
    

    http://www.atalasoft.com/products/dotimage

    0 讨论(0)
  • 2021-01-05 16:16

    Easier than simulating a perspective distort using image manipulation, you could use OpenGL or DirectX (XNA) to actually perform the perspective display.

    Render a simple quad with your image as the texture map. Setup your scene, render to a buffer, and you have your image.

    Update It turns out that XNA is a ridiculous library (geared toward making games and nothing else, yawn). Managed DirectX requires a brain lobotomy. OpenGL is easy to use, but lacks image loading code. That leaves us with WPF:

    alt text http://praeclarum.org/so/persp.png

    The image could be improved by forcing WPF into anti-alias mode (why oh why Microsoft are you so short-sighted?), and by not using Aero glass which forces that 1 pixel black border on all screenshots (or by removing that 1 pixel border).

    (Sorry for the length of this code, but WPF is a chatty API.)

    public partial class Window1 : Window {
        const float ANGLE = 30;
        const float WIDTH = 8;
        public Window1() {
            InitializeComponent();
    
            var group = new Model3DGroup();
            group.Children.Add(Create3DImage(@"C:\Users\fak\Pictures\so2.png"));
            group.Children.Add(new AmbientLight(Colors.White));
    
            ModelVisual3D visual = new ModelVisual3D();
            visual.Content = group;
            viewport.Children.Add(visual);
        }
    
        private GeometryModel3D Create3DImage(string imgFilename) {
            var image = LoadImage(imgFilename);
    
            var mesh = new MeshGeometry3D();
            var height = (WIDTH * image.PixelHeight) / image.PixelWidth;
            var w2 = WIDTH / 2.0;
            var h2 = height / 2.0;
            mesh.Positions.Add(new Point3D(-w2, -h2, 0));
            mesh.Positions.Add(new Point3D(w2, -h2, 0));
            mesh.Positions.Add(new Point3D(w2, h2, 0));
            mesh.Positions.Add(new Point3D(-w2, h2, 0));
            mesh.TriangleIndices.Add(0);
            mesh.TriangleIndices.Add(1);
            mesh.TriangleIndices.Add(2);
            mesh.TriangleIndices.Add(0);
            mesh.TriangleIndices.Add(2);
            mesh.TriangleIndices.Add(3);
            mesh.TextureCoordinates.Add(new Point(0, 1)); // 0, 0
            mesh.TextureCoordinates.Add(new Point(1, 1));
            mesh.TextureCoordinates.Add(new Point(1, 0));
            mesh.TextureCoordinates.Add(new Point(0, 0));
    
            var mat = new DiffuseMaterial(new ImageBrush(image));
            mat.AmbientColor = Colors.White;
    
            var geometry = new GeometryModel3D();
            geometry.Geometry = mesh;
            geometry.Material = mat;
            geometry.BackMaterial = mat;
    
            geometry.Transform = new RotateTransform3D(
                new AxisAngleRotation3D(new Vector3D(0,1,0), ANGLE),
                new Point3D(0, 0, 0));
    
            return geometry;
        }
    
        public static BitmapSource LoadImage(string filename) {
            return BitmapDecoder.Create(new Uri(filename, UriKind.RelativeOrAbsolute),
                BitmapCreateOptions.None, BitmapCacheOption.Default).Frames[0];
        }
    }
    

    And the required XAML:

    <Window x:Class="Persp.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Perspective Window" Height="480" Width="640">
    <Grid>
        <Viewport3D x:Name="viewport">
            <Viewport3D.Resources>
            </Viewport3D.Resources>
            <Viewport3D.Camera>
                <PerspectiveCamera x:Name="cam"
                      FarPlaneDistance="100"
                      LookDirection="0,0,-1"
                      UpDirection="0,1,0"
                      NearPlaneDistance="1"
                      Position="0,0,10"
                      FieldOfView="60" />
            </Viewport3D.Camera>
        </Viewport3D>
    </Grid>
    </Window>
    
    0 讨论(0)
  • 2021-01-05 16:19

    Check out the Perspective warping examples from ImageMagick. It is available for most mainstream platforms.

    0 讨论(0)
提交回复
热议问题