我正在使用OpenCV + Python从(脸部)图像中检测和提取眼镜。我按照这篇文章(https://stackoverflow.com/questi..。)的推理路线进行了以下操作:
1)检测脸部
2)找到面部区域中必须是眼镜外框的最大轮廓
3)找到面部区域的第二和第三大轮廓,它们必须是两个镜片的框架
4)提取这些基本上代表眼镜的轮廓之间的区域
然而,findContours()
确实发现眼镜的外框是轮廓,但它并没有准确地找到两个镜片的框架作为轮廓。
我的结果如下: Original image, Outer frame, Left lens
我的源代码如下:
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('Luc_Marion.jpg')
RGB_img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Detect the face in the image
haar_face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
faces = haar_face_cascade.detectMultiScale(gray_img, scaleFactor=1.1, minNeighbors=8);
# Loop in all detected faces - in our case it is only one
for (x,y,w,h) in faces:
cv2.rectangle(RGB_img,(x,y),(x+w,y+h),(255,0,0), 1)
# Focus on the face as a region of interest
roi = RGB_img[int(y+h/4):int(y+2.3*h/4), x:x+w]
roi_gray = gray_img[int(y+h/4):int(y+2.3*h/4), x:x+w]
# Apply smoothing to roi
roi_blur = cv2.GaussianBlur(roi_gray, (5, 5), 0)
# Use Canny to detect edges
edges = cv2.Canny(roi_gray, 250, 300, 3)
# Dilate and erode to thicken the edges
kernel = np.ones((3, 3), np.uint8)
edg_dil = cv2.dilate(edges, kernel, iterations = 3)
edg_er = cv2.erode(edg_dil, kernel, iterations = 3)
# Thresholding instead of Canny does not really make things better
# ret, thresh = cv2.threshold(roi_blur, 127, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
# thresh = cv2.adaptiveThreshold(blur_edg, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 115, 1)
# Find and sort contours by contour area
cont_img, contours, hierarchy = cv2.findContours(edg_er, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
print("Number of contours: ", len(contours))
cont_sort = sorted(contours, key=cv2.contourArea, reverse=True)
# Draw largest contour on original roi (which is the outer
# frame of eyeglasses)
cv2.drawContours(roi, cont_sort[0], -1, (0, 255, 0), 2)
# Draw second largest contour on original roi (which is the left
# lens of the eyeglasses)
# cv2.drawContours(roi, cont_sort[1], -1, (0, 255, 0), 2)
plt.imshow(RGB_img)
plt.show()
如何准确检测左眼镜片和眼镜右镜片的轮廓?
我希望很明显我的最终输出必须是眼镜本身,因为我的最终目标是从脸部图像中提取眼镜。