2015-03-07 2 views
4

Я хотел был бы иметь foveate изображение с фокальной точкой в ​​центре изображения в Python. Мое входное изображение может быть представлено в виде массива 2D Numpy. Я хотел бы получить изображение с высоким разрешением в центре, но размыто по бокам. Для этой цели я нашел функцию OpenCV с именем logplar_interp, но она, похоже, не присутствует в оболочке OpenCV на Python. Я ценю любую помощь.Изображение foveation в Python

Пример образующей ямки изображения, показанное ниже (взято из Wikipedia):

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

+0

Я добавил в качестве примера изображение, чтобы сделать его самодостаточным. Надеюсь, все в порядке! – rayryeng

+0

Спасибо, сделано более ясно. –

ответ

7

Вот моя попытка воссоздать это с помощью OpenCV Python. Это довольно хак-иш-решение, которое немного интенсивно вычислительно, но оно, безусловно, выполняет свою работу.

Во-первых, создать маску, где пиксели, которые нулевой соответствуют те пиксели, которые вы хотите сохранить в высоком разрешении и пикселей, которые один соответствуют тем пикселей, которые вы хотите, чтобы размыть. Чтобы сделать все просто, я бы создал круг темных пикселей, которые определяют пиксели высокого разрешения.

С этой маской, одним из инструментов, который я могу предложить, чтобы сделать эту работу, является использование distance transform на этой маске. Для каждой точки в двоичной маске соответствующей выходной точкой в ​​преобразовании расстояния является расстояние от этой точки до ближайшего нулевого пикселя. Таким образом, поскольку вы рискуете далеко от нулевых пикселей в маске, тем больше будет расстояние.

Следовательно, чем дальше вы идете от нулевого пикселя в этой маске, тем больше размывает вас. Используя эту идею, я просто написал цикл через изображение и в каждой точке создаю маску размытия - будь то усреднение или гауссовское или что-то связанное с этим - это пропорционально расстоянию в преобразовании расстояния и размывает эту точку с этим размытие маски. Любые значения, равные нулю в этой маске, не должны иметь никакого размытия. Для всех других точек в маске мы используем значения в маске, чтобы направлять нас в собирании окрестности пикселей с центром в этой точке и выполнять размытие. Чем больше расстояние, тем больше будет пиксельная окрестность и тем сильнее будет размытие.

Чтобы упростить работу, я собираюсь использовать маску усреднения. В частности, для каждого значения на расстоянии преобразования, размером этой маски будет M x M, где M является:

M = d/S 

d является значение расстояния от расстояния преобразования и S является масштабным коэффициентом, который масштабирует вниз значение d, так что усреднение может быть более выполнимым. Это связано с тем, что дистанционное преобразование может стать довольно большим, поскольку вы уходите дальше от нулевого пикселя, и поэтому масштабный коэффициент делает усреднение более реалистичным. Формально для каждого пикселя в нашем выводе мы собираем окрестности M x M пикселей, получаем среднее значение и устанавливаем это как наш выход.

Одна сложность, которую мы должны иметь в виду, состоит в том, что когда мы собираем пиксели, где центр окрестности находится вдоль границы изображения, мы должны убедиться, что мы собираем пиксели в границах изображения, чтобы любые места, которые выходят за пределы изображения, мы пропускаем.

Теперь пришло время показать некоторые результаты.Для справки я использовал изображение Camera Man, которое является стандартным образцом для тестирования и очень популярен. Показано здесь:

enter image description here

Я также собираюсь установить маску, которая будет расположена в строке 70 и колонке 100, окружность радиуса 25. Не мудрствуя лукаво, вот код полностью прокомментирован. Я дам вам разобрать сами комментарии.

import cv2 # Import relevant libraries 
import cv 
import numpy as np 

img = cv2.imread('cameraman.png', 0) # Read in image 

height = img.shape[0] # Get the dimensions 
width = img.shape[1] 

# Define mask 
mask = 255*np.ones(img.shape, dtype='uint8') 

# Draw circle at x = 100, y = 70 of radius 25 and fill this in with 0 
cv2.circle(mask, (100, 70), 25, 0, -1)  

# Apply distance transform to mask 
out = cv2.distanceTransform(mask, cv.CV_DIST_L2, 3) 

# Define scale factor 
scale_factor = 10 

# Create output image that is the same as the original 
filtered = img.copy() 

# Create floating point copy for precision 
img_float = img.copy().astype('float') 

# Number of channels 
if len(img_float.shape) == 3: 
    num_chan = img_float.shape[2] 
else: 
    # If there is a single channel, make the images 3D with a singleton 
    # dimension to allow for loop to work properly 
    num_chan = 1 
    img_float = img_float[:,:,None] 
    filtered = filtered[:,:,None] 

# For each pixel in the input... 
for y in range(height): 
    for x in range(width): 

    # If distance transform is 0, skip 
    if out[y,x] == 0.0: 
     continue 

    # Calculate M = d/S 
    mask_val = np.ceil(out[y,x]/scale_factor) 

    # If M is too small, set the mask size to the smallest possible value 
    if mask_val <= 3: 
     mask_val = 3 

    # Get beginning and ending x and y coordinates for neighbourhood 
    # and ensure they are within bounds 
    beginx = x-int(mask_val/2) 
    if beginx < 0: 
     beginx = 0 

    beginy = y-int(mask_val/2) 
    if beginy < 0: 
     beginy = 0 

    endx = x+int(mask_val/2) 
    if endx >= width: 
     endx = width-1 

    endy = y+int(mask_val/2) 
    if endy >= height: 
     endy = height-1 

    # Get the coordinates of where we need to grab pixels 
    xvals = np.arange(beginx, endx+1) 
    yvals = np.arange(beginy, endy+1) 
    (col_neigh,row_neigh) = np.meshgrid(xvals, yvals) 
    col_neigh = col_neigh.astype('int') 
    row_neigh = row_neigh.astype('int') 

    # Get the pixels now 
    # For each channel, do the foveation 
    for ii in range(num_chan): 
     chan = img_float[:,:,ii] 
     pix = chan[row_neigh, col_neigh].ravel() 

     # Calculate the average and set it to be the output 
     filtered[y,x,ii] = int(np.mean(pix)) 

# Remove singleton dimension if required for display and saving 
if num_chan == 1: 
    filtered = filtered[:,:,0] 

# Show the image 
cv2.imshow('Output', filtered) 
cv2.waitKey(0) 
cv2.destroyAllWindows() 

Выход я получаю:

enter image description here

+0

Есть ли ограничение, что входное изображение должно быть полутоновым изображением? – Anuradha

+1

@Anuradha Да, предыдущая версия предполагала, что изображение было в оттенках серого. Я отредактировал код так, чтобы он мог разместиться для цветных изображений. Спасибо за ваши комментарии. – rayryeng

+1

Прежде всего, спасибо за блестящий кусок кода. – Anuradha

Смежные вопросы