Как сдвинуть массив изображений с префиксом supixel в python?
Я пытаюсь сместить 2D-массив, представляющий изображение с субпиксельной точностью, используя 2D-БПФ и теорему о преобразовании Фурье. Это хорошо работает, когда значение сдвига в целых числах (точность пикселей), однако я получаю много артефактов, когда значение сдвига не является целым числом, то есть долей пикселя. Код ниже:
import numpy as np
from scipy.fftpack import fftfreq
def shift_fft(input_array,shift):
shift_rows,shift_cols = shift
nr,nc = input_array.shape
Nr, Nc = fftfreq(nr), fftfreq(nc)
Nc,Nr = np.meshgrid(Nc,Nr)
fft_inputarray = np.fft.fft2(input_array)
fourier_shift = np.exp(1j*2*np.pi*((shift_rows*Nr)+(shift_cols*Nc)))
output_array = np.fft.ifft2(fft_inputarray*fourier_shift)
return np.real(output_array)
Таким образом, shift_fft(input_array,[2,0]) будет работать, но shift_fft(input_array,[2.4,0]) не будет работать без артефактов. Что я делаю не так? Например, рассматривая изображение Лены с разрешением 128х128 пикселей. Если я хочу сдвинуться на 10,4 пикселя в каждом направлении, я получу некоторую колебательную модуляцию изображения. Изображения следующие:
До:
После:
2 ответа
Вы можете попробовать использовать scipy.ndimage.shift. Сдвигает пиксели аналогичноnumpy.roll
, но также допускает дробное смещение значений с интерполяцией.
Для цветного изображения убедитесь, что для третьей оси (каналов) задан сдвиг 0.
import scipy.ndimage
scipy.ndimage.shift(input_array, (2.4, 0))
По умолчанию он устанавливает черный фон, но вы можете настроить режим, чтобы он был обтекаемым или имел собственный цвет.
По какой-то причине я обнаружил, что сдвиг scipy ndimage очень медленный, особенно для n-мерных изображений. Для смещения по определенной оси, для целочисленных и нецелочисленных сдвигов я создал простенькую функцию:
def shift_img_along_axis( img, axis=0, shift = 1 , constant_values=0):
""" shift array along a specific axis. New value is taken as weighted by the two distances to the assocaited original pixels.
NOTE: at the border of image, when not enough original pixel is accessible, data will be meaned with regard to additional constant_values.
constant_values: value to set to pixels with no association in original image img
RETURNS : shifted image.
A.Mau. """
intshift = int(shift)
remain0 = abs( shift - int(shift) )
remain1 = 1-remain0 #if shift is uint : remain1=1 and remain0 =0
npad = int( np.ceil( abs( shift ) ) ) #ceil relative to 0. ( 0.5=> 1 and -0.5=> -1 )
pad_arg = [(0,0)]*img.ndim
pad_arg[axis] = (npad,npad)
bigger_image = np.pad( img, pad_arg, 'constant', constant_values=constant_values)
part1 = remain1*bigger_image.take( np.arange(npad+intshift, npad+intshift+img.shape[axis]) ,axis)
if remain0==0:
shifted = part1
else:
if shift>0:
part0 = remain0*bigger_image.take( np.arange(npad+intshift+1, npad+intshift+1+img.shape[axis]) ,axis) #
else:
part0 = remain0*bigger_image.take( np.arange(npad+intshift-1, npad+intshift-1+img.shape[axis]) ,axis) #
shifted = part0 + part1
return shifted
Быстрый пример:
np.random.seed(1)
img = np.random.uniform(0,10,(3,4)).astype('int')
print( img )
shift = 1.5
shifted = shift_img_along_axis( img, axis=1, shift=shift )
print( shifted )
Печать изображения:
[[4 7 0 3]
[1 0 1 3]
[3 5 4 6]]
Сдвинутое изображение:
[[3.5 1.5 1.5 0. ]
[0.5 2. 1.5 0. ]
[4.5 5. 3. 0. ]]
С нашим смещением 1,5 первое значение в смещенном изображении является средним значением 7 и 0 и т. д. Если значение отсутствует в исходном изображении, будет взято дополнительное значение 0. Если вы хотите получить результат, аналогичный np.roll (изображение возвращается на другую сторону...), вам придется немного изменить его!