Заполнение пробелов на изображении с помощью numpy и scipy

Прикреплено изображение (test.tif). Значения np.nan - самая белая область. Как заполнить этот самый белый регион, используя алгоритмы заполнения пробелов, которые используют значения от соседей?

enter image description here

import scipy.ndimage

data = ndimage.imread('test.tif')

Ответ 1

Я думаю, что вопрос viena больше связан с проблемой inpainting.

Вот несколько идей:

  • Чтобы заполнить пробелы в черно-белых изображениях, вы можете использовать некоторый алгоритм заполнения, например scipy.ndimage.morphology.binary_fill_holes. Но у вас есть изображение на уровне серого, поэтому вы не можете его использовать.

  • Я полагаю, что вы не хотите использовать сложный алгоритм inpainting. Мое первое предложение: не пытайтесь использовать значение Nearest grey (вы не знаете реального значения NaN-пикселей). Использование значения NEarest создаст грязный алгоритм. Вместо этого я предлагаю вам заполнить пробелы другим значением (например, средним значением строки). Вы можете сделать это без кодирования, используя scikit-learn:

Источник:

>>> from sklearn.preprocessing import Imputer
>>> imp = Imputer(strategy="mean")
>>> a = np.random.random((5,5))
>>> a[(1,4,0,3),(2,4,2,0)] = np.nan
>>> a
array([[ 0.77473361,  0.62987193,         nan,  0.11367791,  0.17633671],
   [ 0.68555944,  0.54680378,         nan,  0.64186838,  0.15563309],
   [ 0.37784422,  0.59678177,  0.08103329,  0.60760487,  0.65288022],
   [        nan,  0.54097945,  0.30680838,  0.82303869,  0.22784574],
   [ 0.21223024,  0.06426663,  0.34254093,  0.22115931,         nan]])
>>> a = imp.fit_transform(a)
>>> a
array([[ 0.77473361,  0.62987193,  0.24346087,  0.11367791,  0.17633671],
   [ 0.68555944,  0.54680378,  0.24346087,  0.64186838,  0.15563309],
   [ 0.37784422,  0.59678177,  0.08103329,  0.60760487,  0.65288022],
   [ 0.51259188,  0.54097945,  0.30680838,  0.82303869,  0.22784574],
   [ 0.21223024,  0.06426663,  0.34254093,  0.22115931,  0.30317394]])
  • грязное решение, которое использует значения Nearest, может быть следующим: 1) Найдите точки периметра областей NaN 2) Вычислить все расстояния между точками NaN и периметром 3) Замените NaN с ближайшим значением серого серого

Ответ 2

Как и другие, можно использовать scipy.interpolate. Однако для этого требуется довольно обширная манипуляция с индексами.

Полный пример:

from pylab import *
import numpy
import scipy.ndimage
import scipy.interpolate
import pdb

data = scipy.ndimage.imread('data.png')

# a boolean array of (width, height) which False where there are missing values and True where there are valid (non-missing) values
mask = ~( (data[:,:,0] == 255) & (data[:,:,1] == 255) & (data[:,:,2] == 255) )

# array of (number of points, 2) containing the x,y coordinates of the valid values only
xx, yy = numpy.meshgrid(numpy.arange(data.shape[1]), numpy.arange(data.shape[0]))
xym = numpy.vstack( (numpy.ravel(xx[mask]), numpy.ravel(yy[mask])) ).T

# the valid values in the first, second, third color channel,  as 1D arrays (in the same order as their coordinates in xym)
data0 = numpy.ravel( data[:,:,0][mask] )
data1 = numpy.ravel( data[:,:,1][mask] )
data2 = numpy.ravel( data[:,:,2][mask] )

# three separate interpolators for the separate color channels
interp0 = scipy.interpolate.NearestNDInterpolator( xym, data0 )
interp1 = scipy.interpolate.NearestNDInterpolator( xym, data1 )
interp2 = scipy.interpolate.NearestNDInterpolator( xym, data2 )

# interpolate the whole image, one color channel at a time    
result0 = interp0(numpy.ravel(xx), numpy.ravel(yy)).reshape( xx.shape )
result1 = interp1(numpy.ravel(xx), numpy.ravel(yy)).reshape( xx.shape )
result2 = interp2(numpy.ravel(xx), numpy.ravel(yy)).reshape( xx.shape )

# combine them into an output image
result = numpy.dstack( (result0, result1, result2) )

imshow(result)
show()

Вывод:

enter image description here

Это передает интерполятору все значения, которые мы имеем, а не только те, которые находятся рядом с отсутствующими значениями (что может быть несколько неэффективным). Он также интерполирует каждую точку на выходе, а не только отсутствующие значения (что крайне неэффективно). Лучший способ - интерполировать только отсутствующие значения, а затем исправить их в исходное изображение. Это просто быстрый пример для начала работы:)

Ответ 3

Если вам нужны значения из ближайших соседей, вы можете использовать NearestNDInterpolator из scipy.interpolate. Существуют также другие интерполяторы, которые вы можете рассмотреть.

Вы можете найти значения индекса X, Y для значений NaN с помощью:

import numpy as np

nan_locs = np.where(np.isnan(data))

Есть и другие варианты интерполяции. Один из вариантов заключается в том, чтобы заменить значения NaN результатами медианного фильтра (но ваши области для этого являются большими). Другим вариантом может быть декодирование в оттенках серого. Правильная интерполяция зависит от вашего конечного домена.

Если вы раньше не использовали интерполятор SciPy ND, вам нужно предоставить данные X, Y и value, чтобы они соответствовали интерполятору, а затем X и Y для значений для интерполяции. Вы можете сделать это, используя пример, приведенный выше, в качестве шаблона.

Ответ 4

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

import cv2
import numpy as np
import scipy.ndimage

data = ndimage.imread("test.tif")
mask = np.isnan(data)
inpainted_img = cv2.inpaint(img, mask, inpaintRadius=3, flags=cv2.INPAINT_TELEA)