当前位置: 首页 > news >正文

opencv进阶 ——(十三)基于三角剖分实现换脸

 换脸的关键在于人脸对齐,人脸对齐主要包括以下几点:

1、人脸可能存在一定的角度,因此需要先将倾斜方向进行对齐

2、大小对齐,将模板人脸的大小缩放到同一大小

3、要想有好的效果,关键点选取很重要

4、人脸对齐后,使用seamlessClone函数可以最大化的融合,还可以通过addWeighted函数进行调节比例,让图像看起来更自然。

人脸融合实现

cv::Mat FusionFace(const cv::Mat& srcImg, const cv::Rect& srcBox, const cv::Mat& destImg, const cv::Rect &destBox, std::vector<cv::Point>& vecDstPointRoi)
{auto destFace = destImg(destBox);cv::Mat destAlignFace;cv::resize(destFace, destAlignFace, srcBox.size());std::cout << "srcBox:" << srcBox << std::endl;auto center = (srcBox.br() + srcBox.tl())/2 ;std::vector<cv::Point> vecDstPointKey = vecDstPointRoi;vecDstPointKey.erase(vecDstPointKey.begin() + vecDstPointKey.size() - 8, vecDstPointKey.end());//获取旋转矩阵掩码auto rotateRect = cv::minAreaRect(vecDstPointKey);cv::Point2f pot[4];rotateRect.points(pot);std::vector<cv::Point> rotatePoints{pot[0], pot[1], pot[2], pot[3]};cv::Mat maskRect(srcBox.size(), CV_8UC1, cv::Scalar(0));cv::fillConvexPoly(maskRect, rotatePoints, cv::Scalar(255));//获取圆形掩码cv::Mat maskCicle(srcBox.size(), CV_8UC1, cv::Scalar(0));float radius = std::min(rotateRect.size.width, rotateRect.size.height);cv::circle(maskCicle, rotateRect.center, radius, cv::Scalar(255), -1);//去并集,最小化掩码区域cv::Mat maskArea(srcBox.size(), CV_8UC1, cv::Scalar(0));cv::bitwise_and(maskRect, maskCicle, maskArea);cv::Mat tmpDestImg;cv::Mat srcRoi = srcImg(srcBox);cv::seamlessClone(destAlignFace, srcImg, maskArea, center, tmpDestImg, cv::NORMAL_CLONE);//图像增强return FaceEnhance(srcBox, tmpDestImg, srcImg, vecDstPointKey);
}

融合效果

对图像进行增强后的效果

相关文章:

  • Unity【入门】重要组件和API
  • AIGC的算力与云边协同及应用创新
  • 笔记 | 软件工程04:软件项目管理
  • 收银系统源码-千呼新零售2.0【合作案例】
  • 【Spring Cloud】Feign详细介绍及底层原理解析
  • 深度学习_02_卷积神经网络循环神经网络
  • 【加密与解密】【01】网络安全体系
  • 修改west扩展命令的路径
  • Unity DOTS技术(二)ECS
  • Nginx通过转发代理解决跨域问题
  • Matlab 2024a 建模基础知识全面指南
  • ArrayList——简单洗牌算法
  • uni-app基础框架搭建(vue3+ts+vite)
  • 【杂记-浅谈Internet、Intranet、Extranet】
  • 抖音素材网站有哪些?抖音素材下载网站分享
  • python3.6+scrapy+mysql 爬虫实战
  • “大数据应用场景”之隔壁老王(连载四)
  • Android开源项目规范总结
  • CentOS从零开始部署Nodejs项目
  • CoolViewPager:即刻刷新,自定义边缘效果颜色,双向自动循环,内置垂直切换效果,想要的都在这里...
  • JavaScript学习总结——原型
  • Leetcode 27 Remove Element
  • Traffic-Sign Detection and Classification in the Wild 论文笔记
  • V4L2视频输入框架概述
  • VirtualBox 安装过程中出现 Running VMs found 错误的解决过程
  • 复杂数据处理
  • 构建工具 - 收藏集 - 掘金
  • 使用Envoy 作Sidecar Proxy的微服务模式-4.Prometheus的指标收集
  • 我有几个粽子,和一个故事
  • 协程
  • CMake 入门1/5:基于阿里云 ECS搭建体验环境
  • # MySQL server 层和存储引擎层是怎么交互数据的?
  • (1)无线电失控保护(二)
  • (BAT向)Java岗常问高频面试汇总:MyBatis 微服务 Spring 分布式 MySQL等(1)
  • (delphi11最新学习资料) Object Pascal 学习笔记---第8章第2节(共同的基类)
  • (ibm)Java 语言的 XPath API
  • (Spark3.2.0)Spark SQL 初探: 使用大数据分析2000万KF数据
  • (顺序)容器的好伴侣 --- 容器适配器
  • (四)模仿学习-完成后台管理页面查询
  • (算法二)滑动窗口
  • (转)JAVA中的堆栈
  • (转)shell中括号的特殊用法 linux if多条件判断
  • (转)visual stdio 书签功能介绍
  • (转)德国人的记事本
  • ****三次握手和四次挥手
  • ***通过什么方式***网吧
  • ***原理与防范
  • .bat文件调用java类的main方法
  • .NET Core工程编译事件$(TargetDir)变量为空引发的思考
  • .NET LINQ 通常分 Syntax Query 和Syntax Method
  • .Net OpenCVSharp生成灰度图和二值图
  • .NET 设计一套高性能的弱事件机制
  • .NET 中的轻量级线程安全
  • .NET 中小心嵌套等待的 Task,它可能会耗尽你线程池的现有资源,出现类似死锁的情况
  • ??如何把JavaScript脚本中的参数传到java代码段中