我有一个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”'和矢量化的方法来做到这一点,但我没有能够得到任何工作。
非常感谢任何帮助 谢谢!
答案 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倍,并且需要更少的内存)