Hướng dẫn plot hsv image python - âm mưu hình ảnh hsv python

Màu sắc HSV là gì

HSV, như HSL (hoặc trong OpenCV, HLS), là một trong những màu sắc hình trụ.

Hướng dẫn plot hsv image python - âm mưu hình ảnh hsv python

Tên này có phần mô tả về cách các giá trị của chúng được tham chiếu.

Màu sắc được biểu diễn dưới dạng độ từ 0 đến 360 (trong OpenCV, để phù hợp với định dạng số nguyên không dấu 8 bit, độ phân giải được chia cho hai để nhận số từ 0 đến 179; vì vậy 110 ở OpenCV là 220 độ). Nếu bạn lấy một "phạm vi" của các giá trị màu sắc, nó giống như cắt một lát từ một chiếc bánh. Bạn chỉ đang lấy một số chunk góc của chiếc bánh.

Kênh bão hòa là bạn ở cách trung tâm bao xa --- bán kính bạn đang ở. Trung tâm hoàn toàn không có độ bão hòa --- chỉ có màu xám từ đen sang trắng. Nếu bạn lấy một loạt các giá trị này, nó giống như cạo ra bên ngoài xi lanh hoặc cắt một vòng tròn từ trung tâm. Ví dụ: nếu phạm vi là 0 đến 255, thì phạm vi 0 đến 127 sẽ là một hình trụ chỉ kéo dài đến một nửa bán kính; Phạm vi 127 đến 255 sẽ cắt một hình trụ bên trong với một nửa bán kính.

Kênh giá trị là một tên hơi khó hiểu; Đó không phải là chính xác độ bóng tối vì giá trị cao nhất đại diện cho màu trực tiếp, trong khi giá trị thấp nhất là màu đen. Đây là chiều cao của xi lanh. Không quá khó để tưởng tượng cắt một lát xi lanh theo chiều dọc.

Phạm vi của các giá trị HSV

Hàm cv2.inRange(image, lower_bound, upper_bound) tìm thấy tất cả các giá trị của hình ảnh giữa lower_boundupper_bound. Chẳng hạn, nếu hình ảnh của bạn là hình ảnh 3x3 (chỉ cho mục đích trình diễn đơn giản) với 3 kênh, nó có thể trông giống như thế này:

# h channel    # s channel    # v channel
100 150 250    150 150 100    50  75  225
50  100 125    75  25  50     255 100 50
0   255 125    100 200 250    50  75  100

Nếu chúng tôi muốn chọn màu sắc trong khoảng từ 100 đến 200, thì lower_b của chúng tôi sẽ là [100, 0, 0]upper_b nên là

import numpy as np 
import cv2

lower_b = np.array([110,50,50])
upper_b = np.array([130,255,255])

s_gradient = np.ones((500,1), dtype=np.uint8)*np.linspace(lower_b[1], upper_b[1], 500, dtype=np.uint8)
v_gradient = np.rot90(np.ones((500,1), dtype=np.uint8)*np.linspace(lower_b[1], upper_b[1], 500, dtype=np.uint8))
h_array = np.arange(lower_b[0], upper_b[0]+1)

for hue in h_array:
    h = hue*np.ones((500,500), dtype=np.uint8)
    hsv_color = cv2.merge((h, s_gradient, v_gradient))
    rgb_color = cv2.cvtColor(hsv_color, cv2.COLOR_HSV2BGR)
    cv2.imshow('', rgb_color)
    cv2.waitKey(250)

cv2.destroyAllWindows()
0. Bằng cách đó, mặt nạ của chúng tôi sẽ chỉ tính đến các giá trị trong kênh Hue và không bị ảnh hưởng bởi độ bão hòa và giá trị. Đó là lý do tại sao HSV rất phổ biến --- bạn có thể chọn màu sắc theo Huế bất kể độ sáng hay bóng tối của chúng, vì vậy màu đỏ sẫm và màu đỏ tươi có thể được chọn chỉ bằng cách chỉ định tối thiểu và tối đa của kênh Hue.

Nhưng nói rằng chúng tôi chỉ muốn chọn màu trắng sáng. Hãy nhìn lại mô hình xi lanh --- chúng ta thấy màu trắng được đưa ra ở trung tâm của xi lanh, do đó, các giá trị

import numpy as np 
import cv2

lower_b = np.array([110,50,50])
upper_b = np.array([130,255,255])

