Code Optimization

Interesting things about software development and code optimization

Hello,

Today, I'm going to share one interesting thing that everyone may need - perspective image transformation.

Its 2D transformation that makes image look like in perspective view like 3D but without any 3D:

So, the main thing there is math. We take an image, specify four points and math will do the trick.

First step is to create and calculate matrices from the new four points:

```//original pointsPoint p1 = new Point(0, 0);Point p2 = new Point(width, 0);Point p3 = new Point(width, height);Point p4 = new Point(0, height);
//create matrixA = Matrix3x3.Homogenous(p1, p2, p3, p4);
//new pointsPoint n1 = points[0];Point n2 = points[1];Point n3 = points[2];Point n4 = points[3];
B = Matrix3x3.Homogenous(n1, n2, n3, n4);A.Inverse();
C = B.MultMat(A);C.Inverse();```

Second step is to go through each pixel on your image and calculate new pixel:

```Point ptDest = new Point(0, 0);PointF ptOriginF = new Point(0, 0);int iOrigX = 0;Color pix = new Color();for (int x = 0; x < width; ++x){    for (int y = 0; y < height; ++y)    {        ptDest.X = x;        ptDest.Y = y;        ptOriginF = C.Update(ptDest);        if (ptOriginF.X >= -5 && ptOriginF.X < width && ptOriginF.Y >= -5 && ptOriginF.Y < height)        {            iOrigX = (int)ptOriginF.X; // round to lowest integer            int iOrigY = (int)ptOriginF.Y; // round to lowest integer            double dx = ptOriginF.X - iOrigX;            double dy = ptOriginF.Y - iOrigY;            Point ptOrigin = new Point(iOrigX, iOrigY);            if (dx != 0.0f || dy != 0.0)            {                Color pix1 = Color.FromArgb(0, 255, 255, 255);                Color pix2 = Color.FromArgb(0, 255, 255, 255);                Color pix3 = Color.FromArgb(0, 255, 255, 255);                Color pix4 = Color.FromArgb(0, 255, 255, 255);                //                // Correct square's direction                //                int idx = (dx >= 0.0) ? 1 : -1;                int idy = (dy >= 0.0) ? 1 : -1;                dx = Math.Abs(dx);                dy = Math.Abs(dy);                //                // Get pixels of square                //                if (ptOrigin.X >= 0 && ptOrigin.X < width && ptOrigin.Y >= 0 && ptOrigin.Y < height)                    pix1 = src.GetPixel(ptOrigin.X, ptOrigin.Y);                if (ptOrigin.X + idx >= 0 && ptOrigin.X + idx < width && ptOrigin.Y >= 0 && ptOrigin.Y < height)                    pix2 = src.GetPixel(ptOrigin.X + idx, ptOrigin.Y);
if (ptOrigin.X >= 0 && ptOrigin.X < width && ptOrigin.Y + idy >= 0 && ptOrigin.Y + idy < height)                    pix3 = src.GetPixel(ptOrigin.X, ptOrigin.Y + idy);
if (ptOrigin.X + idx >= 0 && ptOrigin.X + idx < width && ptOrigin.Y + idy >= 0 && ptOrigin.Y + idy < height)                    pix4 = src.GetPixel(ptOrigin.X + idx, ptOrigin.Y + idy);
//                // Use bilinear interpolation                //                double r = pix1.R + (pix2.R - pix1.R) * dx + (pix3.R - pix1.R) * dy + (pix1.R - pix2.R - pix3.R + pix4.R) * dx * dy;                double g = pix1.G + (pix2.G - pix1.G) * dx + (pix3.G - pix1.G) * dy + (pix1.G - pix2.G - pix3.G + pix4.G) * dx * dy;                double b = pix1.B + (pix2.B - pix1.B) * dx + (pix3.B - pix1.B) * dy + (pix1.B - pix2.B - pix3.B + pix4.B) * dx * dy;                double a = pix1.A + (pix2.A - pix1.A) * dx + (pix3.A - pix1.A) * dy + (pix1.A - pix2.A - pix3.A + pix4.A) * dx * dy;                pix = Color.FromArgb((byte)a, (byte)r, (byte)g, (byte)b);            }            else            {                pix = src.GetPixel(ptOrigin.X, ptOrigin.Y);            }            dst.SetPixel(ptDest.X, ptDest.Y, pix);        }    }}```

