Python 用于图像插值的快速numpy索引

Python 用于图像插值的快速numpy索引,python,image,numpy,indexing,slice,Python,Image,Numpy,Indexing,Slice,我有一张图像,里面有一堆死像素。在python中,我有一个用于保存最终图像的numpy数组,还有另一个相同形状的布尔numpy数组,用于指示需要填充哪些像素 我想通过取周围8个像素的平均值来填充死像素,但前提是它们实际包含数据。例如,如果我有这个N意味着那里没有数据?是要填充的像素: 1 2 N N ? 2 N N 5 我来填表格好吗?1+2+2+5/4 现在,我使用for循环来实现这一点,如下所示。outFrame保存最终图像,而填充的是布尔数组,指示已填充的像素: # Lo

我有一张图像,里面有一堆死像素。在python中,我有一个用于保存最终图像的numpy数组,还有另一个相同形状的布尔numpy数组,用于指示需要填充哪些像素

我想通过取周围8个像素的平均值来填充死像素,但前提是它们实际包含数据。例如,如果我有这个N意味着那里没有数据?是要填充的像素:

1 2 N
N ? 2
N N 5
我来填表格好吗?1+2+2+5/4

现在,我使用for循环来实现这一点,如下所示。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索引魔术来实现这种行为。有没有办法在python中快速实现这一功能

编辑:我尝试使用opencv修复功能,如下所示:

mask = (1*~populated).astype(np.uint8)
outFrame = cv2.inpaint(outFrame,mask,3,cv2.INPAINT_NS) # This is very slow 
然而,这比我原来的方法慢了10倍。我的方法需要3-6秒,而修复方法需要60秒。我有大量的死像素,我认为这就是这种方法速度慢的原因

编辑:下面是一个示例图像。 原始图像:
插值后:

很难为您提供帮助,因为您没有提供最低限度的完整可验证代码示例,以及显示如何打开图像的所有导入语句和代码,甚至没有指明您是在使用OpenCV还是PIL或skimage。另外,您还没有为第二个文件提供绘制所需的所有点的遮罩,我也不知道您实际想要实现的目标,因此目前,我只是尝试提供一种方法,在我看来,它得到的结果与您显示的结果类似

无论如何,这里有一个方法,使用形态学,在我的Mac电脑上需要100微秒——这可能与你正在使用的任何东西都不一样-

#!/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)

这很难为您提供帮助,因为您没有提供一个最低限度的完整的可验证代码示例,其中包含显示如何打开图像的所有导入语句和代码,甚至没有指明您使用的是OpenCV、PIL还是skimage。另外,您还没有为第二个文件提供绘制所需的所有点的遮罩,我也不知道您实际想要实现的目标,因此目前,我只是尝试提供一种方法,在我看来,它得到的结果与您显示的结果类似

无论如何,这里有一个方法,使用形态学,在我的Mac电脑上需要100微秒——这可能与你正在使用的任何东西都不一样-

#!/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)

我找到了适合我的用例的完美方法,我想我会发布它。我相信它与我最初的for-loop方法功能完全相同,同时执行速度快了约300倍!3-4秒到0.01秒

import cv2
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,因此它们不会增加模糊步骤的和。 第二行使图像模糊,而不进行标准化,对于每个像素,对其周围的像素求和。 第三行模糊遮罩,这会导致每个像素计算其周围的有效像素数。 最后,第四行通过使用有效数字规范化模糊像素来填充未填充的像素


多亏了Divakar,他有了正确的想法。

我找到了适合我的用例的完美方法,我想我会发布它。我相信它与我最初的for-loop方法功能完全相同,同时执行速度快了约300倍!3-4秒到0.01秒

import cv2
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,因此它们不会增加模糊步骤的和。 第二行使图像模糊,而不进行标准化,对于每个像素,对其周围的像素求和。 第三行模糊遮罩,这会导致每个像素计算其周围的有效像素数。 最后,第四行通过使用有效数字规范化模糊像素来填充未填充的像素


归功于Divakar,他的想法是正确的。

只需对图像和遮罩的3x3内核进行2D卷积,然后将其分割?OpenCV将非常快速地完成此操作-称为修复,请参见此处。。。我编辑以显示使用修复的结果。这对我来说是非常缓慢的me@Divakar,我考虑过这样做,但我不确定如果我使用cv2.Convalve2D,如何忽略死像素appropriately@JayJackman在对遮罩进行卷积时,会考虑死像素。如果没有死像素,图像的直接卷积就足够了。只需对图像和遮罩的3x3内核进行2D卷积并将其分割?OpenCV将非常快地完成此操作-称为修复,请参见此处。。。我编辑以显示使用修复的结果。这对我来说是非常缓慢的me@Divakar,我考虑过这样做,但我不确定如果我使用cv2.Convalve2D,如何忽略死像素appropriately@JayJackman在对遮罩进行卷积时,会考虑死像素。Wi
尽管没有死像素,图像的直接卷积就足够了。我认为这应该很好!我没有想到形态学运算,因为我以为它们只是处理二值图像。我知道我的图像看起来是二值的,但一般来说不会。这对我来说是非常快的0.01秒,这很好。非常感谢。我认为这应该是相当好的!我没有想到形态学运算,因为我以为它们只是处理二值图像。我知道我的图像看起来是二值的,但一般来说不会。这对我来说是非常快的0.01秒,这很好。非常感谢。