Code for a four point transformation of an image-VBForums
Results 1 to 6 of 6

Thread: Code for a four point transformation of an image

  1. #1

    Thread Starter
    Hyperactive Member
    Join Date
    Oct 2008
    Posts
    412

    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. #2
    Fanatic Member
    Join Date
    Mar 2009
    Posts
    735

    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. #3

    Thread Starter
    Hyperactive Member
    Join Date
    Oct 2008
    Posts
    412

    Re: Code for a four point transformation of an image

    Quote Originally Posted by VBClassicRocks View Post
    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.
    Let me address some of your points
    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.
    Last edited by Ben321; Nov 25th, 2012 at 12:11 AM.

  4. #4

    Thread Starter
    Hyperactive Member
    Join Date
    Oct 2008
    Posts
    412

    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).
    Attached Files Attached Files

  5. #5

    Thread Starter
    Hyperactive Member
    Join Date
    Oct 2008
    Posts
    412

    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. #6
    Default Member Bonnie West's Avatar
    Join Date
    Jun 2012
    Location
    InIDE
    Posts
    3,130

    Thumbs up Re: Code for a four point transformation of an image

    On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0

    Declare Sub CrashVB Lib "msvbvm60" (Optional DontPassMe As Any)

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


Click Here to Expand Forum to Full Width

Survey posted by VBForums.