Here is a simple python code for registering two images. The transform is non-rigid. The error metric is sum of squared difference. Code is very simple, does not handle physical spacing. Main aim was to get hands dirty of numpy/scipy, python, opencv cv2 interface etc.
One practical tip for registration: if all else fails, smooth heavily the motion fields ;-)
##################################################
"""
Created on Sun Jan 15 10:41:19 2012
@author: vsk
"""
import sys, os, cv2, numpy, matplotlib, pylab
def SSD_Register(static_image, moving_image):
IMG_BLUR = 11;
ITER = 200;
TIME_STEP = 0.00010;
SMOOTH = 1.0;
K_SIZE = 11;
# Create float versions of all images
registered_image = numpy.empty(static_image.shape, dtype=numpy.float32);
static_image_float = numpy.empty(static_image.shape, dtype=numpy.float32);
mov_image_float = numpy.empty(static_image.shape, dtype=numpy.float32);
for i in range(static_image.shape[0]):
for j in range(static_image.shape[1]):
static_image_float[i,j] = static_image[i,j];
mov_image_float[i,j] = moving_image[i,j];
static_image_blur = cv2.GaussianBlur(static_image_float,(IMG_BLUR,IMG_BLUR), 1.20);
mov_image_float = cv2.GaussianBlur(mov_image_float, (IMG_BLUR,IMG_BLUR), 1.20);
difference_image = numpy.empty(static_image.shape, dtype = numpy.float32);
# Space for motion field
x_field = numpy.empty(static_image.shape, dtype=numpy.float32);
y_field = numpy.empty(static_image.shape, dtype=numpy.float32);
for i in range(x_field.shape[0]):
for j in range(x_field.shape[1]):
x_field[i,j] = j;
y_field[i,j] = i;
x_field_update = numpy.empty_like(x_field);
y_field_update = numpy.empty_like(y_field);
# Gradient image
grad_x = numpy.empty_like(x_field_update);
grad_y = numpy.empty_like(x_field_update);
grad_x = cv2.Sobel(mov_image_float, cv2.CV_32FC1, 1, 0);
grad_y = cv2.Sobel(mov_image_float, cv2.CV_32FC1, 0, 1);
grad_x_resampled = numpy.copy(grad_x);
grad_y_resampled = numpy.copy(grad_y);
# registration iterations begin
for i in range(x_field.shape[0]):
for j in range(x_field.shape[1]):
registered_image[i,j] = mov_image_float[i,j];
difference_image = registered_image - static_image_float;
print(numpy.sum(numpy.abs(difference_image))),
ssd_err = numpy.zeros((ITER,1));
for i in range(ITER):
# print i,
difference_image = registered_image - static_image_float;
#print(numpy.max(difference_image)),
#print(numpy.min(difference_image))
# print(numpy.sum(numpy.abs(difference_image))),
ssd_err[i]= numpy.sum(numpy.abs(difference_image));
x_field_update = TIME_STEP*difference_image*grad_x_resampled;
y_field_update = TIME_STEP*difference_image*grad_y_resampled;
x_field_update = cv2.GaussianBlur(x_field_update, (K_SIZE, K_SIZE), 2.5);
y_field_update = cv2.GaussianBlur(y_field_update, (K_SIZE, K_SIZE), 2.5);
# print(numpy.max(y_field_update))
x_field = x_field - x_field_update;
y_field = y_field - y_field_update;
registered_image = cv2.remap(mov_image_float, x_field, y_field, cv2.INTER_CUBIC);
grad_x_resampled = cv2.remap(grad_x, x_field, y_field, cv2.INTER_CUBIC);
grad_y_resampled = cv2.remap(grad_y, x_field, y_field, cv2.INTER_CUBIC);
print('')
#pylab.imshow(registered_image); pylab.show(); pylab.gray()
print(numpy.sum(numpy.abs(difference_image)))
# display section
display_image = numpy.copy(static_image);
for i in range(x_field.shape[0]):
for j in range(x_field.shape[1]):
display_image[i,j] = registered_image[i,j];
# cv2.namedWindow('Registered');
# cv2.imshow("Registered", display_image);
#
# cv2.namedWindow('Final');
# cv2.imshow("Final", moving_image);
#
# cv2.namedWindow('Initial');
# cv2.imshow("Initial", static_image);
#
# cv2.waitKey(-400)
# cv2.destroyAllWindows();
# pylab.plot(ssd_err)
# pylab.show()
pylab.subplot(131)
pylab.imshow(static_image)
frame = pylab.gca();
frame.axes.get_xaxis().set_visible( False);
frame.axes.get_yaxis().set_visible( False);
pylab.title('Static Image');
pylab.subplot(133)
pylab.imshow(moving_image)
frame = pylab.gca();
frame.axes.get_xaxis().set_visible( False);
frame.axes.get_yaxis().set_visible( False);
pylab.title('Moving Image');
pylab.subplot(132)
pylab.imshow(registered_image),
frame = pylab.gca();
frame.axes.get_xaxis().set_visible( False);
frame.axes.get_yaxis().set_visible( False);
pylab.title('Registered Image');
pylab.show()
return (registered_image, ssd_err);
# ================ Read system arguments else generate images =================
if len(sys.argv) != 3:
#print('Usage: static_image moving_image');
static_im = numpy.zeros( (256, 256), dtype=numpy.ubyte);
static_im[100:150, 100:150] = 100;
x_field = numpy.empty(static_im.shape, dtype=numpy.float32);
y_field = numpy.empty(static_im.shape, dtype=numpy.float32);
for i in range(x_field.shape[0]):
for j in range(x_field.shape[1]):
x_field[i,j] = j + 12.00485;
y_field[i,j] = i - 8.35;
mov_im = numpy.zeros( (256, 256), dtype=numpy.ubyte);
mov_im = cv2.remap(static_im, x_field, y_field, cv2.INTER_CUBIC);
#mov_im[102:152, 100:150] = 100;
SSD_Register(static_im, mov_im);
else:
static_image = cv2.imread(sys.argv[1], cv2.CV_LOAD_IMAGE_GRAYSCALE);
moving_image = cv2.imread(sys.argv[2], cv2.CV_LOAD_IMAGE_GRAYSCALE)
SSD_Register(static_image, moving_image)
One practical tip for registration: if all else fails, smooth heavily the motion fields ;-)
##################################################
"""
Created on Sun Jan 15 10:41:19 2012
@author: vsk
"""
import sys, os, cv2, numpy, matplotlib, pylab
def SSD_Register(static_image, moving_image):
IMG_BLUR = 11;
ITER = 200;
TIME_STEP = 0.00010;
SMOOTH = 1.0;
K_SIZE = 11;
# Create float versions of all images
registered_image = numpy.empty(static_image.shape, dtype=numpy.float32);
static_image_float = numpy.empty(static_image.shape, dtype=numpy.float32);
mov_image_float = numpy.empty(static_image.shape, dtype=numpy.float32);
for i in range(static_image.shape[0]):
for j in range(static_image.shape[1]):
static_image_float[i,j] = static_image[i,j];
mov_image_float[i,j] = moving_image[i,j];
static_image_blur = cv2.GaussianBlur(static_image_float,(IMG_BLUR,IMG_BLUR), 1.20);
mov_image_float = cv2.GaussianBlur(mov_image_float, (IMG_BLUR,IMG_BLUR), 1.20);
difference_image = numpy.empty(static_image.shape, dtype = numpy.float32);
# Space for motion field
x_field = numpy.empty(static_image.shape, dtype=numpy.float32);
y_field = numpy.empty(static_image.shape, dtype=numpy.float32);
for i in range(x_field.shape[0]):
for j in range(x_field.shape[1]):
x_field[i,j] = j;
y_field[i,j] = i;
x_field_update = numpy.empty_like(x_field);
y_field_update = numpy.empty_like(y_field);
# Gradient image
grad_x = numpy.empty_like(x_field_update);
grad_y = numpy.empty_like(x_field_update);
grad_x = cv2.Sobel(mov_image_float, cv2.CV_32FC1, 1, 0);
grad_y = cv2.Sobel(mov_image_float, cv2.CV_32FC1, 0, 1);
grad_x_resampled = numpy.copy(grad_x);
grad_y_resampled = numpy.copy(grad_y);
# registration iterations begin
for i in range(x_field.shape[0]):
for j in range(x_field.shape[1]):
registered_image[i,j] = mov_image_float[i,j];
difference_image = registered_image - static_image_float;
print(numpy.sum(numpy.abs(difference_image))),
ssd_err = numpy.zeros((ITER,1));
for i in range(ITER):
# print i,
difference_image = registered_image - static_image_float;
#print(numpy.max(difference_image)),
#print(numpy.min(difference_image))
# print(numpy.sum(numpy.abs(difference_image))),
ssd_err[i]= numpy.sum(numpy.abs(difference_image));
x_field_update = TIME_STEP*difference_image*grad_x_resampled;
y_field_update = TIME_STEP*difference_image*grad_y_resampled;
x_field_update = cv2.GaussianBlur(x_field_update, (K_SIZE, K_SIZE), 2.5);
y_field_update = cv2.GaussianBlur(y_field_update, (K_SIZE, K_SIZE), 2.5);
# print(numpy.max(y_field_update))
x_field = x_field - x_field_update;
y_field = y_field - y_field_update;
registered_image = cv2.remap(mov_image_float, x_field, y_field, cv2.INTER_CUBIC);
grad_x_resampled = cv2.remap(grad_x, x_field, y_field, cv2.INTER_CUBIC);
grad_y_resampled = cv2.remap(grad_y, x_field, y_field, cv2.INTER_CUBIC);
print('')
#pylab.imshow(registered_image); pylab.show(); pylab.gray()
print(numpy.sum(numpy.abs(difference_image)))
# display section
display_image = numpy.copy(static_image);
for i in range(x_field.shape[0]):
for j in range(x_field.shape[1]):
display_image[i,j] = registered_image[i,j];
# cv2.namedWindow('Registered');
# cv2.imshow("Registered", display_image);
#
# cv2.namedWindow('Final');
# cv2.imshow("Final", moving_image);
#
# cv2.namedWindow('Initial');
# cv2.imshow("Initial", static_image);
#
# cv2.waitKey(-400)
# cv2.destroyAllWindows();
# pylab.plot(ssd_err)
# pylab.show()
pylab.subplot(131)
pylab.imshow(static_image)
frame = pylab.gca();
frame.axes.get_xaxis().set_visible( False);
frame.axes.get_yaxis().set_visible( False);
pylab.title('Static Image');
pylab.subplot(133)
pylab.imshow(moving_image)
frame = pylab.gca();
frame.axes.get_xaxis().set_visible( False);
frame.axes.get_yaxis().set_visible( False);
pylab.title('Moving Image');
pylab.subplot(132)
pylab.imshow(registered_image),
frame = pylab.gca();
frame.axes.get_xaxis().set_visible( False);
frame.axes.get_yaxis().set_visible( False);
pylab.title('Registered Image');
pylab.show()
return (registered_image, ssd_err);
# ================ Read system arguments else generate images =================
if len(sys.argv) != 3:
#print('Usage: static_image moving_image');
static_im = numpy.zeros( (256, 256), dtype=numpy.ubyte);
static_im[100:150, 100:150] = 100;
x_field = numpy.empty(static_im.shape, dtype=numpy.float32);
y_field = numpy.empty(static_im.shape, dtype=numpy.float32);
for i in range(x_field.shape[0]):
for j in range(x_field.shape[1]):
x_field[i,j] = j + 12.00485;
y_field[i,j] = i - 8.35;
mov_im = numpy.zeros( (256, 256), dtype=numpy.ubyte);
mov_im = cv2.remap(static_im, x_field, y_field, cv2.INTER_CUBIC);
#mov_im[102:152, 100:150] = 100;
SSD_Register(static_im, mov_im);
else:
static_image = cv2.imread(sys.argv[1], cv2.CV_LOAD_IMAGE_GRAYSCALE);
moving_image = cv2.imread(sys.argv[2], cv2.CV_LOAD_IMAGE_GRAYSCALE)
SSD_Register(static_image, moving_image)
No comments:
Post a Comment