android 美颜大眼特效

需要知识点,从相机抓取到数据,给opencv进行人脸定位,再用SeetaFaceEngine眼睛的定位,然后渲染的时候在片元着色器中进行计算,对眼睛进行局部放大;

1.开始集成opencv

opencv官网地址:Releases - OpenCV

下载Android 版本:

把已经编译号的库放到我们项目中

把整个头文件放到项目中

 把训练的人脸模板放到项目中:

 

 最后在app build.gradle中添加opencv的相关配置:

        externalNativeBuild {
            cmake {
                //OpenCV新版本用这个C++11的特效
                cppFlags "-std=c++11"
                //NDK从r16开始就切换到了llvm的libC++,所以opencv4从libstdC++切换到了libc++。
                //导致链接错误的根本原因是设置了-DANDRID_STL=gnustl_shared,
                //因为opencv利用的libc++编的,而非gnustl
                //arguments "-DANDROID_STL=gnustl_static" // OpenCV旧版本用这个
                //新版本的opencv 需要添加这个变量
                arguments "-DANDROID_STL=c++_shared"
                abiFilters 'armeabi-v7a'
            }
        }

 在CmakeLists中配置:


cmake_minimum_required(VERSION 3.4.1)

#opencv 头文件
include_directories(include)

#opencv 库文件
set(CMAKE_CXX_FLAGS  "${CMAKE_CXX_FLAGS}")

add_library( # Sets the name of the library.
        native-lib
        SHARED
        native-lib.cpp)

target_link_libraries( # Specifies the target library.
        native-lib
        #链接opencv,也就是libopencv_java4
        opencv_java4
        )

人脸关键点定位使用中科院开源的

https://github.com/seetaface/SeetaFaceEngine

集成到项目中:

 

把model中的模板放到项目中:

 修改CMakeList:

# 他需要用到 C++11特性
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
# 设置他需要的参数
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2")
# 设置他需要的参数
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -msse4.1")
# 导入头文件
include_directories(include)

set(src_files # CPP源码关联
        src/cfan.cpp
        src/face_alignment.cpp
        src/sift.cpp
        )
# 生成静态库
add_library(seeta_fa_lib STATIC ${src_files})

 在总的CMakeList中引入

结合前面的音视频录制,把数据给opencv 定位出人脸,再给SeetaFace去定位眼睛的关键点,然后传给着色器,

FaceTrack.cpp  中处理人脸定位,关键点定位

初始化opencv追踪器,及seeta关键点

FaceTrack::FaceTrack(const char *model, const char *seet) {
        Ptr<CascadeDetectorAdapter> mainDetector = makePtr<CascadeDetectorAdapter>(makePtr<CascadeClassifier>(model)); // OpenCV主探测器
    Ptr<CascadeDetectorAdapter> trackingDetector = makePtr<CascadeDetectorAdapter>(makePtr<CascadeClassifier>(model)); // OpenCV跟踪探测器
    DetectionBasedTracker::Parameters detectorParams;
    // OpenCV创建追踪器,为了下面的(开始跟踪,停止跟踪)
    tracker = makePtr<DetectionBasedTracker>(mainDetector, trackingDetector, detectorParams);

    // 上面是OpenCV模板代码人脸追踪区域, 下面是Seeta人脸关键点代码+OpenCV
    faceAlignment = makePtr<seeta::FaceAlignment>(seet); // Seeta中科院关键特征点
}

获取关键点

void FaceTrack::detector(Mat src, vector <Rect2f> &rects) {
    vector<Rect> faces;
    // src :灰度图(去除 不需要的色彩信息)
    tracker->process(src); // 处理灰度图(OpenCV的东西,灰度,色彩 影响我们人脸追踪)
    tracker->getObjects(faces); // 得到人脸框框的Rect - OpenCV的东西
    if (faces.size()) { // 判断true,说明非零,有人脸
        Rect face = faces[0]; // 有人脸就去第一个人脸,我没有去管,多个人脸了哦
        // 然后把跟踪出来的这个人脸,保存到rects里面去
        rects.push_back(Rect2f(face.x, face.y, face.width, face.height));

        // 根据前面的OpenCV人脸最终结果, 做人脸关键点定位
        seeta::ImageData image_data(src.cols, src.rows); // image_data就是图像数据
        image_data.data = src.data; // (人脸的信息 要送去检测的) = (把待检测图像)

        // 人脸追踪框 信息绑定  人脸关键点定位
        seeta::FaceInfo face_info; // 人脸的信息 要送去检测的
        seeta::Rect bbox; // 人脸框框的信息
        bbox.x = face.x;           // 把人脸信息的x 给 face_info
        bbox.y = face.y;           // 把人脸信息的y 给 face_info
        bbox.width = face.width;   // 把人脸信息的width 给 face_info
        bbox.height = face.height; // 把人脸信息的height 给 face_info
        face_info.bbox = bbox;     // 把人脸信息的bbox 给 face_info

        seeta::FacialLandmark points[5]; // 特征点的检测,固定了5个点

        // 执行采集出 五个点
        faceAlignment->PointDetectLandmarks(image_data, face_info, points);

        // 把五个点 转换 ,因为第二个参数需要 Rect2f
        for (int i = 0; i < 5; ++i) { // 为何不需要宽和高,只需要保存点就够了
            rects.push_back(Rect2f(points[i].x, points[i].y, 0, 0));
        }
    }
}

大眼算法见:http://www.gson.org/thesis/warping-thesis.pdf

代码地址:Seven: Android音视频

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值