在 python 中为 warpAffine 手动编写代码
Manually wirting code for warpAffine in python
我想不使用库函数实现仿射变换。
我有一个名为 "transformed" 的图像,我想应用逆变换来获得 "img_org" 图像。现在,我正在使用我自己的基本 GetBilinearPixel 函数来设置强度值。但是,图像没有改变 properly.This 是我想出的。 :
这是图片("transformed.png"):
这是图片("img_org.png"):
但我的目标是制作这张图片:
你可以在这里看到转换矩阵:
pts1 = np.float32( [[693,349] , [605,331] , [445,59]] )
pts2 = np.float32 ( [[1379,895] , [1213,970] ,[684,428]] )
Mat = cv2.getAffineTransform(pts2,pts1)
B=Mat
代码:
img_org=np.zeros(shape=(780,1050))
img_size=np.zeros(shape=(780,1050))
def GetBilinearPixel(imArr, posX, posY):
return imArr[posX][posY]
for i in range(1,img.shape[0]-1):
for j in range(1,img.shape[1]-1):
pos=np.array([[i],[j],[1]],np.float32)
#print pos
pos=np.matmul(B,pos)
r=int(pos[0][0])
c=int(pos[1][0])
#print r,c
if(c<=1024 and r<=768 and c>=0 and r>=0):
img_size[r][c]=img_size[r][c]+1
img_org[r][c] += GetBilinearPixel(img, i, j)
for i in range(0,img_org.shape[0]):
for j in range(0,img_org.shape[1]):
if(img_size[i][j]>0):
img_org[i][j] = img_org[i][j]/img_size[i][j]
我的逻辑错了吗?我知道我应用了非常低效的算法。
我缺少任何见解吗?
或者你能给我任何其他可以正常工作的算法吗?
(请求)。我不想使用 warpAffine 函数。
所以我对代码进行了向量化处理,这个方法起作用了——我找不到你的实现的确切问题,但也许这会揭示一些问题(而且速度更快)。
矢量化的设置是创建一个包含图像中每个点的线性(均匀)阵列。我们想要一个看起来像
的数组
x0 x1 ... xN x0 x1 ... xN ..... x0 x1 ... xN
y0 y0 ... y0 y1 y1 ... y1 ..... yM yM ... yM
1 1 ... 1 1 1 ... 1 ..... 1 1 ... 1
这样每个点 (xi, yi, 1)
都包含在内。然后转换只是与你的转换矩阵和这个数组的单个矩阵乘法。
为了简化问题(部分原因是你的图像命名约定让我感到困惑),我会说原始起始图像是 "destination" 或 dst
因为我们想转换回 "source" 或 src
图片。记住这一点,创建这个线性同质数组可能看起来像这样:
dst = cv2.imread('img.jpg', 0)
h, w = dst.shape[:2]
dst_y, dst_x = np.indices((h, w)) # similar to meshgrid/mgrid
dst_lin_homg_pts = np.stack((dst_x.ravel(), dst_y.ravel(), np.ones(dst_y.size)))
然后,要转换点,只需创建转换矩阵并相乘即可。我将四舍五入转换后的像素位置,因为我将它们用作索引而不用插值:
src_pts = np.float32([[693, 349], [605, 331], [445, 59]])
dst_pts = np.float32([[1379, 895], [1213, 970], [684, 428]])
transf = cv2.getAffineTransform(dst_pts, src_pts)
src_lin_pts = np.round(transf.dot(dst_lin_homg_pts)).astype(int)
现在这个转换会将一些像素发送到负索引,如果我们用这些索引,它会环绕图像——可能不是我们想要做的。当然,在 OpenCV 实现中,它只是完全切断了这些像素。但是我们可以只移动所有转换后的像素,这样所有的位置都是正的,我们不会切断任何一个(当然你可以在这方面做任何你想做的事):
min_x, min_y = np.amin(src_lin_pts, axis=1)
src_lin_pts -= np.array([[min_x], [min_y]])
然后我们需要创建转换映射到的源图像 src
。我将使用灰色背景创建它,以便我们可以从 dst
图像中看到黑色的程度。
trans_max_x, trans_max_y = np.amax(src_lin_pts, axis=1)
src = np.ones((trans_max_y+1, trans_max_x+1), dtype=np.uint8)*127
现在我们所要做的就是将目标图像中的一些相应像素放入源图像中。由于我没有切断任何像素,并且两个线性点阵列中的像素数量相同,所以我可以将转换后的像素分配给它们在原始图像中的颜色。
src[src_lin_pts[1], src_lin_pts[0]] = dst.ravel()
现在,当然,这不是在图像上插值。但是 OpenCV 中没有用于插值的内置函数(有供其他方法使用的后端 C 函数,但您不能在 Python AFAIK 中访问)。但是,您拥有重要的部分——目标图像映射到的位置,以及原始图像,因此您可以使用任意数量的库在该网格上进行插值。或者自己实现一个线性插值,因为它不太困难。在此之前,您当然可能希望取消扭曲像素位置的舍入。
cv2.imshow('src', src)
cv2.waitKey()
编辑:同样的方法也适用于 warpPerspective
,尽管您得到的矩阵乘法将给出一个三行(齐次)向量,并且您需要将前两行除以第三行让他们回到笛卡尔世界。除此之外,其他一切都保持不变。
我想不使用库函数实现仿射变换。 我有一个名为 "transformed" 的图像,我想应用逆变换来获得 "img_org" 图像。现在,我正在使用我自己的基本 GetBilinearPixel 函数来设置强度值。但是,图像没有改变 properly.This 是我想出的。 :
这是图片("transformed.png"):
这是图片("img_org.png"):
但我的目标是制作这张图片:
你可以在这里看到转换矩阵:
pts1 = np.float32( [[693,349] , [605,331] , [445,59]] )
pts2 = np.float32 ( [[1379,895] , [1213,970] ,[684,428]] )
Mat = cv2.getAffineTransform(pts2,pts1)
B=Mat
代码:
img_org=np.zeros(shape=(780,1050))
img_size=np.zeros(shape=(780,1050))
def GetBilinearPixel(imArr, posX, posY):
return imArr[posX][posY]
for i in range(1,img.shape[0]-1):
for j in range(1,img.shape[1]-1):
pos=np.array([[i],[j],[1]],np.float32)
#print pos
pos=np.matmul(B,pos)
r=int(pos[0][0])
c=int(pos[1][0])
#print r,c
if(c<=1024 and r<=768 and c>=0 and r>=0):
img_size[r][c]=img_size[r][c]+1
img_org[r][c] += GetBilinearPixel(img, i, j)
for i in range(0,img_org.shape[0]):
for j in range(0,img_org.shape[1]):
if(img_size[i][j]>0):
img_org[i][j] = img_org[i][j]/img_size[i][j]
我的逻辑错了吗?我知道我应用了非常低效的算法。 我缺少任何见解吗? 或者你能给我任何其他可以正常工作的算法吗?
(请求)。我不想使用 warpAffine 函数。
所以我对代码进行了向量化处理,这个方法起作用了——我找不到你的实现的确切问题,但也许这会揭示一些问题(而且速度更快)。
矢量化的设置是创建一个包含图像中每个点的线性(均匀)阵列。我们想要一个看起来像
的数组x0 x1 ... xN x0 x1 ... xN ..... x0 x1 ... xN
y0 y0 ... y0 y1 y1 ... y1 ..... yM yM ... yM
1 1 ... 1 1 1 ... 1 ..... 1 1 ... 1
这样每个点 (xi, yi, 1)
都包含在内。然后转换只是与你的转换矩阵和这个数组的单个矩阵乘法。
为了简化问题(部分原因是你的图像命名约定让我感到困惑),我会说原始起始图像是 "destination" 或 dst
因为我们想转换回 "source" 或 src
图片。记住这一点,创建这个线性同质数组可能看起来像这样:
dst = cv2.imread('img.jpg', 0)
h, w = dst.shape[:2]
dst_y, dst_x = np.indices((h, w)) # similar to meshgrid/mgrid
dst_lin_homg_pts = np.stack((dst_x.ravel(), dst_y.ravel(), np.ones(dst_y.size)))
然后,要转换点,只需创建转换矩阵并相乘即可。我将四舍五入转换后的像素位置,因为我将它们用作索引而不用插值:
src_pts = np.float32([[693, 349], [605, 331], [445, 59]])
dst_pts = np.float32([[1379, 895], [1213, 970], [684, 428]])
transf = cv2.getAffineTransform(dst_pts, src_pts)
src_lin_pts = np.round(transf.dot(dst_lin_homg_pts)).astype(int)
现在这个转换会将一些像素发送到负索引,如果我们用这些索引,它会环绕图像——可能不是我们想要做的。当然,在 OpenCV 实现中,它只是完全切断了这些像素。但是我们可以只移动所有转换后的像素,这样所有的位置都是正的,我们不会切断任何一个(当然你可以在这方面做任何你想做的事):
min_x, min_y = np.amin(src_lin_pts, axis=1)
src_lin_pts -= np.array([[min_x], [min_y]])
然后我们需要创建转换映射到的源图像 src
。我将使用灰色背景创建它,以便我们可以从 dst
图像中看到黑色的程度。
trans_max_x, trans_max_y = np.amax(src_lin_pts, axis=1)
src = np.ones((trans_max_y+1, trans_max_x+1), dtype=np.uint8)*127
现在我们所要做的就是将目标图像中的一些相应像素放入源图像中。由于我没有切断任何像素,并且两个线性点阵列中的像素数量相同,所以我可以将转换后的像素分配给它们在原始图像中的颜色。
src[src_lin_pts[1], src_lin_pts[0]] = dst.ravel()
现在,当然,这不是在图像上插值。但是 OpenCV 中没有用于插值的内置函数(有供其他方法使用的后端 C 函数,但您不能在 Python AFAIK 中访问)。但是,您拥有重要的部分——目标图像映射到的位置,以及原始图像,因此您可以使用任意数量的库在该网格上进行插值。或者自己实现一个线性插值,因为它不太困难。在此之前,您当然可能希望取消扭曲像素位置的舍入。
cv2.imshow('src', src)
cv2.waitKey()
编辑:同样的方法也适用于 warpPerspective
,尽管您得到的矩阵乘法将给出一个三行(齐次)向量,并且您需要将前两行除以第三行让他们回到笛卡尔世界。除此之外,其他一切都保持不变。