Răspunsuri (1)
Îți dau ce am. Nu cred că voi reuși să rezolv asta cu datele de testare date. Maparea unui unghi de 45 de grade la o linie dreaptă într-o imagine atât de mică înseamnă că trebuie să se întâmple multă mișcare și nu prea multe date pe care să o bazeze. Am găsit câteva erori specifice care sunt remediate în codul de mai jos, marcate /* */
(din moment ce nu este ceva ce se vede de obicei într-un fișier Python, acel marker ar trebui să iasă în evidență :) ).
Vă rugăm să încercați acest cod pe datele dvs. reale și să-mi spuneți dacă funcționează! Cu acest set de date de intrare, există câteva ieșiri diferite de zero.
Marile probleme au fost:
- Datele
interp
trebuie sortate - multe dintre punctele de control au fost lipsite de sens, deoarece nu există suficiente date în acest set de date (de exemplu, maparea unor intervale mari ale unei coloane la un singur punct)
- intervalul de valori din imagine a fost dezactivat (deci rezultatul original a fost aproape 0 - patch-urile de culoare au fost valori în jurul valorii de 1e-9).
Cel mai important lucru pe care l-am adăugat, de dragul viitoarei codări, este un diagramă 3D care arată cum punctele de control „adevărate” se mapează la punctele de control „ideale”. Acest lucru vă oferă un instrument de depanare pentru a vă arăta dacă maparea punctelor de control este așa cum vă așteptați. Acest complot este ceea ce m-a condus la problema interp
.
Apropo, vă rugăm să folosiți nume precum „înainte” și „după” în loc de ideal
și true
:) . Încerc să-mi amintesc care m-a împiedicat cel puțin o dată.
Prima încercare
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 https://stackoverflow.com/a/14491059/2877364 by
# https://stackoverflow.com/users/1355221/dansalmo
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 https://stackoverflow.com/a/2828121/2877364 by
# https://stackoverflow.com/users/208339/steve-tjoa **/
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 https://stackoverflow.com/a/11453235/2877364 by
# https://stackoverflow.com/users/449449/eumiro
#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 **/
A doua încercare
Se apropie:
Și iată o vedere a maparii punctelor de control care arată mai promițătoare:
Puteți vedea că încearcă să învârtească puțin imaginea, ceea ce m-aș aștepta de la acest set de date.
Cod
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 https://stackoverflow.com/a/14491059/2877364 by
# https://stackoverflow.com/users/1355221/dansalmo
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 https://stackoverflow.com/a/19122075/2877364 by
# https://stackoverflow.com/users/2588210/christian-k
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 https://stackoverflow.com/a/2828121/2877364 by
# # https://stackoverflow.com/users/208339/steve-tjoa **/
#
#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 https://stackoverflow.com/a/11453235/2877364 by
# https://stackoverflow.com/users/449449/eumiro
#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 **/
Explicaţie
Gândiți-vă la interpolare diferit: coordonatele X și Y nu sunt de fapt ceea ce doriți să mapați, nu-i așa? Cred că ceea ce doriți să mapați este distanța de-a lungul conturului, astfel încât conturul diagonală să fie întins pentru a fi un contur vertical. Asta fac aceste rânduri:
nc_by_t = equispace(tc,ic.shape[0])
ic_by_t = equispace(ic,ic.shape[0])
Facem ic.shape[0]
număr de puncte egal distanțate de-a lungul fiecărui contur și apoi mapăm acele puncte unul cu celălalt. equispace
este modificat de la acest răspuns. Deci, aceasta întinde conturul mai scurt pentru a se potrivi mai lung, indiferent de sens, cu numărul de puncte definit de lungimea conturului în ic
. De fapt, puteți folosi orice număr de puncte cu această tehnică; Tocmai am testat 100 de puncte și am obținut în mod substanțial același rezultat.
Din nou, testați acest lucru pe datele dvs. reale. Gândiți-vă care este exact referința dvs. pentru interpolare. Este într-adevăr coordonata X sau Y? Este distanța de-a lungul conturului? Procentul conturului (ca mai sus)?
OK, încă o idee
Pentru acest caz de testare, mai multe date ar ajuta? Da!
Am folosit imagini mai mari pentru a determina punctele de control, apoi am cartografiat o imagine mai mică în centrul acelei regiuni.
Cod
(ceea ce este o mizerie totală până în acest moment - vezi marcajele ===========
)
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 https://stackoverflow.com/a/14491059/2877364 by
# https://stackoverflow.com/users/1355221/dansalmo
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 https://stackoverflow.com/a/19122075/2877364 by
# https://stackoverflow.com/users/2588210/christian-k
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 https://stackoverflow.com/a/2828121/2877364 by
# # https://stackoverflow.com/users/208339/steve-tjoa **/
#
#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 https://stackoverflow.com/a/11453235/2877364 by
# https://stackoverflow.com/users/449449/eumiro
#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 **/
subplot
. Primul lucru pe care trebuie să îl încercați este să reprezentați imaginea deformată cuplt.figure
/plt.imshow
mai degrabă decât cuplt.subplots
/ax.imshow
. De asemenea,, vă rog să vă editați întrebarea pentru a includeimport
declarații? Mulțumiri! De asemenea, ce versiune Python? - person cxw   schedule 31.10.2016