2012-01-11 134 views
2

我有一个反映图像上已知位置的坐标数组。我们称之为模板图像。它有一个独特的条形码和方向标记(也在坐标数组中)。C中的矩阵/坐标变换#

图像被打印,扫描并反馈到我的应用程序中进行检测。在打印和扫描过程中,图像可以通过三种方式进行转换;翻译,旋转和缩放。

假设我可以在扭曲的图像上找到方向标记,我如何使用矩阵变换来获取其余坐标的相对位置?

我在SO before上发布了这个问题,但是太复杂了,无法理解我想要的东西。

编辑

namespace MatrixTest 
{ 
using System; 
using System.Drawing; 
using System.Drawing.Drawing2D; 
using System.Collections.Generic; 

public static class Program 
{ 
public static void Main() 
{ 
Template template = new Template(); // Original template image. 
Document document = new Document(); // Printed and scanned distorted image. 

template.CreateTemplateImage(); 

// The template image is printed and scanned. This method generates an example scan or this question. 
document.CreateDistortedImageFromTemplateImage(); 
// Stuck here. 
document.Transform(); 
// Draw transformed points on the image to verify that transformation is successful. 
document.DrawPoints(); 

System.Diagnostics.Process.Start(new System.IO.FileInfo(System.Reflection.Assembly.GetExecutingAssembly().Location).Directory.FullName); 
} 
} 

public class Page 
{ 
public Bitmap Image { get; set; } 
public Point[] Markers = new Point[3]; // Orientation markers: 1=TopLeft, 2=TopRight, 3=BottomRight. 
public Point[] Points = new Point[100]; // Coordinates to transform in the TemplateScanned derived class! 
} 

// This class represents the originalk template image. 
public class Template: Page 
{ 
public Template() 
{ 
this.Image = new Bitmap(300, 400); 

// Known dimentions for marker rectangles. 
this.Markers[0] = new Point(10, 10); 
this.Markers[1] = new Point(this.Image.Width - 20 - 10, 10); 
this.Markers[2] = new Point(this.Image.Width - 20 - 10, this.Image.Height - 20 - 10); 

// Known points of interest. Consider them hardcoded. 
int index = 0; 
for (int y = 0; y < 10; y++) 
for (int x = 0; x < 10; x++) 
this.Points[index++] = new Point((this.Image.Width/10) + (x * 20), (this.Image.Height/10) + (y * 20)); 
} 

public void CreateTemplateImage() 
{ 
using (Graphics graphics = Graphics.FromImage(this.Image)) 
{ 
graphics.Clear(Color.White); 

for (int i = 0; i < this.Markers.Length; i++) 
graphics.FillRectangle(Brushes.Black, this.Markers[i].X, this.Markers[i].Y, 20, 20); 

for (int i = 0; i < this.Points.Length; i++) 
graphics.DrawRectangle(Pens.Red, this.Points[i].X, this.Points[i].Y, 5, 5); 
} 

this.Image.Save("Document Original.png"); 
} 
} 

// This class represents the scanned image. 
public class Document: Page 
{ 
public struct StructTransformation 
{ 
public float AngleOfRotation; 
public SizeF ScaleRatio; 
public SizeF TranslationOffset; 
} 

private Template Template = new Template(); 
private StructTransformation Transformation = new StructTransformation(); 

public Document() 
{ 
this.Template = new Template(); 
this.Transformation = new StructTransformation { AngleOfRotation = 5f, ScaleRatio = new SizeF(.8f, .7f), TranslationOffset = new SizeF(100f, 30f) }; 

this.Template.CreateTemplateImage(); 

// Copy points from template. 
for (int i = 0; i < this.Template.Markers.Length; i++) 
this.Markers[i] = this.Template.Markers[i]; 

for (int i = 0; i < this.Points.Length; i++) 
this.Points[i] = this.Template.Points[i]; 
} 

// Just distorts the original template image as if it had been read from a scanner. 
public void CreateDistortedImageFromTemplateImage() 
{ 
// Distort coordinates. 
Matrix matrix = new Matrix(); 
matrix.Rotate(this.Transformation.AngleOfRotation); 
matrix.Scale(this.Transformation.ScaleRatio.Width, this.Transformation.ScaleRatio.Height); 
matrix.Translate(this.Transformation.TranslationOffset.Width, this.Transformation.TranslationOffset.Height); 
matrix.TransformPoints(this.Markers); 
matrix.TransformPoints(this.Points); 

// Distort and save image for visual reference. 
this.Image = new Bitmap(this.Template.Image.Width, this.Template.Image.Height); 
using (Graphics graphics = Graphics.FromImage(this.Image)) 
{ 
graphics.Clear(Color.White); 
graphics.RotateTransform(this.Transformation.AngleOfRotation); 
graphics.ScaleTransform(this.Transformation.ScaleRatio.Width, this.Transformation.ScaleRatio.Height); 
graphics.TranslateTransform(this.Transformation.TranslationOffset.Width, this.Transformation.TranslationOffset.Height); 
graphics.DrawImage(this.Template.Image, 0, 0); 
} 
this.Image.Save("Document Scanned.png"); 
} 

public void Transform() 
{ 
// The rectangles of the ScannedDcoument are not known at this time. They would obviously be relative to the three orientation markers. 
// I can't figure out how to use the following code properly i.e. using Matrix to apply all three transformations. 
Matrix matrix = new Matrix(); 
matrix.Rotate(-this.Transformation.AngleOfRotation); 
matrix.Scale(1f/this.Transformation.ScaleRatio.Width, 1f/this.Transformation.ScaleRatio.Height); 
matrix.Translate(-this.Transformation.TranslationOffset.Width, -this.Transformation.TranslationOffset.Height); 
matrix.TransformPoints(this.Markers); 
matrix.TransformPoints(this.Points); 
} 

public void DrawPoints() 
{ 
using (Graphics graphics = Graphics.FromImage(this.Image)) 
{ 
graphics.Clear(Color.White); 

for (int i = 0; i < this.Markers.Length; i++) 
graphics.FillRectangle(Brushes.Blue, this.Markers[i].X, this.Markers[i].Y, 20, 20); 

for (int i = 0; i < this.Points.Length; i++) 
graphics.DrawRectangle(Pens.Purple, this.Points[i].X, this.Points[i].Y, 5, 5); 
} 
this.Image.Save("Document Fixed.png"); 
} 
} 
} 
+0

