接下来的目标就是将这些坐标抽取到OpenGL项目中了。作为landmarks,输入进来。
当然,这一点也可以先不做,可以先找到人像部位对应的位置。
landmarks信息传入之后。
3.5 OpenFace索引解析
在网上搜索资料,终于找到了这一部分的点:
传入pixel中:
发现不太行,之前的这个是归一化过的。
得归一化才可以。
但不知道这个归一化原则是什么,按照最小值和最大值进行归一化试试。
发现不太行。
描点描的非常散乱。
按照图像宽度和高度归一化后,就成功了。
但是OpenGL渲染出来的图像还是不太行。
3.6 OpenGL渲染问题修复
现在渲染不出来的原因是关键点没了,但是关键点没了具体是怎么让OpenGL失能的,我也是不太清楚的。目前的主要矛盾到底是不是这个?
关键点补全了,是否能渲染齐全呢,我再试试。
是可以的。
那也就是意味着:
OpenGL渲染是依据着landmarks数据进行渲染的。
而我们之前有结论:
几种美颜滤镜是依据着landmarks的数据进行处理的,美颜滤镜会把最终的版本送给GLFW库让其渲染。
由此我们得出结论:
OpenGL渲染不出来的原因是因为滤镜给不出来最终答案。
所以主要矛盾还是在滤镜答案的给出上。修复滤镜成了重中之重。
如何进行滤镜的修复?
弄明白滤镜是如何拿着这些点进行“美颜的”,验证能否用68个点来实现滤镜的美化。
如何弄明白滤镜是如何拿这些点美颜的呢?
就得先框定滤镜代码的范围,明白每一部分的代码是什么意思,是怎么工作起来的原理。
3.6.1 美颜滤镜代码的范围
首先在app.cc部分创建了滤镜实例:
这段代码是滤镜实例。
4个滤镜就是4个对象:
是个派生类,派生自FaceMakeupFilter父类。继承create、而init进行了一个重写。这段代码的主要意图在于声明一个对象,是没有具体的实现的。
接下来看看create。
这段代码是create静态成员函数的实现。该函数试图创建一个LipstickFilter实例,并返回一个指向该实例的指针。接下来调用init方法来初始化这个实例。如果初始化失败,则调用reset函数来释放这个智能指针所管理的对象,使其变成nullptr。最后,返回这个智能指针。
接下来就是init函数了。
1,首先通过create创建了一个mouth图像的实例对象,并将这个智能指针传给了mouth变量,此时mouth具有了那个图像的纹理数据(宽度、高度、通道数、像素信息)。
2,然后再把这个纹理数据给了全局变量,这个时候大家都能访问了。
3,以下代码设置了纹理在人脸上的应用区域。
其中frambounds是个结构体:
用来定义坐标和长宽。然后传入到全局变量中:
4,最后调用了基类的初始化函数:
(1)先初始化顶点着色器、再初始化片段着色器。
(2)再设置关键的参数和引用,这些都是渲染时所用到的。
(3)设置滤镜的强度信息;
(4)设置关键点信息。
这样就初始化完一个滤镜了。
之后这些滤镜应用关键点信息。
这一步很关键了,landmarks进来之后。这些滤镜修改了哪些数据?
进来之后,存储在了这个位置:
这儿打印一下试试水。
是136...我看看landmarks是多少吧。
他也是136。不过确实是136. 68*2可不就等于136吗。这没毛病。
这个回调函数的作用就是让每个滤镜都能获取关键点数据。
之后就应用这个函数对图像进行一个应用了。
gpuSourceImage是图像处理的起点,接下来深入到内部看一看。
最后发现,是这个函数进行的处理。
就是它进行的更新。
在这其中:
这一步将切换到专门用于美妆效果的渲染程序。传入的参数是之前通过顶点和片段着色器初始化的,专门用于处理美妆效果。然后将然后将landmarks作为顶点位置信息,这些关键点数据在SetFaceLandmarks方法中已经被转换和存储。通过glVertexAttribPointer将这些顶点位置信息传递给GPU,这些位置信息将决定美妆效果被应用的具体位置。
faceTextureCoordinates方法提供了美妆效果纹理的坐标,这些坐标基于面部关键点进行了调整,以确保美妆纹理正确映射到面部的特定区域(如嘴唇或眼睛周围)。
打印一下coord看是不是136个点。
答案不是:
是222个点,这意味着,使用的111个点版本的,而不是222个点的版本的。
打印了这个东西,发现OpenGL是按照这个来打印的。
这个坐标是按着这个来的:
现在弄清楚这些坐标是什么玩意儿,为什么有了landmarks,还有这个纹理坐标呢?
面部关键点(landmarks):这些是从面部检测算法得到的,标识了面部的特定特征点位置,比如眼睛、鼻子、嘴巴的轮廓等。这些关键点用于确定美妆效果应该被应用到图像的哪些具体位置上。
faceTextureCoordinates提供的一组纹理坐标,用于控制美妆纹理在面部的具体投影方式。
那现在就得重新调整这部分纹理坐标了。
暂时将landmarks放上去了。现在都一样了。
然后
这一步进行一个绑定并应用。
之后进入这段代码:
auto face_indexs = this->getFaceIndexs();这行代码调用了getFaceIndexs函数,获取一个包含面部数据索引的数组。这些索引定义了如何将关键点连接起来形成多个三角形,这些三角形最终构成了整个面部的网格模型。
关键核心就是face_indexs.data(),这部分代码。
得把它改一下。
手动加完之后,再试试。
还是不太行。
那这个问题就得仔细琢磨琢磨了。
可能的问题:
(1)片段着色器可能返回了高红色和绿色分量、低蓝色分量的颜色。这可能是混合函数逻辑的结果。fgColor.a(在片段着色器中的alpha通道)可能存在问题。如果alpha始终为0,bgColor可能没有正确与前景色混合。
(2)纹理可能没有正确绑定,这可能意味着inputImageTexture2(嘴唇纹理)没有被正确采样。
(3)传递给着色器的纹理坐标或顶点可能存在问题。像intensity和blendMode这样的uniform变量可能设置不正确,导致意外的混合结果。
接下来的两条路:
插值、或者改底层代码。
插值这条路线还是最简单的。还是这么来吧。
3.6.2 插值路线
这条路线要怎么走呢?
第一步,先恢复之前的正常代码吧。恢复完成之后。
下一步选择一张差异大点的图片然后将VNN的landmarks保存下来,识别每一个点的含义,然后用这个材料插值到Openface生成的这个landmarks里面去。
眉毛的地方,有差距,还有脸的位置。既然如此。
然后开始识别之前每一个点的意思和现在每一个点的意思。
先看看能不能用Opencv给每个点打一个标号。
这是Openface。
再看看VNN。
然后将VNN的值输出出来。
已获得。
接下来开始插值。核心思路是将VNN的部分值用OpenFace代替。
插完值后运行,有一个不太好的结果。
我总感觉人脸识别失败了。
我先尝试下原始的数据试试。
原始的数据是正常的:
那也就意味着,只要重新编译了,这个图像识别的数据就已经定死了。
问题还是出在插值上,插值有问题。
这样,先将原有的landmarks的数值插进去试试。
有问题。
并且打印出来的这个值也对不上。
这绝对是把皇军给我的数据都吃了回扣了!!!!!
这个landmarks值出来的不太对。
我发现这些数据大有玄机。
Tmd,数值重复了!!!
清澈多了。
再换上试试。
这......是数量出问题了,重新打印后,恢复正常了。
到此为止。重新插值。
然后创建两个文件夹。分别是插值前和插值后效果展示。
去除掉OpenGL界面,转换成图片输出的形式。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。