Быстрая numpy индексация для интерполяции изображения - PullRequest
1 голос
/ 31 января 2020

У меня есть изображение с кучей битых пикселей. В python у меня есть один массив numpy, который будет содержать окончательное изображение, и у меня есть другой логический массив numpy той же формы, который указывает, какие пиксели необходимо заполнить.

Я хочу заполнить битые пиксели, взяв среднее из 8 окружающих пикселей, но только если они действительно содержат данные. Например, если у меня есть это (N означает, что там нет данных, - это пиксель для заполнения):

1 2 N
N ? 2
N N 5

Я заполню? с (1 + 2 + 2 + 5) / 4.

Прямо сейчас я делаю это с помощью для l oop следующим образом. outFrame содержит окончательное изображение, а заполненный - логический массив, указывающий, какие пиксели были заполнены:

        # Loop through each pixel in the image
        for row in range(height):
            for col in range(width):
                # Check to see if the pixel needs to be filled in
                if not populated[row,col]:
                    # Check for boundary conditions
                    xmin = max(0,col-1)
                    xmax = min(width-1,col+1)
                    ymin = max(0,row-1)
                    ymax = min(height-1,row+1)

                    # Find the 8 surrounding values
                    vals = outFrame[ymin:ymax+1,xmin:xmax+1]
                    mask = populated[ymin:ymax+1,xmin:xmax+1]

                    # Find the average of only the populated pixels
                    if vals[mask].size != 0:
                        outFrame[row,col] = np.mean(vals[mask])

Очевидно, что python зацикливание идет медленно, но я не могу понять какие-либо индексные волхвы numpy c чтобы получить такое поведение. Есть ли способ быстро выполнить эту функцию в python?

РЕДАКТИРОВАТЬ: я попытался использовать функцию inpainting opencv следующим образом:

mask = (1*~populated).astype(np.uint8)
outFrame = cv2.inpaint(outFrame,mask,3,cv2.INPAINT_NS) # This is very slow 

Однако, это было в 10 раз медленнее, чем мой оригинал метод (мой метод занимает ~ 3-6 секунд, в то время как метод рисования занял 60 секунд). У меня очень большое количество битых пикселей, и я думаю, что по этой причине он медленный для этого метода

РЕДАКТИРОВАТЬ: Вот пример изображения.
Необработанное изображение: https://imgur.com/a/ax3nOAK
После интерполяции: https://imgur.com/a/2apOe7p

Ответы [ 2 ]

1 голос
/ 04 февраля 2020

Довольно сложно помочь вам, потому что вы не предоставили Минимально завершенный проверяемый пример вашего кода со всеми import кодами и кодом, показывающими, как вы открываете свои изображения, или даже указали, используют OpenCV или PIL или лыжный маг . Кроме того, вы не предоставили второй файл с маской всех точек, которые нужно нарисовать, и я не знаю, чего вы на самом деле пытаетесь достичь, поэтому на данный момент я просто пытаюсь предоставить метод, который выглядит для меня это похоже на результат, подобный тому, который вы показываете.

В любом случае, вот метод, который использует морфологию и занимает 100 микросекунд на моей маме c - что может отличаться от того, что вы используете; -)

#!/usr/bin/env python3

import cv2
import numpy as np

# Load image and make into Numpy array
im = cv2.imread('holey.png')

# Use morphology to find maximum pixel in each 3x3 square
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3,3))
morph = cv2.morphologyEx(im, cv2.MORPH_DILATE, kernel)

# Save result
cv2.imwrite('result.png', morph)

enter image description here

0 голосов
/ 06 февраля 2020

Я нашел идеальный метод для своего варианта использования, думал, что выложу его. Я считаю, что он обладает точной функциональностью моего оригинала для метода l oop, в то же время он работает в ~ 300 раз быстрее! (От 3-4 секунд до 0,01 секунды)

image = <READ IMAGE IN>
populated = <BOOLEAN MASK OF SAME SHAPE AS image>

image[~populated] = 0
blurred = cv2.boxfilter(image,-1,(3,3),normalize=False)
countMask = cv2.boxFilter(populated.astype('int'),-1,(3,3),normalize=False)
image[countMask != 0] = blurred[countMask != 0] / countMask[countMask != 0]

В первой строке для незаполненных пикселей устанавливается значение 0, поэтому они не увеличивают сумму для шага размытия.
Вторая строка размывает изображение без нормализации, которое для каждого пикселя суммирует пиксели вокруг него.
Третья строка «размывает» маску, в результате чего каждый пиксель считает количество действительных пикселей вокруг него.
Наконец, четвертая строка заполняет незаполненные пиксели путем нормализации размытых пикселей с действительным числом

Кредит Дивакару, у него была правильная идея.

...