Code for a four point transformation of an image-VBForums

# Thread: Code for a four point transformation of an image

1. ## Code for a four point transformation of an image

This code can be used to manipulate an image into any space defined by four corners. Unlike an affine-transform (3 point transformation) which uses a parallelogram shaped space, this 4 point transformation can use absolutely any generic shape that can be defined by four points. Below is this code, split into the two files that I ended up using.

Code for DPointType.bas
Code:
```Public Type DPOINT
X As Double
Y As Double
End Type```
Code for FourPointTransform.cls
Code:
```'Requires DPointType.bas

'The Points array holds 4 points. Below is an explanation of each point.
'Points(0) is the position that a rectangle's upper left point is mapped to.
'Points(1) is the position that a rectangle's upper right point is mapped to.
'Points(2) is the position that a rectangle's lower left point is mapped to.
'Points(3) is the position that a rectangle's lower right point is mapped to.

Friend Function X2(ByVal X As Double, ByVal Y As Double, ByVal ImgWidth As Double, ByVal ImgHeight As Double, _
ByRef Points() As DPOINT) As Double
Dim a As Double
Dim b As Double
Dim c As Double
Dim d As Double
b = (Points(1).X - Points(0).X) / (ImgWidth - 1)
d = Points(0).X
c = (Points(2).X - Points(0).X) / (ImgHeight - 1)
a = (Points(3).X - (ImgHeight - 1) * c - d - (ImgWidth - 1) * b) / ((ImgWidth - 1) * (ImgHeight - 1))
X2 = X * (Y * a + b) + Y * c + d
End Function

Friend Function Y2(ByVal X As Double, ByVal Y As Double, ByVal ImgWidth As Double, ByVal ImgHeight As Double, _
ByRef Points() As DPOINT) As Double
Dim a As Double
Dim b As Double
Dim c As Double
Dim d As Double
b = (Points(2).Y - Points(0).Y) / (ImgHeight - 1)
d = Points(0).Y
c = (Points(1).Y - Points(0).Y) / (ImgWidth - 1)
a = (Points(3).Y - (ImgHeight - 1) * b - (ImgWidth - 1) * c - d) / ((ImgHeight - 1) * (ImgWidth - 1))
Y2 = Y * (X * a + b) + X * c + d
End Function```
Use the above class to transform an image in one picture box into a random shape in a second picture box, using the sample code below:
Code:
```Private Sub TransformImage()
dim Xfrm as new FourPointTransform
dim Points(3) as DPOINT
Points(0).X=100 : Points(0).Y=20
Points(1).X=300 : Points(1).Y=45
Points(2).X=115 : Points(2).Y=200
Points(3).X=290 : Points(3).Y=230
for y = 0 to Picture1.Height-1
for x = 0 to Picture1.Width-1
u = Xfrm.X2(X, Y, Picture1.Width, Picture1.Height, Points)
v = Xfrm.Y2(X, Y, Picture1.Width, Picture1.Height, Points)
Picture2.pset(u,v),Picture1.point(x,y)
next x
next y
End Sub```
Or use the above class to transform a portion of an image defined by any random 4-point shape in one picture box to fit correctly into a second picture box. This is the inverse of the above transformation. The code is very similar to the above, with just a few changes. See the code below
Code:
```Private Sub InverseTransformImage()
dim Xfrm as new FourPointTransform
dim Points(3) as DPOINT
Points(0).X=100 : Points(0).Y=20
Points(1).X=300 : Points(1).Y=45
Points(2).X=115 : Points(2).Y=200
Points(3).X=290 : Points(3).Y=230
for y = 0 to Picture2.Height-1
for x = 0 to Picture2.Width-1
u = Xfrm.X2(X, Y, Picture2.Width, Picture2.Height, Points)
v = Xfrm.Y2(X, Y, Picture2.Width, Picture2.Height, Points)
Picture2.pset(x,y),Picture1.point(u,v)
next x
next y
End Sub```

2. ## Re: Code for a four point transformation of an image

Nice job Ben. I think this is what MS Paint calls Skew.
A few recommendations:
Your TransformImage routine uses arbitrary points on an unknown picture so it is
hard to see what is happening. Write a little demo that allows the user to
select 4 points on the destination picture, then do the transformation.
I would change all the doubles to singles, since your code mixes & matches them.
Replace the Point & PSet calls with SetPixelV & GetPixel APIs for speed.
Change all the Widths/Heights to ScaleWidths/ScaleHeights.

