加速图像上的逐像素操作

时间:2019-10-17 17:43:18

标签: python parallel-processing cython distributed-computing numba

我正在尝试对图像进行逐像素操作,但是速度很慢。一张尺寸为(512 * 512)的图像需要7-8个小时,而我的图像最大可以达到2048 * 2048。

我还尝试过使用 Numba 进行优化,但是由于存在大量pyobjects(根据this教程,这很糟糕),因此需要花费相同的时间,因为numba无法将变量转换为它可以理解的内容,因此无法实现优化。

下面是我的问题的简短版本,我附上了完整的详细信息 因此,现在我尝试通过遵循this来使用cython 教程。 以下是我正在尝试优化的代码-

img = Image.open(path_dir)
pixelMap = img.load()
roi = []
for i in range(img.size[0]):
    for j in range(img.size[1]):
        if pix[i,j] == 255:
            roi.append([i,j])

notroi = img.size[0]*img.size[1] - len(roi)

在此之上,它不需要花费很多时间,并且我不需要对其进行修改。

def roifun(img,roi,notroi,newmap,pix):
    while(notroi):
        border_pixels = []
        h = img.size[0]
        w = img.size[1]
        for i in range(0,h):    //---1
            for j in range(0,w):
                if [i,j] not in roi and ([i+1, j] in roi or [i-1, j] in roi or [i, j+1] in roi or [i, j-1] in roi):
                    border_pixels.append([i,j])
        for (each_i,each_j) in border_pixels: //---2
            color_sum = 0
            count = 1
            eight_neighbourhood = [[each_i-1,each_j],[each_i+1,each_j],[each_i,each_j-1],[each_i,each_j+1],[each_i-1,each_j-1],[each_i-1,each_j+1],[each_i+1,each_j-1],[each_i+1,each_j+1]]
            for pix_i,pix_j in eight_neighbourhood:
                if (pix_i,pix_j) in roi:
                    color_sum+=pix[pix_i,pix_j]
                    count+=1
            newmap[each_i,each_j]=(color_sum//count)

        for (i,j) in border_pixels: //----3
            roi.append([i,j])
            border_pixels.remove([i,j])
            notroi = notroi-1
            print(notroi)

现在,我刚刚解决了将上述代码分为3部分(根据其for循环)转换为cython的问题,以便于调试。

我以以下方式转换了第一个循环-

%%cython -a
import cython
cimport numpy as np
# @cython.boundscheck(False)
cpdef border(img,roi):
    border_pixels = []
    cdef long h,w,i,j
    h = img.shape[0]
    w = img.shape[1]
    for i in range(0,h):
        for j in range(0,w):
            if [i,j] not in roi and ([i+1, j] in roi or [i-1, j] in roi or [i, j+1] in roi or [i, j-1] in roi):
                border_pixels.append([i,j])

问题我遇到了-
1)在调用TypeError: a bytes-like object is required, not 'list'函数的同时获取border
我不知道为什么它期望列表位于byte like object中,以及如何执行。
2)我不知道如何以cython方式转换图像,我尝试将其转换为char[:,:],但收到错误TypeError: a bytes-like object is required, not 'GIFImageFile

在第二个循环中,我将遇到相同的问题,但现在我还必须尝试将pix转换为pixel object

以防万一,如果您想知道我要达到的目标,请在此问题中提供完整的详细信息。
Expanding the Region of interest of an image

不使用cython的任何其他方式也将受到赞赏。

1 个答案:

答案 0 :(得分:2)

我肯定会考虑使用scikit-image或至少将numpy用于需要处理图像中像素的任何事物。在纯python中将花费太长时间。

要使用skimage复制第一段代码,我会这样做:

from skimage import io

img = io.imread(path_dir)
mask = img == 255

这将为您提供一个numpy的True / False值数组,其中像素等于255。然后,您可以扩展该蒙版以获得感兴趣的扩展区域。