2012-01-11 74 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