将存储为numpy数组的图像转换为hsv的有效方法

时间:2016-06-27 13:19:44

标签: python numpy image-processing parallel-processing

我正在对图像进行一些数据分析。对于某些分析,我想将图像的像素从最初存储它们的RGB转换为HSV。

目前我正在使用此代码:

def generate_hsv(im):
    coords = product(range(im.shape[0]), range(im.shape[1]))
    num_cores = multiprocessing.cpu_count()

    m = Parallel(n_jobs=num_cores)(delayed(process_pixels)(im[i]) for i in coords)
    return np.array(m).reshape(im.shape)

process_pixels只是我转换函数的包装器:

def process_pixels(pixel):
    return rgb_to_hsv(pixel[0], pixel[1], pixel[2])

事情是它运行缓慢。

有更有效的方法吗?还是更好的并行化方法?

2 个答案:

答案 0 :(得分:1)

正如Warren Weckesser所说,转换功能存在问题。我最终使用了matplotlib:

matplotlib.colors.rgb_to_hsv(arr)

现在运行速度提高了一百万倍。

答案 1 :(得分:1)

Colorsys模块具有每个像素的实现,输入预期为(R,G,B)。现在,colorsys's implementation列在下面 -

def rgb_to_hsv(r, g, b):
    maxc = max(r, g, b)
    minc = min(r, g, b)
    v = maxc
    if minc == maxc:
        return 0.0, 0.0, v
    s = (maxc-minc) / maxc
    rc = (maxc-r) / (maxc-minc)
    gc = (maxc-g) / (maxc-minc)
    bc = (maxc-b) / (maxc-minc)
    if r == maxc:
        h = bc-gc
    elif g == maxc:
        h = 2.0+rc-bc
    else:
        h = 4.0+gc-rc
    h = (h/6.0) % 1.0
    return h, s, v

我假设正在读取的图像是(B,G,R)格式,就像使用OpenCV的cv2.imread一样。因此,让我们对上面提到的函数进行矢量化,以便我们可以以矢量化方式处理所有像素。对于矢量化,通常优选的方法是broadcasting。因此,使用它,rgb_to_hsv的矢量化实现看起来像这样(请注意如何在此处传输循环代码中的相应部分) -

def rgb_to_hsv_vectorized(img): # img with BGR format
    maxc = img.max(-1)
    minc = img.min(-1)

    out = np.zeros(img.shape)
    out[:,:,2] = maxc
    out[:,:,1] = (maxc-minc) / maxc

    divs = (maxc[...,None] - img)/ ((maxc-minc)[...,None])
    cond1 = divs[...,0] - divs[...,1]
    cond2 = 2.0 + divs[...,2] - divs[...,0]
    h = 4.0 + divs[...,1] - divs[...,2]
    h[img[...,2]==maxc] = cond1[img[...,2]==maxc]
    h[img[...,1]==maxc] = cond2[img[...,1]==maxc]
    out[:,:,0] = (h/6.0) % 1.0

    out[minc == maxc,:2] = 0
    return out

运行时测试

让我们为大小为(256,256)的标准RGB图像计时,并创建让我们使用[0,255]中的随机数。

以下是在像素图像上使用colorsys的rgb_to_hsv的典型方法:

def rgb_to_hsv_loopy(img): 
    out_loopy = np.zeros(img.shape)
    for i in range(img.shape[0]):
        for j in range(img.shape[1]):   
            out_loopy[i,j] = colorsys.rgb_to_hsv(img[i,j,2],img[i,j,1],img[i,j,0])
    return out_loopy

作为替代方案,还有matplotlib'sOpenCV's色彩转换版本,但它们似乎会产生不同的结果。为了时间安排,我们还是要包括它们。

In [69]: img = np.random.randint(0,255,(256,256,3)).astype('uint8')

In [70]: %timeit rgb_to_hsv_loopy(img)
1 loops, best of 3: 987 ms per loop

In [71]: %timeit matplotlib.colors.rgb_to_hsv(img)
10 loops, best of 3: 22.7 ms per loop

In [72]: %timeit cv2.cvtColor(img,cv2.COLOR_BGR2HSV)
1000 loops, best of 3: 1.23 ms per loop

In [73]: %timeit rgb_to_hsv_vectorized(img)
100 loops, best of 3: 13.4 ms per loop

In [74]: np.allclose(rgb_to_hsv_vectorized(img),rgb_to_hsv_loopy(img))
Out[74]: True   # Making sure vectorized version replicates intended behavior