在python中手动编写warpafine代码

2024-05-19 09:15:09 发布

您现在位置:Python中文网/ 问答频道 /正文

我想通过不使用库函数来实现仿射变换。 我有一个名为“transformed”的图像,我想应用逆变换来获得“img_org”图像。现在,我正在使用我自己的基本GetBilinearPixel函数来设置强度值。但是,形象并没有改变好吧。这个是我想出来的。公司名称:

这是图像(“已转换.png“):

enter image description here

这是图像(“img_org.png“):

enter image description here

但我的目标是创造这样的形象: enter image description here

您可以在这里看到转换矩阵:

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

代码:

^{pr2}$

我的逻辑错了吗?我知道我使用了非常低效的算法。 有什么我遗漏的见解吗? 或者你能给我其他的算法吗。在

(请求)。我不想用仿射函数。在


Tags: 函数org图像算法imgpngnptransformed
1条回答
网友
1楼 · 发布于 2024-05-19 09:15:09

所以我对代码进行了矢量化,这个方法起作用了——我找不到你的实现的确切问题,但也许这会给你一些启示(加上速度快得多)。在

矢量化的设置是创建一个包含图像中每个点的线性(齐次)数组。我们需要一个看起来像

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图像。请记住,创建这种线性同质阵列可以如下所示:

^{pr2}$

然后,要转换这些点,只需创建转换矩阵并乘法。我将取整变换后的像素位置,因为我将它们用作索引,而不必担心插值:

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函数供其他方法使用,但不能在pythonafaik中访问)。但是,您有重要的部分-目标图像映射到的地方,以及原始图像,因此您可以使用任意数量的库来插值到网格上。或者你自己实现一个线性插值,因为它不太困难。当然,在此之前,您可能需要取消扭曲的像素位置。在

cv2.imshow('src', src)
cv2.waitKey()

Source image

编辑:同样的方法也适用于warpPerspective,尽管你得到的矩阵乘法将得到一个三行(齐次)向量,并且你需要将前两行除以第三行,将它们重新设置为笛卡尔世界。其他的都是一样的。在

相关问题 更多 >

    热门问题