Joe*_*lip 5 python numpy affinetransform python-2.7 scikit-image
我有一个图像,我试图使用skimage.PiecewiseAffineTransform和来扭曲skimage.warp。我有一组控制点 ( true) 映射到一组新的控制点 ( ideal),但扭曲没有返回我期望的结果。
在这个例子中,我有一个简单的波长梯度,我试图将其“拉直”成列。(您可能会问为什么我要查找轮廓和插值,但那是因为我实际上将此代码应用于更复杂的用例。我只是想重现这个简单示例的所有代码,这会导致相同的奇怪输出。)
为什么我的输出图像只是将输入图像扭曲成正方形和插图?我正在使用 Python 2.7.12 和 matplotlib 1.5.1。这是代码。
import matplotlib.pyplot as plt
import numpy as np
from skimage import measure, transform
true = np.array([range(i,i+10) for i in range(20)])
ideal = np.array([range(10)]*20)
# Find contours of ideal and true images and create list of control points for warp
true_control_pts = []
ideal_control_pts = []
for lam in ideal[0]:
try:
# Get the isowavelength contour in the true and ideal images
tc = measure.find_contours(true, lam)[0]
ic = measure.find_contours(ideal, lam)[0]
nc = np.ones(ic.shape)
# Use the y coordinates of the ideal contour
nc[:, 0] = ic[:, 0]
# Interpolate true contour onto ideal contour y axis so there are the same number of points
nc[:, 1] = np.interp(ic[:, 0], tc[:, 0], tc[:, 1])
# Add the control points to the appropriate list
true_control_pts.append(nc.tolist())
ideal_control_pts.append(ic.tolist())
except (IndexError,AttributeError):
pass
true_control_pts = np.array(true_control_pts)
ideal_control_pts = np.array(ideal_control_pts)
length = len(true_control_pts.flatten())/2
true_control_pts = true_control_pts.reshape(length,2)
ideal_control_pts = ideal_control_pts.reshape(length,2)
# Plot the original image
image = np.array([range(i,i+10) for i in range(20)]).astype(np.int32)
plt.figure()
plt.imshow(image, origin='lower', interpolation='none')
plt.title('Input image')
# Warp the actual image given the transformation between the true and ideal wavelength maps
tform = transform.PiecewiseAffineTransform()
tform.estimate(true_control_pts, ideal_control_pts)
out = transform.warp(image, tform)
# Plot the warped image!
fig, ax = plt.subplots()
ax.imshow(out, origin='lower', interpolation='none')
plt.title('Should be parallel lines')
Run Code Online (Sandbox Code Playgroud)
其输出如下所示:
任何帮助将不胜感激!
我会给你我所拥有的。我认为我无法通过给出的测试数据来确定这一点。在如此小的图像中将 45 度角映射到直线意味着需要发生大量运动,但没有大量数据作为基础。我确实发现了一些在下面的代码中修复的特定错误,并进行了标记/* */(因为这不是您通常在 Python 文件中看到的内容,所以该标记应该突出:))。
请在您的真实数据上尝试此代码,并让我知道它是否有效!对于此输入数据集,有一些非零输出。
最大的问题是:
interp数据需要排序为了您将来的编码,我添加的最重要的事情是一个 3D 绘图,显示“真实”控制点如何映射到“理想”控制点。这为您提供了一个调试工具,可以显示您的控制点映射是否符合您的预期。这个情节导致了我的问题interp。
顺便说一下,请使用“before”和“after”之类的名称,而不是idealand true:) 。试图记住哪一个至少让我绊倒过一次。
import pdb
import matplotlib.pyplot as plt
import numpy as np
from skimage import measure, transform, img_as_float
from mpl_toolkits.mplot3d import Axes3D # /**/
#/**/
# From /sf/answers/1014374161/ by
# /sf/users/94865501/
def flatten_list(L):
for item in L:
try:
for i in flatten_list(item): yield i
except TypeError:
yield item
#end flatten_list
true_input = np.array([range(i,i+10) for i in range(20)]) # /** != True **/
ideal = np.array([range(10)]*20)
#pdb.set_trace()
# Find contours of ideal and true_input images and create list of control points for warp
true_control_pts = []
ideal_control_pts = []
OLD_true=[] # /**/ for debugging
OLD_ideal=[]
for lam in [x+0.5 for x in ideal[0]]: # I tried the 0.5 offset just to see,
try: # but it didn't make much difference
# Get the isowavelength contour in the true_input and ideal images
tc = measure.find_contours(true_input, lam)[0]
ic = measure.find_contours(ideal, lam)[0]
nc = np.zeros(ic.shape) # /** don't need ones() **/
# Use the y /** X? **/ coordinates of the ideal contour
nc[:, 0] = ic[:, 0]
# Interpolate true contour onto ideal contour y axis so there are the same number of points
# /** Have to sort first - https://docs.scipy.org/doc/numpy/reference/generated/numpy.interp.html#numpy-interp **/
tc_sorted = tc[tc[:,0].argsort()]
# /** Thanks to /sf/answers/197968501/ by
# /sf/users/14583761/ **/
nc[:, 1] = np.interp(ic[:, 0], tc_sorted[:, 0], tc_sorted[:, 1],
left=np.nan, right=np.nan)
# /** nan: If the interpolation is out of range, we're not getting
# useful data. Therefore, flag it with a nan. **/
# /** Filter out the NaNs **/
# Thanks to /sf/answers/801726481/ by
# /sf/users/31461461/
#pdb.set_trace()
indices = ~np.isnan(nc).any(axis=1)
nc_nonan = nc[indices]
ic_nonan = ic[indices]
# Add the control points to the appropriate list.
# /** Flattening here since otherwise I wound up with dtype=object
# in the numpy arrays. **/
true_control_pts.append(nc_nonan.flatten().tolist())
ideal_control_pts.append(ic_nonan.flatten().tolist())
OLD_true.append(nc) # /** for debug **/
OLD_ideal.append(ic)
except (IndexError,AttributeError):
pass
#pdb.set_trace()
# /** Make vectors of all the control points. **/
true_flat = list(flatten_list(true_control_pts))
ideal_flat = list(flatten_list(ideal_control_pts))
true_control_pts = np.array(true_flat)
ideal_control_pts = np.array(ideal_flat)
# Make the vectors 2d
length = len(true_control_pts)/2
true_control_pts = true_control_pts.reshape(length,2)
ideal_control_pts = ideal_control_pts.reshape(length,2)
#pdb.set_trace()
# Plot the original image
image = np.array([range(i,i+10) for i in range(20)]) / 30.0 # /**.astype(np.int32)**/
# /** You don't want int32 images! See
# http://scikit-image.org/docs/dev/user_guide/data_types.html .
# Manually rescale the image to [0.0,1.0] by dividing by 30. **/
image_float = img_as_float(image) #/** make sure skimage is happy */
fig = plt.figure()
plt.imshow(image_float, origin='lower', interpolation='none')
plt.title('Input image')
fig.show() # /** I needed this on my test system **/
# Warp the actual image given the transformation between the true and ideal wavelength maps
tform = transform.PiecewiseAffineTransform()
tform.estimate(true_control_pts, ideal_control_pts)
out = transform.warp(image, tform)
# /** since we started with float, and this is float, too, the two are
# comparable. **/
pdb.set_trace()
# Plot the warped image!
fig, ax = plt.subplots()
ax.imshow(out, origin='lower', interpolation='none') # /**note: float**/
plt.title('Should be parallel lines')
fig.show()
# /** Show the control points.
# The z=0 plane will be the "true" control points (before), and the
# z=1 plane will be the "ideal" control points (after). **/
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
fig.show()
for rowidx in range(length):
ax.plot([true_control_pts[rowidx,0], ideal_control_pts[rowidx,0]],
[true_control_pts[rowidx,1], ideal_control_pts[rowidx,1]],
[0,1])
input() # /** because I was running from the command line **/
Run Code Online (Sandbox Code Playgroud)
越来越近:
这是看起来更有希望的控制点映射视图:
您可以看到它正在尝试稍微旋转图像,这正是我对该数据集的期望。
import pdb
import matplotlib.pyplot as plt
import numpy as np
from skimage import measure, transform, img_as_float
from mpl_toolkits.mplot3d import Axes3D # /**/
#/**/
# From /sf/answers/1014374161/ by
# /sf/users/94865501/
def flatten_list(L):
for item in L:
try:
for i in flatten_list(item): yield i
except TypeError:
yield item
#end flatten_list
#/**/
# Modified from /sf/answers/1338545281/ by
# /sf/users/181174731/
def equispace(data, npts):
x,y = data.T
xd =np.diff(x)
yd = np.diff(y)
dist = np.sqrt(xd**2+yd**2)
u = np.cumsum(dist)
u = np.hstack([[0],u])
t = np.linspace(0,u.max(),npts)
xn = np.interp(t, u, x)
yn = np.interp(t, u, y)
return np.column_stack((xn, yn))
true_input = np.array([range(i,i+10) for i in range(20)]) # /** != True **/
ideal = np.array([range(10)]*20)
#pdb.set_trace()
# Find contours of ideal and true_input images and create list of control points for warp
true_control_pts = []
ideal_control_pts = []
OLD_true=[] # /**/ for debugging
OLD_ideal=[]
for lam in [x+0.5 for x in ideal[0]]: # I tried the 0.5 offset just to see,
try: # but it didn't make much difference
# Get the isowavelength contour in the true_input and ideal images
tc = measure.find_contours(true_input, lam)[0]
# /** So this might not have very many numbers in it. **/
ic = measure.find_contours(ideal, lam)[0]
# /** CAUTION: this is assuming the contours are going the same
# direction. If not, you'll need to make it so. **/
#nc = np.zeros(ic.shape) # /** don't need ones() **/
# /** We just want to find points on _tc_ to match _ic_. That's
# interpolation _within_ a curve. **/
#pdb.set_trace()
nc_by_t = equispace(tc,ic.shape[0])
ic_by_t = equispace(ic,ic.shape[0])
### /** Not this **/
## Use the y /** X? **/ coordinates of the ideal contour
#nc[:, 0] = ic[:, 0]
#
## Interpolate true contour onto ideal contour y axis so there are the same number of points
#
## /** Have to sort first - https://docs.scipy.org/doc/numpy/reference/generated/numpy.interp.html#numpy-interp **/
#tc_sorted = tc[tc[:,0].argsort()]
# # /** Thanks to /sf/answers/197968501/ by
# # /sf/users/14583761/ **/
#
#nc[:, 1] = np.interp(ic[:, 0], tc_sorted[:, 0], tc_sorted[:, 1],
# left=np.nan, right=np.nan)
# # /** nan: If the interpolation is out of range, we're not getting
# # useful data. Therefore, flag it with a nan. **/
# /** Filter out the NaNs **/
# Thanks to /sf/answers/801726481/ by
# /sf/users/31461461/
#pdb.set_trace()
#indices = ~np.isnan(nc).any(axis=1)
#nc_nonan = nc[indices]
#ic_nonan = ic[indices]
#
# Add the control points to the appropriate list.
## /** Flattening here since otherwise I wound up with dtype=object
## in the numpy arrays. **/
#true_control_pts.append(nc_nonan.flatten().tolist())
#ideal_control_pts.append(ic_nonan.flatten().tolist())
#OLD_true.append(nc) # /** for debug **/
#OLD_ideal.append(ic)
true_control_pts.append(nc_by_t)
ideal_control_pts.append(ic_by_t)
except (IndexError,AttributeError):
pass
pdb.set_trace()
# /** Make vectors of all the control points. **/
true_flat = list(flatten_list(true_control_pts))
ideal_flat = list(flatten_list(ideal_control_pts))
true_control_pts = np.array(true_flat)
ideal_control_pts = np.array(ideal_flat)
# Make the vectors 2d
length = len(true_control_pts)/2
true_control_pts = true_control_pts.reshape(length,2)
ideal_control_pts = ideal_control_pts.reshape(length,2)
#pdb.set_trace()
# Plot the original image
image = np.array([range(i,i+10) for i in range(20)]) / 30.0 # /**.astype(np.int32)**/
# /** You don't want int32 images! See
# http://scikit-image.org/docs/dev/user_guide/data_types.html .
# Manually rescale the image to [0.0,1.0] by dividing by 30. **/
image_float = img_as_float(image) #/** make sure skimage is happy */
fig = plt.figure()
plt.imshow(image_float, origin='lower', interpolation='none')
plt.title('Input image')
fig.show() # /** I needed this on my test system **/
# Warp the actual image given the transformation between the true and ideal wavelength maps
tform = transform.PiecewiseAffineTransform()
tform.estimate(true_control_pts, ideal_control_pts)
out = transform.warp(image, tform)
# /** since we started with float, and this is float, too, the two are
# comparable. **/
pdb.set_trace()
# Plot the warped image!
fig, ax = plt.subplots()
ax.imshow(out, origin='lower', interpolation='none') # /**note: float**/
plt.title('Should be parallel lines')
fig.show()
# /** Show the control points.
# The z=0 plane will be the "true" control points (before), and the
# z=1 plane will be the "ideal" control points (after). **/
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
fig.show()
for rowidx in range(length):
ax.plot([true_control_pts[rowidx,0], ideal_control_pts[rowidx,0]],
[true_control_pts[rowidx,1], ideal_control_pts[rowidx,1]],
[0,1])
input() # /** because I was running from the command line **/
Run Code Online (Sandbox Code Playgroud)
以不同的方式思考插值:X 和 Y 坐标实际上并不是您想要映射的,是吗?我认为你想要映射的是沿轮廓的距离,以便对角线轮廓被拉伸为垂直轮廓。这就是这些行的作用:
nc_by_t = equispace(tc,ic.shape[0])
ic_by_t = equispace(ic,ic.shape[0])
Run Code Online (Sandbox Code Playgroud)
我们ic.shape[0]沿着每个轮廓制作许多等距的点,然后将这些点相互映射。 equispace是根据这个答案修改的。因此,这会拉伸较短的轮廓以适应较长的轮廓,无论哪种方式,其点数由 中的轮廓长度定义ic。实际上,您可以使用此技术使用任意数量的点;我刚刚测试了100点,得到了基本相同的结果。
再次使用您的实际数据进行测试。考虑一下您的插值参考到底是什么。它真的是X坐标还是Y坐标吗?是沿着轮廓的距离吗?轮廓的百分比(如上所述)?
对于这个特定的测试用例,更多数据会有帮助吗?是的!
我使用较大的图像来确定控制点,然后在该区域的中心映射较小的图像。
(此时完全是一团糟 - 请参阅===========标记)
import pdb
import matplotlib.pyplot as plt
import numpy as np
from skimage import measure, transform, img_as_float
from mpl_toolkits.mplot3d import Axes3D # /**/
#/**/
def test_figure(data,title):
image_float = img_as_float(data) #/** make sure skimage is happy */
fig = plt.figure()
plt.imshow(image_float, origin='lower', interpolation='none')
plt.title(title)
fig.show()
#/**/
# From /sf/answers/1014374161/ by
# /sf/users/94865501/
def flatten_list(L):
for item in L:
try:
for i in flatten_list(item): yield i
except TypeError:
yield item
#end flatten_list
#/**/
# Modified from /sf/answers/1338545281/ by
# /sf/users/181174731/
def equispace(data, npts):
x,y = data.T
xd =np.diff(x)
yd = np.diff(y)
dist = np.sqrt(xd**2+yd**2)
u = np.cumsum(dist)
u = np.hstack([[0],u])
t = np.linspace(0,u.max(),npts)
xn = np.interp(t, u, x)
yn = np.interp(t, u, y)
return np.column_stack((xn, yn))
# ====================== BIGGER
true_input = np.array([range(i,i+20) for i in range(30)]) # /** != True **/
ideal = np.array([range(20)]*30)
# ======================
test_figure(true_input / 50.0, 'true_input')
test_figure(ideal / 20.0, 'ideal')
#pdb.set_trace()
# Find contours of ideal and true_input images and create list of control points for warp
true_control_pts = []
ideal_control_pts = []
OLD_true=[] # /**/ for debugging
OLD_ideal=[]
for lam in [x+0.5 for x in ideal[0]]: # I tried the 0.5 offset just to see,
try: # but it didn't make much difference
# Get the isowavelength contour in the true_input and ideal images
tc = measure.find_contours(true_input, lam)[0]
# /** So this might not have very many numbers in it. **/
ic = measure.find_contours(ideal, lam)[0]
# /** CAUTION: this is assuming the contours are going the same
# direction. If not, you'll need to make it so. **/
#nc = np.zeros(ic.shape) # /** don't need ones() **/
# /** We just want to find points on _tc_ to match _ic_. That's
# interpolation _within_ a curve. **/
#pdb.set_trace()
nc_by_t = equispace(tc,ic.shape[0])
ic_by_t = equispace(ic,ic.shape[0])
### /** Not this **/
## Use the y /** X? **/ coordinates of the ideal contour
#nc[:, 0] = ic[:, 0]
#
## Interpolate true contour onto ideal contour y axis so there are the same number of points
#
## /** Have to sort first - https://docs.scipy.org/doc/numpy/reference/generated/numpy.interp.html#numpy-interp **/
#tc_sorted = tc[tc[:,0].argsort()]
# # /** Thanks to /sf/answers/197968501/ by
# # /sf/users/14583761/ **/
#
#nc[:, 1] = np.interp(ic[:, 0], tc_sorted[:, 0], tc_sorted[:, 1],
# left=np.nan, right=np.nan)
# # /** nan: If the interpolation is out of range, we're not getting
# # useful data. Therefore, flag it with a nan. **/
# /** Filter out the NaNs **/
# Thanks to /sf/answers/801726481/ by
# /sf/users/31461461/
#pdb.set_trace()
#indices = ~np.isnan(nc).any(axis=1)
#nc_nonan = nc[indices]
#ic_nonan = ic[indices]
#
# Add the control points to the appropriate list.
## /** Flattening here since otherwise I wound up with dtype=object
## in the numpy arrays. **/
#true_control_pts.append(nc_nonan.flatten().tolist())
#ideal_control_pts.append(ic_nonan.flatten().tolist())
#OLD_true.append(nc) # /** for debug **/
#OLD_ideal.append(ic)
true_control_pts.append(nc_by_t)
ideal_control_pts.append(ic_by_t)
except (IndexError,AttributeError):
pass
#pdb.set_trace()
# /** Make vectors of all the control points. **/
true_flat = list(flatten_list(true_control_pts))
ideal_flat = list(flatten_list(ideal_control_pts))
true_control_pts = np.array(true_flat)
ideal_control_pts = np.array(ideal_flat)
# Make the vectors 2d
length = len(true_control_pts)/2
true_control_pts = true_control_pts.reshape(length,2)
ideal_control_pts = ideal_control_pts.reshape(length,2)
#pdb.set_trace()
# Plot the original image
image = np.array([range(i,i+10) for i in range(20)]) / 30.0 # /**.astype(np.int32)**/
# /** You don't want int32 images! See
# http://scikit-image.org/docs/dev/user_guide/data_types.html .
# Manually rescale the image to [0.0,1.0] by dividing by 30. **/
# ======================
# /** Pad from 10x20 to 20x30 just for grins **/
#pdb.set_trace()
image = np.concatenate( (np.zeros((20,5)),image,np.zeros((20,5))), 1)
# now it's 20x20
image = np.concatenate( (np.zeros((5,20)),image,np.zeros((5,20))), 0)
# ======================
#Plot it
image_float = img_as_float(image) #/** make sure skimage is happy */
fig = plt.figure()
plt.imshow(image_float, origin='lower', interpolation='none')
plt.title('Input image')
fig.show() # /** I needed this on my test system **/
# Warp the actual image given the transformation between the true and ideal wavelength maps
tform = transform.PiecewiseAffineTransform()
tform.estimate(true_control_pts, ideal_control_pts)
out = transform.warp(image, tform)
# /** since we started with float, and this is float, too, the two are
# comparable. **/
pdb.set_trace()
# Plot the warped image!
fig, ax = plt.subplots()
ax.imshow(out, origin='lower', interpolation='none') # /**note: float**/
plt.title('Should be parallel lines')
fig.show()
# /** Show the control points.
# The z=0 plane will be the "true" control points (before), and the
# z=1 plane will be the "ideal" control points (after). **/
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
fig.show()
for rowidx in range(length):
ax.plot([true_control_pts[rowidx,0], ideal_control_pts[rowidx,0]],
[true_control_pts[rowidx,1], ideal_control_pts[rowidx,1]],
[0,1])
input() # /** because I was running from the command line **/
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2916 次 |
| 最近记录: |