(学习笔记)opencv和dlib的基础操作

news2024/10/7 8:20:20

来源:投稿 作者:LSC

编辑:学姐

本篇文章将讲述作者对opencv和dlib基础操作的学习笔记。

首先来看opencv的11种基础操作

(1)imread 读取图片

(2)resize 图片缩放

(3)cvtColor 灰度化

(4)threshold 阈值化

(5)bitwise_not 图像取反

(6)add 按位加

(7)抠图操作

(8)rectangle 绘制方框

(9)Text 绘制文字

(10)circle 画圆

(11)VideoCapture 读取视频

其中抠图操作比较奇怪:

因为opencv读取图像像素的顺序,是先行后列,通过上面的操作,先把行找出来,再找列(这是请教了江大白大佬的),所以是img_crop = img[20:100,50:400] #[y1:y2,x1:x2]。

我猜测可能是opencv和dlib里面的坐标系有点不一样,和平时我们矩阵的坐标系是反过来的。

然后学习dlib包的安装

这个包安装了好久,一开始一直报错,先是缺了CMake这个包,安装完后还是一直报错,尝试各种办法,换国内镜像也不行,最终找到解决方案,Python 3.7 两步安装dlib(超简单!亲测有效)。https://blog.csdn.net/sinat_32857543/article/details/107396022

接着学习dlib的基础使用方法,对图像和视频分别人脸检测+关键点定位,感觉好厉害!

实战作业1

直接抠图,在原图上的左上角把抠的图直接复制上去。代码如下:

import cv2import dlib
img = cv2.imread('task1.jpg')
print(type(img))
# img = cv2.resize(img, (500, 600))
print(img.shape)
detector = dlib.get_frontal_face_detector()
faceRets = detector(img)
x_min, y_min, x_max, y_max = faceRets[0].left(), faceRets[0].top(), faceRets[0].right(), faceRets[0].bottom()
print(x_min, y_min, x_max, y_max)
cv2.rectangle(img, (x_min, y_min), (x_max, y_max), (0, 255, 0), 2)
x_text, y_text = (x_max + x_min) // 2,  y_min - 15
cv2.putText(img, "face", (x_text - 30, y_text), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 1)
# print(x_max - x_min)
face = img[y_min: y_max, x_min: x_max]
print(face.shape)
lenx, leny = x_max - x_min, y_max - y_min 
# 也可以写出face.shape[0], face.shape[1]# 
# 令 img[0: lenx, 0:leny]这个区域与face一一对应
# for i in range(lenx):
#     for j in range(leny):
#         img[i, j] = face[i, j]
img[0: leny, 0: lenx] = face  #也可以写成这样
cv2.imshow('homework_tesk1', img)
cv2.imwrite('homework_task1.jpg', img)
cv2.waitKey(0)

最终的结果图片是

还有一种方法,按位加也是可以的,把原图左上角的元素先赋值为0,然后在原图上的那块区域内加上截取出的人脸部分,我试了,但是结果是全黑的:

import cv2
import dlib

img = cv2.imread('task1.jpg')
print(type(img))
# img = cv2.resize(img, (500, 600))
print(img.shape)
detector = dlib.get_frontal_face_detector()
faceRets = detector(img)
x_min, y_min, x_max, y_max = faceRets[0].left(), faceRets[0].top(), faceRets[0].right(), faceRets[0].bottom()
print(x_min, y_min, x_max, y_max)
cv2.rectangle(img, (x_min, y_min), (x_max, y_max), (0, 255, 0), 2)
x_text, y_text = (x_max + x_min) // 2,  y_min - 15
cv2.putText(img, "face", (x_text - 30, y_text), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 1)

# print(x_max - x_min)
face = img[y_min: y_max, x_min: x_max]
print(face.shape)

lenx, leny = x_max - x_min, y_max - y_min # 也可以写出face.shape[0], face.shape[1]
# 令 img[0: lenx, 0:leny]这个区域全为0
for i in range(lenx):
    for j in range(leny):
        img[i, j] = 0
