5

I am using Opencv python interface and got the homography matrix H. It seems to work properly as I can use warp perspective to get warped image from the source image. I now tried to use H and Inverse H to transform a point (not image) back and forth between the two coordinates and is not getting the expected results.

To get the matrix, I did this:

pts1 = np.float32(corners)
pts2 = np.float32([[0,0], [400,0], [400,400], [0,400]])
self.transform_matrix = cv2.getPerspectiveTransform(pts1, pts2)

Given this matrix, I use the following to do a forward and inverse transform:

def transformPoints(self, x, y, reverse=False, integer=True):

        if reverse == False:
            H = self.transform_matrix
        else:
            val, H = cv2.invert(self.transform_matrix)

        # get the elements in the transform matrix
        h0 = H[0,0]
        h1 = H[0,1]
        h2 = H[0,2]
        h3 = H[1,0]
        h4 = H[1,1]
        h5 = H[1,2]
        h6 = H[2,0]
        h7 = H[2,1]
        h8 = H[2,2]

        tx = (h0*x + h1*y + h2)
        ty = (h3*x + h4*x + h5)
        tz = (h6*x + h7*y + h8)

        if integer==True:
            px = int(tx/tz)
            py = int(ty/tz)
            Z = int(1/tz)
        else:
            px = tx/tz
            py = ty/tz
            Z = 1/tz

        return (px, py)

Now, if I do this:

s, t = 100,200
print "s=%d, t=%d" % (s,t)
a, b = pt.transformPoints(s,t)
print "a=%d, b=%d" % (a,b)

c, d = pt.transformPoints(a, b, True)
print "c=%d, d=%d" % (c,d)

This is what it prints: a=395, b=169 c=91, d=226

I was expecting c=100 and d=200, or at least something close.

This is the matrix and it's inverse.
H matrix

[[ -1.01486350e-01  -1.99156329e+01   8.44058060e+02]
 [  1.82486862e+00   3.62765073e-01  -1.49259809e+03]
 [ -4.43678849e-03  -4.28012674e-02   1.00000000e+00]]

Inverse:

[[  4.13378829e-01   1.05495739e-01  -1.91452995e+02]
 [ -3.12201095e-02  -2.37099792e-02  -9.03788455e+00]
 [  4.97814178e-04  -5.46754880e-04  -2.36269358e-01]]

I tried to do a dot product, and it seems to generate an identity matrix ok:

[[  1.00000000e+00   1.77635684e-15  -5.68434189e-14]
 [ -6.93889390e-18   1.00000000e+00   5.32907052e-15]
 [ -2.16840434e-19   1.73472348e-18   1.00000000e+00]]

Any help is appreciated.

Fuithecat
  • 131
  • 2
  • 5
  • if A*B is identity the A and B indeed ARE the inverse of each other. – Micka Sep 03 '15 at 05:42
  • guess: numpy uses x,y indexing instead of row,col indexing. can you try h0 = H[0,0] h1 = H[1,0] h2 = H[2,0] h3 = H[0,1] and so on? – Micka Sep 03 '15 at 05:51
  • thanks for the suggestion. If I print h0, h1, ... individually, they are the right elements from the matrix, so I don't think this is the issue though. – Fuithecat Sep 05 '15 at 03:36
  • please try with integer = false... you transform and round your resulting points to int precision. then you expect the rounded points to inversely transform back to your original points which is nonsense... – Micka Sep 05 '15 at 06:03
  • please try t=200 print "s=%d, t=%d" % (s, t) (a,b) = pt.transformPoints(s, t, False, False) print "a=%d, b=%d" % (a,b) (c,d) = pt.transformPoints(a,b, True, False) print "transformPoints = %d, %d" % (c,d) and post results – Micka Sep 05 '15 at 13:42
  • s=100 t=200 print "s=%d, t=%d" % (s, t) (a,b) = pt.transformPoints(s, t, False, False) print "a=%d, b=%d" % (a,b) (c,d) = pt.transformPoints(a,b, True, False) print "transformPoints = %d, %d" % (c,d) Generates:s=100, t=200 a=394, b=356 transformPoints = 1441, 942 . Note that I manually click the 4 points to get the matrix so it may be different than my previous example, but the errors in the generated number doesn't make sense. Initially I thought it was rounding error, hence I added the integer flag, but it appears not too matter much. – Fuithecat Sep 05 '15 at 14:01
  • in your initial sample, the result (91,226) isnt so far away from expected (100,200) and I'm very sure that comes from feeding rounded points to the inverse transformation. In your latest result it looks like you switched the order of "inverse" and "integer" parameters and transformed two times non-inverse with integer precision... – Micka Sep 05 '15 at 14:09
  • I was searching and I found another way to do this with cv2.perspectiveTransform. This gave me the expected response: def transformPoints2(self, x, y, reverse=False): src = np.array([((x, y), (0, 0))], dtype=np.float32) if reverse == False: cvt = cv2.perspectiveTransform(src, self.transformMatrix) else: (_, I) = cv2.invert(self.transformMatrix) cvt = cv2.perspectiveTransform(src, I) #print cvt return (cvt[0][0][0], cvt[0][0][1]) Results: s=100, t=200 a=391, b=556 transformPoints2 = 100, 200 So there must be something wrong with the way I did it originally – Fuithecat Sep 05 '15 at 14:09

1 Answers1

3

You have a typo in second line

tx = (h0*x + h1*y + h2) 
ty = (h3*x + h4*x + h5) 
tz = (h6*x + h7*y + h8)

h4 should be multiplied with y coordinate

alexisrozhkov
  • 1,623
  • 12
  • 18
  • this could be it. Thanks for spotting it, has been nagging me for a while. I haven't yet tried it out but very likely will solve the problem. – Fuithecat Dec 15 '15 at 05:40