Как выполнить логическую операцию и логическую индексацию с помощью VIPS в Python?

У меня были следующие коды, которые используют Python и OpenCV. Вкратце, у меня есть стопка изображения, сделанная с разной фокусной глубиной. Коды выбирают пиксели в каждой позиции (x, y), которая имеет самый большой лапласиан гуассовой реакции среди всех фокусных глубин (z), создавая таким образом изображение с фокусным стеклом. Функция get_fmap создает массив 2d, в котором каждый пиксель будет содержать номер фокальной плоскости, имеющий наибольший ответ журнала. В следующих кодах строки, которые закомментированы, являются моей текущей реализацией VIPS. Они не выглядят совместимыми в определении функции, поскольку это лишь частичное решение.

# from gi.repository import Vips
def get_log_kernel(siz, std):
 x = y = np.linspace(-siz, siz, 2*siz+1)
 x, y = np.meshgrid(x, y)
 arg = -(x**2 + y**2) / (2*std**2)
 h = np.exp(arg)
 h[h < sys.float_info.epsilon * h.max()] = 0
 h = h/h.sum() if h.sum() != 0 else h
 h1 = h*(x**2 + y**2 - 2*std**2) / (std**4)
 return h1 - h1.mean()
def get_fmap(img): # img is a 3-d numpy array.
 log_response = np.zeros_like(img[:, :, 0], dtype='single')
 fmap = np.zeros_like(img[:, :, 0], dtype='*****')
 log_kernel = get_log_kernel(11, 2)
 # kernel = get_log_kernel(11, 2)
 # kernel = [list(row) for row in kernel]
 # kernel = Vips.Image.new_from_array(kernel)
 # img = Vips.new_from_file("testimg.tif")
 for ii in range(img.shape[2]): 
 # img_filtered = img.conv(kernel)
 img_filtered = cv2.filter2D(img[:, :, ii].astype('single'), -1, log_kernel)
 index = img_filtered > log_response
 log_response[index] = img_filtered[index]
 fmap[index] = ii
 return fmap

а затем fmap будет использоваться для выделения пикселей из разных фокальных плоскостей, чтобы создать изображение с фокусной фокусировкой

Это делается на чрезвычайно большом изображении, и я чувствую, что VIPS может работать лучше, чем OpenCV. Однако официальная документация предоставляет довольно скудную информацию о ее связывании с Python. Из информации, которую я могу найти в Интернете, я могу только сделать работу свертки изображения (что в моем случае на порядок быстрее, чем OpenCV.). Мне интересно, как реализовать это в VIPS, особенно эти строки?

log_response = np.zeros_like(img[:, :, 0], dtype = 'single')
index = img_filtered > log_response
log_response[index] = im_filtered[index]
fmap[index] = ii
2 ответа

После консультации с Python VIPS manual и некоторыми пробными ошибками, я придумал свой собственный ответ. Моя проблема с numpy и OpenCV может быть переведена в VIPS следующим образом:

from gi.repository import Vips
img = []
for ii in range(num_z_levels):
 img.append(Vips.Image.new_from_file("testimg_z" + str(ii) + ".tif")
def get_fmap(img)
 log_kernel = get_log_kernel(11,2) # get_log_kernel is my own function, which generates a 2-d numpy array.
 log_kernel = [list(row) for row in log_kernel] # Vips.Image.new_from_array takes 1-d list array.
 log_kernel = Vips.Image.new_from_array(log_kernel) # Turn the kernel into Vips array so it can be used by Vips.
 log_response = img[0].conv(log_kernel, precision = Vips.Precision.FLOAT)
 for ii in range(len(img)):
 img_filtered = img[ii+1].conv(log_kernel, precision = Vips.Precision.FLOAT)
 log_response = (img_filtered > log_response).ifthenelse(img_filtered, log_response)
 fmap = (img_filtered > log_response).ifthenelse(ii+1, 0)

Логическое индексирование достигается с помощью метода ifthenelse:

result_img = (test_condition).ifthenelse(value_if_true, value_if_false)

Синтаксис довольно гибкий. Условием проверки может быть сравнение между двумя изображениями того же размера или между изображением и значением, например. img1 > img2 или img > 5. Как и мудрый, value_if_true может быть единственным значением или изображением Vips.


log_response и fmap инициализируются как 3D-массивы в коде вопроса, тогда как в тексте вопроса указано, что вывод fmap является двумерным массивом. Итак, я предполагаю, что log_response и fmap должны быть инициализированы как 2D-массивы с их формами, одинаковыми с каждым изображением. Таким образом, редактирование будет -

log_response = np.zeros_like(img[:,:,0], dtype='single')
fmap = np.zeros_like(img[:,:,0], dtype='*****')

Теперь, вернемся к теме вопроса, вы выполняете 2D-фильтрацию на каждом изображении один за другим и получаете максимальный индекс отфильтрованного вывода по всем сложным изображениям. В случае, если вы не знали в документации cv2.filter2D, его также можно было использовать в многомерном массиве, многомерный массив в качестве выходного. Затем получение максимального индекса по всем изображениям так же просто, как .argmax(2). Таким образом, реализация должна быть чрезвычайно эффективной и будет просто -

fmap = cv2.filter2D(img,-1,log_kernel).argmax(2)

licensed under cc by-sa 3.0 with attribution.