So this is bilinear interpolation is the main thing to transform your image.

Thank you.

PS

will extend this and provide source code if you will request.

PPS

```    public class Matrix3x3
{
double [,] m_val = new double [3,3];

public Matrix3x3()
{
}
public Matrix3x3(Point p1, Point p2, Point p3)
{
m_val = new double[3, 3];
m_val[0, 0] = p1.X;
m_val[0, 1] = p2.X;
m_val[0, 2] = p3.X;

m_val[1, 0] = p1.Y;
m_val[1, 1] = p2.Y;
m_val[1, 2] = p3.Y;

m_val[2, 0] = 1.0;
m_val[2, 1] = 1.0;
m_val[2, 2] = 1.0;
}

public double Determinant()
{
double result = 0;
result = m_val[0, 0] * (m_val[1, 1] * m_val[2, 2] - m_val[1, 2] * m_val[2, 1]);
result-= m_val[0, 1] * (m_val[1, 0] * m_val[2, 2] - m_val[1, 2] * m_val[2, 0]);
result+= m_val[0, 2] * (m_val[1, 0] * m_val[2, 1] - m_val[1, 1] * m_val[2, 0]);

return result;
}
public double a(int i, int j)
{
return m_val[i-1, j-1];
}

public void Inverse()
{
double a11 = a(2, 2) * a(3, 3) - a(2, 3) * a(3, 2);
double a12 = a(2, 1) * a(3, 3) - a(2, 3) * a(3, 1);
double a13 = a(2, 1) * a(3, 2) - a(2, 2) * a(3, 1);

double a21 = a(1, 2) * a(3, 3) - a(1, 3) * a(3, 2);
double a22 = a(1, 1) * a(3, 3) - a(1, 3) * a(3, 1);
double a23 = a(1, 1) * a(3, 2) - a(1, 2) * a(3, 1);

double a31 = a(1, 2) * a(2, 3) - a(1, 3) * a(2, 2);
double a32 = a(1, 1) * a(2, 3) - a(1, 3) * a(2, 1);
double a33 = a(1, 1) * a(2, 2) - a(1, 2) * a(2, 1);

double od = 1.0/Determinant();

m_val[0, 0] = od * a11;
m_val[0, 1] = -od * a21;
m_val[0, 2] = od * a31;

m_val[1, 0] = -od * a12;
m_val[1, 1] = od * a22;
m_val[1, 2] = -od * a32;

m_val[2, 0] = od * a13;
m_val[2, 1] = -od * a23;
m_val[2, 2] = od * a33;
}

public void MultByVec(double [] vector)
{
for (int row = 0; row < 3; ++row)
{
m_val[row, 0] *= vector[0];
m_val[row, 1] *= vector[1];
m_val[row, 2] *= vector[2];
}
}
public PointD Update(PointD vector)
{
double x = a(1, 1) * vector.X + a(1, 2) * vector.Y + a(1, 3) * 1.0;
double y = a(2, 1) * vector.X + a(2, 2) * vector.Y + a(2, 3) * 1.0;
double z = a(3, 1) * vector.X + a(3, 2) * vector.Y + a(3, 3) * 1.0;
//
PointD result = new PointD();
result.X = (x / z);
result.Y = (y / z);
return result;
}

public Matrix3x3 MultMat(Matrix3x3 B)
{
Matrix3x3 result = new Matrix3x3();

result.m_val[0, 0] = a(1, 1) * B.a(1, 1) + a(1, 2) * B.a(2, 1) + a(1, 3) * B.a(3, 1);
result.m_val[0, 1] = a(1, 1) * B.a(1, 2) + a(1, 2) * B.a(2, 2) + a(1, 3) * B.a(3, 2);
result.m_val[0, 2] = a(1, 1) * B.a(1, 3) + a(1, 2) * B.a(2, 3) + a(1, 3) * B.a(3, 3);

result.m_val[1, 0] = a(2, 1) * B.a(1, 1) + a(2, 2) * B.a(2, 1) + a(2, 3) * B.a(3, 1);
result.m_val[1, 1] = a(2, 1) * B.a(1, 2) + a(2, 2) * B.a(2, 2) + a(2, 3) * B.a(3, 2);
result.m_val[1, 2] = a(2, 1) * B.a(1, 3) + a(2, 2) * B.a(2, 3) + a(2, 3) * B.a(3, 3);

result.m_val[2, 0] = a(3, 1) * B.a(1, 1) + a(3, 2) * B.a(2, 1) + a(3, 3) * B.a(3, 1);
result.m_val[2, 1] = a(3, 1) * B.a(1, 2) + a(3, 2) * B.a(2, 2) + a(3, 3) * B.a(3, 2);
result.m_val[2, 2] = a(3, 1) * B.a(1, 3) + a(3, 2) * B.a(2, 3) + a(3, 3) * B.a(3, 3);

return result;
}

public static Matrix3x3 Homogenous(Point p1, Point p2, Point p3, Point p4)
{
Matrix3x3 Major = new Matrix3x3(p1, p2, p3);
Matrix3x3 Minor1 = new Matrix3x3(p4, p2, p3);
Matrix3x3 Minor2 = new Matrix3x3(p1, p4, p3);
Matrix3x3 Minor3 = new Matrix3x3(p1, p2, p4);
double MajorD = Major.Determinant();
double Minor1D = Minor1.Determinant();
double Minor2D = Minor2.Determinant();
double Minor3D = Minor3.Determinant();

double[] coeff = new double[3];
coeff[0] = Minor1D / MajorD;
coeff[1] = Minor2D / MajorD;
coeff[2] = Minor3D / MajorD;
//
Major.MultByVec(coeff);

return Major;
}
}```

