5.23. Hiệu chỉnh phối cảnh

Cảnh báo

Ma trận transform 3x3 tùy ý chỉ được hỗ trợ trên OpenMV Cam N6 -- từ khóa này bị bỏ qua một cách im lặng trên mọi board khác. Các ứng dụng cần chạy ở nơi khác phải sử dụng phương thức rotation_corr() đóng gói sẵn (với dạng corners= của nó) hoặc tính toán trước ảnh đã hiệu chỉnh ngoài board.

Phương thức rotation_corr() đóng gói sẵn đóng gói một họ biến dạng phối cảnh cụ thể sau một tập tham số nhỏ và chạy trên mọi board được hỗ trợ. Một số ứng dụng cần biến dạng không phù hợp với dạng đó: ánh xạ chiếu xạ tùy ý từ một tứ giác sang tứ giác khác, hiệu chỉnh đã hiệu chỉnh cho một giá đỡ đã biết được tính toán ngoại tuyến, ma trận biến dạng được chuyển giao sẵn sàng bởi một thuật toán thượng nguồn nào đó. Đối với những trường hợp đó, draw_image() -- cùng với copy(), crop()scale() -- chấp nhận từ khóa transform nhận một ma trận 3x3 được xây dựng thủ công mô tả biến dạng trực tiếp.

5.23.1. Các phép biến đổi affine và xạ ảnh

Các biến dạng hình học được biểu diễn trong tọa độ thuần nhất: vị trí điểm ảnh (x, y) với 1 được thêm vào, nhân với ma trận 3x3.

Dạng affine là nơi để bắt đầu. Hàng dưới cùng của nó được cố định ở \((0, 0, 1)\):

\[\begin{split}\begin{bmatrix} x' \\ y' \\ 1 \end{bmatrix} = \begin{bmatrix} a & b & c \\ d & e & f \\ 0 & 0 & 1 \end{bmatrix} \begin{bmatrix} x \\ y \\ 1 \end{bmatrix}\end{split}\]

Viết ra, mỗi tọa độ đầu ra là tổ hợp tuyến tính của các tọa độ đầu vào cộng một hằng số:

\[x' = a x + b y + c, \qquad y' = d x + e y + f\]

bao gồm tỷ lệ, xoay, cắt và dịch chuyển ở bất kỳ tổ hợp nào -- và với tất cả chúng, các đường thẳng song song vẫn song song.

Dạng xạ ảnh (phối cảnh) giải phóng hàng dưới cùng:

\[\begin{split}\begin{bmatrix} x'' \\ y'' \\ w' \end{bmatrix} = \begin{bmatrix} a & b & c \\ d & e & f \\ g & h & 1 \end{bmatrix} \begin{bmatrix} x \\ y \\ 1 \end{bmatrix}, \qquad (x', y') = \left( \frac{x''}{w'}, \; \frac{y''}{w'} \right)\end{split}\]

Viết ra:

\[x' = \frac{a x + b y + c}{g x + h y + 1}, \qquad y' = \frac{d x + e y + f}{g x + h y + 1}\]

Phép chia cho \(w' = g x + h y + 1\) là điều làm cho phép biến đổi trở thành xạ ảnh thay vì chỉ là affine. Khi cả \(g\)\(h\) đều bằng không, \(w'\) giữ ở một và phép chia không làm gì -- lại là dạng affine. Khi một trong hai khác không, \(w'\) thay đổi theo vị trí đầu vào và các điểm ảnh ở các vị trí khác nhau bị thu ngắn với các lượng khác nhau, không còn giữ các đường thẳng song song -- đây chính xác là hiệu ứng thang hình khi nhìn vào một mặt phẳng từ góc xiên. Phép biến đổi xạ ảnh là biến dạng hình học tổng quát nhất biến đường thẳng thành đường thẳng; tỷ lệ, lật, hoán vị, xoay và hiệu chỉnh xoay bốn góc đều là các trường hợp đặc biệt của nó.

Các phép biến đổi được đặt tên xuất hiện trực tiếp từ dạng affine. Phép biến đổi đồng nhất là ma trận đơn vị, và:

\[\begin{split}\underbrace{\begin{bmatrix} 1 & 0 & t_x \\ 0 & 1 & t_y \\ 0 & 0 & 1 \end{bmatrix}}_{\text{translate by } (t_x, \; t_y)} \qquad \underbrace{\begin{bmatrix} s_x & 0 & 0 \\ 0 & s_y & 0 \\ 0 & 0 & 1 \end{bmatrix}}_{\text{scale by } (s_x, \; s_y)} \qquad \underbrace{\begin{bmatrix} \cos\theta & -\sin\theta & 0 \\ \sin\theta & \cos\theta & 0 \\ 0 & 0 & 1 \end{bmatrix}}_{\text{rotate by } \theta}\end{split}\]

Đối với hầu hết các phép biến đổi được xây dựng thủ công, ứng dụng bắt đầu với một trong số này làm cơ sở và nhân thêm các ma trận khác cho mỗi thao tác bổ sung, kết thúc với một ma trận 3x3 duy nhất mô tả biến dạng tổ hợp. Ma trận áp dụng từ phải sang trái: \(M = T R S\) chạy tỷ lệ trước, rồi xoay, rồi dịch chuyển. Phép tổ hợp mà mọi người cuối cùng đều cần là xoay quanh tâm ảnh -- ma trận xoay thuần quay ảnh quanh gốc tọa độ điểm ảnh ở góc trên bên trái, vì vậy phiên bản tập trung di chuyển tâm \((c_x, c_y)\) về gốc tọa độ, xoay, rồi di chuyển lại:

\[\begin{split}M = \underbrace{\begin{bmatrix} 1 & 0 & c_x \\ 0 & 1 & c_y \\ 0 & 0 & 1 \end{bmatrix}}_{\text{move centre back}} \underbrace{\begin{bmatrix} \cos\theta & -\sin\theta & 0 \\ \sin\theta & \cos\theta & 0 \\ 0 & 0 & 1 \end{bmatrix}}_{\text{rotate}} \underbrace{\begin{bmatrix} 1 & 0 & -c_x \\ 0 & 1 & -c_y \\ 0 & 0 & 1 \end{bmatrix}}_{\text{move centre to origin}}\end{split}\]

5.23.2. Từ khóa transform

Ma trận được truyền vào qua từ khóa transform, được cung cấp dưới dạng ulab.numpy.ndarray 3x3. Phương thức cần dùng là draw_image(), biến dạng nguồn qua ma trận khi vẽ lên đích -- kết quả đổ vào bộ đệm mà ứng dụng kiểm soát, và biến dạng tổ hợp với mọi thứ khác trong lần gọi: tỷ lệ, pha trộn alpha, che khuất.

import ulab.numpy as np

M = np.array([[1.2,  0.0, -20.0],
              [0.0,  1.2, -15.0],
              [0.0,  0.0,   1.0]])

canvas.draw_image(img, transform=M)

Ví dụ biến dạng img lên canvas được thu phóng 1.2 lần theo mỗi hướng và dịch chuyển sang trái và lên trên lần lượt 20 và 15 điểm ảnh -- một biến dạng affine được xây dựng trực tiếp từ các mục ma trận được mô tả ở trên. Cùng từ khóa đó trên copy(), crop()scale() áp dụng biến dạng cho chính ảnh đó.