2012-01-14 12 views
6

मैंने एक छवि के भीतर एक रंग खोजने के लिए एक फ़ंक्शन बनाया है, और x, y वापस कर दिया है। अब मुझे एक नया फ़ंक्शन जोड़ने की ज़रूरत है, जहां मुझे दिए गए टोलरेंस के साथ रंग मिल सकता है। आसान होना चाहिए?पायथन - समान रंग खोजें, सर्वोत्तम तरीका

कोड छवि में रंग मिल जाए, और वापसी एक्स के लिए, वाई:

def FindColorIn(r,g,b, xmin, xmax, ymin, ymax): 
    image = ImageGrab.grab() 
    for x in range(xmin, xmax): 
     for y in range(ymin,ymax): 
      px = image.getpixel((x, y)) 
      if px[0] == r and px[1] == g and px[2] == b: 
       return x, y 

def FindColor(r,g,b): 
    image = ImageGrab.grab() 
    size = image.size 
    pos = FindColorIn(r,g,b, 1, size[0], 1, size[1]) 
    return pos 

परिणाम:

जवाब दो रंगों की तुलना में सामान्य तरीके इयूक्लिडियन दूरी में हैं से लिया , या चेबिशहेव दूरी।

मैंने अधिकतर (वर्ग) यूक्लिडियन दूरी, और कई अलग-अलग रंग-रिक्त स्थान का उपयोग करने का निर्णय लिया। एलएबी, डेल्टाई (एलसीएच), एक्सवाईजेड, एचएसएल, और आरजीबी। मेरे कोड में, अधिकांश रंग-रिक्त स्थान अंतर की गणना करने के लिए स्क्वायर यूक्लिडियन दूरी का उपयोग करते हैं।

उदाहरण के लिए एलएबी, आरजीबी और एक्सवाईजेड के साथ एक साधारण वर्ग ईक। दूरी काम कर देता है:

if ((X-X1)^2 + (Y-Y1)^2 + (Z-Z1)^2) <= (Tol^2) then 
    ... 

एलसीएच, और के रूप में दोनों एक बेलनाकार रंग है एचएसएल एक छोटे से अधिक जटिल है, लेकिन गणित के कुछ टुकड़े को हल करती है कि, तो यह वर्ग eucl का उपयोग करने पर है। यहाँ भी।

इन मामलों में मैंने प्रत्येक चैनल के लिए सहिष्णुता के लिए "अलग पैरामीटर" जोड़ा है (1 वैश्विक सहिष्णुता और वैकल्पिक "संशोधक" HueTol := Tolerance * hueMod या LightTol := Tolerance * LightMod का उपयोग करके)।


ऐसा लगता है जैसे एक्सवाईजेड (एलएबी, एलसीएच) के शीर्ष पर बने रंगस्थान मेरे कई परिदृश्यों में सर्वश्रेष्ठ प्रदर्शन करते हैं। कुछ मामलों में एचएसएल बहुत अच्छे नतीजे पैदा करता है, और आरजीबी से कनवर्ट करना बहुत सस्ता है, आरजीबी भी बहुत अच्छा है, और मेरी अधिकांश जरूरतों को भरता है।

+0

यदि आपको छवि में रंग नहीं मिलता है तो आपको कुछ वापस करना चाहिए। यानी, एक त्रुटि कोड। –

+0

आप सहिष्णुता को कैसे परिभाषित कर रहे हैं? 'R',' g' और 'b' के लिए अलग-अलग श्रेणियां? –

+0