s_gradient = np.ones((500,1), dtype=np.uint8)*np.linspace(lower_b[1], upper_b[1], 500, dtype=np.uint8)
v_gradient = np.rot90(np.ones((500,1), dtype=np.uint8)*np.linspace(lower_b[1], upper_b[1], 500, dtype=np.uint8))
h_array = np.arange(lower_b[0], upper_b[0]+1)

for hue in h_array:
    h = hue*np.ones((500,500), dtype=np.uint8)
    hsv_color = cv2.merge((h, s_gradient, v_gradient))
    rgb_color = cv2.cvtColor(hsv_color, cv2.COLOR_HSV2BGR)
    cv2.imshow('', rgb_color)
    cv2.waitKey(250)

cv2.destroyAllWindows()
1 thấp và các giá trị
import numpy as np 
import cv2

lower_b = np.array([110,50,50])
upper_b = np.array([130,255,255])

s_gradient = np.ones((500,1), dtype=np.uint8)*np.linspace(lower_b[1], upper_b[1], 500, dtype=np.uint8)
v_gradient = np.rot90(np.ones((500,1), dtype=np.uint8)*np.linspace(lower_b[1], upper_b[1], 500, dtype=np.uint8))
h_array = np.arange(lower_b[0], upper_b[0]+1)

for hue in h_array:
    h = hue*np.ones((500,500), dtype=np.uint8)
    hsv_color = cv2.merge((h, s_gradient, v_gradient))
    rgb_color = cv2.cvtColor(hsv_color, cv2.COLOR_HSV2BGR)
    cv2.imshow('', rgb_color)
    cv2.waitKey(250)

cv2.destroyAllWindows()
2 cao và góc màu không quan trọng. Vì vậy, lower_b sẽ trông giống như
import numpy as np 
import cv2

lower_b = np.array([110,50,50])
upper_b = np.array([130,255,255])

s_gradient = np.ones((500,1), dtype=np.uint8)*np.linspace(lower_b[1], upper_b[1], 500, dtype=np.uint8)
v_gradient = np.rot90(np.ones((500,1), dtype=np.uint8)*np.linspace(lower_b[1], upper_b[1], 500, dtype=np.uint8))
h_array = np.arange(lower_b[0], upper_b[0]+1)

for hue in h_array:
    h = hue*np.ones((500,500), dtype=np.uint8)
    hsv_color = cv2.merge((h, s_gradient, v_gradient))
    rgb_color = cv2.cvtColor(hsv_color, cv2.COLOR_HSV2BGR)
    cv2.imshow('', rgb_color)
    cv2.waitKey(250)

cv2.destroyAllWindows()
4 và upper_b sẽ trông giống như
import numpy as np 
import cv2

lower_b = np.array([110,50,50])
upper_b = np.array([130,255,255])

s_gradient = np.ones((500,1), dtype=np.uint8)*np.linspace(lower_b[1], upper_b[1], 500, dtype=np.uint8)
v_gradient = np.rot90(np.ones((500,1), dtype=np.uint8)*np.linspace(lower_b[1], upper_b[1], 500, dtype=np.uint8))
h_array = np.arange(lower_b[0], upper_b[0]+1)

for hue in h_array:
    h = hue*np.ones((500,500), dtype=np.uint8)
    hsv_color = cv2.merge((h, s_gradient, v_gradient))
    rgb_color = cv2.cvtColor(hsv_color, cv2.COLOR_HSV2BGR)
    cv2.imshow('', rgb_color)
    cv2.waitKey(250)

cv2.destroyAllWindows()
6. Điều đó có nghĩa là tất cả các giá trị
import numpy as np 
import cv2

lower_b = np.array([110,50,50])
upper_b = np.array([130,255,255])

s_gradient = np.ones((500,1), dtype=np.uint8)*np.linspace(lower_b[1], upper_b[1], 500, dtype=np.uint8)
v_gradient = np.rot90(np.ones((500,1), dtype=np.uint8)*np.linspace(lower_b[1], upper_b[1], 500, dtype=np.uint8))
h_array = np.arange(lower_b[0], upper_b[0]+1)

for hue in h_array:
    h = hue*np.ones((500,500), dtype=np.uint8)
    hsv_color = cv2.merge((h, s_gradient, v_gradient))
    rgb_color = cv2.cvtColor(hsv_color, cv2.COLOR_HSV2BGR)
    cv2.imshow('', rgb_color)
    cv2.waitKey(250)

cv2.destroyAllWindows()
7 sẽ được bao gồm và sẽ không ảnh hưởng đến mặt nạ của chúng tôi. Nhưng sau đó, chỉ bao gồm các giá trị
import numpy as np 
import cv2

lower_b = np.array([110,50,50])
upper_b = np.array([130,255,255])

s_gradient = np.ones((500,1), dtype=np.uint8)*np.linspace(lower_b[1], upper_b[1], 500, dtype=np.uint8)
v_gradient = np.rot90(np.ones((500,1), dtype=np.uint8)*np.linspace(lower_b[1], upper_b[1], 500, dtype=np.uint8))
h_array = np.arange(lower_b[0], upper_b[0]+1)

for hue in h_array:
    h = hue*np.ones((500,500), dtype=np.uint8)
    hsv_color = cv2.merge((h, s_gradient, v_gradient))
    rgb_color = cv2.cvtColor(hsv_color, cv2.COLOR_HSV2BGR)
    cv2.imshow('', rgb_color)
    cv2.waitKey(250)

cv2.destroyAllWindows()
8 từ 0 đến 50 (về phía trung tâm của xi lanh) và chỉ bao gồm các giá trị
import numpy as np 
import cv2

lower_b = np.array([110,50,50])
upper_b = np.array([130,255,255])

s_gradient = np.ones((500,1), dtype=np.uint8)*np.linspace(lower_b[1], upper_b[1], 500, dtype=np.uint8)
v_gradient = np.rot90(np.ones((500,1), dtype=np.uint8)*np.linspace(lower_b[1], upper_b[1], 500, dtype=np.uint8))
h_array = np.arange(lower_b[0], upper_b[0]+1)

for hue in h_array:
    h = hue*np.ones((500,500), dtype=np.uint8)
    hsv_color = cv2.merge((h, s_gradient, v_gradient))
    rgb_color = cv2.cvtColor(hsv_color, cv2.COLOR_HSV2BGR)
    cv2.imshow('', rgb_color)
    cv2.waitKey(250)

cv2.destroyAllWindows()
9 từ 200 đến 255 (về phía trên cùng của xi lanh).

Hình dung một loạt các màu từ HSV

Một cách để hình dung tất cả các màu trong một phạm vi là tạo độ dốc đi theo chiều dài của cả hai hướng cho mỗi hai kênh, và sau đó làm động trên kênh thứ ba thay đổi.

Chẳng hạn, bạn có thể tạo một gradient của các giá trị từ trái sang phải cho phạm vi của các giá trị

import numpy as np 
import cv2

lower_b = np.array([110,50,50])
upper_b = np.array([130,255,255])

s_gradient = np.ones((500,1), dtype=np.uint8)*np.linspace(lower_b[1], upper_b[1], 500, dtype=np.uint8)
v_gradient = np.rot90(np.ones((500,1), dtype=np.uint8)*np.linspace(lower_b[1], upper_b[1], 500, dtype=np.uint8))
h_array = np.arange(lower_b[0], upper_b[0]+1)

for hue in h_array:
    h = hue*np.ones((500,500), dtype=np.uint8)
    hsv_color = cv2.merge((h, s_gradient, v_gradient))
    rgb_color = cv2.cvtColor(hsv_color, cv2.COLOR_HSV2BGR)
    cv2.imshow('', rgb_color)
    cv2.waitKey(250)

cv2.destroyAllWindows()
8, từ trên xuống dưới cho phạm vi của các giá trị
import numpy as np 
import cv2

lower_b = np.array([110,50,50])
upper_b = np.array([130,255,255])

s_gradient = np.ones((500,1), dtype=np.uint8)*np.linspace(lower_b[1], upper_b[1], 500, dtype=np.uint8)
v_gradient = np.rot90(np.ones((500,1), dtype=np.uint8)*np.linspace(lower_b[1], upper_b[1], 500, dtype=np.uint8))
h_array = np.arange(lower_b[0], upper_b[0]+1)

for hue in h_array:
    h = hue*np.ones((500,500), dtype=np.uint8)
    hsv_color = cv2.merge((h, s_gradient, v_gradient))
    rgb_color = cv2.cvtColor(hsv_color, cv2.COLOR_HSV2BGR)
    cv2.imshow('', rgb_color)
    cv2.waitKey(250)

cv2.destroyAllWindows()
9, sau đó lặp qua mỗi giá trị
import numpy as np 
import cv2

lower_b = np.array([110,50,50])
upper_b = np.array([130,255,255])

