使用scikit-image和transform.PolynomialTransform进行图像变形

时间:2014-11-18 13:29:25

标签: python image transformation distortion scikit-image

我附上一个zip archive,其中包含说明和重现问题所需的所有文件。

(我还没有上传图片的权限......)

我有一个带有曲线的图像(zip存档中的test2.png)。

我试着扭曲它以使线条笔直。 我想过使用scikit-image变换,特别是transform.PolynomialTransform,因为变换涉及高阶失真。

首先,我在x中以固定间隔测量每条线的精确位置,以定义输入兴趣点(在文件source_test2.csv中)。 然后我计算相应的所需位置,位于一条直线上(在文件destination_test2.csv中)。

figure correspondence.png显示了它的外观。

接下来,我只使用3阶多项式调用transform.PolynomialTransform()。 它找到了一个解决方案,但是当我使用transform.warp()应用它时,结果很疯狂,如文件Crazy_Warped.png所示

任何人都能说出我做错了什么? 我试过没有运气的2阶多项式... 我设法为子图像(仅前400列)进行了很好的转换。 在像我这样的情况下,transform.PolynomialTransform()是否完全不稳定?

以下是整个代码:

import numpy as np
import matplotlib.pyplot as plt
import asciitable
import matplotlib.pylab as pylab
from skimage import io, transform

# read image 
orig=io.imread("test2.png",as_grey=True)
# read tables with reference points and their desired transformed positions
source=asciitable.read("source_test2.csv")
destination=asciitable.read("destination_test2.csv")

# format as numpy.arrays as required by scikit-image
# (need to add 1 because I started to count positions from 0...)
source=np.column_stack((source["x"]+1,source["y"]+1))
destination=np.column_stack((destination["x"]+1,destination["y"]+1))
# Plot
plt.imshow(orig, cmap='gray', interpolation='nearest')
plt.plot(source[:,0],source[:,1],'+r')
plt.plot(destination[:,0],destination[:,1],'+b')
plt.xlim(0,orig.shape[1])
plt.ylim(0,orig.shape[0])

# Compute the transformation
t = transform.PolynomialTransform()
t.estimate(destination,source,3)

# Warping the image
img_warped = transform.warp(orig, t, order=2, mode='constant',cval=float('nan'))

# Show the result
plt.imshow(img_warped, cmap='gray', interpolation='nearest')
plt.plot(source[:,0],source[:,1],'+r')
plt.plot(destination[:,0],destination[:,1],'+b')
plt.xlim(0,img_warped.shape[1])
plt.ylim(0,img_warped.shape[0])
# Save as a file
io.imsave("warped.png",img_warped)

提前致谢!

2 个答案:

答案 0 :(得分:3)

这里有一些问题,主要是它们与坐标约定有关。例如,如果我们检查您绘制原始图像的代码,然后将点击的点放在其上:

plt.imshow(orig, cmap='gray', interpolation='nearest')
plt.plot(source[:,0],source[:,1],'+r')
plt.xlim(0,orig.shape[1])
plt.ylim(0,orig.shape[0])

(我已取出目的地点以使其更清洁)然后我们得到以下图像:

the y-axis is inverted!

如您所见,如果我们将y轴反转为:

,则会翻转y轴
source[:,1] = orig.shape[0] - source[:,1]

在绘图之前,我们得到以下内容:

That's much better

这是第一个问题(不要忘记反转目标点),第二个问题与变换本身有关:

t.estimate(destination,source,3)

documentation我们看到呼叫先获取源点,然后是目标点。因此,应该翻转这些参数的顺序。

最后,点击的点的形式为(x,y),但图像存储为(y,x),因此我们必须在应用变换之前调换图像,然后再转置回来:

img_warped = transform.warp(orig.transpose(), t, order=2, mode='constant',cval=float('nan'))
img_warped = img_warped.transpose()

进行这些更改时,会出现以下扭曲图像:

correctly warped

这些线条并不完全平坦,但更有意义。

答案 1 :(得分:0)

非常感谢您的详细解答!我不敢相信我没有看到轴反转问题...感谢抓住它! 但我担心你的最终解决方案无法解决我的问题......你得到的形象仍然是疯狂的。它应该是连续的,没有这么大的漏洞和奇怪的扭曲......(见下面的最终解决方案)

我发现我可以使用RANSAC获得合理的解决方案:

from skimage.measure import ransac
t, inliers = ransac((destination,source), transform.PolynomialTransform, min_samples=20,residual_threshold=1.0, max_trials=1000)
outliers = inliers == False

然后我得到following result

请注意,我认为我按顺序使用(目标,来源)!我认为这与transform.warp需要inverse_map作为转换对象的输入而不是前向映射这一事实有关。但也许我错了?我得到的好结果表明它是正确的。

我猜多项式变换太不稳定了,使用RANSAC可以得到合理的解决方案。 我的问题是找到一种方法来改变RANSAC调用中的多项式顺序...... transform.PolynomialTransform()不接受任何参数,默认情况下使用二阶多项式,但从结果我可以看出我需要一个三阶或四阶多项式。

所以我打开了new question,得到了Stefan van der Walt的解决方案。点击链接查看如何操作。

再次感谢您的帮助!