我正在使用scipy optimize进行生物医学成像应用。我正在尝试编写一种算法,通过在两者之间找到仿射变换(在这种情况下是移位,缩放和旋转)来对齐两个图像。我正在使用优化器来最小化两个图像之间的差异。我想要优化的参数是x和y移位,围绕图像中心的旋转,以及x和y维度的缩放。理想情况下,步长将全部接近整数而不是1e-6(当前步长)。有没有办法在scipy optimize中指定用于参数的最小步长?
我目前正在将它们映射到正确的数量级,但这仅适用于Nelder-Mead方法一次或两个参数。 (我的目标是使用L-BFGS-B,因为渐变,但这是目前另外一组问题。)添加更多参数会导致优化认为错位图像是正确的答案。 scipy优化的这种“假阳性”结果是否典型?除了改变公差外,还有什么方法可以提高准确度吗?
工作代码:
class toy():
def __init__(self, img1, img2):
self.original = img1
self.shifted = img2
def find_affine(self, parameters):
# extract parameters
x = 0
y = 0
r = 0.0
sx = 1.0
sy = 1.0
# x = int(parameters[0]*10000)
# y = int(parameters[1]*10000)
# r = int(parameters[2]*10000)
# sx = 1.0 + abs(round(parameters[3]*1000, 1))
# sy = 1.0 + abs(round(parameters[4]*1000, 1))
print "Updated parameters: [" + str(x) + ", " + str(y) + ", " + str(r) + ", " + str(sx) + ", " + str(sy) + "]"
# image data
original_dims = [len(self.original), len(self.original[0])]
shifted_dims = [len(self.shifted), len(self.shifted[0])]
mod_orig = self.original
# set up rotation
if r != 0.0:
rotation = cv2.getRotationMatrix2D((original_dims[0]/2, original_dims[1]/2), r, 1)
mod_orig = cv2.warpAffine(mod_orig, rotation, (len(self.original), len(self.original[0])))
# set up scaling
if sx != 1.0 or sy != 1.0:
dims = [int(round(sx*original_dims[0])), int(round(sy*original_dims[1]))]
mod_orig = cv2.resize(mod_orig, (dims[0], dims[1]), interpolation=cv2.INTER_CUBIC)
original_dims = [len(mod_orig), len(mod_orig[0])]
print "New dimensions: " + str(len(mod_orig)) + " " + str(len(mod_orig[0]))
# set up translation
shift = [y*sy, x*sx, 0] # does this need to be scaled?
# convert to pixels
# set the overlap bounds: x
if (x <= 0):
rows_orig = [abs(shift[1]), original_dims[1]]
rows_shift = [0, shifted_dims[1]+shift[1]]
else:
rows_shift = [shift[1], shifted_dims[1]]
rows_orig = [0, original_dims[1]-shift[1]]
# set the overlap bounds: y
if (y <= 0):
cols_orig = [abs(shift[0]), original_dims[0]]
cols_shift = [0, shifted_dims[0]+shift[0]]
else:
cols_shift = [shift[0], shifted_dims[0]]
cols_orig = [0, original_dims[0]-shift[0]]
# get the relevant pixels
original_overlap = mod_orig[cols_orig[0]:cols_orig[1], rows_orig[0]:rows_orig[1]]
shifted_overlap = self.shifted[cols_shift[0]:cols_shift[1], rows_shift[0]:rows_shift[1]]
self.show_overlap(original_overlap, shifted_overlap)
return (original_overlap, shifted_overlap)
def objective(self, parameters):
stable_pts, warped_pts = self.find_affine(parameters)
stable_pts = stable_pts.flatten()
warped_pts = warped_pts.flatten()
N = max(len(stable_pts), len(warped_pts))
print "Number of points: " + str(N)
if N == 0:
return 99999999999
score = 0.0
for s_pt, w_pt in zip(stable_pts, warped_pts):
score = score + ((float(s_pt) - float(w_pt))**2)
score = score/N
print "Objective score: " + str(score) + " for x = " + str(parameters)
return score
def show_overlap(self, img1, img2):
print "Dims"
print " Img1 Dims: " + str(len(img1)) + " " + str(len(img1[0]))
print " Img2 Dims: " + str(len(img2)) + " " + str(len(img2[0]))
dims = [min(len(img1), len(img2)), min(len(img1[0]), len(img2[0]))]
overlap = numpy.zeros(dims)
for x in xrange(len(overlap)):
for y in xrange(len(overlap[0])):
overlap[x][y] = abs(int(img1[x][y])-int(img2[x][y]))
overlap = numpy.uint8(overlap)
cv2.imshow("Overlapping Image", overlap)
cv2.waitKey(500)
cv2.destroyAllWindows()
def _main(status):
# read in images
img1 = cv2.imread("data/smile_orig.png")
img2 = cv2.imread("data/smiletest.png")
# convert to grayscale
img1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
img2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)
test = toy(img1, img2)
initial_conditions = [0.0]
transform = optimize.minimize(test.objective, initial_conditions, method='nelder-mead', tol=1e-8)
# Show minimization at the end
params = transform.x
original_img, shifted_img = test.find_affine(params)
print "COMPLETED MINIMIZATION"
print transform
# show difference between transformed image and desired image
overlap = numpy.zeros([min(len(original_img), len(shifted_img)),
min(len(original_img[0]), len(shifted_img[0]))])
print "shape of overlap: " + str(overlap.shape)
for x in xrange(len(overlap)):
for y in xrange(len(overlap[0])):
overlap[x][y] = abs(int(original_img[x][y])-int(shifted_img[x][y]))
overlap = numpy.uint8(overlap)
cv2.imshow("Overlapping Image", overlap)
print "Final Image Shown"
print "Dimensions: " + str(len(overlap)) + " " + str(len(overlap[0]))
cv2.waitKey(0)
cv2.destroyAllWindows()
if __name__ == "__main__":
_main(status)
使用的图片:
结果:
COMPLETED MINIMIZATION
status: 0
nfev: 95
success: True
fun: 11.051886006332982
x: array([ -1.29629630e-04, 8.42592593e-04, 2.77777778e-05])
message: 'Optimization terminated successfully.'
nit: 29
通过参数映射,实现的变换是ax尺寸偏移-1,ay尺寸偏移8,旋转0。两幅图像之间的实际仿射变换是ax尺寸偏移10,ay尺寸偏移20,旋转-10。
它很接近,它的分数很低,但它需要更接近(理想情况下完美得分为0.0,或至少笑脸没有留下任何东西)。任何建议都会受到欢迎。
相关: