Kết hợp bài 3 và bài 4 chúng ta phát hiện vật theo màu và đồng thời tìm tâm, vị trí của vật.
code xử lý như sau : khai báo thư viện sử dụng
tải ảnh trên và khai báo giới hạn màu cho từng quả bóng:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<strong><span style="color: #993300;"># cài thư viện cần sử dụng</span></strong> <strong><span style="color: #993300;">import numpy as np</span></strong> <strong><span style="color: #993300;">import cv2</span></strong> <strong><span style="color: #993300;">import imutils</span></strong> <strong><span style="color: #993300;"># tải hình ảnh</span></strong> <strong><span style="color: #993300;">image = cv2.imread("color-ball.jpeg")</span></strong> <strong><span style="color: #993300;"># khai báo danh sách giới hạn màu</span></strong> <strong><span style="color: #993300;">boundaries = [</span></strong> <strong><span style="color: #993300;"> ([198 - 30, 115 - 30, 16 - 16], [198 + 30, 115 + 30, 16 + 30]),# Lam đậm</span></strong> <strong><span style="color: #993300;"> ([138 - 30, 32 - 30, 148 - 30], [138 + 30, 32 + 30, 148 + 30]), # Tím</span></strong> <strong><span style="color: #993300;"> ([17 - 17, 33 - 30, 246 - 30], [17 + 30, 33 + 30, 255]), # Đỏ</span></strong> <strong><span style="color: #993300;"> ([54 - 30, 113 - 30, 253 - 30], [54 + 30, 113 + 30, 253 + 2]), # Cam</span></strong> <strong><span style="color: #993300;"> ([0, 186 - 30, 254 - 30], [2 + 30, 186 + 30, 255]), #Vàng</span></strong> <strong><span style="color: #993300;"> ([64 - 30, 153 - 30, 43 - 30], [64 + 30, 153 + 30, 43 + 30]), #Lục</span></strong> <strong><span style="color: #993300;"> ([0, 186 - 30, 179 - 30], [17 + 30, 186 + 30, 179 + 30]),#Vàng chanh</span></strong> <strong><span style="color: #993300;"> ([131 - 30, 6 - 6, 252 - 30], [131 + 30, 6 + 30, 252 + 3]), #Hồng</span></strong> <strong><span style="color: #993300;"> ([217 - 30, 163 - 30, 8 - 8], [217 + 30, 163 + 30, 8 + 30]) # lam nhạt</span></strong> <strong><span style="color: #993300;">]</span></strong> |
Trong vòng lặp để xử lý cho từng quả bóng màu ta làm các bước sau: xác định vật theo màu, tìm đường bao quanh,vẽ đường tròn bao quanh, tìm tâm của quả bóng. Đầu tiên ta xác định vật theo màu:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<strong><span style="color: #993300;">for (lower, upper) in boundaries:</span></strong> <strong><span style="color: #993300;"> #tạo mảng numpy từ dải giới hạn màu</span></strong> <strong><span style="color: #993300;"> lower = np.array(lower, dtype = "uint8")</span></strong> <strong><span style="color: #993300;"> upper = np.array(upper, dtype = "uint8")</span></strong> <strong><span style="color: #993300;"> # Tìm màu trong dải giới hạn, và áp dụng cho ảnh mặt lạ</span></strong> <strong><span style="color: #993300;"> mask = cv2.inRange(image, lower, upper)</span></strong> <strong><span style="color: #993300;"> #Dùng hàm xói mòn để cắt bớt các chi tiết thừa hoặc nhỏ</span></strong> <strong><span style="color: #993300;"> kernel = np.ones((1, 1), np.uint8)</span></strong> <strong><span style="color: #993300;"> mask = cv2.erode(mask, kernel, iterations=2)</span></strong> <strong><span style="color: #993300;"> # Dùng hàm giãn nở để lấp đầy các khoảng trống của hình, làm nối bật hình</span></strong> <strong><span style="color: #993300;"> kernel = np.ones((4, 4), np.uint8)</span></strong> <strong><span style="color: #993300;"> mask = cv2.dilate(mask, kernel, iterations=2)</span></strong> |
Tiếp theo tìm đường bao quanh hình có diện tích lớn nhất, bán kính đạt tối thiểu mục đích loại bỏ các chi tiết thừa, nhiễu không phải quả bóng, Sau đó xác định tâm và vẽ đường tròn bao quanh:
1 2 3 4 |
<strong><span style="color: #993300;">cnts = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL,</span></strong> <strong><span style="color: #993300;"> cv2.CHAIN_APPROX_SIMPLE)</span></strong> <strong><span style="color: #993300;">cnts = imutils.grab_contours(cnts)</span></strong> <strong><span style="color: #993300;">center = None</span></strong> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<strong><span style="color: #993300;">if len(cnts) > 0:</span></strong> <strong><span style="color: #993300;"> # Tìm đuường bao lớn nhất trong tập hợp hình đường bao tìm được</span></strong> <strong><span style="color: #993300;"> # Từ đó tính toán đường tròn kín bao quanh và tâm đường tròn</span></strong> <strong><span style="color: #993300;"> c = max(cnts, key=cv2.contourArea) # Tìm đường bao có diện tích lớn nhất</span></strong> <strong><span style="color: #993300;"> ((x, y), radius) = cv2.minEnclosingCircle(c) # tìm đường tròn kín có kích thước nhỏ nhất bao quanh</span></strong> <strong><span style="color: #993300;"> M = cv2.moments(c)</span></strong> <strong><span style="color: #993300;"> center = (int(M["m10"] / M["m00"]), int(M["m01"] / M["m00"]))</span></strong> <strong><span style="color: #993300;"> # chỉ xử lý khi đáp ứng bán kính tối thiểu</span></strong> <strong><span style="color: #993300;"> if radius > 20:</span></strong> <strong><span style="color: #993300;"> # vẽ đường tròn và tâm</span></strong> <strong><span style="color: #993300;"> cv2.circle(image, (int(x), int(y)), int(radius)+2,</span></strong> <strong><span style="color: #993300;"> (0, 0, 255), 2)</span></strong> <strong><span style="color: #993300;"> cv2.putText(image, "{0},{1}".format(center[0],center[1]), (center[0] - 30, center[1]),</span></strong> <strong><span style="color: #993300;"> cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1)</span></strong> <strong><span style="color: #993300;"> cv2.circle(image, center, 5, (0, 0, 255), -1)</span></strong> |
Tiếp theo hiển thị ảnh sau khi xử lý:
1 2 3 4 5 6 7 |
<strong><span style="color: #993300;">#tạo ảnh mới bằng phép and bit màu giữa ảnh gốc và ảnh măt lạ</span></strong> <strong><span style="color: #993300;">cv2.imshow("mask", mask)</span></strong> <strong><span style="color: #993300;">output = cv2.bitwise_and(image, image, mask = mask)</span></strong> <strong><span style="color: #993300;"># hiển thị ảnh ghép giữa ảnh gốc và ảnh output</span></strong> <strong><span style="color: #993300;">cv2.imshow("images", np.hstack([image, output]))</span></strong> <strong><span style="color: #993300;">cv2.waitKey(0)</span></strong> |
kết quả:
Toàn bộ code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
<strong><span style="color: #993300;"># cài thư viện cần sử dụng</span></strong> <strong><span style="color: #993300;">import numpy as np</span></strong> <strong><span style="color: #993300;">import cv2</span></strong> <strong><span style="color: #993300;">import imutils</span></strong> <strong><span style="color: #993300;"># tải hình ảnh</span></strong> <strong><span style="color: #993300;">image = cv2.imread("color-ball.jpeg")</span></strong> <strong><span style="color: #993300;"># khai báo danh sách giới hạn màu</span></strong> <strong><span style="color: #993300;">boundaries = [</span></strong> <strong><span style="color: #993300;"> ([198 - 30, 115 - 30, 16 - 16], [198 + 30, 115 + 30, 16 + 30]),# Lam đậm</span></strong> <strong><span style="color: #993300;"> ([138 - 30, 32 - 30, 148 - 30], [138 + 30, 32 + 30, 148 + 30]), # Tím</span></strong> <strong><span style="color: #993300;"> ([17 - 17, 33 - 30, 246 - 30], [17 + 30, 33 + 30, 255]), # Đỏ</span></strong> <strong><span style="color: #993300;"> ([54 - 30, 113 - 30, 253 - 30], [54 + 30, 113 + 30, 253 + 2]), # Cam</span></strong> <strong><span style="color: #993300;"> ([0, 186 - 30, 254 - 30], [2 + 30, 186 + 30, 255]), #Vàng</span></strong> <strong><span style="color: #993300;"> ([64 - 30, 153 - 30, 43 - 30], [64 + 30, 153 + 30, 43 + 30]), #Lục</span></strong> <strong><span style="color: #993300;"> ([0, 186 - 30, 179 - 30], [17 + 30, 186 + 30, 179 + 30]),#Vàng chanh</span></strong> <strong><span style="color: #993300;"> ([131 - 30, 6 - 6, 252 - 30], [131 + 30, 6 + 30, 252 + 3]), #Hồng</span></strong> <strong><span style="color: #993300;"> ([217 - 30, 163 - 30, 8 - 8], [217 + 30, 163 + 30, 8 + 30]) # lam nhạt</span></strong> <strong><span style="color: #993300;">]</span></strong> <strong><span style="color: #993300;"># Vòng lặp cho mỗi 1 dải giới hạn màu</span></strong> <strong><span style="color: #993300;">for (lower, upper) in boundaries:</span></strong> <strong><span style="color: #993300;"> #tạo mảng numpy từ dải giới hạn màu</span></strong> <strong><span style="color: #993300;"> lower = np.array(lower, dtype = "uint8")</span></strong> <strong><span style="color: #993300;"> upper = np.array(upper, dtype = "uint8")</span></strong> <strong><span style="color: #993300;"> # Tìm màu trong dải giới hạn, và áp dụng cho ảnh mặt lạ</span></strong> <strong><span style="color: #993300;"> mask = cv2.inRange(image, lower, upper)</span></strong> <strong><span style="color: #993300;"> #Dùng hàm xói mòn để cắt bớt các chi tiết thừa hoặc nhỏ</span></strong> <strong><span style="color: #993300;"> kernel = np.ones((1, 1), np.uint8)</span></strong> <strong><span style="color: #993300;"> mask = cv2.erode(mask, kernel, iterations=2)</span></strong> <strong><span style="color: #993300;"> # Dùng hàm giãn nở để lấp đầy các khoảng trống của hình, làm nối bật hình</span></strong> <strong><span style="color: #993300;"> kernel = np.ones((4, 4), np.uint8)</span></strong> <strong><span style="color: #993300;"> mask = cv2.dilate(mask, kernel, iterations=2)</span></strong> <strong><span style="color: #993300;"> cnts = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL,</span></strong> <strong><span style="color: #993300;"> cv2.CHAIN_APPROX_SIMPLE)</span></strong> <strong><span style="color: #993300;"> cnts = imutils.grab_contours(cnts)</span></strong> <strong><span style="color: #993300;"> center = None</span></strong> <strong><span style="color: #993300;"> # Chỉ xử lý khi tìm thấy ít nhất 1 đường bao, đường viền</span></strong> <strong><span style="color: #993300;"> if len(cnts) > 0:</span></strong> <strong><span style="color: #993300;"> # Tìm đuường bao lớn nhất trong tập hợp hình đường bao tìm được</span></strong> <strong><span style="color: #993300;"> # Từ đó tính toán đường tròn kín bao quanh và tâm đường tròn</span></strong> <strong><span style="color: #993300;"> c = max(cnts, key=cv2.contourArea) # Tìm đường bao có diện tích lớn nhất</span></strong> <strong><span style="color: #993300;"> ((x, y), radius) = cv2.minEnclosingCircle(c) # tìm đường tròn kín có kích thước nhỏ nhất bao quanh</span></strong> <strong><span style="color: #993300;"> M = cv2.moments(c)</span></strong> <strong><span style="color: #993300;"> center = (int(M["m10"] / M["m00"]), int(M["m01"] / M["m00"]))</span></strong> <strong><span style="color: #993300;"> # chỉ xử lý khi đáp ứng bán kính tối thiểu</span></strong> <strong><span style="color: #993300;"> if radius > 20:</span></strong> <strong><span style="color: #993300;"> # vẽ đường tròn và tâm</span></strong> <strong><span style="color: #993300;"> cv2.circle(image, (int(x), int(y)), int(radius)+2,</span></strong> <strong><span style="color: #993300;"> (0, 0, 255), 2)</span></strong> <strong><span style="color: #993300;"> cv2.putText(image, "{0},{1}".format(center[0],center[1]), (center[0] - 30, center[1]),</span></strong> <strong><span style="color: #993300;"> cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1)</span></strong> <strong><span style="color: #993300;"> cv2.circle(image, center, 5, (0, 0, 255), -1)</span></strong> <strong><span style="color: #993300;"> #tạo ảnh mới bằng phép and bit màu giữa ảnh gốc và ảnh măt lạ</span></strong> <strong><span style="color: #993300;"> cv2.imshow("mask", mask)</span></strong> <strong><span style="color: #993300;"> output = cv2.bitwise_and(image, image, mask = mask)</span></strong> <strong><span style="color: #993300;"> # hiển thị ảnh ghép giữa ảnh gốc và ảnh output</span></strong> <strong><span style="color: #993300;"> cv2.imshow("images", np.hstack([image, output]))</span></strong> <strong><span style="color: #993300;"> cv2.waitKey(0)</span></strong> |