我的目標是以這樣一種方式轉換圖像,即將三個源點映射到空數組中的三個目標點。我已經解決了正確的仿射矩陣的發現,但是我無法對彩色圖像應用仿射變換。如何使用scipy的affine_transform對彩色圖像進行任意仿射變換?
更具體地說,我正在努力正確使用scipy.ndimage.interpolation.affine_transform
方法。由於這個question和awers指出,affine_transform方法可能有點不直觀(特別是關於偏移量計算),但是,用戶timday顯示如何應用旋轉和剪切圖像並將其放置在另一個數組中,而用戶地理數據給出更多背景信息。
我的問題是推廣那裏顯示的方法(1)爲圖像着色和(2)我計算自己的任意轉換。
這是我的代碼(這應該運行作爲您的計算機上):
我試着包括與逆工作import numpy as np
from scipy import ndimage
import matplotlib.pyplot as plt
def calcAffineMatrix(sourcePoints, targetPoints):
# For three source- and three target points, find the affine transformation
# Function works correctly, not part of the question
A = []
b = []
for sp, trg in zip(sourcePoints, targetPoints):
A.append([sp[0], 0, sp[1], 0, 1, 0])
A.append([0, sp[0], 0, sp[1], 0, 1])
b.append(trg[0])
b.append(trg[1])
result, resids, rank, s = np.linalg.lstsq(np.array(A), np.array(b))
a0, a1, a2, a3, a4, a5 = result
# Ignoring offset here, later use timday's suggested offset calculation
affineTrafo = np.array([[a0, a1, 0], [a2, a3, 0], [0, 0, 1]], 'd')
# Testing the correctness of transformation matrix
for i, _ in enumerate(sourcePoints):
src = sourcePoints[i]
src.append(1.)
trg = targetPoints[i]
trg.append(1.)
at = affineTrafo.copy()
at[2, 0:2] = [a4, a5]
assert(np.array_equal(np.round(np.array(src).dot(at)), np.array(trg)))
return affineTrafo
# Prepare source image
sourcePoints = [[162., 112.], [130., 112.], [162., 240.]]
targetPoints = [[180., 102.], [101., 101.], [190., 200.]]
image = np.empty((300, 300, 3), dtype='uint8')
image[:] = 255
# Mark border for better visibility
image[0:2, :] = 0
image[-3:-1, :] = 0
image[:, 0:2] = 0
image[:, -3:-1] = 0
# Mark source points in red
for sp in sourcePoints:
sp = [int(u) for u in sp]
image[sp[1] - 5:sp[1] + 5, sp[0] - 5:sp[0] + 5, :] = np.array([255, 0, 0])
# Show image
plt.subplot(3, 1, 1)
plt.imshow(image)
# Prepare array in which the image is placed
array = np.empty((400, 300, 3), dtype='uint8')
array[:] = 255
a2 = array.copy()
# Mark target points in blue
for tp in targetPoints:
tp = [int(u) for u in tp]
a2[tp[1] - 2:tp[1] + 2, tp[0] - 2:tp[0] + 2] = [0, 0, 255]
# Show array
plt.subplot(3, 1, 2)
plt.imshow(a2)
# Next 5 program lines are actually relevant for question:
# Calculate affine matrix
affineTrafo = calcAffineMatrix(sourcePoints, targetPoints)
# This follows the c_in-c_out method proposed in linked stackoverflow issue
# extended for color channel (no translation here)
c_in = np.array([sourcePoints[0][0], sourcePoints[0][1], 0])
c_out = np.array([targetPoints[0][0], targetPoints[0][1], 0])
offset = (c_in - np.dot(c_out, affineTrafo))
# Affine transform!
ndimage.interpolation.affine_transform(image, affineTrafo, order=2, offset=offset,
output=array, output_shape=array.shape,
cval=255)
# Mark blue target points in array, expected to be above red source points
for tp in targetPoints:
tp = [int(u) for u in tp]
array[tp[1] - 2:tp[1] + 2, tp[0] - 2:tp[0] + 2] = [0, 0, 255]
plt.subplot(3, 1, 3)
plt.imshow(array)
plt.show()
其他辦法,調換或兩者affineTrafo的:
affineTrafo = np.linalg.inv(affineTrafo)
affineTrafo = affineTrafo.T
affineTrafo = np.linalg.inv(affineTrafo.T)
affineTrafo = np.linalg.inv(affineTrafo).T
在他的回答中,地理數據顯示瞭如何計算affine_trafo
需要進行縮放和旋轉的矩陣:
如果有人想先縮放S然後旋轉R,則認爲
T=R*S
因此T.inv=S.inv*R.inv
(注意顛倒的順序)。
這點我嘗試使用矩陣分解(分解我的仿射變換成旋轉,剪切和另一個旋轉)來複制:
u, s, v = np.linalg.svd(affineTrafo[:2,:2])
uInv = np.linalg.inv(u)
sInv = np.linalg.inv(np.diag((s)))
vInv = np.linalg.inv(v)
affineTrafo[:2, :2] = uInv.dot(sInv).dot(vInv)
再次,沒有成功。
對於我的所有結果,它不是(唯一)一個抵消問題。從圖中清楚可見,源點和目標點的相對位置不一致。
我搜索了網絡和計算器,並沒有找到我的問題的答案。請幫幫我! :)
我的答案[這裏](https://stackoverflow.com/questions/44457064/displaying-stitched-images-together-without-cutoff-using-warpaffine/44459869#44459869)是相關的,可能會幫助你理解這個'偏移量是和如何計算它。 –
@AlexanderReynolds謝謝你,我已閱讀你的答案,但問題比偏移更早。您是否嘗試運行代碼?你會看到轉換完全錯誤,不僅是偏移。藍色和紅色的點應重疊,但甚至沒有正確的相對位置。 –
是的,但我不知道發生了什麼事。文件非常缺乏。目前還不清楚這些位置是使用前乘法還是後乘法計算的(誰知道是使用變換還是反算),何時應用偏移量,或者變形點與目標圖像的座標有什麼關係。我可以告訴你,你正在計算'c_in'和'c_out'錯誤,你不會在最後得到正確的具有'0'的像素位置(它們應該是同樣的點,就像我的答案所說的那樣, 0「)。不是主要問題。 –