मेरे पास एक आरजीबी छवि है जिसे मैं पीआईएल का उपयोग करके 2 डी सरणी में लोड कर रहा हूं

img = Image.open(path)
imgData = numpy.array(img)

मुझे इसे आरजीबी टुपल्स (कुछ अर्थों में एक 3 डी सरणी) के 2 डी सरणी में कुशलतापूर्वक अनुवाद करने की आवश्यकता है, जिसमें प्रत्येक पिक्सेल का एक मोटा 'वर्गीकरण' होता है - 'लाल', 'हरा', 'सफेद' या 'अन्य' - प्रत्येक सूचकांक के आधार पर वे किस 'रंग क्षेत्र' के भीतर स्थित हैं। यह छवि पहचान के प्रयोजनों के लिए है।

मेरा वर्तमान कार्यान्वयन लूप के लिए तत्व-वार का उपयोग करता है लेकिन बहुत धीमा है (8 एमपी छवि में 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

(मुझे एहसास है कि अगर यहां बयानों का क्रम वर्गीकरण की प्राथमिकता को प्रभावित करता है - यह अभी के लिए एक प्रमुख मुद्दा नहीं है, हालांकि मैं विशेष रूप से रंग रिक्त स्थान को परिभाषित करना पसंद करूंगा)

मैं पायथन 3.6.4 चला रहा हूं और NumPy का उपयोग करके खुश हूं या नहीं। शोध का एक गुच्छा करने के बाद, ऐसा लगता है कि ऐसा करने के लिए कई तेज़ और अधिक 'पायथनिक' और वेक्टरकृत तरीके हैं लेकिन मुझे कोई काम नहीं मिल रहा है।

किसी भी मदद की सराहना की जाएगी, धन्यवाद!

0
jt78 29 मार्च 2018, 02:18

3 जवाब

सबसे बढ़िया उत्तर

np.where का उपयोग करने से यह काफी तेज हो जाता है।

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

लेकिन जब इसे किसी तस्वीर पर लागू किया जाता है तो केवल वही परिणाम मिलते हैं। क्या मुझे कुछ याद आया या मामलों को अलग तरीके से बनाया जाना चाहिए?

1
pythonic833 28 मार्च 2018, 23:35

रंग वर्गीकरण आमतौर पर आरजीबी रंगों को वैक्टर के रूप में मानकर किया जाता है। प्रत्येक को परिमाण के अनुसार सामान्य करें, फिर अपने लक्षित रंग से दूरी ज्ञात करें।

उदाहरण के लिए, 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 से 2x या 3x तेज होता है और बहुत कम मेमोरी की आवश्यकता होती है)

0
jcupitt 1 अप्रैल 2018, 15:04

इस समय आपका एल्गोरिदम इस तरह कैप्चर किया जा सकता है:

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
dROOOze 28 मार्च 2018, 23:28