# Reproduce 2 successive perspectives transformations with a dot product

**URL:** <https://forum.opencv.org/t/reproduce-2-successive-perspectives-transformations-with-a-dot-product/16916>\
**Category:** Python\
**Created:** [March 21, 2024, 5:30pm UTC](https://forum.opencv.org/t/reproduce-2-successive-perspectives-transformations-with-a-dot-product/16916 "2024-03-21T17:30:19Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![domlysz](https://avatars.discourse-cdn.com/v4/letter/d/ac91a4/32.png) [@domlysz](https://forum.opencv.org/u/domlysz)\
**Post date:** [March 21, 2024, 5:30pm UTC](https://forum.opencv.org/t/reproduce-2-successive-perspectives-transformations-with-a-dot-product/16916/1 "2024-03-21T17:30:19Z")

</div>

Hello,

I have 3 photos taken from the same point of view at years 2014, 2017 and 2020. I’d like to align theses photos using controls points and a perspective transformation.

I’ve computed the following perspectives matrices :  
M1 transform from 2017 to 2014  
M2 transform from 2020 to 2014.

The alignment is very good !

I thought I could align the picture from 2017 to the picture from 2020 by combining 2 successive transformations (M1 following inverse of M2). It work great if I decompose the steps with 2 calls of _warpPerspective()_

> M2 = np.linalg.inv(M2)  
> im = cv2.warpPerspective(im, M1, (w, h))  
> im = cv2.warpPerspective(im, M2, (w, h))

But if I try to combine the 2 matrices with a dot product, then the alignment is not as perfect.

```auto
M = np.dot(M1, M2)
im = cv2.warpPerspective(im, M, (w, h))

```

 ![alignement](https://us1.discourse-cdn.com/flex020/uploads/opencv/original/2X/1/1af4900e96a7c39b198dbfadf1f51b045d6744e9.jpeg)  
_Left is the picture from 2020, right the result of the 2 successive transformations and then on right comparison, the result of the dot product_

I thought I’d get the same result. Anyone can help me to understand what’s can be wrong in this assumption ?

thanks you very much

---

<div class="post-metadata">

**Author:** ![crackwitz](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.opencv.org/crackwitz/32/14_2.png) [@crackwitz](https://forum.opencv.org/u/crackwitz)\
**Post date:** [March 22, 2024, 8:50am UTC](https://forum.opencv.org/t/reproduce-2-successive-perspectives-transformations-with-a-dot-product/16916/2 "2024-03-22T08:50:07Z")

</div>

Wrong order.

Linear algebra:

```none
v' = M2 (M1 v)
   = (M2 M1) v

```

why did you reassign M2 to be inv(M2)? that is confusing. I’ll ignore that and expect that your issue is due to the wrong order of matrix multiplications.

---

<div class="post-metadata">

**Author:** ![domlysz](https://avatars.discourse-cdn.com/v4/letter/d/ac91a4/32.png) [@domlysz](https://forum.opencv.org/u/domlysz)\
**Post date:** [March 22, 2024, 9:20am UTC](https://forum.opencv.org/t/reproduce-2-successive-perspectives-transformations-with-a-dot-product/16916/3 "2024-03-22T09:20:08Z")

</div>

Thank you, changing the order of the dot product solve the issue.

```auto
m2i = np.linalg.inv(m2)
m = np.dot(m2i, m1)

```

My apologies, it was a very simple mistake !

---

<div class="post-metadata">

**Author:** ![crackwitz](https://sea2.discourse-cdn.com/flex020/user_avatar/forum.opencv.org/crackwitz/32/14_2.png) [@crackwitz](https://forum.opencv.org/u/crackwitz)\
**Post date:** [March 22, 2024, 9:52am UTC](https://forum.opencv.org/t/reproduce-2-successive-perspectives-transformations-with-a-dot-product/16916/4 "2024-03-22T09:52:29Z")

</div>

mind the “frames”, i.e. coordinate/reference frames, origins, that stuff. and mind the way each matrix transforms.

matrix mul is not commutative. if you have a common frame A and other frames B and C, and you have T\_A\_B (transforming from B into A), and T\_A\_C (from C into A), and you want to go from B to C, then you need `T_B_A @ T_A_C = inv(T_A_B) @ T_A_C` which is _wildly different_ from `T_A_C @ inv(T_A_B)` or `T_A_B @ inv(T_A_C)` or any other expression you could come up with.

don’t just go by whether the resulting picture looks right or wrong. it might just accidentally _look_ right (but _be_ wrong) because of how the numbers fall (how the dice fall).
