Матрица / преобразование координат в C # - PullRequest
2 голосов
/ 11 января 2012

У меня есть массив координат, которые отражают известные позиции на изображении. Давайте назовем это шаблоном изображения. Он имеет уникальный штрих-код и маркеры ориентации (которые также находятся в массиве координат).

Изображение распечатывается, сканируется и возвращается в мое приложение для обнаружения. Во время печати и сканирования изображение может быть преобразовано тремя способами; перевод, вращение и масштаб.

Предполагая, что я могу найти маркеры ориентации на искаженном изображении, как я могу использовать матричное преобразование для получения относительных положений оставшихся координат?

Я разместил этот вопрос на SO до , но сделал его слишком сложным, чтобы понять, что я хотел.

EDIT

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");
}
}
}

1 Ответ

5 голосов
/ 11 января 2012

Я предполагаю, что вы хотите преобразовать изображение в единицу площади ((0, 0) - (1.0, 1.0)) Вам нужны три точки, одна из которых является исходной, другая будет преобразована в ось X (1,0, 0), а другая в ось Y (0, 1,0).

В исходной системе координат:

  • Происхождение (Ox, Oy)
  • Ось X (X1, Y2)
  • Ось Y (X2, Y2)
  • Ось X относительно начала координат (X1-Ox, Y1-Oy) будет сокращена до (RX1, RY1)
  • Ось Y относительно начала координат (X2-ox, Y2-Oy) будет сокращена до (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)
(-RY1/D   RX1/D   0)
(  0       0      1)

Теперь вы можете умножить обе матрицы сначала, выполнив перевод, а затем использовать вторую матрицу для преобразования базиса.

...