s_gradient = np.ones((500,1), dtype=np.uint8)*np.linspace(lower_b[1], upper_b[1], 500, dtype=np.uint8)
v_gradient = np.rot90(np.ones((500,1), dtype=np.uint8)*np.linspace(lower_b[1], upper_b[1], 500, dtype=np.uint8))
h_array = np.arange(lower_b[0], upper_b[0]+1)

for hue in h_array:
    h = hue*np.ones((500,500), dtype=np.uint8)
    hsv_color = cv2.merge((h, s_gradient, v_gradient))
    rgb_color = cv2.cvtColor(hsv_color, cv2.COLOR_HSV2BGR)
    cv2.imshow('', rgb_color)
    cv2.waitKey(250)

cv2.destroyAllWindows()
7. Toàn bộ chương trình này có thể trông giống như thế này:

import numpy as np 
import cv2

lower_b = np.array([110,50,50])
upper_b = np.array([130,255,255])

s_gradient = np.ones((500,1), dtype=np.uint8)*np.linspace(lower_b[1], upper_b[1], 500, dtype=np.uint8)
v_gradient = np.rot90(np.ones((500,1), dtype=np.uint8)*np.linspace(lower_b[1], upper_b[1], 500, dtype=np.uint8))
h_array = np.arange(lower_b[0], upper_b[0]+1)

for hue in h_array:
    h = hue*np.ones((500,500), dtype=np.uint8)
    hsv_color = cv2.merge((h, s_gradient, v_gradient))
    rgb_color = cv2.cvtColor(hsv_color, cv2.COLOR_HSV2BGR)
    cv2.imshow('', rgb_color)
    cv2.waitKey(250)

cv2.destroyAllWindows()

Hướng dẫn plot hsv image python - âm mưu hình ảnh hsv python

Bây giờ GIF này hiển thị giá trị

import numpy as np 
import cv2

lower_b = np.array([110,50,50])
upper_b = np.array([130,255,255])

s_gradient = np.ones((500,1), dtype=np.uint8)*np.linspace(lower_b[1], upper_b[1], 500, dtype=np.uint8)
v_gradient = np.rot90(np.ones((500,1), dtype=np.uint8)*np.linspace(lower_b[1], upper_b[1], 500, dtype=np.uint8))
h_array = np.arange(lower_b[0], upper_b[0]+1)

for hue in h_array:
    h = hue*np.ones((500,500), dtype=np.uint8)
    hsv_color = cv2.merge((h, s_gradient, v_gradient))
    rgb_color = cv2.cvtColor(hsv_color, cv2.COLOR_HSV2BGR)
    cv2.imshow('', rgb_color)
    cv2.waitKey(250)

cv2.destroyAllWindows()
7 mới mỗi khung hình. Và từ trái sang phải, chúng ta có các giá trị tối đa đến tối đa
import numpy as np 
import cv2

lower_b = np.array([110,50,50])
upper_b = np.array([130,255,255])

s_gradient = np.ones((500,1), dtype=np.uint8)*np.linspace(lower_b[1], upper_b[1], 500, dtype=np.uint8)
v_gradient = np.rot90(np.ones((500,1), dtype=np.uint8)*np.linspace(lower_b[1], upper_b[1], 500, dtype=np.uint8))
h_array = np.arange(lower_b[0], upper_b[0]+1)

for hue in h_array:
    h = hue*np.ones((500,500), dtype=np.uint8)
    hsv_color = cv2.merge((h, s_gradient, v_gradient))
    rgb_color = cv2.cvtColor(hsv_color, cv2.COLOR_HSV2BGR)
    cv2.imshow('', rgb_color)
    cv2.waitKey(250)

cv2.destroyAllWindows()
8 và từ trên xuống dưới, chúng ta có các giá trị tối đa đến tối đa
import numpy as np 
import cv2

lower_b = np.array([110,50,50])
upper_b = np.array([130,255,255])

s_gradient = np.ones((500,1), dtype=np.uint8)*np.linspace(lower_b[1], upper_b[1], 500, dtype=np.uint8)
v_gradient = np.rot90(np.ones((500,1), dtype=np.uint8)*np.linspace(lower_b[1], upper_b[1], 500, dtype=np.uint8))
h_array = np.arange(lower_b[0], upper_b[0]+1)

for hue in h_array:
    h = hue*np.ones((500,500), dtype=np.uint8)
    hsv_color = cv2.merge((h, s_gradient, v_gradient))
    rgb_color = cv2.cvtColor(hsv_color, cv2.COLOR_HSV2BGR)
    cv2.imshow('', rgb_color)
    cv2.waitKey(250)

