opencv人脸检测,旋转处理
年会签到,拍自己的大头照,有的人可能会拍成横向的,需要旋转,用人脸检测并修正它(图片)。
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长度)
代码段
if angle%90 == 0:
# 90° 裁剪图片
logging.debug("90° 裁剪图片")
logging.debug(f"{ix}, {iy}, {x}, {y}, {w}, {h}")
length2 = min(ix, iy)
# 如果人脸太小,放大区域但又不超过图片长度
length = int(w*2.5)
length = min(length2, length)
logging.debug(f"length: {length2} {length}")
ow = length-w
ow1 = ow//2
oh = length-h
oh1 = oh//2
y1, y2 = y-oh1, y+h+oh1
x1, x2 = x-ow1, x+w+ow1
# 检测图片溢出
logging.debug(f"{y1}, {y2}, {x1}, {x2}")
if y1 < 0:
logging.debug('裁剪:1 顶部溢出')
y1 = 0
y2 = length
if y2 > iy:
logging.debug('裁剪:2 底部溢出')
y2 = iy
y1 = iy-length
if x1 < 0:
logging.debug('裁剪:3 左侧溢出')
x1 = 0
x2 = length
if x2 > ix:
logging.debug('裁剪:4 右侧溢出')
x2 = ix
x1 = ix-length
# 裁剪标记
cv2.rectangle(img, (x1, y1), (x2, y2), (255, 0, 0), 2)
斜矩形裁剪探索
那么gakki那张斜的如何裁剪呢,斜矩形之外有黑色背景。举例:应该取到绿色矩形的扩大版,但又没有取到黑色背景。比如这样的蓝色区域
转换为数学方法为:todo, 画在本子上的,最后再补
编写数学函数:
else:
# 非90°裁剪图片
logging.debug(f"{angle}°裁剪图片")
# 1. 求A点坐标
origin_h, origin_w = self.img_bgr.shape[:2]
# 旋转角度取的ab ad边不同
if angle%180<90:
ab = origin_w
ad = origin_h
else:
ab = origin_h
ad = origin_w
op = ix
ap = math.cos(math.radians(angle)) * ab
oa = op-ap
A = Point(oa, 0)
logging.debug(f"ab={ab}, ad={ad}, op={op}, ap={ap}, oa={oa}, {A}")
# 2. 人脸中心Z坐标
face_rect = Rectangle(Point(x, y), w, h)
z = face_rect.center_p
logging.debug(f"{face_rect} center point is {z}")
# 3. Z到AB、AD距离
k = math.tan(math.radians(angle)) # tan(α)
k2 = -1/k # 垂直
logging.info(f"k1 = {k}, k2 = {k2}")
z_ab_len = abs(k*z.x-z.y-oa*k)/math.sqrt(k**2+1)
z_ad_len = abs(k2*z.x-z.y-oa*k2)/math.sqrt(k2**2+1)
logging.debug(f"z-ab len is {z_ab_len}, z-ad len is {z_ad_len}")
# 4. 距离四边最小距离
h1 = z_ab_len
h2 = z_ad_len
h3 = ad-h1
h4 = ab-h2
min_len = min(h1, h2, h3, h4)
logging.debug(f"face around len is {h1} {h2} {h3} {h4}, min:{int(min_len)}")
# 5. 圆形标注
#cv2.line(img, z.r_tuple(), (50, 100), (0,255,0))
for r in (h1, h2, h3, h4):
r = int(r)
if int(min_len) == r:
cv2.circle(img, z.r_tuple(), r, (255, 0, 0), 3)
else:
cv2.circle(img, z.r_tuple(), r, (0, 0, 255), 2)
来测试一波,最后的圆形标注只是为了辅助验证。
其实是有问题的,看效果,最小的蓝色圆形标注位置不对,超出原图片了,而且观察其他三个圆也不在图片边上。
if angle%180<90:
ab = origin_w
ad = origin_h
else:
ab = origin_h
ad = origin_w
这块处理不同角度下取的矩形ABCD边不同,数学角度看是没有错的,但是Opencv坐标圆心在左上角,所以得将数学图形画为:todo
上面赋值代码只需改为
if angle%180<90:
ab = origin_h
ad = origin_w
else:
ab = origin_w
ad = origin_h
蓝色圈已经是我们要求的矩形头像外接圆了,其他三个圆输出也是贴紧各自的边框,完美。
在蓝圈中画黑色正方形:
是想要的效果,最后裁剪即可。
多角度修复
测试初始角度为横向或者侧向时,需修复角度:
# 最后取的图片和角度无关,只取锐角
angle=angle%90
测试三张不同角度照片,和一张不需旋转的图:
结果为:
过程:
参考
- 手把手教你如何用 OpenCV + Python 实现人脸识别
- Rotate images (correctly) with OpenCV and Python 旋转函数优化
- OpenCV实践之路——人脸检测(C++/Python)
detectMultiScale
参数说明 - 使用Python和OpenCV检测图像中的物体并将物体裁剪下来 裁剪方式
image[y1:y1+hight, x1:x1+width]
- OPENCV中的图像坐标和行列的关系
opencv人脸检测,旋转处理的更多相关文章
- keras系列︱人脸表情分类与识别:opencv人脸检测+Keras情绪分类(四)
引自:http://blog.csdn.net/sinat_26917383/article/details/72885715 人脸识别热门,表情识别更加.但是表情识别很难,因为人脸的微表情很多,本节 ...
- 人脸检测学习笔记(数据集-DLIB人脸检测原理-DLIB&OpenCV人脸检测方法及对比)
1.Easily Create High Quality Object Detectors with Deep Learning 2016/10/11 http://blog.dlib.net/201 ...
- opencv人脸检测分类器训练小结
这两天在初学目标检测的算法及步骤,其中人脸检测作为最经典的算法,于是进行了重点研究.该算法最重要的是建立人脸检测分类器,因此我用了一天的时间来学习分类器的训练.这方面的资料很多,但是能按照一个资料运行 ...
- Android+openCV人脸检测2(静态图片)
前几篇文章中有提到对openCV环境配置,这里再重新梳理导入和使用openCV进行简单的人脸检测(包括使用级联分类器) 一 首先导入openCVLibrary320 二 设置gradle的sdk版本号 ...
- OpenCV人脸检测并把图片写成avi视频
读出某一个文件夹下“jpg”后缀的全部图片后,用的OpenCV自带的人脸检测检测图片中的人脸,调整图片的大小写成一个avi视频. 主要是要记录一下CvVideoWriter的用法和如何从文件夹中读取某 ...
- OpenCV——人脸检测
OpenCV支持的目标检测的方法: 利用样本的Haar特征进行的分类器训练,得到的级联boosted分类器(Cascade Classification) 1.加载级联分类器 CascadeClass ...
- OpenCV: OpenCV人脸检测框可信度排序
参考文章:http://blog.csdn.net/hua_007/article/details/45368607 使用OpenCV进行人脸识别时,使用 casecade.detectMultiSc ...
- OpenCV人脸检测demo--facedetect
&1 问题来源 在运行官网的facedetect这个demo的时候,总是不会出来result的图形,电脑右下角提示的错误是“显示器驱动程序已停止响应,而且已恢复 windows 8(R)”. ...
- android opencv 人脸检测
转载自http://blog.csdn.net/jesse__zhong/article/details/24889709 .......省略包 public class Staticdetectio ...
随机推荐
- day11.3分页操作divmod
# 分页显示 divmod(被除数,除数) INFO_LIST = [] for i in range(836): template = "第%s天,笨笨先僧 always be there ...
- 自适应reset.js布局 用于手机端页面编写
以下是reset.js具体内容,是从淘宝网站拔下来的.把它存为js文件引入html里,它的默认尺寸是iphone4的分辨率也就是320*480,美工给你的图不管多少尺寸用ps量图后像素值(px)除以4 ...
- AJAX 应用
ajax简介 AJAX即“Asynchronous Javascript And XML”(异步JavaScript和XML),是指一种创建交互式网页应用的网页开发技术.Ajax不是一种新的编程语言, ...
- JAVA for(i = 0; i<a.length; i++) 解析
下列 System.out.printf 语句输出的结果是什么? Char a[]={„a‟,‟b‟,‟c‟,‟d‟,‟e‟}; For(i=0; i<=a.length/2; i++) { c ...
- 渗透测试学习 三、Linux基础
Linux发行版本 内核+应用程序 打包在一起 一.优点: 完全免费 完全兼容POSIX 1.0标准 多用户,多任务 良好的界面 可靠安全稳定的性能 支持多种平台 丰富的网络功能 安全性更好(针对 ...
- eclipse与visualVM与mat
GC与CPU与内存的查看与分析 本文主要讲visualVM,MAT的下载配置;以及如何运用visualVM生成hprof文件;如何用visualVM分析CPU消耗,程序瓶颈在哪里;怎么用MAT导入hp ...
- windows7 64位系统安装CPU版本TensorFlow(anaconda3.6)
1>下载anaconda3.6,https://www.anaconda.com/download/,选择64位的anaconda3.6,安装时候,路径可以自定义,但是要选择把路径添加到环境变量 ...
- magento 1.9 上传后图片前后台无法正常显示
1.上传后图片不显示,设置 允许 flash 2.保证php 执行是内存大小至少为为128M,多种方式设置,这里以init_set为例子,在index.php 加入下面一行代码,根据情况而定 ini_ ...
- VUE踩坑之路
一.常见报错 1.vue-cli-service 不是内部或外部命令,也不是可运行程序 解决方案: 用以下命令安装Vue CLI就好 npm install -g @vue/cli # OR yarn ...
- Cent os6.5 安装python3.2
1.CentOS6.5 安装Python 的依赖包 yum groupinstall "Development tools" yum install zlib-devel bzip ...