2012-01-14 32 views
6

Tôi đã thực hiện một chức năng để tìm màu trong hình ảnh và trả lại x, y. Bây giờ tôi cần phải thêm một chức năng mới, nơi tôi có thể tìm thấy một màu sắc với một dung sai nhất định. Nên dễ dàng?Python - Tìm các màu tương tự, cách tốt nhất

Mã để tìm màu sắc trong hình ảnh, và trở về 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 

Kết quả:

Taken từ các câu trả lời các phương pháp bình thường so sánh hai màu sắc là trong khoảng cách Euclide , hoặc Chebyshev khoảng cách.

Tôi quyết định sử dụng chủ yếu (bình phương) khoảng cách euclide và nhiều không gian màu khác nhau. LAB, deltaE (LCH), XYZ, HSL và RGB. Trong mã của tôi, hầu hết các không gian màu sử dụng khoảng cách bình phương euclide để tính toán sự khác biệt.

Ví dụ: LAB, RGB và XYZ một bình phương đơn giản. khoảng cách hiện các trick:

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

LCH, và HSL là một chút phức tạp hơn khi cả hai đều có một màu sắc hình trụ, nhưng một số mảnh toán giải quyết đó, sau đó nó tiếp tục sử dụng eucl phương. ở đây là tốt.

Trong hầu hết các trường hợp này, tôi đã thêm "thông số riêng biệt" cho dung sai cho mỗi kênh (sử dụng 1 dung sai toàn cầu và "công cụ sửa đổi" thay thế HueTol := Tolerance * hueMod hoặc LightTol := Tolerance * LightMod).


Dường như các không gian màu được xây dựng trên đầu trang của XYZ (LAB, LCH) hoạt động tốt nhất trong nhiều trường hợp của tôi. Tho HSL mang lại kết quả rất tốt trong một số trường hợp, và rẻ hơn rất nhiều để chuyển đổi sang RGB, RGB cũng rất tuyệt vời và đáp ứng hầu hết các nhu cầu của tôi.

+0

Bạn nên trả lại nội dung nếu bạn không tìm thấy màu trong hình ảnh. tức là một mã lỗi. –

+0

Bạn xác định mức độ dung sai như thế nào? Các dải ô riêng biệt cho 'r',' g' và 'b'? –

+0

Tôi với John: bạn đã thử những gì? Bạn có thể xem [tương tự cosin] (https://en.wikipedia.org/wiki/Cosine_similarity) và tìm kiếm các triển khai Python. –

Trả lời

17

Tính toán khoảng cách giữa các màu RGB, theo cách có ý nghĩa đối với mắt, không dễ dàng như việc chỉ lấy khoảng cách Euclidian giữa hai vectơ RGB.

Có một bài viết thú vị về vấn đề này ở đây: http://www.compuphase.com/cmetric.htm

Ví dụ thực hiện trong C là:

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)); 
} 

Nó không nên quá khó khăn để cổng để Python.

EDIT:

Ngoài ra, theo đề nghị trong this answer, bạn có thể sử dụng HLS and HSV. Mô-đun colorsys dường như có chức năng chuyển đổi từ RGB. tài liệu hướng dẫn của nó cũng liên kết tới các trang này, đó là đáng đọc để hiểu tại sao RGB Euclide khoảng cách không thực sự làm việc:

EDIT 2:

Theo số this answer, thư viện này sẽ hữu ích: http://code.google.com/p/python-colormath/

+0

Xem câu trả lời của tôi cho phiên bản 'Python' được tối ưu hóa. – Developer

0

đơn giản:

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

Giả sử rằng rtol, gtol, và btol là dung sai cho r, g, b tương ứng, tại sao không làm:

if abs(px[0]- r) <= rtol and \ 
    abs(px[1]- g) <= gtol and \ 
    abs(px[2]- b) <= btol: 
    return x, y 
1

Thay vì điều này:

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

Hãy thử cách này:

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

Trong đó tolerance là chênh lệch tối đa bạn sẵn sàng chấp nhận trong bất kỳ kênh màu nào.

Điều cần làm là trừ mỗi kênh khỏi giá trị mục tiêu của bạn, lấy giá trị tuyệt đối, sau đó là giá trị tối đa của các giá trị đó.

+0

'toán tử nhập'. –

+0

@SLACKY, trước tiên bạn cần phải nhập toán tử '. (Điều này được nói, đây vẫn là một công thức cho khoảng cách Euclidian: điều này sẽ không cung cấp cho bạn kết quả bạn mong đợi một cách trực quan.) – Bruno

+0

@Bruno: số liệu của tôi thậm chí còn tệ hơn khoảng cách Euclide! Tôi đã không đặt bất kỳ sự nhấn mạnh vào phần đó (nhưng upvoted câu trả lời của bạn để làm như vậy). Nếu dung sai nhỏ thì có thể không quan trọng, nhưng nếu dung sai lớn thì có lẽ nó sẽ quan trọng. –

2

Dưới đây là một tối ưu hóa Python phiên bản chuyển thể từ Bruno 's 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 

sử dụng:

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

Từ những gì tôi đã thấy, 'x ** 0,5' chậm hơn nhiều so với' từ sqrt nhập toán học, sau đó sử dụng 'sqrt (x)'. Nhưng nếu bạn 'nhập toán học' và sử dụng' math.sqrt (x) 'bạn sẽ thấy ít hoặc không có sự khác biệt. – JHolta

+0

'(35,255,24)' so với '(38,38,120)' trả về 'nan' –

0

từ 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) 

bạn chỉ cần một chút sửa chữa và bạn đã sẵn sàng để đi.

Các vấn đề liên quan