मैं जॉन के साथ हूं: आपने पहले से क्या प्रयास किया है? आप [कोसाइन समानता] (https://en.wikipedia.org/wiki/Cosine_similarity) देख सकते हैं और पाइथन कार्यान्वयन की खोज कर सकते हैं। –

उत्तर

17

आरजीबी रंगों के बीच कंप्यूटिंग दूरी, आंखों के लिए सार्थक तरीके से, दो आरजीबी वैक्टरों के बीच यूक्लिडियन दूरी को लेना उतना आसान नहीं है।http://www.compuphase.com/cmetric.htm

सी में उदाहरण दिया गया है::

typedef struct { 
    unsigned char r, g, b; 
} RGB; 

double ColourDistance(RGB e1, RGB e2) 
{ 
    long rmean = ((long)e1.r + (long)e2.r)/2; 
    long r = (long)e1.r - (long)e2.r; 
    long g = (long)e1.g - (long)e2.g; 
    long b = (long)e1.b - (long)e2.b; 
    return sqrt((((512+rmean)*r*r)>>8) + 4*g*g + (((767-rmean)*b*b)>>8)); 
} 

यह अजगर को बंदरगाह के लिए भी मुश्किल नहीं होना चाहिए

यह यहाँ के बारे में एक दिलचस्प लेख है।

संपादित करें:

वैकल्पिक रूप से, के रूप में this answer में सुझाव दिया है, तो आप HLS and HSV इस्तेमाल कर सकते हैं। लगता है कि colorsys मॉड्यूल में आरजीबी से रूपांतरण करने के लिए फ़ंक्शन हैं। इसके प्रलेखन भी इन पृष्ठों है, जो पढ़ने लायक समझने के लिए कर रहे हैं के लिए लिंक क्यों आरजीबी Euclidian दूरी वास्तव में काम नहीं करता है:

संपादित करें 2:

this answer के अनुसार, यह पुस्तकालय उपयोगी होना चाहिए: http://code.google.com/p/python-colormath/

+0

अनुकूलित 'पायथन' संस्करण के लिए मेरा उत्तर देखें। – Developer

0

सरल:

def eq_with_tolerance(a, b, t): 
    return a-t <= b <= a+t 

def FindColorIn(r,g,b, xmin, xmax, ymin, ymax, tolerance=0): 
    image = ImageGrab.grab() 
    for x in range(xmin, xmax): 
     for y in range(ymin,ymax): 
      px = image.getpixel((x, y)) 
      if eq_with_tolerance(r, px[0], tolerance) and eq_with_tolerance(g, px[1], tolerance) and eq_with_tolerance(b, px[2], tolerance): 
       return x, y 
2

यह मानते हुए कि rtol, gtol, और btol आर, जी, और बी के लिए सहिष्णुता क्रमशः रहे हैं, ऐसा क्यों नहीं:

if abs(px[0]- r) <= rtol and \ 
    abs(px[1]- g) <= gtol and \ 
    abs(px[2]- b) <= btol: 
    return x, y 
1
इसके बजाय इस बात का

:

if px[0] == r and px[1] == g and px[2] == b: 

इस प्रयास करें:

if max(map(lambda a,b: abs(a-b), px, (r,g,b))) < tolerance: 

जहां tolerance अधिकतम रंग अंतर है जिसे आप किसी भी रंगीन चैनल में स्वीकार करने के इच्छुक हैं।

प्रत्येक चैनल को अपने लक्षित मूल्यों से घटाना, पूर्ण मान लेना, फिर उनमें से अधिकतम करना है।

+0

'आयात ऑपरेटर'। –

+0

@ स्लैकी, आपको पहले 'ऑपरेटर आयात' करने की आवश्यकता होगी। (यह कहा जा रहा है, यह अभी भी यूक्लिडियन दूरी के लिए एक सूत्र है: यह आपको उन परिणामों को नहीं देगा जो आप अपेक्षा करते हैं।) – Bruno

+0

@ ब्रूनो: मेरी मीट्रिक यूक्लिडियन दूरी से भी बदतर है! मैंने उस हिस्से पर कोई जोर नहीं दिया (लेकिन ऐसा करने के लिए आपका जवाब ऊपर उठाया)। यदि सहिष्णुता छोटी है तो इससे कोई फर्क नहीं पड़ता है, लेकिन यदि सहिष्णुता बड़ी है तो शायद इससे कोई फर्क नहीं पड़ता। –

2

यहाँ एक अनुकूलित Python संस्करण ब्रूनो के asnwer से अनुकूलित है:

def ColorDistance(rgb1,rgb2): 
    '''d = {} distance between two colors(3)''' 
    rm = 0.5*(rgb1[0]+rgb2[0]) 
    d = sum((2+rm,4,3-rm)*(rgb1-rgb2)**2)**0.5 
    return d 

उपयोग:

>>> import numpy 
>>> rgb1 = numpy.array([1,1,0]) 
>>> rgb2 = numpy.array([0,0,0]) 
>>> ColorDistance(rgb1,rgb2) 
2.5495097567963922 
+0

जो मैंने देखा है, 'x ** 0.5'' गणित आयात sqrt' से 'धीमा है, फिर' sqrt (x) 'का उपयोग करें। लेकिन अगर आप 'गणित आयात' करते हैं और 'math.sqrt (x)' का उपयोग करते हैं, तो आप थोड़ा अंतर नहीं देखेंगे। – JHolta

+0

'(35,255,24)' बनाम '(38,38,120)' रिटर्न 'नान ' –

0
pyautogui से

source code

def pixelMatchesColor(x, y, expectedRGBColor, tolerance=0): 
r, g, b = screenshot().getpixel((x, y)) 
exR, exG, exB = expectedRGBColor 

return (abs(r - exR) <= tolerance) and (abs(g - exG) <= tolerance) and (abs(b - exB) <= tolerance) 

तुम सिर्फ एक छोटे से की जरूरत है ठीक है और आप जाने के लिए तैयार हैं।

संबंधित मुद्दे