Python元素智能矢量化布尔运算,根据颜色

时间:2018-03-28 23:18:01

标签: python python-3.x image numpy

我有一个RGB图像,我使用PIL

加载到2D数组中
img = Image.open(path)
imgData = numpy.array(img)

我需要有效地将其转换为RGB元组的二维数组(在某种意义上说是一个3D数组),其大小相同,包含粗略的分类'每个像素 - ' red',' green',' white'或者'其他' - 在每个指数的基础上,哪个'颜色区域'他们躺在里面。这是为了图像识别的目的。

我当前的实现使用了逐个元素的for循环,但速度非常慢(800万像素需要1分钟以上):

for i in range(cols): # for every col
    for j in range(rows): # for every row
        r,g,b = imgData[i,j]

        if b > 220:     # white
            n = 3
        elif r > 230:   # red
            n = 2
        else:           # green
            n = 1

        mapData[i,j] = n

(我意识到if语句的顺序会影响分类的优先级 - 现在这不是一个主要问题,尽管我更喜欢专门定义颜色空间)

我正在运行Python 3.6.4并且乐于使用NumPy。经过一系列的研究,似乎有一些更快,更多的“pythonic”'和矢量化的方法来做到这一点,但我没有能够得到任何工作。

非常感谢任何帮助 谢谢!

3 个答案:

答案 0 :(得分:1)

您当前的算法可以像这样捕获:

r, g, b = imgData[...,0], imgData[...,1], imgData[...,2]
mapData = np.ones_like(r, dtype=int)
mapData[r > 230] = 2
mapData[b > 220] = 3

请注意分配这些数字的操作顺序。

答案 1 :(得分:1)

使用np.where可以非常快。

mapData = np.where(imgData[:,:,2] > 220, 3, np.where(imgData[:,:,0]>230, 2, 1))

但是当将它应用于图片时,唯一的结果就是那些。我是否遗漏了任何事情,或者是否应以不同的方式提出案件?

答案 2 :(得分:0)

颜色分类通常通过将RGB颜色视为矢量来完成。将每个值标准化为幅度,然后找到目标颜色的距离。

例如,smartcrop.js中的皮肤检测器就是这样(使用pyvips):

def pythag(im):
    return sum([x ** 2 for x in im]) ** 0.5

skin = [0.78, 0.57, 0.44]
score = 1 - pythag(img / pythag(img) - skin)

现在score是浮点图像,其值为0 - 1,对于最有可能是肤色的像素为1。请注意,它会忽略亮度:您需要另一条规则来切断非常暗的区域。

在你的情况下,我猜你需要一组目标向量,然后计算所有颜色概率,最后用最高得分向量的索引标记输出像素。类似的东西:

import sys
import pyvips

def pythag(im):
    return sum([x ** 2 for x in im]) ** 0.5

def classify(img, target):
    return 1 - pythag(img / pythag(img) - target)

# find [index, max] of an array of pyvips images
def argmax(ar):
    if len(ar) == 1:
        return [0, ar[0]]
    else:
        index, mx = argmax(ar[:-1])
        return [(ar[-1] > mx).ifthenelse(len(ar) - 1, index),
                (ar[-1] > mx).ifthenelse(ar[-1], mx)]

skin = [0.78, 0.57, 0.44]
red = [1, 0, 0]
green = [0, 1, 0]
targets = [red, green, skin] 

# we're not doing any coordinate transformations, so we can stream the image
img = pyvips.Image.new_from_file(sys.argv[1], access="sequential")

scores = [classify(img, x) for x in targets]
index, mx = argmax(scores)

index.write_to_file(sys.argv[2])

(插件:pyvips通常比numpy快2倍或3倍,并且需要更少的内存)