Заполнить изображение ближайшим значением в пределах региона - PullRequest
0 голосов
/ 30 мая 2020

Я хочу заполнить изображение за пределами круглой области ближайшим значением внутри круга. Эффект похож на режим skimage = 'edge', но применяется к круглой области изображения вместо прямоугольной angular области.

Простой код, который делает правильные вещи - очень медленно:

def circle_pad(img, xc, yc, r):
    img_out = img.copy()

    for i in range(img.shape[0]):
        for j in range(img.shape[1]):
            d = math.sqrt( (i-yc)**2 + (j-xc)**2 )
            if d > r:
                i1, j1 = int( yc + (i-yc)*(r/d) ), int( xc + (j-xc)*(r/d) )
                img_out[i,j] = img[i1,j1]

    return img_out

Как это ускорить с помощью numpy? (возможно, избегайте зацикливания на каждом пикселе в коде python; типичные изображения составляют десятки миллионов пикселей)

Я подумал об использовании чего-нибудь вдоль линий сетки в качестве отправной точки для вычисления координат значения для заполнения в каждой точке, но как это сделать неясно.

1 Ответ

1 голос
/ 30 мая 2020

Решено с помощью mgrid - не красиво, но быстро. На всякий случай это полезно в качестве примера для других людей с аналогичными проблемами обработки изображений:

def circle_pad(img, xc, yc, r):
    mg = np.mgrid[:img.shape[0],0:img.shape[1]]
    yi, xi = mg[0,:,:], mg[1,:,:]

    mask = ((yi-yc)**2 + (xi-xc)**2) < r**2

    d = np.sqrt( (yi-yc)**2 + (xi-xc)**2 )
    d = np.clip(d, r, None)
    ye = yc + (yi-yc)*(r/d)
    xe = xc + (xi-xc)*(r/d)

    ye = np.clip(ye.astype(int), 0, img.shape[0])
    xe = np.clip(xe.astype(int), 0, img.shape[1])

    img_out = img * mask + img[ye,xe] * (~mask)
    return img_out

Ключевые части:

  • создание индексных массивов, подобных сетке xi, yi с np.mgrid - каждый имеет тот же размер, что и изображение
  • вычислить массивы координат xe, ye ближайшего краевого пикселя, выполнив математику xi, yi
  • замените значения, указав нижний индекс изображение, например: img[ye,xe]
...