[this](http://www.willamette.edu/~gorr/classes/GeneralGraphics/Transforms/transforms2d.htm)可以帮助你。有2点起点和2点终点,你*应该*能够得到正确的变换矩阵。 – Tigran 2012-01-11 06:53:15

+0

@Tigran:链接似乎被打破。实际上,该域名似乎至少在我的位置无法访问。你能否提供一个替代方案? – 2012-01-11 15:41:15

+0

@Rageel Khan:我刚打开它。 – Tigran 2012-01-11 15:42:13

回答

4

我假设你想将图像转换为单位正方形((0,0) - (1.0,1.0)) 你需要三点,一个是另一个将转换为x轴(1.0,0),另一个转换为y轴(0,1.0)。

在原始坐标系统:

  • 原点是(OX,OY)
  • X轴是(X1,Y2)
  • Y轴为(X2,Y2)
  • 相对于原点(X2-ox,Y2-Oy)的X轴将缩短为(RX1,RY1)
  • 相对于原点(X2-ox,Y2-Oy)的Y轴将缩短为(RX2,RY2 )

首先,我们将在均匀移动原点到(0,0)的坐标变换矩阵将是

(1 0 -Ox) 
(0 1 -Oy) 
(0 0 1) 

来自新空间变换到旧之一由以下矩阵表示:

(RX1 RX2 0) 
(RY1 RY2 0) 
(0 0  1) 

因为你想要的逆变换,从旧空间的新的,我们需要反转这个矩阵: 让我们缩短(RX1 * RY2-RX2 * RY1)为d

(RY2/D -RX2/D 0) 
(-RY2/D RX1/D 0) 
( 0  0  1) 

现在,您可以先将两个矩阵相乘,然后使用第二个矩阵来转换基础。

+0

对矩阵的理解有限,请让我这样说。我们有一个带有方向标记'Rectangle r1,r2,r3'的图像。坐标是已知的。然后我们在图像上有多个矩形作为数组'Rectangle [100] = whatever.'。这些坐标也是已知的。现在我们收到相同图像的扭曲副本,并且能够检测到三个方向标记r1,r2和r3。基于此,我们可以得到旋转角度,平移偏移和比例尺。在下一封邮件中继续。 – 2012-01-11 17:41:06

+0

我可以使用新的Matrix.Rotate(rotationAngle,rect [100])等等,但是按照什么顺序。每个转变如何影响下一个?最终的结果是:获得一组经过变换的'Rectangle [100]',这样我就可以读取失真图像的那些区域。 – 2012-01-11 17:43:26

+0

我已将简化的代码添加到问题中。该方法是“Document.Transform”。转换值是检测到的值。因此,调用代码“按原样”将两次应用转换。我不确定是否否定价值或什么? – 2012-01-12 07:10:17