img[0:leny, 0:lenx] = cv2.add(img[0:leny, 0:lenx], face)
cv2.imshow('homework_task1', img)
cv2.imwrite('homework_task1.jpg', img)
cv2.waitKey(0)

实战作业二

同理的,但是有3张图,加一个循环逐一操作:

import cv2
import dlib

img = cv2.imread('task2.jpg')
detector = dlib.get_frontal_face_detector()
faceRets = detector(img)
num = 0
x_start, y_start = 0, 0
for box_info in faceRets:
    x_min, y_min, x_max, y_max = box_info.left(), box_info.top(), box_info.right(), box_info.bottom()
    num += 1
    face = img[y_min: y_max, x_min: x_max]
    cv2.rectangle(img, (x_min, y_min), (x_max, y_max), (255, 0, 0), 3)
    cv2.putText(img, "face"+str(num), ((x_min + x_max) // 2 - 30, y_min - 15), cv2.FONT_HERSHEY_SIMPLEX, 1,
                (255, 0, 0), 1)
    img[y_start: y_start + y_max - y_min, x_start: x_start + x_max - x_min] = face
    # y_start += y_max - y_min
    x_start += x_max - x_min
cv2.imshow("homeword_task2", img)
cv2.imwrite('homework_task2.jpg', img)
cv2.waitKey(0)

最终结果图片是:

人脸检测添加特效实战

下文中的代码先是介绍了对图像中的人脸添加墨镜的特效的原理、步骤和实现代码,注释非常详细,再是进阶介绍对视频中的人脸添加墨镜的特效,最后是对图像中的人脸添加兔耳帽子的特效。

实现对视频中的人脸添加兔耳帽子的特效代码和详细注释、步骤,这些都是在借鉴大白大佬的代码的基础上:

# 本文件代码目的: 读取视频,对视频中的人脸进行检测,并添加兔子耳朵的特效# 作者: lsc
import cv2  # 图像处理的opencv库import math  # 数学运算库import dlib  # 加载dlib算法模块import argparse  # 加载解析模块
def hat_face(opt):
    # 加载dlib自带的人脸检测模型
    detector = dlib.get_frontal_face_detector()
    # 读取兔子帽子的图片
    img_hat = cv2.imread(opt.hat_path)
    # 使用opencv中的VideoCapture函数,读取视频
    cap = cv2.VideoCapture(opt.video_path)
    # 初始化定义frame_id,便于后面跳帧
    frame_id = 0
    # 判断cap是否读取成功
    while cap.isOpened():
        # 因为视频采集,每秒可能会采集N帧图片,因此使用read函数,逐帧读取图片
        # ret 返回True或Fasle,表示是否读取到图片
        # frame 返回读取的图片信息
        ret, frame = cap.read()
        # 如果ok为false,则采集结束
        if not ret:
            # 打印输出,提示信息
            print("Camera cap over!")
            break
        # frame_id加1,便于跳帧
        frame_id += 1
        # 如果frame_id除以10,不等于0,则不断循环,只有等于0时,才进行到下面的显示步骤,这样可以达到跳帧的效果
        # 因为在算法处理中,比如一秒有25帧图像,为了提升项目速度,没有必要对每一帧都进行算法处理
        # 注意:这里的10可以自行设置,如觉得跳帧太慢,可以设置大一些,比如15
        if not int(frame_id) % 10 == 0:
            continue
        # 对读取的原始图像,进行人脸检测
        faceRects = detector(frame)
        # 如果len(faces)>0,则说明图片上存在人脸
        if len(faceRects) > 0:
            # 图片中可能存在多张人脸,依次遍历输出每张人脸的位置信息,并在特定位置,添加兔子帽子特效
            for box_info in faceRects:
                # 对读取的原始图像,进行人脸特征点定位
                x0, y0, width_face, height_face = box_info.left(), box_info.top(), box_info.right() - box_info.left(), box_info.bottom() - box_info.top()
                # 获得帽子图片的高height_hat,宽width_hat,便于后面控制帽子显示的大小
                height_hat, width_hat = img_hat.shape[0], img_hat.shape[1]
                # 将帽子的高度变成,适合检测到的脸型的大小
                imgComposeSizeH = int(height_hat / width_hat * width_face)
                # 因为帽子在脸部上方,当脸部靠近视频顶部,为了保证帽子能显示出来,帽子的高度默认为脸部到视频上方的距离
                if imgComposeSizeH > (y0 - 20):
                    imgComposeSizeH = (y0 - 20)
                # 将帽子的图片归一化到适合的宽和高大小,宽度为人脸的宽度,高度为上面调整后的帽子高度
                imgComposeSize = cv2.resize(img_hat, (width_face, imgComposeSizeH), interpolation=cv2.INTER_NEAREST)
                # 为了实现在人脸上方的额头,添加兔子帽子特效,只需要将兔子帽子贴到额头处即可
                # 注意:y0是人脸检测框左上方顶点的y坐标,y0-20,则差不多定位到额头处,再减去imgComposeSizeH,调整后兔子帽子的高度
                #      即从这个位置开始贴合兔子帽子,可以实现人脸帽子特效
                top = (y0 - 20 - imgComposeSizeH)
                # 当人脸太靠近图片上方,通过前一行的计算,有可能为负数,所以当出现这样的情况时,top设置为0
                if top <= 0:
                    top = 0
                # 获得调整尺寸后,帽子新的高height_hat_new,新的宽width_hat_new
                height_hat_new, width_hat_new = imgComposeSize.shape[0], imgComposeSize.shape[1]
                # 将额头上方,对应的帽子区域截取出来
                # 注意:通常从大图中抠取小图的方式,比如待截取小图的坐标是[x0,y0,x1,y1],则使用img[y0:y1,x0:x1即可]即可。
                small_img_hat = frame[top:top + height_hat_new, x0:x0 + width_hat_new]
                # 如需查看,上一行的效果,可将cv2.imwrite前面的#取消,运行后,保存到本目录查看
                cv2.imwrite("1.jpg",small_img_hat)
                # 将帽子图像,从RGB彩色图像转换为灰度图像
                small_img_hat_gray = cv2.cvtColor(imgComposeSize, cv2.COLOR_RGB2GRAY)
                # 如需查看,上一行的效果,可将cv2.imwrite前面的#取消,运行后,保存到本目录查看
                cv2.imwrite("2.jpg", small_img_hat_gray)
                # 阈值化处理,将10<像素<255区间的图像抠出来
                # 因为背景为黑色,所以阈值设置10到255,即可将帽子区域提取出来
                ret, mask_hat = cv2.threshold(small_img_hat_gray, 10, 255, cv2.THRESH_BINARY)
                # 如需查看,上一行的效果,可将cv2.imwrite前面的#取消,运行后,保存到本目录查看
                cv2.imwrite("3.jpg", mask_hat)
                # 使用取反操作,将帽子的图像从黑色0变为白色255,将白色255变成黑色0
                mask_hat_inv = cv2.bitwise_not(mask_hat)
                # 如需查看,上一行的效果,可将cv2.imwrite前面的#取消,运行后,保存到本目录查看
                cv2.imwrite("4.jpg", mask_hat_inv)
                # 使用按位与操作,将抠出的帽子区域和取反后的帽子图像相加
                img1_bg = cv2.bitwise_and(small_img_hat, small_img_hat, mask=mask_hat_inv)
                # 如需查看,上一行的效果,可将cv2.imwrite前面的#取消,运行后,保存到本目录查看
                cv2.imwrite("5.jpg", img1_bg)
                # 使用按位与操作,将像素值在[10,255]之间的帽子RGB区域抠取出来
                img2_fg = cv2.bitwise_and(imgComposeSize, imgComposeSize, mask=mask_hat)
                # 如需查看,上一行的效果,可将cv2.imwrite前面的#取消,运行后,保存到本目录查看
                cv2.imwrite("6.jpg", img2_fg)
                # 将img1_bg和img2_fg相加,等于戴了帽子的区域图像
                dst = cv2.add(img1_bg, img2_fg)
                # 如需查看,上一行的效果,可将cv2.imwrite前面的#取消,运行后,保存到本目录查看
                cv2.imwrite("7.jpg", dst)
                # 将带了帽子的局部区域,贴合到原始图像上
                frame[top:top + height_hat_new, x0:x0 + width_hat_new] = dst
                # 如需查看,上一行的效果,可将cv2.imwrite前面的#取消,运行后,保存到本目录查看
                # cv2.imwrite("8.jpg", img)

        # 很多时候,图片的长宽太大,屏幕显示不全
        # 为了便于查看图片,可以将图片的大小,缩放到某一尺寸,比如(800,600),即宽800像素,高600像素
        img = cv2.resize(frame, (800, 600))
        # 显示图片
        cv2.imshow("image", img)
        # 显示图片停顿的时间,如果是0,则一直显示。如果是100,则显示100ms
        cv2.waitKey(10)
# 函数主入口if __name__ == '__main__':
    # 新建一个解析器
    parser = argparse.ArgumentParser()
    # 为解析器添加选项,比如image_path,添加图片地址,可以更换其他图片尝试。(在default后面,添加需要读取的图片路径)
    # 注意:不同的图片,宽高大小可能不同,大家可以根据自己的图片比例,调试前面的的cv2.resize中的数值,修改显示窗口的大小。
    parser.add_argument('--video_path', default="video.mov", help='path of read vedio')
    # 为解析器添加选项,比如hat_path,添加帽子图片地址。(在default后面,添加需要读取的帽子图片路径)
    parser.add_argument('--hat_path', default="maozi.png", help='path of hat image')
    # 解析选项的参数
    opt = parser.parse_args()
    # 调用hat_face函数,对人脸进行检测,添加兔子帽子特效
    hat_face(opt)

效果如下:

整个兔耳朵帽子特效的流程拆解

(1)读取兔耳朵帽子图片和要加特性的原视频。

(2)检测每帧视频中人脸(这里是每10帧读取一次,这样运行比较快),进行人脸特征点定位。

(3)然后基本步骤和对图像添加兔耳帽子的特效一样,先将帽子的宽度高度变成适合检测到的脸型的大小,然后将兔子帽子贴到额头处即可。

具体通过把额头上对应的帽子区域截取出来、把帽子图片转为灰度图、二值化处理、再取反、把取反后的帽子图片和截取的帽子图片按位与、按位与操作把原来帽子为彩色的区域(这里设为像素值>=10)抠取出来、把前面两个按位与的图片按位相加得到新图,最后把这个新图赋值给对应的原图区域。

(4)对于人脸特效的处理,第一步都是先检测人脸,然后根据人脸调整处理特效图片,再把人脸和特效图片贴合,通过抠图、二值化、取反、按位与、按位加等基础操作完成,最后将原图的对应区域替换成特效图片。

我终于初步体会和理解了opencv的强悍和完善,只需要人脸检测模型的配合,就能做出这么多好看的特效,对抖音快手等app里面特效功能的原理有了初步了解啦,果然是cv领域必备技能啊。

CVPR500+篇论文已打包🚀🚀🚀

关注下方《学姐带你玩AI》回复“CVPR”领取

码字不易,欢迎大家点赞评论收藏!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/179414.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JavaEE-初识网络

目录一、局域网二、广域网三、网络通信基础3.1 IP地址3.2 端口号3.3 协议四、协议分层五、封装和分用一、局域网 局域网&#xff0c;网络种类&#xff0c;覆盖范围一般是方圆几千米之内&#xff0c;其具备的安装便捷、成本节约、扩展方便等特点使其在各类办公室内运用广泛。局…

有序列表标签与无序列表标签

<!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title></title> </head> <body bgcolor"bisque"> <!-- 在ol有序列表标签和ul无序列表标签…

【初识数据库】进入数据库的大门+数据库基本操作

前言&#xff1a; 大家好&#xff0c;我是良辰丫&#x1f353;&#x1f353;&#x1f353;&#xff0c;这个专栏我将带领大家去探索数据库的汪洋大海&#xff0c;我主要使用的数据库软件是MySQL&#xff0c;数据库软件大同小异&#xff0c;嘿嘿嘿&#xff0c;废话不多说&#x…

分布式事务Seata学习笔记

目录 1.Seata 是什么 2. Seata快速开始 2.1 Seata Server&#xff08;TC&#xff09;环境搭建 db存储模式Nacos(注册&配置中心)部署 3. Seata Client快速开始 4.demo源码:springcloudAlibaba: Alibaba微服务学习demo 1.Seata 是什么 Seata 是一款开源的分布式事务…

神级程序员上网都在看什么?

同样都是上网&#xff0c;为什么大神总能在最短时间内汲取最有效的信息呢&#xff1f; 不怕大神不上网&#xff0c;就怕大神上网比你精&#xff01;其实&#xff0c;你与大神的区别都藏在细节中。 这些神级网站都是我偷看他们电脑抄来的&#xff08;误&#xff09;&#xff0c;…

超链接(还称热连接)标签

<!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title>超链接(还称热连接)</title> </head> <body> <!-- 超链接的特点&#xff1a; 1、有…

Python内置函数

5.6 Python内置函数 Python自带的所有内置函数如下&#xff1a; Python函数 以上为Python3.10中所有的内置函数&#xff0c;其中绝大部分在前面的学习当中都已经接触过了。这里在补充介绍下没有提到或学习到的函数。 5.6.1 callable(object) 描述 如果参数 object 是可调…

Java面试题,mysql相关基础问题(全是自己的总结,如有不对,敬请斧正)

mysql相关基础问题一、mysql中int类型单引号问题二、静态SQL与动态SQL1. 静态SQL2. 动态SQL3. 动态SQL与静态SQL的区别与联系一、mysql中int类型单引号问题 今天写mysql的时候发现了一个问题&#xff0c;在查询的时候不小心把int类型的id加上引号查询了&#xff0c;但是也能查…

Day08 C++STL入门基础知识五——vector容器(下) 插入删除-数据存取-交换容器-预留空间【全面深度剖析+例题代码展示】

More haste, less speed. 欲速则不达 文章目录1. 承接上文2. 插入操作2.1 函数原型(总括)2.2 尾插尾删2.2.1 操作2.2.2 代码展示2.2.3 测试结果2.3 迭代器插入2.3.1 操作2.3.2 代码展示2.3.3 测试结果2.4 think小思考2.4.1 小疑问2.4.2 思路2.4.3 代码展示2.4.4 测试结果3. 删除…

数据结构---堆

堆 定义 基本操作 建堆 堆排序 优先队列 一、堆的定义&#xff1a; 堆必须是一个完全二叉树 还得满足堆序性 什么是完全二叉树呢&#xff1f; 完全二叉树只允许最后一行不为满 且最后一行必须从左到右排序 最后一行元素之间不可有间隔&#xff0c;中间不可有空缺 如下几棵树…

CSS基础学习

HTMLCSSJavaScript 结构表现交互 学习内容&#xff1a; CSS是什么CSS怎么用&#xff08;快速入门&#xff09;CSS选择器&#xff08;重点难点&#xff09;美化网页&#xff08;文字&#xff0c;阴影&#xff0c;超链接&#xff0c;列表&#xff0c;渐变…&#xff09;盒子模型…

基于电压型磁链观测器的异步电机矢量控制学习

导读&#xff1a;本期主要介绍电压型磁链观测器&#xff08;voltage flux observer&#xff09;在静止坐标系下的表现形式&#xff0c;应用在异步电机矢量控制系统中。如需要文中的仿真模型&#xff0c;关注微信公众号&#xff1a;浅谈电机控制&#xff0c;获取。一、引言磁链估…

万字长文--详解Node.js(快速入门)

Node.js基础与扩展Node.js1、初识Node.js与内置模块1.1 Node.js初识1.2 fs文件系统模块1.3 path路径模块1.4 http模块2、模块化2.1 模块化的基本概念2.2 Node.js中模块化2.3 npm与包2.4 模块的加载机制3、Express3.1 初识Express3.2 Express路由3.3 Express中间件3.4 使用Expre…

LeetCode刷题复盘笔记—一文搞懂贪心算法之45. 跳跃游戏 II问题(贪心算法系列第五篇)

今日主要总结一下可以使用贪心算法解决的一道题目&#xff0c;45. 跳跃游戏 II 题目&#xff1a;45. 跳跃游戏 II Leetcode题目地址 题目描述&#xff1a; 给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]。 每个元素 nums[i] 表示从索引 i 向前跳转的最大长度…

论文投稿指南——中文核心期刊推荐(铁路运输)

【前言】 &#x1f680; 想发论文怎么办&#xff1f;手把手教你论文如何投稿&#xff01;那么&#xff0c;首先要搞懂投稿目标——论文期刊 &#x1f384; 在期刊论文的分布中&#xff0c;存在一种普遍现象&#xff1a;即对于某一特定的学科或专业来说&#xff0c;少数期刊所含…

Windows卸载与清除工具“ Geek 与 CCleaner ” (带你快速了解)

&#x1f4dc; “作者 久绊A” 专注记录自己所整理的Java、web、sql等&#xff0c;IT技术干货、学习经验、面试资料、刷题记录&#xff0c;以及遇到的问题和解决方案&#xff0c;记录自己成长的点滴。 &#x1f341; 操作系统【带你快速了解】对于电脑来说&#xff0c;如果说…

什么是闭包,Python闭包

闭包&#xff0c;又称闭包函数或者闭合函数&#xff0c;其实和前面讲的嵌套函数类似&#xff0c;不同之处在于&#xff0c;闭包中外部函数返回的不是一个具体的值&#xff0c;而是一个函数。一般情况下&#xff0c;返回的函数会赋值给一个变量&#xff0c;这个变量可以在后面被…

剑指 Offer 第5天、第6天

目录 剑指 Offer 04. 二维数组中的查找 剑指 Offer 50. 第一个只出现一次的字符 剑指 Offer 11. 旋转数组的最小数字 剑指 Offer 32 - I. 从上到下打印二叉树 剑指 Offer 32 - II. 从上到下打印二叉树 II 剑指 Offer 32 - III. 从上到下打印二叉树 III 剑指 Offer 04. 二…

Java线程池应用实例

线程池的学习基本概念好处应用场景ThreadPoolExecutor实例理解&#xff1a;执行流程自定义线程池4大核心参数测试demo结论&#xff1a;ExecutorService常用方法思考获取ExecutorService代码示例ScheduleExecutorService常用获取方式如下ScheduledExecutorService常用方法如下:代…

Linux | 一文带你真正搞懂Linux中的权限问题

在Linux下你有多少权限呢❓一、权限的基本概念二、Linux上的用户分类2.1 超级用户与普通用户2.2 用户之间的切换2.3 文件访问者的分类2.4 用户与访问者之间的联系三、文件属性与访问权限3.1 Linux下的文件类型&#xff08;1&#xff09;文件的八种类型&#xff08;2&#xff09…