- Phát hiện đối tượng bằng SIFT
- Phát hiện đối tượng bằng ORB
- Biểu đồ Gradients định hướng (HOG's)
- Biểu đồ phân định hướng (HOG's), từng bước:
- Bộ phân loại thác HAAR
- Nhận diện khuôn mặt và mắt
- Nhận diện khuôn mặt và mắt trực tiếp
- Điều chỉnh phân loại tầng
- Phát hiện xe hơi và người đi bộ trong video
Chúng tôi đã bắt đầu cài đặt python OpenCV trên windows và cho đến nay đã thực hiện một số xử lý hình ảnh cơ bản, phân đoạn hình ảnh và phát hiện đối tượng bằng Python, được đề cập trong các hướng dẫn dưới đây:
- Bắt đầu với Python OpenCV: Cài đặt và xử lý hình ảnh cơ bản
- Thao tác hình ảnh trong Python OpenCV (Phần 1)
- Thao tác hình ảnh trong OpenCV (Phần 2)
- Phân đoạn hình ảnh bằng OpenCV - Trích xuất các vùng cụ thể của hình ảnh
Chúng tôi cũng đã tìm hiểu về các phương pháp và thuật toán khác nhau để Phát hiện đối tượng trong đó một số điểm chính được xác định cho mọi đối tượng bằng cách sử dụng các thuật toán khác nhau. Trong hướng dẫn này, chúng tôi sẽ sử dụng các thuật toán đó để phát hiện các đối tượng trong cuộc sống thực, ở đây chúng tôi sẽ sử dụng SIFT và ORB để phát hiện.
Phát hiện đối tượng bằng SIFT
Ở đây, phát hiện đối tượng sẽ được thực hiện bằng cách sử dụng luồng webcam trực tiếp, vì vậy nếu nó nhận ra đối tượng, nó sẽ đề cập đến đối tượng được tìm thấy. Trong mã, phần chính được đóng bởi hàm được gọi là bộ dò SIFT, hầu hết quá trình xử lý được thực hiện bởi hàm này.
Và trong nửa đoạn mã còn lại, chúng ta đang bắt đầu với việc mở luồng webcam, sau đó tải mẫu hình ảnh, tức là hình ảnh tham chiếu, tức là chương trình đang thực sự xem qua luồng webcam.
Tiếp theo, chúng tôi đang tiếp tục chụp những hình ảnh từ dòng webcam với sự giúp đỡ của vô hạn trong khi vòng lặp, và sau đó nắm bắt được chiều cao tương ứng và chiều rộng của khung webcam, và sau đó xác định các thông số của khu vực quan tâm (ROI) hộp trong đó đối tượng của chúng ta có thể vừa với bằng cách lấy chiều cao và chiều rộng tương ứng của khung webcam. Và sau đó chúng tôi vẽ hình chữ nhật từ các thông số ROI mà chúng tôi đã xác định ở trên. Sau đó, cuối cùng cắt hình chữ nhật ra và đưa nó vào phần dò SWIFT của mã.
Bây giờ trình dò tìm SIFT về cơ bản có hai đầu vào, một là hình ảnh đã cắt và đầu kia là mẫu hình ảnh mà chúng ta đã xác định trước đó và sau đó nó cung cấp cho chúng ta một số kết quả khớp, vì vậy về cơ bản các kết quả khớp là số đối tượng hoặc điểm chính tương tự trong hình ảnh được cắt và hình ảnh mục tiêu. Sau đó, chúng tôi xác định giá trị ngưỡng cho các kết quả phù hợp, nếu giá trị phù hợp lớn hơn ngưỡng, chúng tôi đặt hình ảnh tìm thấy trên màn hình của chúng tôi với màu xanh lá cây của hình chữ nhật ROI.
Bây giờ chúng ta hãy quay trở lại phần chính của mã, hàm được gọi là bộ phát hiện SIFT, nó nhận đầu vào là hai hình ảnh, một là hình ảnh nơi nó đang tìm kiếm đối tượng và một là đối tượng mà chúng ta đang cố gắng đối sánh sang (mẫu hình ảnh). Sau đó, tỷ lệ màu xám cho hình ảnh đầu tiên và xác định mẫu hình ảnh là hình ảnh thứ hai. Sau đó, chúng tôi tạo một đối tượng dò tìm SIFT và chạy chức năng tính toán và phát hiện OpenCV SIFT, để phát hiện các điểm chính và tính toán các bộ mô tả, bộ mô tả về cơ bản là các vectơ lưu trữ thông tin về các điểm chính và nó thực sự quan trọng khi chúng tôi thực hiện đối sánh giữa các mô tả của hình ảnh.
Và sau đó xác định đối sánh dựa trên FLANN, chúng tôi sẽ không đi sâu vào lý thuyết toán học về đối sánh đằng sau nó, nhưng bạn có thể dễ dàng Google về nó. Đầu tiên, xác định chỉ mục kdtree bằng 0 và sau đó chúng tôi đặt các tham số chỉ mục và tìm kiếm ở định dạng từ điển, chúng tôi chỉ xác định thuật toán chúng tôi sẽ sử dụng là KDTREE và số lượng cây chúng tôi sẽ sử dụng, càng nhiều cây chúng ta sử dụng càng phức tạp thì nó càng chậm hơn. Và trong tham số tìm kiếm, hãy xác định số lần kiểm tra, về cơ bản là số lượng đối sánh mà nó sẽ hoàn thành.
Và sau đó tạo đối tượng đối sánh dựa trên FLANN của chúng tôi bằng cách tải thông số mà chúng tôi đã xác định trước đó là các thông số chỉ mục và thông số tìm kiếm và dựa trên điều này, tạo đối tượng dựa trên FLANN của chúng tôi, là đối tượng KNN trong đó KNN là K-láng giềng gần nhất, về cơ bản đó là một cách chúng tôi tìm kiếm các đối sánh và mô tả gần nhất và chúng tôi thực hiện đối sánh với hằng số khởi tạo k. Giờ đây, trình đối sánh dựa trên FLANN này trả về số lượng trận đấu mà chúng tôi nhận được.
Đối sánh dựa trên FLANN chỉ là một phép gần đúng, do đó, để tăng độ chính xác của đối sánh dựa trên FLANN, chúng tôi thực hiện kiểm tra tỷ lệ của Lowe và những gì nó thực hiện là tìm kiếm các khớp từ trình đối sánh dựa trên knn flann và xác định một số thông số ma trận là khoảng cách ở đây, đối với khoảng cách là một hàm numpy và khi nó đáp ứng các tiêu chí, nối các kết quả phù hợp với các kết quả phù hợp và trả về các kết quả phù hợp được tìm thấy và do đó, luồng video trực tiếp cho biết số lượng các kết quả phù hợp được tìm thấy ở góc màn hình.
Bây giờ chúng ta hãy xem mã cho mô tả trên:
import cv2 import numpy as np def sift_detector (new_image, image_template): # Hàm so sánh hình ảnh đầu vào với mẫu # Sau đó trả về số lượng SIFT phù hợp giữa chúng image1 = cv2.cvtColor (new_image, cv2.COLOR_BGR2GRAY) image2 = image_template # Tạo Đối tượng dò tìm SIFT #sift = cv2.SIFT () sift = cv2.xfeatures2d.SIFT_create () # Lấy các điểm chính và bộ mô tả bằng cách sử dụng SIFT keypoints_1, descriptors_1 = sift.detectAndCompute (image1, None) keypoints_2, descriptors_2 = sift.duteetect (imageAnd) Không có) # Xác định các tham số cho Flann Matcher FLANN_INDEX_KDTREE = 0 index_params = dict (thuật toán = FLANN_INDEX_KDTREE, cây = 3) search_params = dict (checks = 100) # Tạo đối tượng Flann Matcher flann = cv2.FlannBasedMatcher (index_params, search_params) # Lấy kết quả phù hợp bằng K-Nearest Neighbor Method # kết quả 'so khớp' là số lượng kết quả tương tự được tìm thấy trong cả hai hình ảnh trùng khớp = flann.knnMatch (descriptors_1, descriptors_2, k = 2) # Lưu trữ các kết quả phù hợp bằng cách sử dụng kiểm tra tỷ lệ của Lowe good_matches = cho m, n trong các trận đấu: nếu m.distance <0,7 * n.distance: good_matches.append (m) return len (good_matches) cap = cv2.VideoCapture (0) # Tải mẫu hình ảnh của chúng tôi, đây là hình ảnh tham chiếu của chúng tôi image_template = cv2.imread ('phone.jpg', 0) trong khi True: # Lấy hình ảnh từ webcam ret, frame = cap.read () # Lấy chiều cao và chiều rộng của chiều cao khung webcam , width = frame.shape # Xác định Kích thước hộp ROI top_left_x = int (width / 3) top_left_y = int ((height / 2) + (height / 4)) bottom_right_x = int ((width / 3) * 2) bottom_right_y = int ((height / 2) - (height / 4)) # Vẽ cửa sổ hình chữ nhật cho vùng quan tâm của chúng ta cv2.rectangle (frame, (top_left_x, top_left_y)), (bottom_right_x, bottom_right_y), 255, 3) # Cắt cửa sổ quan sát mà chúng tôi đã xác định ở trên crop = frame # Lật hướng khung theo chiều ngang khung = cv2.flip (frame, 1) # Lấy số lượng các kết quả phù hợp SIFT phù hợp = sift_detector (đã cắt, image_template) # Hiển thị chuỗi trạng thái hiển thị số hiện tại. trong tổng số các kết quả phù hợp cv2.putText (frame, str (so khớp), (450,450), cv2.FONT_HERSHEY_COMPLEX, 2, (0,255,0), 1) # Ngưỡng của chúng tôi để chỉ ra đối tượng dò tìm # Chúng tôi sử dụng 10 vì trình dò SIFT trả về một ít vị trí sai ngưỡng = 10 # Nếu kết quả phù hợp vượt quá ngưỡng của chúng tôi thì đối tượng đã được phát hiện nếu khớp> ngưỡng: cv2.rectangle (frame, (top_left_x, top_left_y), (bottom_right_x, bottom_right_y), (0,255,0), 3) cv2.putText (frame, 'Object Found', (50,50), cv2.FONT_HERSHEY_COMPLEX, 2, (0,255,0), 2) cv2.imshow ('Object Detector using SIFT', frame) if cv2.waitKey (1) == 13: # 13 là giới hạn ngắt phím Enter.release () cv2.destroyAllWindows ()
Phát hiện đối tượng bằng ORB
Phát hiện đối tượng bằng cách sử dụng SIFT khá thú vị và chính xác, vì nó tạo ra một số lượng khớp chính xác dựa trên các điểm chính, tuy nhiên, nó đã được cấp bằng sáng chế và điều đó gây khó khăn cho việc sử dụng nó cho các ứng dụng thương mại, một cách khác là thuật toán ORB để phát hiện đối tượng.
Tương tự như phương pháp phát hiện đối tượng bằng SIFT, chúng tôi chia chương trình thành hai phần, phần tương tự sẽ được thực hiện ở đây.
Đầu tiên, chúng tôi xác định hàm ORB_detector lấy hai đầu vào, một là hình ảnh luồng trực tiếp đến từ webcam và một là mẫu hình ảnh trên cơ sở chúng tôi sẽ đối sánh hình ảnh của mình. Sau đó, chúng tôi chia tỷ lệ màu xám cho hình ảnh webcam của mình và sau đó khởi chạy trình dò ORB và chúng tôi đang đặt nó ở đây ở 1000 điểm chính và thông số tỷ lệ là 1,2. bạn có thể dễ dàng thử với các thông số này, sau đó phát hiện các điểm chính (kp) và bộ mô tả (des) cho cả hình ảnh và tham số thứ hai mà chúng tôi đang xác định trong hàm DetANDCompute là KHÔNG, nó có yêu cầu sử dụng mặt nạ hình ảnh hay không và chúng tôi đang phủ nhận nó ở đây.
Sau đó, chuyển đến bộ dò trước đó chúng ta đã sử dụng trình so khớp dựa trên FLANN, nhưng ở đây chúng ta sẽ sử dụng BFMatcher và bên trong BFMatcher, chúng ta xác định hai tham số một là NORM_HAMMING và một là crossCheck có giá trị là TRUE.
Sau đó, tính toán các kết quả phù hợp giữa hai hình ảnh đó bằng cách sử dụng các bộ mô tả được xác định ở trên, tất cả đều trả về số lượng kết quả phù hợp vì các kết quả phù hợp này không phải là gần đúng và do đó không cần thực hiện kiểm tra tỷ lệ của Lowe, thay vào đó chúng tôi sắp xếp các kết quả phù hợp dựa trên khoảng cách, ít nhất khoảng cách càng nhiều thì kết quả phù hợp càng tốt (ở đây khoảng cách có nghĩa là khoảng cách giữa các điểm), và cuối cùng, chúng tôi trả về số trận đấu bằng cách sử dụng hàm độ dài.
Và trong chức năng chính, chúng tôi đặt ngưỡng thành một giá trị cao hơn nhiều, vì bộ dò quả cầu tạo ra nhiều tiếng ồn.
Bây giờ chúng ta hãy xem mã để phát hiện dựa trên ORB
import cv2 import numpy as np def ORB_detector (new_image, image_template): # Hàm so sánh hình ảnh đầu vào với mẫu # Sau đó trả về số lượng ORB phù hợp giữa chúng image1 = cv2.cvtColor (new_image, cv2.COLOR_BGR2GRAY) # Tạo bộ dò ORB với 1000 điểm chính với hệ số kim tự tháp tỷ lệ 1,2 orb = cv2.ORB_create (1000, 1,2) # Phát hiện điểm chính của hình ảnh gốc (kp1, des1) = orb.detectAndCompute (image1, None) # Phát hiện các điểm chính của hình ảnh được xoay (kp2, des2) = orb.detectAndCompute (image_template, None) # Tạo đối sánh # Lưu ý rằng chúng tôi không còn sử dụng đối sánh Flannbased bf = cv2.BFMatcher (cv2.NORM_HAMMING, crossCheck = True) # Làm các kết quả phù hợp = bf.match (des1, des2) # Sắp xếp các kết quả phù hợp dựa trên khoảng cách. Khoảng cách ít nhất # là tốt hơn so khớp = sorted (trận đấu, key = lambda val: val.distance) return len (trận đấu) cap = cv2.VideoCapture (0) # Tải mẫu hình ảnh của chúng tôi, đây là hình ảnh tham chiếu của chúng tôi image_template = cv2.imread ('phone.jpg', 0) # image_template = cv2.imread ('images / kitkat.jpg', 0) while True: # Lấy ảnh webcam ret, frame = cap.read () # Lấy chiều cao và chiều rộng của chiều cao khung webcam , width = frame.shape # Xác định Kích thước Hộp ROI (Lưu ý rằng một số điều này phải nằm ngoài vòng lặp) top_left_x = int (width / 3) top_left_y = int ((height / 2) + (height / 4)) bottom_right_x = int ((width / 3) * 2) bottom_right_y = int ((height / 2) - (height / 4)) # Vẽ cửa sổ hình chữ nhật cho vùng quan tâm cv2.rectangle (frame, (top_left_x, top_left_y), (bottom_right_x, bottom_right_y), 255, 3) # Cửa sổ quan sát mà chúng ta đã xác định ở trên crop = frame # Lật hướng khung theo chiều ngang frame = cv2.flip (frame, 1) # Lấy số lượng ORB đối sánh phù hợp = ORB_detector (crop, image_template) # Hiển thị chuỗi trạng thái hiển thị số hiện tại. trong tổng số các kết quả phù hợp output_string = "Matches =" + str (so khớp) cv2.putText (frame, output_string, (50,450), cv2.FONT_HERSHEY_COMPLEX, 2, (250,0,150), 2) # Ngưỡng của chúng tôi để chỉ ra đối tượng phát hiện # Đối với hình ảnh mới hoặc điều kiện ánh sáng, bạn có thể cần thử nghiệm một chút # Lưu ý: Bộ phát hiện ORB để có được 1000 kết quả phù hợp nhất, 350 về cơ bản là ngưỡng đối sánh tối thiểu 35% = 250 # Nếu kết quả phù hợp vượt quá ngưỡng thì đối tượng đã được phát hiện nếu khớp với> ngưỡng: cv2.rectangle (frame, (top_left_x, top_left_y), (bottom_right_x, bottom_right_y), (0,255,0), 3) cv2.putText (frame, 'Object Found', (50, 50), cv2.FONT_HERSHEY_COMPLEX, 2, (0,255,0), 2) cv2.imshow ('Object Detector using ORB', frame) if cv2.waitKey (1) == 13: # 13 là Enter Key break cap.release () cv2.destroyAllWindows ()
Biểu đồ Gradients định hướng (HOG's)
Bây giờ chúng ta hãy nói về một bộ mô tả khác là Biểu đồ Gradients Định hướng (HOG's).
HOG là những bộ mô tả khá hay và hữu ích và chúng được sử dụng rộng rãi và thành công để phát hiện đối tượng, như đã thấy trước đây các bộ mô tả hình ảnh như SIFT và ORB, nơi chúng ta phải tính toán các điểm chính và sau đó phải tính toán các bộ mô tả từ các điểm chính đó, HOG thực hiện quy trình đó khác nhau. Nó đại diện cho các đối tượng dưới dạng một vectơ đặc trưng đơn lẻ thay vì một tập hợp các vectơ đặc trưng trong đó mỗi vectơ đại diện cho một đoạn của hình ảnh. Nó có nghĩa là chúng ta có một đặc điểm vector duy nhất cho toàn bộ hình ảnh.
Nó được tính toán bằng bộ dò cửa sổ trượt trên một hình ảnh, trong đó bộ mô tả HOG được tính toán cho từng vị trí. Và sau đó mỗi vị trí được kết hợp cho một vectơ đặc trưng.
Giống như SIFT, tỷ lệ của hình ảnh được điều chỉnh bằng cách tạo hình chóp.
Trước đây, chúng tôi đã sử dụng các trình so khớp như FLANN và BFMatcher, nhưng HOG làm điều đó theo cách khác với sự trợ giúp của bộ phân loại SVM (máy vectơ hỗ trợ), trong đó mỗi bộ mô tả HOG được tính toán sẽ được cấp cho bộ phân loại SVM để xác định xem đối tượng có được tìm thấy hay không.
Đây là liên kết đến một bài báo tuyệt vời của Dalal & Triggs về việc sử dụng HOG để phát hiện con người:
Biểu đồ phân định hướng (HOG's), từng bước:
Hiểu HOG's có thể khá phức tạp, nhưng ở đây chúng ta sẽ chỉ giải quyết lý thuyết của HOG mà không đi sâu hơn vào toán học liên quan đến nó.
Vì vậy, chúng ta hãy chụp bức ảnh này, nó hơi bị pixel hóa một chút, và ở góc trên là hộp 8x8 pixel ở đây, vì vậy trong hộp này, chúng tôi tính toán vector gradient hoặc các hướng cạnh ở mỗi pixel. Vì vậy, nó có nghĩa là trong hộp này, chúng tôi tính toán vector gradient hình ảnh của các pixel bên trong hộp (chúng là loại hướng hoặc luồng của chính cường độ hình ảnh) và điều này tạo ra 64 (8 x 8) vector gradient sau đó được biểu diễn dưới dạng biểu đồ. Vì vậy, hãy tưởng tượng một biểu đồ đại diện cho mỗi vector gradient. Vì vậy, nếu tất cả các điểm hoặc cường độ nằm theo một hướng, biểu đồ cho hướng đó giả sử là 45 độ, biểu đồ sẽ có đỉnh ở 45 độ.
Vì vậy, những gì chúng ta làm bây giờ là chúng ta chia mỗi ô thành các thùng góc, trong đó mỗi ô tương ứng với một hướng gradient (ví dụ: x, y). Trong giấy Dalal và Triggs, họ sử dụng 9 thùng 0-180 ° (mỗi thùng 20 °). Điều này làm giảm hiệu quả 64 vectơ xuống chỉ còn 9 giá trị. Vì vậy, những gì chúng tôi đã làm là giảm kích thước nhưng vẫn giữ tất cả các thông tin quan trọng cần thiết.
Bước tiếp theo trong việc tính toán độ sáng là chuẩn hóa, chúng ta chuẩn hóa các gradient để đảm bảo sự bất biến với những thay đổi về độ sáng, tức là Độ sáng và Độ tương phản.
Trong hình ảnh này, các giá trị cường độ được hiển thị trong hình vuông theo hướng tương ứng và tất cả đều có sự khác biệt 50 giữa nhau
∆ H = 50, ∆ v = 50; │∆│ = √50 2 +50 = 70,72, 70,72 / 100 = 0,707
Chúng tôi chia các vectơ cho các cường độ gradient, chúng tôi nhận được 0,707 cho tất cả, đây là chuẩn hóa.
Tương tự, nếu chúng ta thay đổi cường độ hoặc thay đổi độ tương phản, chúng ta nhận được các giá trị dưới đây.
∆ H = 50, ∆ v = 50; │∆│ = √50 2 +50 = 70,72, 70,72 / 100 = 0,707; ∆ H = 100, ∆ v = 100; │∆│ = √100 2 +100 = 141,42, 141,42 / 100 = 1,41
Quá trình chuẩn hóa không diễn ra ở cấp độ ô, thay vào đó nó diễn ra ở cấp độ khối, vì vậy ở đây các khối về cơ bản là một nhóm gồm 4 ô, điều này sẽ tính đến các khối lân cận để chuẩn hóa trong khi xem xét các phân đoạn lớn hơn của hình ảnh.
Bây giờ chúng ta hãy nhìn vào mã
import numpy as np import cv2 import matplotlib.pyplot as plt # Load image then grayscale image = cv2.imread ('Elephant.jpg') gray = cv2.cvtColor (image, cv2.COLOR_BGR2GRAY) # Hiển thị Hình ảnh gốc cv2.imshow (' Hình ảnh đầu vào ', hình ảnh) cv2.waitKey (0) # xác định thông số, kích thước ô và kích thước khối # hxw tính bằng pixel cell_size = (8, 8) # hxw trong ô block_size = (2, 2) # số ngăn định hướng nbins = 9 # Sử dụng Bộ mô tả HOG của OpenCV # winSize là kích thước của hình ảnh được cắt thành bội số của kích thước ô hog = cv2.HOGDescriptor (_winSize = (gray.shape // cell_size * cell_size, gray.shape // cell_size * cell_size), _blockSize = (block_size * cell_size, block_size * cell_size), _blockStride = (cell_size, cell_size), _cellSize = (cell_size, cell_size), _nbins = nbins) # Tạo hình dạng mảng numpy mà chúng tôi sử dụng để tạo hog_features n_cells = (gray.shape // cell_size, gray.shape // cell_size) # Đầu tiên chúng ta lập chỉ mục các khối theo hàng. # hog_feats hiện chứa biên độ gradient cho mỗi hướng, # cho mỗi ô trong nhóm của mỗi nhóm. Lập chỉ mục là theo hàng sau đó là cột. hog_feats = hog.compute (xám).reshape (n_cells - block_size + 1, n_cells - block_size + 1, block_size, block_size, nbins).transpose ((1, 0, 2, 3, 4)) # Tạo mảng gradient của chúng tôi với kích thước nbin để lưu trữ các hướng gradient gradient = np.zeros ((n_cells, n_cells, nbins)) # Tạo mảng kích thước cell_count = np.full ((n_cells, n_cells, 1), 0, dtype = int) # Chuẩn hóa khối cho off_y trong phạm vi (block_size): cho off_x trong phạm vi (block_size): gradient - block_size + off_y + 1, off_x: n_cells - block_size + off_x + 1] + = \ hog_feats cell_count - block_size + off_y + 1, off_x: n_cells - block_size + off_x + 1] + = 1 # Gradient gradient trung bình / = cell_count # Plot HOGs sử dụng Matplotlib # angle là 360 / nbins * direction color_bins = 5 plt.pcolor (gradient) plt.gca (). invert_yaxis () plt.gca (). set_aspect ('bằng', điều chỉnh = 'hộp') plt.colorbar () plt.show () cv2.destroyAllWindows ()
Hình ảnh cho thấy hình ảnh đầu vào được biểu diễn như thế nào dưới dạng biểu diễn HOG.
Bộ phân loại thác HAAR
Như đã thảo luận trước đây, chúng ta có thể trích xuất các tính năng từ một hình ảnh và sử dụng các tính năng đó để phân loại hoặc phát hiện các đối tượng.
HAAR Cascade Classifier là gì?
Một phương pháp phát hiện đối tượng đưa các đặc trưng của Haar vào một loạt các bộ phân loại (thác) để xác định các đối tượng trong một hình ảnh. Chúng được đào tạo để xác định một loại đối tượng, tuy nhiên, chúng ta có thể sử dụng song song một số chúng, ví dụ như phát hiện mắt và mặt cùng nhau.
Bộ phân loại HAAR Giải thích:
Các bộ phân loại HAAR được đào tạo bằng cách sử dụng rất nhiều hình ảnh dương tính (tức là hình ảnh có đối tượng) và
hình ảnh tiêu cực (tức là hình ảnh không có đối tượng).
Khi chúng tôi có những hình ảnh đó, chúng tôi sau đó trích xuất các tính năng bằng cách sử dụng cửa sổ trượt của các khối hình chữ nhật. Các tính năng này (các tính năng HAAR) có giá trị đơn lẻ và được tính bằng cách trừ tổng các cường độ pixel bên dưới các hình chữ nhật màu trắng cho các hình chữ nhật màu đen.
Tuy nhiên, đây là một con số tính toán vô lý, ngay cả đối với cửa sổ cơ sở 24 x 24 pixel (180.000 đối tượng được tạo).
Vì vậy, các nhà nghiên cứu đã nghĩ ra một phương pháp được gọi là Hình ảnh tích phân tính toán điều này với bốn tham chiếu mảng. Tuy nhiên, chúng vẫn có 180.000 tính năng và phần lớn chúng không có giá trị thực.
Sau đó, tăng cường được sử dụng để xác định các tính năng nhiều thông tin nhất, với AdaBoost của Freund & Schapire và nó tìm thấy hầu hết các tính năng thông tin trong hình ảnh. Thúc đẩy là quá trình chúng tôi sử dụng các bộ phân loại yếu để xây dựng các bộ phân loại mạnh, đơn giản bằng cách ấn định các hình phạt có trọng số nặng hơn đối với các phân loại không chính xác. Giảm 180.000 tính năng xuống còn 6000, vẫn còn khá nhiều tính năng.
Trong 6000 tính năng đó, một số sẽ có nhiều thông tin hơn những tính năng khác. Vì vậy, nếu chúng tôi sử dụng các tính năng thông tin nhất để trước tiên kiểm tra xem khu vực có thể có khuôn mặt hay không (dương tính giả sẽ không có vấn đề gì lớn). Làm như vậy loại bỏ nhu cầu tính toán tất cả 6000 tính năng cùng một lúc. Khái niệm này được gọi là Cascade of Classifier - để nhận diện khuôn mặt, phương pháp Viola Jones đã sử dụng 38 giai đoạn.
Nhận diện khuôn mặt và mắt
Vì vậy, sau khi đạt được một số kiến thức lý thuyết về các tầng HAAR, cuối cùng chúng tôi sẽ thực hiện nó, để làm cho mọi thứ rõ ràng hơn, chúng tôi sẽ chia bài học thành từng phần, đầu tiên chúng tôi sẽ phát hiện khuôn mặt trực diện sau đó chúng tôi sẽ chuyển sang phát hiện khuôn mặt trực diện với mắt và cuối cùng chúng tôi sẽ phát hiện trực tiếp khuôn mặt và mắt qua webcam.
Vì vậy, đối với điều này, chúng tôi sẽ sử dụng các bộ phân loại đã được đào tạo trước do OpenCV cung cấp dưới dạng tệp.xml, xml là viết tắt của ngôn ngữ đánh dấu có thể mở rộng, ngôn ngữ này được sử dụng để lưu trữ lượng lớn dữ liệu, thậm chí bạn có thể xây dựng cơ sở dữ liệu trên đó.
Bạn có thể có quyền truy cập các bộ phân loại này tại liên kết này .
Phát hiện khuôn mặt
Hãy thử tính năng phát hiện khuôn mặt trực diện, bạn có thể có quyền truy cập vào dãy dò tìm khuôn mặt trực diện tại đây. Chỉ cần giải nén tệp zip để lấy tệp xml.
import numpy as np import cv2 # Chúng ta trỏ hàm CascadeClassifier của OpenCV tới nơi lưu trữ # classifier (định dạng tệp XML) của chúng ta , hãy nhớ giữ mã và phân loại trong cùng một thư mục face_cascade = cv2.CascadeClassifier ('haarcascade_frontalface_default.xml') # Load hình ảnh của chúng tôi sau đó chuyển đổi nó thành hình ảnh thang độ xám = cv2.imread ('Trump.jpg') gray = cv2.cvtColor (image, cv2.COLOR_BGR2GRAY) # Bộ phân loại của chúng tôi trả về ROI của khuôn mặt được phát hiện dưới dạng một bộ giá trị # Nó lưu trữ ở trên cùng bên trái tọa độ và tọa độ dưới cùng bên phải # nó trả về danh sách danh sách, là vị trí của các khuôn mặt khác nhau được phát hiện. face = face_cascade.detectMultiScale (xám, 1.3, 5) # Khi không phát hiện được khuôn mặt nào, face_classifier trả về và bộ giá trị trống nếu các khuôn mặt là (): print ("Không tìm thấy khuôn mặt") # Chúng ta lặp qua mảng khuôn mặt của mình và vẽ một hình chữ nhật # trên mỗi khuôn mặt trong các khuôn mặt cho (x, y, w, h) ở các khuôn mặt: cv2.rectangle (image, (x, y), (x + w, y + h), (127,0,255), 2) cv2.imshow ('Face Detection', image) cv2.waitKey (0) cv2.destroyAllWindows ()
Bây giờ chúng ta hãy kết hợp nhận diện khuôn mặt và mắt với nhau, bạn có thể có quyền truy cập vào dòng máy dò mắt trong cùng một tệp zip.
import numpy dưới dạng np import cv2 face_classifier = cv2.CascadeClassifier ('haarcascade_frontalface_default.xml') eye_classifier = cv2.CascadeClassifier ('haarcascade_eye.xml') img = cv2.imread ('Trump.jpg', gray = cvtColor cv2.COLOR_BGR2GRAY) face = face_classifier.detectMultiScale (xám, 1.3, 5) # Khi không phát hiện được khuôn mặt nào, face_classifier trả về và bộ giá trị trống nếu khuôn mặt là (): print ("Không tìm thấy khuôn mặt") cho (x, y, w, h) trong các khuôn mặt: cv2.rectangle (img, (x, y), (x + w, y + h), (127,0,255), 2) cv2.imshow ('img', img) roi_gray = gray roi_color = img eyes = eye_classifier.detectMultiScale (roi_gray) cv2.waitKey (0) for (ex, ey, ew, eh) in eyes: cv2.rectangle (roi_color, (ex, ey), (ex + ew, ey + eh), (255,255,0), 2) cv2.imshow ('img', img) cv2.waitKey (0) cv2.destroyAllWindows () cv2.waitKey (0)
Vì vậy, mã này giống như mã cho nhận diện khuôn mặt, nhưng ở đây chúng tôi đã thêm các tầng mắt và phương pháp để phát hiện chúng, như bạn có thể thấy, chúng tôi đã chọn phiên bản tỷ lệ Xám của khuôn mặt làm tham số cho detectorMultiScale cho mắt, đưa chúng ta đến việc giảm thiểu tính toán vì chúng ta sẽ chỉ phát hiện mắt duy nhất ở khu vực đó.
Nhận diện khuôn mặt và mắt trực tiếp
Vì vậy, cho đến bây giờ chúng tôi đã thực hiện nhận diện khuôn mặt và mắt, bây giờ hãy thực hiện tương tự với luồng video trực tiếp từ webcam. Trong phần này, chúng tôi sẽ thực hiện tương tự như phát hiện khuôn mặt và mắt nhưng lần này chúng tôi sẽ làm điều đó cho hình thức phát trực tiếp qua webcam. Trong hầu hết các ứng dụng, bạn sẽ thấy khuôn mặt của mình được làm nổi bật với một hộp xung quanh nó, nhưng ở đây chúng tôi đã làm một điều gì đó khác biệt mà bạn sẽ thấy khuôn mặt của mình bị cắt xéo và mắt chỉ nhận diện được trong đó.
Vì vậy, ở đây chúng tôi đang nhập cả bộ phân loại khuôn mặt và mắt, đồng thời xác định một hàm để thực hiện tất cả các quá trình xử lý nhận diện khuôn mặt và mắt. Và sau đó, bắt đầu luồng webcam và gọi chức năng dò tìm khuôn mặt để nhận diện khuôn mặt và mắt. Thông số chúng tôi đang xác định bên trong chức năng dò tìm khuôn mặt là các hình ảnh liên tục từ luồng trực tiếp trên web cam
import cv2 import numpy as np face_classifier = cv2.CascadeClassifier ('haarcascade_frontalface_default.xml') eye_classifier = cv2.CascadeClassifier ('haarcascade_eye.xml') def face_detector (img, size = 0.5): # Chuyển đổi hình ảnh màu xám thành cvys2.calevtColor (img, cv2.COLOR_BGR2GRAY) face = face_classifier.detectMultiScale (xám, 1.3, 5) nếu các khuôn mặt là (): trả về img cho (x, y, w, h) trong các khuôn mặt: x = x - 50 w = w + 50 y = y - 50 h = h + 50 cv2.rectangle (img, (x, y), (x + w, y + h), (255,0,0), 2) roi_gray = gray roi_color = img eyes = eye_classifier.detectMultiScale (roi_gray) cho (ex, ey, ew, eh) trong mắt: cv2.rectangle (roi_color, (ex, ey), (ex + ew, ey + eh), (0,0,255), 2) roi_color = cv2.flip (roi_color, 1) return roi_color cap = cv2.VideoCapture (0) while True: ret, frame = cap.read () cv2.imshow ('Our Face Extractor', face_detector (frame)) if cv2.waitKey (1) == 13: # 13 là Enter Key break cap.release () cv2.destroyAllWindows ()
Điều chỉnh phân loại tầng
Các tham số được xác định bên trong detectorMultiScale khác với hình ảnh đầu vào có ý nghĩa sau
ourClassifier. detectMultiScale (hình ảnh đầu vào, Scale Factor, Min xóm)
- Hệ số tỷ lệ Chỉ định mức độ chúng tôi giảm kích thước hình ảnh mỗi khi chúng tôi chia tỷ lệ. Ví dụ: trong nhận diện khuôn mặt, chúng tôi thường sử dụng 1.3. Điều này có nghĩa là chúng tôi giảm hình ảnh đi 30% mỗi khi nó được thu nhỏ. Các giá trị nhỏ hơn, chẳng hạn như 1,05 sẽ mất nhiều thời gian hơn để tính toán, nhưng sẽ tăng tỷ lệ phát hiện.
- Min Neighbors Chỉ định số lượng hàng xóm mà mỗi cửa sổ tiềm năng phải có để coi đó là một phát hiện tích cực. Thường đặt từ 3-6. Nó hoạt động như cài đặt độ nhạy, các giá trị thấp đôi khi sẽ phát hiện nhiều khuôn mặt trên một khuôn mặt. Giá trị cao sẽ đảm bảo ít dương tính giả hơn, nhưng bạn có thể bỏ sót một số mặt.
Phát hiện xe hơi và người đi bộ trong video
Bây giờ chúng tôi sẽ phát hiện người đi bộ và ô tô trong video bằng cách sử dụng các tầng HAAR, nhưng trong trường hợp không có video nào đang tải và biên dịch mã không có lỗi, bạn cần làm theo các bước sau:
Nếu không có video nào tải sau khi chạy mã, bạn có thể cần phải sao chép opencv_ffmpeg.dl của chúng tôi từ : opencv \ sources \ 3rdparty \ ffmpeg để dán vào nơi đã cài đặt python của bạn, ví dụ C: \ Anaconda2
Sau khi nó được sao chép, bạn sẽ cần đổi tên tệp theo phiên bản OpenCV bạn đang sử dụng. Ví dụ: nếu bạn đang sử dụng OpenCV 2.4.13, sau đó đổi tên tệp thành: opencv_ffmpeg2413_64.dll hoặc opencv_ffmpeg2413.dll (nếu bạn sử dụng máy X86) opencv_ffmpeg310_64.dll hoặc opencv_ffmpeg310.dll (nếu bạn đang sử dụng máy X86)
Để tìm nơi bạn cài đặt python.exe, chỉ cần chạy hai dòng mã này, nó sẽ in ra vị trí nơi python được cài đặt.
nhập sys print (sys.executable)
Bây giờ nếu bạn đã thực hiện thành công các bước này, hãy chuyển sang mã phát hiện người đi bộ, Bạn có thể có dòng thác để phát hiện người đi bộ và từ tệp zip đính kèm ở đây.
import cv2 import numpy as np # Tạo body classifier body_classifier = cv2.CascadeClassifier ('haarcascade_fullbody.xml') # Bắt đầu quay video cho tệp video, ở đây chúng tôi đang sử dụng tệp video trong đó người đi bộ sẽ được phát hiện cap = cv2.VideoCapture ('walk.avi') # Loop khi video được tải thành công trong khi cap.isOpened (): # Đọc từng khung hình của video ret, frame = cap.read () # ở đây chúng tôi đang thay đổi kích thước khung hình thành một nửa kích thước của nó, chúng tôi đang làm để tăng tốc độ phân loại # vì hình ảnh lớn hơn có nhiều cửa sổ hơn để trượt qua, vì vậy về tổng thể, chúng tôi giảm độ phân giải #of video giảm một nửa, đó là chỉ số 0,5 và chúng tôi cũng đang sử dụng phương pháp nội suy nhanh hơn là #interlinear frame = cv2.resize (frame, None, fx = 0.5, fy = 0.5, interpolation = cv2.INTER_LINEAR) gray = cv2. cvtColor (frame, cv2.COLOR_BGR2GRAY) # Truyền frame đến body classifier body = body_classifier.detectMultiScale (gray, 1.2, 3) # Trích xuất các hộp giới hạn cho bất kỳ phần nào được xác định cho (x, y, w, h) trong các phần thân: cv2. hình chữ nhật (khung, (x, y), (x + w, y + h), (0, 255, 255), 2) cv2.imshow ('Người đi bộ', khung) if cv2.waitKey (1) == 13: # 13 là giới hạn ngắt phím Enter.release () cv2.destroyAllWindows ()
Sau khi phát hiện thành công người đi bộ trong video, hãy chuyển sang mã phát hiện ô tô, Bạn có thể có một tầng để phát hiện người đi bộ từ đây.
import time import cv2 import numpy as np # Create our body classifier car_classifier = cv2.CascadeClassifier ('haarcascade_car.xml') # Bắt đầu quay video cho tệp video cap = cv2.VideoCapture ('ô tô.avi') # Vòng lặp sau khi video thành công được tải trong khi cap.isOpened (): time.sleep (.05) # Đọc ret frame đầu tiên , frame = cap.read () gray = cv2.cvtColor (frame, cv2.COLOR_BGR2GRAY) # Chuyển frame tới bộ phân loại ô tô của chúng tôi, ô tô = car_classifier.detectMultiScale (xám, 1.4, 2) # Trích xuất các hộp giới hạn cho bất kỳ phần nào được xác định cho (x, y, w, h) trong ô tô: cv2.rectangle (frame, (x, y), (x + w, y + h), (0, 255, 255), 2) cv2.imshow ('Cars', frame) if cv2.waitKey (1) == 13: # 13 là Enter Key break cap.release () cv2.destroyAllWindows ()
Bạn nhận thấy rằng chúng tôi đã thêm time.sleep (.05) , đó chỉ là độ trễ về tốc độ khung hình để bạn có thể xác nhận rằng tất cả các ô tô đã được xác định chính xác hoặc bạn có thể dễ dàng xóa nó chỉ bằng cách thêm nhãn nhận xét vào đó.
Bài viết này được tham khảo từ Master Computer Vision ™ OpenCV4 bằng Python với khóa học Deep Learning trên Udemy, do Rajeev Ratan tạo, hãy đăng ký để tìm hiểu thêm về Computer Vision và Python.