cv2.destroyAllWindows()
9. Mỗi một trong số các màu hiển thị trong hoạt hình này sẽ được chọn từ hình ảnh của bạn để trở thành một phần của
def inRange(img, lower_b, upper_b):
    ch2, ch2, ch3 = cv2.split(img)
    ch2m = (lower_b[0] <= ch2) & (ch2 <= upper_b[0])
    ch2m = (lower_b[1] <= ch2) & (ch2 <= upper_b[1])
    ch3m = (lower_b[2] <= ch3) & (ch3 <= upper_b[2])
    mask = ch2m & ch2m & ch3m
    return mask.astype(np.uint8)*255
6 của bạn.

Tự tạo ra hàm của bạn ()

Để hiểu đầy đủ chức năng OpenCV, cách dễ nhất là chỉ làm chức năng của riêng bạn để hoàn thành nhiệm vụ. Nó không khó chút nào, và không nhiều mã.

Ý tưởng đằng sau hàm rất đơn giản: Tìm các giá trị của mỗi kênh rơi vào giữa

def inRange(img, lower_b, upper_b):
    ch2, ch2, ch3 = cv2.split(img)
    ch2m = (lower_b[0] <= ch2) & (ch2 <= upper_b[0])
    ch2m = (lower_b[1] <= ch2) & (ch2 <= upper_b[1])
    ch3m = (lower_b[2] <= ch3) & (ch3 <= upper_b[2])
    mask = ch2m & ch2m & ch3m
    return mask.astype(np.uint8)*255
7 và
def inRange(img, lower_b, upper_b):
    ch2, ch2, ch3 = cv2.split(img)
    ch2m = (lower_b[0] <= ch2) & (ch2 <= upper_b[0])
    ch2m = (lower_b[1] <= ch2) & (ch2 <= upper_b[1])
    ch3m = (lower_b[2] <= ch3) & (ch3 <= upper_b[2])
    mask = ch2m & ch2m & ch3m
    return mask.astype(np.uint8)*255
8, và sau đó
def inRange(img, lower_b, upper_b):
    ch2, ch2, ch3 = cv2.split(img)
    ch2m = (lower_b[0] <= ch2) & (ch2 <= upper_b[0])
    ch2m = (lower_b[1] <= ch2) & (ch2 <= upper_b[1])
    ch3m = (lower_b[2] <= ch3) & (ch3 <= upper_b[2])
    mask = ch2m & ch2m & ch3m
    return mask.astype(np.uint8)*255
9 tất cả các kênh lại với nhau.

def inRange(img, lower_b, upper_b):
    ch2, ch2, ch3 = cv2.split(img)
    ch2m = (lower_b[0] <= ch2) & (ch2 <= upper_b[0])
    ch2m = (lower_b[1] <= ch2) & (ch2 <= upper_b[1])
    ch3m = (lower_b[2] <= ch3) & (ch3 <= upper_b[2])
    mask = ch2m & ch2m & ch3m
    return mask.astype(np.uint8)*255

Bạn có thể đọc các tài liệu OpenCV để thấy rằng đây thực sự là công thức được sử dụng. Và chúng ta cũng có thể xác minh nó.

lower_b = np.array([200,200,200])
upper_b = np.array([255,255,255])

mask = cv2.inRange(img, lower_b, upper_b) # OpenCV function
mask2 = inRange(img, lower_b, upper_b) # above defined function
print((mask==mask2).all()) # checks that the masks agree on all values
# True

Làm thế nào để tìm đúng màu sắc

Có thể là một chút khó khăn để tìm các giá trị chính xác để sử dụng cho một hình ảnh cụ thể. Có một cách dễ dàng để thử nghiệm, mặc dù. Bạn có thể tạo TrackBars trong OpenCV và sử dụng chúng để kiểm soát Min và tối đa cho mỗi kênh và có chương trình Python cập nhật mặt nạ của bạn mỗi khi bạn thay đổi các giá trị. Tôi đã thực hiện một chương trình cho điều này mà bạn có thể lấy trên GitHub ở đây. Đây là một hoạt hình

lower_b = np.array([200,200,200])
upper_b = np.array([255,255,255])

mask = cv2.inRange(img, lower_b, upper_b) # OpenCV function
mask2 = inRange(img, lower_b, upper_b) # above defined function
print((mask==mask2).all()) # checks that the masks agree on all values
# True
0 của nó đang được sử dụng, để chứng minh:

Hướng dẫn plot hsv image python - âm mưu hình ảnh hsv python