Finally, you don't really need a class for this. Your 2 workhorse functions
(X2 & Y2) can go in a module along with the Point UDT & the APIs.

3. ## Re: Code for a four point transformation of an image

Originally Posted by VBClassicRocks
Nice job Ben. I think this is what MS Paint calls Skew.
A few recommendations:
Your TransformImage routine uses arbitrary points on an unknown picture so it is
hard to see what is happening. Write a little demo that allows the user to
select 4 points on the destination picture, then do the transformation.
I would change all the doubles to singles, since your code mixes & matches them.
Replace the Point & PSet calls with SetPixelV & GetPixel APIs for speed.
Change all the Widths/Heights to ScaleWidths/ScaleHeights.

Finally, you don't really need a class for this. Your 2 workhorse functions
(X2 & Y2) can go in a module along with the Point UDT & the APIs.
MSPaint's skew is not like this. It is based on a transform defined by only 3 points called an affine transform. Strangest shape you can get out of that is a parallelogram. Opposing sides are always parallel with an affine transform. With my transform (which I believe is called a "projection transform") it uses 4 points so each of the 4 points of the output shape (or input shape if it's being used as an inverse transform) defines a corner of the quadrangle. This means that you can make the transform shape be ANY 4 sided shape, including a shape in which none of the sides are parallel to any of the other sides. That can NOT be done with an affine transform (such as MSPaint's "skew").

I am currently workng on a test program that allows you to set the 4 points of the transform shape by just clicking on the image. I'll send post the complete code for it here when it's finished.

I'm not sure where the SINGLEs are in my code. I've only DIMed DOUBLEs. If I use SINGLEs I'll get more artifacts for loss of precision.

The test program I am working on is indeed using SetPixel and GetPixel.
Also for compiling the EXE file I've set some of the special optimizations:
Remove Array Bounds Checks (because I don't have any array indexes that go over the bounds of an array, so I don't need error checking for this and such checks just slow down the program)
Remove Integer Overflow Checks (because I don't have any operations that would produce an overflow in any condition, so I don't need error checking on this, and it would just slow down my program)
Remove Floating Point Error Checks (I'm not expecting to get any INF or NAN or other overflow problems out of the operations in this program, so once again it is just an error check that can only serve to slow down my program)
Remove Safe Pentium FDIV Checks (completely unnececary as this only applies to Pentium computers, not Pentium Pro, Pentium II, Pentium III, Pentium IIII, or any newer Intel CPUs or any other brand of CPU, and most people now days are not using that ancient CPU that was just called "Pentium", so these Safe Pentium checks are useless for modern computers and could only serve to slow down my program)

By putting these functions in a class, it allows them to be easily implemented in other programs that use the same algorithm. Also since X2 or Y2 may be defined elsewhere as something else putting them in a class so that you need to call the class, guaranties that there are no conflicts with other possible definitions of X2 and Y2 (maybe in some context these would be variables like Dim X2 as Double, instead of the name of a function). This way you can use X2 as both a variable and a function even, like this:
Code:
```Dim A As New FourPointTransform
Dim X2 As Double
X2 = A.X2(X,Y,Picture1.Width,Picture1.Height,Points)```
If I put these functions into a module or in the Declarations part of a form, they may conflict with variables of the same name. Thus a class is needed to separate them from the "main code" of the program.

As for ScaleHeight and ScaleWidth, I already have set my pictureboxes to have a scalemode of pixels, and not to have any border (thus the upperleft pixel has coordinates x=0 y=0 and the scalewidth=width and scaleheight=height for my pictureboxes, and this simplifies a LOT of code later on so I have less to type so it physically is quicker to write my program). I don't need to explicitly refer to scalewidth and scaleheight in my pictureboxes.

4. ## Re: Code for a four point transformation of an image

I've finally completed my program. I've attached a zip file with containing my program to this message. It has all the source code and the compiled EXE file. I've included a minor improvement in my code in the class (the implementation in the CLS file in the attached ZIP file now differs slightly from the above pasted code). It now uses the forth point as the lower left corner instead of the lower right corner. This is great because it allows lines to be drawn in the image between the points (not just the corner points) to better help one visualize where the pixels are being drawn to (for a forward transformation) or taken from (for an inverse transformation).

5. ## Re: Code for a four point transformation of an image

Does nobody have a reply to my posting of the program I finally made utilizing this algorithm?

6. ## Re: Code for a four point transformation of an image

#### Posting Permissions

• You may not post new threads
• You may not post replies
• You may not post attachments
• You may not edit your posts
•

Featured