年会签到,拍自己的大头照,有的人可能会拍成横向的,需要旋转,用人脸检测并修正它(图片)。
1. 无脑检测步骤为: 1. opencv 读取图片,灰度转换 2. 使用CascadeClassifier()通过训练数据训练分类器 3. detectMultiScale()检测人脸训练数据集下最基本的人脸haarcascade_frontalface_default.xml
2. 开始检测1) 斜脸检测失败
用了一张逃避可耻但有用剧照,不知是gakki脸斜还是不清晰的缘故,face_cascade.detectMultiScale无结果。
网上找了一张人脸图发现可以有结果[[436 142 604 604]]
2) 旋转图片,被裁剪
测试图片旋转90°,180°,270°时,发现有个问题。下面为旋转180°,90°的效果:90°(以及270°)的图片大小没变,导致横向过长,纵向太窄,图片被裁减。
粗暴的尝试,直接用:
if angle in (90,270): w,h = h,w转换宽高后,输出90°为:
出现了奇怪的边框。
再来看一个45°的输出,也同样被裁剪
直到我找到了 Rotate images (correctly) with OpenCV and Python 这篇文章,写的太好了,用的动图也恰到好处。
rotating oblong pills using the OpenCV’s standard cv2.getRotationMatrix2D and cv2.warpAffine functions caused me some problems that weren’t immediately obvious.
作者检测原型药片旋转没关系,用椭圆的药片就有被裁剪的问题,我上面的那些就是被裁剪了。
使用作者给的函数实验:
def rotate_bound(image, angle): # grab the dimensions of the image and then determine the # center (h, w) = image.shape[:2] (cX, cY) = (w // 2, h // 2) # grab the rotation matrix (applying the negative of the # angle to rotate clockwise), then grab the sine and cosine # (i.e., the rotation components of the matrix) M = cv2.getRotationMatrix2D((cX, cY), -angle, 1.0) cos = np.abs(M[0, 0]) sin = np.abs(M[0, 1]) # compute the new bounding dimensions of the image nW = int((h * sin) + (w * cos)) nH = int((h * cos) + (w * sin)) # adjust the rotation matrix to take into account translation M[0, 2] += (nW / 2) - cX M[1, 2] += (nH / 2) - cY # perform the actual rotation and return the image return cv2.warpAffine(image, M, (nW, nH))-45°旋转
-90°旋转
完成。
4) 自动旋转图片
作者旋转的很好看,所以也模仿了一把,将自己展示图片的函数改为:「 获取图片宽高,然后动态改变宽高显示图片,ms参数为停留的毫秒数(宽高除以3是因为图片太大了,展示不好看)」
def show(img, ms=0): """ 显示 """ cv2.imshow('show', img) h, w = img.shape[:2] cv2.resizeWindow("show", w//3, h//3) cv2.waitKey(ms)用自己之前不正确的旋转函数rotate_img_old测试,有裁剪
for angle in range(0,360,10): show(rotate_img_bad(img_bgr, angle), 200)用正确的测试:裴斐科特
for angle in range(0,360,10): show(rotate_img(img_bgr, angle), 200)3) 再试gakki图
range(0,360,45)以45°为步长检测,发现-315°(即45°)有结果:
检测到两处人脸:修改配置 每次缩减比例:scaleFactor=1.2,检测多次: minNeighbors=10
# 探测图片中的人脸 faces = face_cascade.detectMultiScale( img_gray, scaleFactor=1.2, # 每次缩减比例 minNeighbors=10, # 检测多次 flags=cv2.CASCADE_SCALE_IMAGE, minSize=(50,50) )之后检测,只有一处。
4. 生成头像最后,想截取有效的最大头像,
90°旋转裁剪
在这次真实的年会场合实际使用的时候,不能转45°去裁剪显示,斜着头拍照的可不想转成正经的证件照,
所以只用转90°然后裁剪其中最大正方形,取高和宽中小的一个。较简单,蓝色为实际裁剪区域。
斜的图则不可这样,会裁剪黑色的区域,(避免脸在图中过小,取了**检测到的脸宽*2.5长度**)