1vqHSTrq1GEoEF7QsL8dhmJfRMDVxhv2y

• Daniel

Thanks for this. In the end I went with solution that didn't use matrices:

Vector ab = new Vector(Points[0], Points[1]);
Vector bc = new Vector(Points[1], Points[2]);
Vector cd = new Vector(Points[2], Points[3]);
Vector da = new Vector(Points[3], Points[0]);

ab /= ab.Magnitude;
bc /= bc.Magnitude;
cd /= cd.Magnitude;
da /= da.Magnitude;

double dab = Math.Abs((new Vector(Points[0], point).CrossProduct(ab)));
double dbc = Math.Abs((new Vector(Points[1], point).CrossProduct(bc)));
double dcd = Math.Abs((new Vector(Points[2], point).CrossProduct(cd)));
double dda = Math.Abs((new Vector(Points[3], point).CrossProduct(da)));

point.X = (int)(width * (dda / (dda + dbc)));
point.Y = (int)(height * (dab / (dab + dcd)));

• okarpov

Cool! Thank you! Hope it will help anybody.

• Taalaibek

Вы можете отправить мне исходный код, пожалуйста. Я не знаю как использовать ваш код.

• Christa Thresher

Thankyou  for helping out,  great  info .

Thank you

• Shayne Gienger

You have brought up a very  great   details ,  appreciate it for the post.

• Talia Kole

Wow, fantastic blog layout! How long have you been blogging for? you make blogging look easy. The overall look of your site is fantastic, as well as the content!

• Margarito Karstens

I do believe all the ideas you've introduced in your post. They're really convincing and can certainly work. Still, the posts are very short for newbies. Could you please lengthen them a bit from next time? Thanks for the post.

• Stephenie Orantes

I don’t even know how I ended up here, but I thought this post was good. I don't know who you are but definitely you're going to a famous blogger if you aren't already ;) Cheers!

I like the valuable information you provide in your articles. I’ll bookmark your weblog and check again here frequently. I'm quite certain I’ll learn plenty of new stuff right here! Best of luck for the next!

• Dusti Eblin

This is really interesting, You're a very skilled blogger. I've joined your rss feed and look forward to seeking more of your excellent post. Also, I have shared your website in my social networks!

• Anti aging

Enjoyed the post.