- การตรวจจับวัตถุโดยใช้ SIFT
- การตรวจจับวัตถุโดยใช้ ORB
- ฮิสโตแกรมของการไล่ระดับสีเชิง (HOG's)
- ฮิสโตแกรมของการไล่ระดับสีเชิง (HOG) ทีละขั้นตอน:
- ตัวแยกประเภทน้ำตก HAAR
- การตรวจจับใบหน้าและดวงตา
- Live Face and Eye detection
- การปรับแต่งตัวแยกประเภท Cascade
- การตรวจจับรถยนต์และคนเดินถนนในวิดีโอ
เราเริ่มต้นด้วยการติดตั้ง python OpenCV บน windows และจนถึงตอนนี้ได้ทำการประมวลผลภาพขั้นพื้นฐานการแบ่งส่วนภาพและการตรวจจับวัตถุโดยใช้ Python ซึ่งครอบคลุมอยู่ในบทช่วยสอนด้านล่าง:
- เริ่มต้นใช้งาน Python OpenCV: การติดตั้งและการประมวลผลภาพพื้นฐาน
- การจัดการรูปภาพใน Python OpenCV (ตอนที่ 1)
- การจัดการรูปภาพใน OpenCV (ตอนที่ 2)
- การแบ่งส่วนภาพโดยใช้ OpenCV - การแยกพื้นที่เฉพาะของภาพ
เรายังได้เรียนรู้เกี่ยวกับวิธีการและอัลกอริทึมต่างๆสำหรับการตรวจจับวัตถุซึ่งมีการระบุประเด็นสำคัญสำหรับทุกวัตถุโดยใช้อัลกอริทึมที่แตกต่างกัน ในบทช่วยสอนนี้เราจะใช้อัลกอริทึมเหล่านั้นเพื่อตรวจจับวัตถุในชีวิตจริงที่นี่เราจะใช้SIFT และ ORBในการตรวจจับ
การตรวจจับวัตถุโดยใช้ SIFT
นี่คือการตรวจจับวัตถุที่จะทำได้โดยใช้กระแสเว็บแคมสดดังนั้นถ้ามันตระหนักถึงวัตถุที่มันจะพูดถึงพบ Objet ในโค้ดส่วนหลักจะเล่นโดยฟังก์ชันซึ่งเรียกว่าตัวตรวจจับ SIFT การประมวลผลส่วนใหญ่ทำโดยฟังก์ชันนี้
และในอีกครึ่งหนึ่งของโค้ดเราเริ่มต้นด้วยการเปิดสตรีมเว็บแคมจากนั้นโหลดเทมเพลตรูปภาพนั่นคือรูปภาพอ้างอิงนั่นคือโปรแกรมกำลังมองผ่านสตรีมเว็บแคมจริงๆ
ต่อไปเราจะจับภาพจากสตรีมเว็บแคมอย่างต่อเนื่องด้วยความช่วยเหลือของ infinite while loop จากนั้นจับความสูงและความกว้างที่สอดคล้องกันของกรอบเว็บแคมจากนั้นกำหนดพารามิเตอร์ของช่องภูมิภาคที่สนใจ (ROI) ซึ่ง วัตถุของเราสามารถพอดีได้โดยใช้ความสูงและความกว้างของเฟรมเว็บแคมที่สอดคล้องกัน จากนั้นเราวาดรูปสี่เหลี่ยมผืนผ้าจากพารามิเตอร์ ROI ที่เราได้กำหนดไว้ข้างต้น จากนั้นครอบตัดสี่เหลี่ยมออกแล้วป้อนเข้าไปในส่วนตัวตรวจจับ SWIFT ของโค้ด
ตอนนี้ตัวตรวจจับ SIFT โดยทั่วไปมีอินพุตสองอินพุตหนึ่งคือรูปภาพที่ครอบตัดและอีกอันคือเทมเพลตรูปภาพที่เรากำหนดไว้ก่อนหน้านี้จากนั้นจะให้การจับคู่กับเราดังนั้นการจับคู่จึงเป็นจำนวนวัตถุหรือจุดสำคัญที่คล้ายกันในภาพที่ครอบตัด และภาพเป้าหมาย จากนั้นเรากำหนดค่าขีด จำกัด สำหรับการจับคู่หากค่าที่ตรงกันมากกว่าเกณฑ์เราจะใส่ภาพที่พบบนหน้าจอของเราด้วยสีเขียวของสี่เหลี่ยมผืนผ้า ROI
ตอนนี้ขอย้ายกลับไปที่ส่วนหลักของรหัสซึ่งเป็นฟังก์ชันที่เรียกว่าเครื่องตรวจจับ SIFT จะใช้อินพุตเป็นสองภาพหนึ่งคือภาพที่กำลังมองหาวัตถุและอื่น ๆ คือวัตถุที่เราพยายามจับคู่ ถึง (เทมเพลตรูปภาพ) จากนั้นปรับขนาดภาพแรกเป็นสีเทาและกำหนดเทมเพลตรูปภาพเป็นภาพที่สอง จากนั้นเราจะสร้างวัตถุตัวตรวจจับ SIFT และเรียกใช้ฟังก์ชันตรวจจับและคำนวณ OpenCV SIFT เพื่อตรวจจับจุดสำคัญและคำนวณตัวบอกตัวบอกโดยทั่วไปแล้วตัวบอกจะเป็นเวกเตอร์ที่เก็บข้อมูลเกี่ยวกับจุดสำคัญและมันสำคัญมากเมื่อเราทำการจับคู่ ระหว่างตัวอธิบายภาพ
จากนั้นกำหนดตัวจับคู่ที่ใช้ FLANNเราจะไม่เข้าสู่ทฤษฎีทางคณิตศาสตร์ของการจับคู่ที่อยู่เบื้องหลัง แต่คุณสามารถ Google ได้อย่างง่ายดาย ประการแรกกำหนดดัชนี kdtree เป็นศูนย์จากนั้นเราตั้งค่าดัชนีและพารามิเตอร์การค้นหาในรูปแบบพจนานุกรมเราเพียงกำหนดอัลกอริทึมที่เราจะใช้ซึ่งก็คือ KDTREE และจำนวนต้นไม้ที่เราจะใช้ยิ่งต้นไม้มากขึ้น เราใช้ความซับซ้อนมากขึ้นและช้าลง และในพารามิเตอร์การค้นหากำหนดจำนวนการตรวจสอบซึ่งโดยพื้นฐานแล้วคือจำนวนการจับคู่ที่จะเสร็จสมบูรณ์
จากนั้นสร้างวัตถุตัวจับคู่ที่ใช้ FLANN ของเราโดยโหลดพารามิเตอร์ที่เรากำหนดไว้ก่อนหน้านี้ซึ่งเป็นพารามิเตอร์ดัชนีและพารามิเตอร์การค้นหาและจากสิ่งนี้สร้างตัวจับคู่ตาม FLANN ของเราซึ่งเป็นตัวจับคู่ KNN โดยที่ KNN เป็นเพื่อนบ้านที่ใกล้ที่สุด K เรามองหาตัวจับคู่และตัวบอกที่ใกล้ที่สุดและเราทำการจับคู่กับค่าคงที่เริ่มต้น k ตอนนี้ตัวจับคู่ที่ใช้ FLANN นี้จะส่งคืนจำนวนการจับคู่ที่เราได้รับ
การจับคู่ตาม FLANN เป็นเพียงการประมาณดังนั้นเพื่อเพิ่มความแม่นยำของตัวจับคู่ที่ใช้ FLANN เราทำการทดสอบอัตราส่วนของ Lowe และสิ่งที่มันทำคือค้นหาการจับคู่จากตัวจับคู่ที่ใช้ knn flann และกำหนดพารามิเตอร์เมทริกบางส่วนซึ่งเป็นระยะทางที่นี่ ซึ่งระยะทางเป็นฟังก์ชัน numpy และเมื่อตรงตามเกณฑ์แล้วให้เพิ่มการจับคู่กับการจับคู่ที่ดีและส่งคืนการจับคู่ที่ดีที่พบดังนั้นสตรีมวิดีโอสดจะบอกจำนวนการแข่งขันที่พบที่มุมของหน้าจอ
ตอนนี้ลองดูรหัสสำหรับคำอธิบายด้านบน:
import cv2 import numpy เป็น np def sift_detector (new_image, image_template): # ฟังก์ชั่นที่เปรียบเทียบภาพอินพุตกับเทมเพลต # จากนั้นจะส่งคืนจำนวนการจับคู่ SIFT ระหว่าง image1 = cv2.cvtColor (new_image, cv2.COLOR_BGR2GRAY) image2 = image_template # Create วัตถุตัวตรวจจับ SIFT #sift = cv2.SIFT () sift = cv2.xfeatures2d.SIFT_create () # รับคีย์พอยต์และตัวอธิบายโดยใช้ SIFT keypoints_1, descriptors_1 = sift.detectAndCompute (image1, None) keypoints_2, descriptors_2 = sift.detectAndCompute ไม่มี) # กำหนดพารามิเตอร์สำหรับ Flann Matcher FLANN_INDEX_KDTREE = 0 index_params = dict (algorithm = FLANN_INDEX_KDTREE, trees = 3) search_params = dict (checks = 100) # สร้างวัตถุ Flann Matcher flann = cv2.FlannBasedMatcher (index_params, search_params) # รับการจับคู่โดยใช้ K-Nearest Neighbor Method # ผลลัพธ์ 'การจับคู่' คือจำนวนการจับคู่ที่คล้ายกันที่พบในภาพทั้งสองที่ ตรงกัน = flann.knnMatch (descriptors_1, descriptors_2, k = 2) # จัดเก็บการจับคู่ที่ดีโดยใช้การทดสอบอัตราส่วนของ Lowe good_matches = สำหรับ m, n ในการจับคู่: ถ้า m.distance <0.7 * n.distance: good_matches.append (m) return len (good_matches) cap = cv2.VideoCapture (0) # โหลดเทมเพลตรูปภาพของเรานี่คือรูปภาพอ้างอิง image_template = cv2.imread ('phone.jpg', 0) ในขณะที่ True: # รับภาพเว็บแคม ret, frame = cap.read () # รับความสูงและความกว้างของความสูงของเฟรมเว็บแคม , width = frame.shape # กำหนด ROI Box Dimensions 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)) # วาดหน้าต่างสี่เหลี่ยมสำหรับพื้นที่ที่เราสนใจ cv2.rectangle (กรอบ, (top_left_x, top_left_y), (bottom_right_x, bottom_right_y), 255, 3) # ครอบตัดหน้าต่างการสังเกตที่เรากำหนดไว้ข้างต้น cropped = frame # พลิกการวางแนว กรอบ แนวนอนกรอบ = cv2.flip (เฟรม, 1) # รับจำนวนการจับคู่ SIFT = sift_detector (ครอบตัด, image_template) # แสดงสตริงสถานะที่แสดงหมายเลขปัจจุบัน ของการจับคู่ cv2.putText (frame, str (ตรงกัน), (450,450), cv2.FONT_HERSHEY_COMPLEX, 2, (0,255,0), 1) # เกณฑ์ของเราในการระบุ deteciton วัตถุ # เราใช้ 10 เนื่องจากตัวตรวจจับ SIFT ส่งคืนตำแหน่งเท็จเพียงเล็กน้อย threshold = 10 # ถ้าตรงกันเกินเกณฑ์ของเราจะตรวจพบวัตถุ ถ้าตรงกัน> threshold: 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) ถ้า cv2.waitKey (1) == 13: # 13 คือ Enter Key break cap.release () cv2.destroyAllWindows ()
การตรวจจับวัตถุโดยใช้ ORB
การตรวจจับวัตถุโดยใช้ SIFT นั้นค่อนข้างเจ๋งและแม่นยำเนื่องจากสร้างจำนวนการจับคู่ที่แม่นยำมากตามจุดสำคัญอย่างไรก็ตามได้รับการจดสิทธิบัตรแล้วและทำให้ยากต่อการใช้สำหรับแอปพลิเคชันเชิงพาณิชย์ส่วนอีกวิธีหนึ่งคืออัลกอริทึม ORB สำหรับการตรวจจับวัตถุ
เช่นเดียวกับวิธีการตรวจจับวัตถุโดย SIFT ซึ่งเราแบ่งโปรแกรมออกเป็นสองส่วนจะเป็นไปตามนี้
ประการแรกเรากำหนดฟังก์ชัน ORB_detector ซึ่งใช้อินพุตสองอินพุตหนึ่งคือรูปภาพสตรีมสดที่มาจากเว็บแคมและอื่น ๆ คือเทมเพลตรูปภาพตามที่เราจะจับคู่รูปภาพของเราจากนั้นเราปรับขนาดภาพเว็บแคมของเราให้เป็นสีเทาจากนั้นเริ่มต้นเครื่องตรวจจับ ORB ของเราและเราตั้งค่าไว้ที่จุดสำคัญ 1,000 จุดและพารามิเตอร์มาตราส่วน 1.2 คุณสามารถเล่นกับพารามิเตอร์เหล่านี้ได้อย่างง่ายดายจากนั้นตรวจจับจุดสำคัญ (kp) และตัวอธิบาย (des) สำหรับทั้งรูปภาพและพารามิเตอร์ที่สองที่เรากำหนดในฟังก์ชัน detectANDCompute คือ NONE มันกำลังขอให้ใช้มาสก์รูปภาพหรือไม่และ เรากำลังปฏิเสธที่นี่
จากนั้นย้ายไปที่เครื่องตรวจจับก่อนหน้านี้เราใช้ตัวจับคู่แบบ FLANN แต่ที่นี่เราจะใช้BFMatcherและภายใน BFMatcher เรากำหนดพารามิเตอร์สองตัวหนึ่งคือ NORM_HAMMING และอื่น ๆ คือ crossCheck ที่มีค่าเป็น TRUE
จากนั้นคำนวณการจับคู่การจับคู่ระหว่างสองภาพโดยใช้ตัวอธิบายที่กำหนดไว้ด้านบนซึ่งทั้งหมดจะส่งกลับจำนวนการจับคู่เนื่องจากการจับคู่เหล่านี้ไม่ใช่การประมาณดังนั้นจึงไม่จำเป็นต้องทำการทดสอบอัตราส่วนของ Lowe แต่เราเรียงลำดับการจับคู่ตามระยะทาง อย่างน้อยระยะทางที่มากกว่าการจับคู่จะดีกว่า (ในที่นี้ระยะทางหมายถึงระยะห่างระหว่างจุด) และในตอนท้ายเราจะส่งคืนจำนวนการแข่งขันโดยใช้ฟังก์ชันความยาว
และในฟังก์ชั่นหลักเราตั้งค่า threshold เป็นค่าที่สูงกว่ามากเนื่องจากเครื่องตรวจจับลูกโลกสร้างสัญญาณรบกวนได้มาก
ตอนนี้เรามาดูรหัสสำหรับการตรวจจับตาม ORB
import cv2 import numpy เป็น np def ORB_detector (new_image, image_template): # ฟังก์ชั่นที่เปรียบเทียบภาพอินพุตกับเทมเพลต # จากนั้นจะส่งคืนจำนวนการจับคู่ ORB ระหว่าง image1 = cv2.cvtColor (new_image, cv2.COLOR_BGR2GRAY) # สร้างตัวตรวจจับ ORB ด้วย 1,000 จุดสำคัญที่มีพีระมิดปรับขนาด 1.2 orb = cv2.ORB_create (1000, 1.2) # ตรวจหาจุดสำคัญของภาพต้นฉบับ (kp1, des1) = orb.detectAndCompute (image1, None) # ตรวจหาจุดสำคัญของภาพที่หมุนแล้ว (kp2, des2) = orb.detectAndCompute (image_template, None) # สร้างตัวจับคู่ # โปรดทราบว่าเราไม่ได้ใช้การจับคู่ Flannbased bf = cv2.BFMatcher อีกต่อไป(cv2.NORM_HAMMING, crossCheck = True) # ทำการจับคู่ที่ ตรงกัน = bf.match (des1, des2) # เรียงลำดับการแข่งขันตามระยะทาง ระยะทางที่น้อย # จะดีกว่า การแข่งขัน = เรียง (แมตช์ที่สำคัญ = แลมบ์ดาวาล: val.distance) ผลตอบแทน len (ขีด) หมวก = cv2.VideoCapture (0) # โหลดแม่แบบภาพของเรานี้เป็นภาพอ้างอิงของเรา image_template = cv2.imread ('phone.jpg', 0) # image_template = cv2.imread ('images / kitkat.jpg', 0) ในขณะที่ True: # รับภาพเว็บแคม ret, frame = cap.read () # รับความสูงและความกว้างของ ความสูง ของเฟรมเว็บแคม, width = frame.shape # กำหนด ROI Box Dimensions (โปรดทราบว่าบางสิ่งเหล่านี้ควรอยู่นอกลูป) 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)) # วาดหน้าต่างสี่เหลี่ยมสำหรับเรา ขอบเขตที่น่าสนใจ cv2.rectangle (เฟรม, (top_left_x, top_left_y), (bottom_right_x, bottom_right_y), 255, 3) # ครอบตัดหน้าต่างการสังเกตที่เรากำหนดไว้ข้างต้น cropped = frame # การวางแนว กรอบ พลิกตามแนวนอนframe = cv2.flip (เฟรม, 1) # รับจำนวนการจับคู่ ORB = ORB_detector (ครอบตัด, image_template) # แสดงสตริงสถานะที่แสดงหมายเลขปัจจุบัน ของการแข่งขัน output_string = "Matches =" + str (ตรงกัน) cv2.putText (frame, output_string, (50,450), cv2.FONT_HERSHEY_COMPLEX, 2, (250,0,150), 2) # เกณฑ์ของเราเพื่อระบุการตรวจจับวัตถุ # สำหรับภาพใหม่หรือเงื่อนไขการลดน้ำหนักคุณอาจต้องทดลองเล็กน้อย # หมายเหตุ: เครื่องตรวจจับ ORB เพื่อให้ได้การแข่งขัน 1,000 อันดับแรก 350 เป็น เกณฑ์การ จับคู่ขั้นต่ำ 35% = 250 # หากการจับคู่เกินของเรา ขีด จำกัด แล้ววัตถุจะถูกตรวจพบ ถ้าตรงกัน> threshold: cv2.rectangle (เฟรม, (top_left_x, top_left_y), (bottom_right_x, bottom_right_y), (0,255,0), 3) cv2.putText (เฟรม, 'Object Found', (50, 50), cv2.FONT_HERSHEY_COMPLEX, 2, (0,255,0), 2) cv2.imshow ('Object Detector using ORB', frame) ถ้า cv2.waitKey (1) == 13: # 13 คือ Enter Key break cap.release () cv2.destroyAllWindows ()
ฮิสโตแกรมของการไล่ระดับสีเชิง (HOG's)
ตอนนี้เรามาพูดถึงตัวอธิบายที่แตกต่างกันซึ่งก็คือฮิสโตแกรมของการไล่ระดับสีเชิงทิศทาง (HOG's)
HOG เป็นตัวบอกที่ยอดเยี่ยมและมีประโยชน์มากและใช้กันอย่างแพร่หลายและประสบความสำเร็จในการตรวจจับวัตถุดังที่เห็นก่อนหน้านี้คือตัวบอกภาพเช่น SIFT และ ORB ที่เราต้องคำนวณจุดสำคัญจากนั้นต้องคำนวณตัวอธิบายจากจุดสำคัญเหล่านั้น HOG ทำกระบวนการนั้น แตกต่างกัน มันแสดงถึงวัตถุเป็นเวกเตอร์คุณลักษณะเดียวเมื่อเทียบกับชุดของเวกเตอร์คุณลักษณะที่แต่ละส่วนแทนส่วนของภาพ มันหมายความว่าเรามีคุณลักษณะเวกเตอร์เดียวสำหรับภาพทั้งหมด
ซึ่งคำนวณโดยเครื่องตรวจจับหน้าต่างบานเลื่อนเหนือรูปภาพโดยที่ตัวบ่งชี้ HOG จะคำนวณสำหรับแต่ละตำแหน่ง จากนั้นแต่ละตำแหน่งจะรวมกันเป็นเวกเตอร์คุณลักษณะเดียว
เช่นเดียวกับ SIFT ขนาดของภาพจะถูกปรับโดยการปิรามิด
ก่อนหน้านี้เราใช้ตัวจับคู่เช่น FLANN และ BFMatcher แต่HOG ทำแตกต่างกันด้วยความช่วยเหลือของตัวแยกประเภท SVM (support vector machine) โดยที่ตัวบอก HOG แต่ละตัวที่คำนวณจะถูกป้อนเข้ากับตัวจำแนก SVM เพื่อตรวจสอบว่าพบวัตถุหรือไม่
นี่คือลิงค์ไปยัง Great Paper โดย Dalal & Triggs เกี่ยวกับการใช้ HOGs for Human Detection:
ฮิสโตแกรมของการไล่ระดับสีเชิง (HOG) ทีละขั้นตอน:
การทำความเข้าใจเกี่ยวกับ HOG อาจค่อนข้างซับซ้อน แต่ที่นี่เราจะจัดการกับทฤษฎีของ HOG โดยไม่ต้องเจาะลึกลงไปในคณิตศาสตร์ที่เกี่ยวข้อง
ลองถ่ายภาพนี้มันเป็นพิกเซลเล็กน้อยและที่มุมบนคือกล่อง 8x8 พิกเซลตรงนี้ดังนั้นในกล่องนี้เราจะคำนวณเวกเตอร์ไล่ระดับสีหรือการวางแนวขอบในแต่ละพิกเซล ดังนั้นหมายความว่าในกล่องนี้เราคำนวณเวกเตอร์การไล่ระดับสีของพิกเซลภายในกล่อง (เป็นลำดับทิศทางหรือการไหลของความเข้มของภาพเอง) และสร้างเวกเตอร์ไล่ระดับ 64 (8 x 8) ซึ่งจะแสดงเป็นฮิสโตแกรม. ลองนึกภาพฮิสโตแกรมซึ่งแสดงถึงเวกเตอร์ไล่ระดับสีแต่ละตัว ดังนั้นหากจุดหรือความเข้มทั้งหมดอยู่ในทิศทางเดียวฮิสโตแกรมของทิศทางนั้นสมมติว่า 45 องศาฮิสโตแกรมจะมีจุดสูงสุดที่ 45 องศา
สิ่งที่เราทำตอนนี้คือเราแยกแต่ละเซลล์ออกเป็นถังขยะเชิงมุมโดยที่แต่ละถังจะสอดคล้องกับทิศทางการไล่ระดับสี (เช่น x, y) ในกระดาษ Dalal และ Triggs พวกเขาใช้ 9 bins0-180 ° (20 ° each bin) สิ่งนี้ช่วยลด 64 เวกเตอร์ให้เหลือเพียง 9 ค่าได้อย่างมีประสิทธิภาพ ดังนั้นสิ่งที่เราทำคือลดขนาด แต่เก็บข้อมูลสำคัญทั้งหมดที่จำเป็น
ขั้นตอนต่อไปในการคำนวณหมูคือการทำให้เป็นมาตรฐานเราปรับการไล่ระดับสีให้เป็นปกติเพื่อให้แน่ใจว่าการเปลี่ยนแปลงของการส่องสว่างไม่คงที่เช่นความสว่างและความคมชัด
ในภาพนี้ค่าความเข้มจะแสดงในรูปสี่เหลี่ยมจัตุรัสตามทิศทางที่เกี่ยวข้องและทั้งหมดมีความแตกต่าง 50 ระหว่างกัน
∆ H = 50, ∆ v = 50; │∆│ = √50 2 +50 = 70.72, 70.72 / 100 = 0.707
เราหารเวกเตอร์ด้วยขนาดการไล่ระดับสีที่เราได้ 0.707 สำหรับทั้งหมดนี่คือการทำให้เป็นมาตรฐาน
ในทำนองเดียวกันถ้าเราเปลี่ยนความเข้มหรือเปลี่ยนความคมชัดเราจะได้ค่าด้านล่าง
∆ 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
การทำให้เป็นมาตรฐานไม่ได้เกิดขึ้นในระดับเซลล์ แต่จะเกิดขึ้นในระดับบล็อกดังนั้นที่นี่บล็อกจึงเป็นกลุ่มของเซลล์ 4 เซลล์ซึ่งจะคำนึงถึงบล็อกที่อยู่ใกล้เคียงดังนั้นจึงทำให้เป็นปกติโดยคำนึงถึงส่วนที่ใหญ่ขึ้นของภาพ
ทีนี้มาดูโค้ดกัน
นำเข้า numpy เป็น np นำเข้า cv2 นำเข้า matplotlib.pyplot เป็น plt # โหลดภาพจากนั้นภาพสีเทา = cv2.imread ('elephant.jpg') สีเทา = cv2.cvtColor (ภาพ cv2.COLOR_BGR2GRAY) # แสดงภาพต้นฉบับ cv2.imshow (' Input Image ', image) cv2.waitKey (0) #defining the parameters, cell size and block size # hxw in pixels cell_size = (8, 8) # hxw in cells block_size = (2, 2) # number of orientation bins nbins = 9 # การใช้ HOG Descriptor ของ OpenCV # winSize คือขนาดของภาพที่ครอบตัดเป็นจำนวนเซลล์ขนาด หมู = 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) # สร้างรูปทรงอาร์เรย์ numpy ที่เราใช้ เพื่อสร้าง hog_features n_cells = (gray.shape // cell_size, gray.shape // cell_size) # เราทำดัชนีบล็อกตามแถวก่อน # hog_feats ตอนนี้มีแอมพลิจูดไล่ระดับสำหรับแต่ละทิศทาง # สำหรับแต่ละเซลล์ของกลุ่มสำหรับแต่ละกลุ่ม การจัดทำดัชนีเป็นแถวตามคอลัมน์ hog_feats = hog.compute (สีเทา).reshape (n_cells - block_size + 1, n_cells - block_size + 1, block_size, block_size, nbins).transpose ((1, 0, 2, 3, 4)) # สร้างอาร์เรย์การไล่ระดับสีของเราด้วยขนาด nbin เพื่อจัดเก็บการวางแนว ไล่ระดับไล่ระดับสี = np.zeros ((n_cells, n_cells, nbins)) # สร้างอาร์เรย์ของมิติ cell_count = np.full ((n_cells, n_cells, 1), 0, dtype = int) # Block Normalization สำหรับ off_y ในช่วง (block_size): สำหรับ off_x ในช่วง (block_size): การ ไล่ระดับสี - 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 # การไล่ระดับสีเฉลี่ย / = cell_count # Plot HOGs โดยใช้ Matplotlib # มุมคือ 360 / nbins * ทิศทาง color_bins = 5 plt.pcolor (การไล่ระดับสี) plt.gca (). invert_yaxis () plt.gca (). set_aspect ('เท่ากับ', ปรับได้ = 'กล่อง') plt.colorbar () plt.show () cv2.destroyAllWindows ()
ภาพแสดงวิธีการแสดงภาพอินพุตเป็นตัวแทน HOG
ตัวแยกประเภทน้ำตก HAAR
ตามที่กล่าวไว้ก่อนหน้านี้เราสามารถแยกคุณสมบัติจากรูปภาพและใช้คุณสมบัติเหล่านั้นเพื่อจำแนกหรือตรวจจับวัตถุ
HAAR Cascade Classifiers คืออะไร?
วิธีการตรวจจับวัตถุที่ป้อนคุณลักษณะ Haarลงในชุดตัวแยกประเภท (cascade) เพื่อระบุวัตถุในภาพ พวกเขาได้รับการฝึกฝนให้ระบุวัตถุประเภทหนึ่งอย่างไรก็ตามเราสามารถใช้หลายอย่างควบคู่กันเช่นการตรวจจับดวงตาและใบหน้าร่วมกัน
ตัวแยกประเภท HAAR อธิบาย:
HAAR Classifiers ได้รับการฝึกฝนโดยใช้ภาพเชิงบวกจำนวนมาก(เช่นภาพที่มีวัตถุอยู่) และ
ภาพเชิงลบ (เช่นภาพที่ไม่มีวัตถุอยู่)
เมื่อเรามีภาพเหล่านั้นเราแล้วดึงคุณสมบัติที่ใช้หน้าต่างบานเลื่อนของบล็อกสี่เหลี่ยมคุณสมบัติเหล่านี้ (คุณลักษณะ HAAR) เป็นคนเดียวที่มีคุณค่าและมีการคำนวณโดยการลบผลรวมของความเข้มพิกเซลภายใต้รูปสี่เหลี่ยมสีขาวจากสี่เหลี่ยมสีดำ
อย่างไรก็ตามนี่เป็นการคำนวณจำนวนที่ไร้สาระแม้แต่สำหรับหน้าต่างฐานที่มีขนาด 24 x 24 พิกเซล (สร้างคุณลักษณะ 180,000 รายการ)
ดังนั้นนักวิจัยจึงคิดค้นวิธีการที่เรียกว่าIntegral Imagesซึ่งคำนวณสิ่งนี้ด้วยการอ้างอิงอาร์เรย์สี่รายการ อย่างไรก็ตามพวกเขายังคงมีคุณสมบัติ 180,000 รายการและส่วนใหญ่ไม่ได้เพิ่มมูลค่าที่แท้จริง
จากนั้นการเพิ่มกำลังถูกใช้เพื่อกำหนดคุณสมบัติที่ให้ข้อมูลมากที่สุดด้วยAdaBoostของ Freund & Schapire และพบคุณสมบัติที่ให้ข้อมูลส่วนใหญ่ในภาพ Boosting เป็นกระบวนการที่เราใช้ตัวแยกประเภทที่อ่อนแอเพื่อสร้างตัวแยกประเภทที่แข็งแกร่งเพียงแค่กำหนดบทลงโทษที่มีน้ำหนักมากขึ้นสำหรับการจำแนกประเภทที่ไม่ถูกต้อง การลดฟีเจอร์ 180,000 ให้เหลือ 6000 ซึ่งยังเป็นฟีเจอร์ที่ค่อนข้างน้อย
ในคุณสมบัติ 6000 รายการบางอย่างจะให้ข้อมูลมากกว่าคุณสมบัติอื่น ๆ ดังนั้นหากเราใช้คุณสมบัติที่ให้ข้อมูลมากที่สุดเพื่อตรวจสอบก่อนว่าภูมิภาคนั้นสามารถมีใบหน้าได้หรือไม่ (ผลบวกปลอมจะไม่ใช่เรื่องใหญ่) การทำเช่นนี้ไม่จำเป็นต้องคำนวณคุณสมบัติทั้งหมด 6000 รายการในครั้งเดียว แนวคิดนี้เรียกว่า Cascade of Classifiers - สำหรับการตรวจจับใบหน้าวิธี Viola Jones ใช้ 38 ขั้นตอน
การตรวจจับใบหน้าและดวงตา
ดังนั้นหลังจากได้รับความรู้เชิงทฤษฎีเกี่ยวกับการลดหลั่นของ HAAR แล้วเราจะนำไปใช้ในที่สุดเพื่อให้สิ่งต่างๆชัดเจนมากขึ้นเราจะแบ่งบทเรียนออกเป็นส่วน ๆก่อนอื่นเราจะตรวจจับใบหน้าส่วนหน้าหลังจากนั้นเราจะย้ายไปตรวจจับใบหน้าส่วนหน้าด้วย ตาและสุดท้ายเราจะตรวจจับใบหน้าและดวงตาผ่านเว็บแคม
ดังนั้นสำหรับสิ่งนี้เราจะใช้ตัวแยกประเภทที่ได้รับการฝึกฝนมาก่อนซึ่ง OpenCV จัดหาให้เป็นไฟล์. xml xml ย่อมาจากภาษามาร์กอัปที่ขยายได้ภาษานี้ใช้เพื่อจัดเก็บข้อมูลจำนวนมากคุณสามารถสร้างฐานข้อมูลได้
คุณสามารถเข้าถึงตัวแยกประเภทเหล่านี้ได้ที่ลิงค์นี้
การตรวจจับใบหน้า
ลองใช้การตรวจจับใบหน้าด้านหน้าคุณสามารถเข้าถึงน้ำตกของเครื่องตรวจจับใบหน้าได้ที่นี่ เพียงแตกไฟล์ zip เพื่อรับไฟล์ xml
นำเข้า numpy เป็น np import cv2 # เราชี้ฟังก์ชัน CascadeClassifier ของ OpenCV ไปยังที่ จัดเก็บ # ลักษณนาม (รูปแบบไฟล์ XML) อย่าลืมเก็บรหัสและลักษณนามไว้ในโฟลเดอร์เดียวกัน face_cascade = cv2.CascadeClassifier ('haarcascade_frontalface_default.xml') # Load ภาพของเราแล้วแปลงเป็น ภาพ สีเทา= cv2.imread ('Trump.jpg') สีเทา = cv2.cvtColor (รูปภาพ, cv2.COLOR_BGR2GRAY) # ลักษณนามของเราจะส่งคืน ROI ของใบหน้าที่ตรวจพบเป็นทูเพิล # มันเก็บด้านบนซ้าย พิกัดและพิกัดล่างขวา # จะส่งกลับรายการซึ่งเป็นตำแหน่งของใบหน้าที่ตรวจพบต่างกัน faces = face_cascade.detectMultiScale (สีเทา, 1.3, 5) # เมื่อตรวจไม่พบใบหน้า face_classifier จะส่งกลับและทูเพิลว่าง หากใบหน้าคือ (): พิมพ์ ("ไม่พบใบหน้า") # เราวนซ้ำตามอาร์เรย์ใบหน้าของเราและวาดรูปสี่เหลี่ยมผืนผ้า # เหนือแต่ละใบหน้าในใบหน้า สำหรับ (x, y, w, h) ในใบหน้า: cv2.rectangle (รูปภาพ, (x, y), (x + w, y + h), (127,0,255), 2) cv2.imshow ('Face Detection', รูปภาพ) cv2.waitKey (0) cv2.destroyAllWindows ()
ตอนนี้เรามารวมการตรวจจับใบหน้าและดวงตาเข้าด้วยกันคุณสามารถเข้าถึงเครื่องตรวจจับดวงตาแบบเรียงซ้อนในไฟล์ zip เดียวกันได้
นำเข้า numpy เป็น np import cv2 face_classifier = cv2.CascadeClassifier ('haarcascade_frontalface_default.xml') eye_classifier = cv2.CascadeClassifier ('haarcascade_eye.xml') img = cv2.imread ('Trump.jpg') grey = cv2.c cv2.COLOR_BGR2GRAY) faces = face_classifier.detectMultiScale (สีเทา, 1.3, 5) # เมื่อไม่พบใบหน้า face_classifier จะส่งคืนค่าและ tuple ว่าง หากใบหน้าเป็น (): พิมพ์ ("ไม่พบใบหน้า") สำหรับ (x, y, w, h) ในใบหน้า: 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) สำหรับ (ex, ey, ew, eh) ในสายตา: cv2.rectangle (roi_color, (ex, ey), (เช่น + ew, ey + eh), (255,255,0), 2) cv2.imshow ('img', img) cv2.waitKey (0) cv2.destroyAllWindows () cv2.waitKey (0)
ดังนั้นรหัสนี้จึงเหมือนกับรหัสสำหรับการตรวจจับใบหน้า แต่ที่นี่เราได้เพิ่มชั้นตาและวิธีการในการตรวจจับดังที่คุณเห็นเราได้เลือกใบหน้าที่ปรับขนาดเป็นสีเทาเป็นพารามิเตอร์สำหรับการ ตรวจจับหลายสเกล สำหรับ ดวงตาซึ่งนำเราไปสู่การลดลงของการคำนวณเนื่องจากเราจะตรวจจับดวงตาเฉพาะในบริเวณนั้นเท่านั้น
Live Face and Eye detection
ดังนั้นจนถึงขณะนี้เราได้ทำใบหน้าและการตรวจสอบตาตอนนี้ขอใช้เหมือนกันกับวิดีโอสตรีมสดจากเว็บแคมในการนี้เราจะทำการตรวจจับใบหน้าและดวงตาแบบเดียวกัน แต่คราวนี้เราจะทำการสตรีมสดในรูปแบบเว็บแคม ในแอปพลิเคชันส่วนใหญ่คุณจะพบว่าใบหน้าของคุณถูกไฮไลต์ด้วยกล่องรอบ ๆ แต่ที่นี่เราได้ทำสิ่งที่แตกต่างออกไปซึ่งคุณจะพบว่าใบหน้าของคุณถูกครอบตัดออกและดวงตาจะระบุเฉพาะในสิ่งนั้น
ดังนั้นในที่นี้เรากำลังนำเข้าทั้งลักษณนามใบหน้าและดวงตาและกำหนดฟังก์ชันสำหรับการประมวลผลทั้งหมดสำหรับการตรวจจับใบหน้าและดวงตา และหลังจากนั้นก็เริ่มสตรีมเว็บแคมและเรียกใช้ฟังก์ชันตรวจจับใบหน้าเพื่อตรวจจับใบหน้าและดวงตา พารามิเตอร์ที่เรากำหนดภายในฟังก์ชั่นตรวจจับใบหน้าคือภาพต่อเนื่องจากสตรีมเว็บแคมสด
import cv2 import numpy เป็น np face_classifier = cv2.CascadeClassifier ('haarcascade_frontalface_default.xml') eye_classifier = cv2.CascadeClassifier ('haarcascade_eye.xml') def face_detector (img, size = 0.5): # แปลงรูปภาพ = cv2.colorcale (img, cv2.COLOR_BGR2GRAY) faces = face_classifier.detectMultiScale (สีเทา, 1.3, 5) หากใบหน้าเป็น (): ส่งคืน img สำหรับ (x, y, w, h) ในใบหน้า: x = x - 50 w = w + 50 y = y - 50 h = h + 50 cv2. การแก้ไข (img, (x, y), (x + w, y + h), (255,0,0), 2) roi_gray = สีเทา roi_color = img ตา = eye_classifier.detectMultiScale (roi_gray) สำหรับ (เช่น ey, ew, eh) ในสายตา: cv2.rectangle (roi_color, (ex, ey), (ex + ew, ey + eh), (0,0,255), 2) roi_color = cv2.flip (roi_color, 1) ส่งคืน roi_color cap = cv2.VideoCapture (0) ในขณะที่ True: ret, frame = cap.read () cv2.imshow ('Our Face Extractor', face_detector (frame)) ถ้า cv2.waitKey (1) == 13: # 13 คือ Enter Key break cap.release () cv2.destroyAllWindows ()
การปรับแต่งตัวแยกประเภท Cascade
พารามิเตอร์ที่กำหนดภายในdetectMultiScaleนอกเหนือจากอิมเมจอินพุตมีความสำคัญดังต่อไปนี้
ourClassifier detectMultiScale (ภาพอินพุต, Scale Factor, Min Neighbours)
- Scale Factor ระบุจำนวนที่เราลดขนาดภาพในแต่ละครั้งที่ปรับขนาด เช่นในการตรวจจับใบหน้าเรามักใช้ 1.3 ซึ่งหมายความว่าเราจะลดรูปภาพลง 30% ทุกครั้งที่ปรับขนาด ค่าที่น้อยกว่าเช่น 1.05 จะใช้เวลาคำนวณนานขึ้น แต่จะเพิ่มอัตราการตรวจจับ
- Min Neighbours ระบุจำนวนของเพื่อนบ้านแต่ละหน้าต่างที่มีศักยภาพควรมีเพื่อพิจารณาว่าเป็นการตรวจจับเชิงบวก โดยทั่วไปจะตั้งค่าระหว่าง 3-6 มันทำหน้าที่เป็นการตั้งค่าความไวบางครั้งค่าที่ต่ำจะตรวจพบหลายใบหน้าบนใบหน้าเดียว ค่าที่สูงจะช่วยให้แน่ใจว่ามีผลบวกปลอมน้อยกว่า แต่คุณอาจพลาดบางใบหน้า
การตรวจจับรถยนต์และคนเดินถนนในวิดีโอ
ตอนนี้เราจะตรวจจับคนเดินเท้าและรถยนต์ในวิดีโอโดยใช้น้ำตก HAAR แต่ในกรณีที่ไม่มีวิดีโอกำลังโหลดและรวบรวมโค้ดโดยไม่มีข้อผิดพลาดคุณต้องทำตามขั้นตอนต่อไปนี้:
หากไม่มีวิดีโอโหลดหลังจากรันโค้ดคุณอาจต้องคัดลอก opencv_ffmpeg.dl ของเรา จาก : opencv \ ources \ 3rdparty \ ffmpeg เพื่อวางใน ตำแหน่งที่ติดตั้ง python ของคุณเช่น C: \ Anaconda2
เมื่อคัดลอกแล้วคุณจะต้องเปลี่ยนชื่อไฟล์ตามเวอร์ชันของ OpenCV ที่คุณใช้อยู่ถ้าคุณใช้ OpenCV 2.4.13 ให้เปลี่ยนชื่อไฟล์เป็น: opencv_ffmpeg2413_64.dll หรือ opencv_ffmpeg2413.dll (หากคุณเป็น โดยใช้เครื่อง X86) opencv_ffmpeg310_64.dll หรือ opencv_ffmpeg310.dll (หากคุณใช้เครื่อง X86)
หากต้องการทราบตำแหน่งที่คุณติดตั้ง python.exeเพียงเรียกใช้โค้ดสองบรรทัดนี้มันจะพิมพ์ตำแหน่งที่ติดตั้ง python
นำเข้า sys พิมพ์ (sys.executable)
ตอนนี้ถ้าคุณทำตามขั้นตอนเหล่านี้สำเร็จแล้วให้ไปที่รหัสสำหรับการตรวจจับคนเดินถนน
คุณสามารถมีน้ำตกสำหรับตรวจจับคนเดินถนนและจากไฟล์ zip ที่แนบมาที่นี่
นำเข้า cv2 นำเข้า numpy เป็น np # สร้างตัวจำแนกร่างกายของเรา body_classifier = cv2.CascadeClassifier ('haarcascade_fullbody.xml') # เริ่มต้นการจับภาพวิดีโอสำหรับไฟล์วิดีโอที่นี่เรากำลังใช้ไฟล์วิดีโอที่ตรวจพบคนเดินถนน cap = cv2.VideoCapture ('walking.avi') # วนซ้ำเมื่อโหลดวิดีโอสำเร็จ ในขณะที่ cap.isOpened (): # การอ่านแต่ละเฟรมของวิดีโอ ret, frame = cap.read () # ที่นี่เรากำลังปรับขนาดเฟรมเป็นครึ่งหนึ่งของขนาด เรากำลังทำเพื่อเร่งการจัดหมวดหมู่ # เนื่องจากภาพขนาดใหญ่มีหน้าต่างให้เลื่อนผ่านได้มากขึ้นดังนั้นโดยรวมแล้วเราจึงลดความละเอียดลง #of วิดีโอครึ่งหนึ่งนั่นคือสิ่งที่ 0.5 ระบุและเรายังใช้วิธีการแก้ไขที่เร็วกว่านั่นคือ #interlinear frame = cv2.resize (frame, None, fx = 0.5, fy = 0.5, interpolation = cv2.INTER_LINEAR) gray = cv2 cvtColor (เฟรม, cv2.COLOR_BGR2GRAY) # ส่งผ่านเฟรมไปยังร่างกายลักษณนามของร่างกายของเรา = body_classifier.detectMultiScale (สีเทา, 1.2, 3) # แยกกรอบขอบเขตสำหรับเนื้อหาใด ๆ ที่ระบุ สำหรับ (x, y, w, h) ในร่างกาย: cv2 สี่เหลี่ยมผืนผ้า (เฟรม, (x, y), (x + w, y + h), (0, 255, 255), 2) cv2.imshow ('Pedestrians', frame) ถ้า cv2.waitKey (1) == 13: # 13 คือ Enter Key break cap.release () cv2.destroyAllWindows ()
หลังจากตรวจจับคนเดินถนนในวิดีโอสำเร็จแล้วให้ไปที่รหัสสำหรับการตรวจจับรถคุณสามารถมีน้ำตกสำหรับตรวจจับคนเดินถนนได้จากที่นี่
import cv2 import time numpy เป็น np # สร้าง body classifier car_classifier = cv2.CascadeClassifier ('haarcascade_car.xml') # Initiate video capture for video file cap = cv2.VideoCapture ('cars.avi') # วนซ้ำเมื่อวิดีโอสำเร็จ โหลด ในขณะ cap.isOpened (): time.sleep (.05) # อ่าน ret กรอบแรก frame = cap.read () gray = cv2.cvtColor (frame, cv2.COLOR_BGR2GRAY) # ส่งเฟรมไปยังรถลักษณนาม รถยนต์ ของเรา= car_classifier.detectMultiScale (สีเทา, 1.4, 2) # แยกกรอบขอบเขตสำหรับร่างใด ๆ ที่ระบุ สำหรับ (x, y, w, h) ในรถยนต์: cv2.rectangle (เฟรม, (x, y), (x + w, y + h), (0, 255, 255), 2) cv2.imshow ('Cars', frame) ถ้า cv2.waitKey (1) == 13: # 13 คือ Enter Key break cap.release () cv2.destroyAllWindows ()
คุณสังเกตเห็นว่าเราได้เพิ่ม time.sleep (.05) มันเป็นเพียงความล่าช้าของอัตราเฟรมดังนั้นคุณสามารถยืนยันได้ว่ารถทุกคันได้รับการระบุอย่างถูกต้องหรือคุณสามารถลบออกได้อย่างง่ายดายเพียงแค่เพิ่มป้ายกำกับความคิดเห็น
บทความนี้อ้างอิงจาก Master Computer Vision ™ OpenCV4 ในหลักสูตร Python with Deep Learning บน Udemy ที่สร้างโดย Rajeev Ratan สมัครรับข้อมูลเพื่อเรียนรู้เพิ่มเติมเกี่ยวกับ Computer Vision และ Python