上一篇文章描述了在ndk环境下编译opencv JNI用于简单的图像处理的流程。本篇文章主要讲述在Android环境下基于opencv + dlib 进行人脸68个特征点提取。
分别下载dlib库和opencv库,网站如下:
http://dlib.net/files/
opencv的下载请参照上篇文章。
java层代码如下:
public class FaceActivity extends AppCompatActivity implements CameraBridgeViewBase.CvCameraViewListener2 {
private JavaCameraView cameraView;
private Mat rgba;
static {
System.loadLibrary(“opencv_java3”);
System.loadLibrary(“native-lib”);
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE); //设置无标题
// getWindow().setFlags(WindowManager.LayoutParams.FILL_PARENT, WindowManager.LayoutParams.FILL_PARENT); //设置全屏
setContentView(R.layout.activity_face);
cameraView = findViewById(R.id.javaCameraView);
cameraView.setCvCameraViewListener(this);
faceinit();
}
public void onCameraViewStarted(int width, int height) {
//定义Mat对象
rgba = new Mat(width, height, CvType.CV_8UC3);
}
public void onCameraViewStopped() {
rgba.release();
}
public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {
rgba = inputFrame.rgba();
//得到当前一帧图像的内存地址
long addr = rgba.getNativeObjAddr();
//对一帧图像进行处理
nativeRgba(addr);
//得到一帧灰度图
// rgba = inputFrame.gray();
return rgba;
}
@Override
protected void onResume() {
super.onResume();
if (!OpenCVLoader.initDebug()) {
} else {
cameraView.enableView();
}
}
@Override
protected void onPause() {
super.onPause();
if (cameraView != null) {
cameraView.disableView();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (cameraView != null) {
cameraView.disableView();
}
}
public static native void nativeRgba(long jrgba);
public static native void faceinit();
}
8. jni层代码如下:
9.
extern “C” float getDistance(CvPoint pointO, CvPoint pointA)
{
float distance;
distance = powf((pointO.x - pointA.x), 2) + powf((pointO.y - pointA.y), 2);
distance = sqrtf(distance);
return distance;
}
extern “C” JNIEXPORT void JNICALL Java_com_facetest_FaceActivity_faceinit(
JNIEnv *env, jclass obj){
LOGD("------------JNI to nativeRgba 1 ");
deserialize("/sdcard/shape_predictor_68_face_landmarks.dat") >> pose_model;
detector = get_frontal_face_detector();
}
extern “C” JNIEXPORT void JNICALL Java_com_facetest_FaceActivity_nativeRgba(
JNIEnv *env, jclass obj, jlong jrgba)
{
Mat &img = *(Mat*)jrgba;
Mat out;
int A = 0,B = 0,C = 0;
// cvtColor(img,out,COLOR_RGBA2GRAY);
clock_t t1 = 0,t2 = 0;
dlib::array2d arrimg(img.rows, img.cols);
for(int i=0; i < img.rows; i++)
{
for(int j=0; j < img.cols; j++)
{
arrimg[i][j].blue = img.at< cv::Vec3b>(i,j)[0];
arrimg[i][j].green=img.at< cv::Vec3b>(i,j)[1];
arrimg[i][j].red = img.at< cv::Vec3b>(i,j)[2];
}
}
t1 = clock();
std::vector faces= detector(arrimg);
t2 = clock();
std::vector shapes;
for (unsigned long i = 0; i < faces.size(); ++i)
shapes.push_back(pose_model(arrimg, faces[i]));
if (!shapes.empty()) {
for (int i = 0; i < 68; i++) {
circle(img, cvPoint(shapes[0].part(i).x(), shapes[0].part(i).y()), 3, cv::Scalar(0, 0,255), -1);
}
//用于计算眼宽比
A = getDistance(Point(shapes[0].part(37).x(),shapes[0].part(37).y()),Point(shapes[0].part(41).x(),shapes[0].part(41).y()));
B = getDistance(Point(shapes[0].part(38).x(),shapes[0].part(38).y()),Point(shapes[0].part(40).x(),shapes[0].part(40).y()));
C = getDistance(Point(shapes[0].part(36).x(),shapes[0].part(36).y()),Point(shapes[0].part(39).x(),shapes[0].part(39).y()));
char temp[32] = {0 };
sprintf(temp,"rightEye:%f time: %lu",((A+B)/(C*2.0)),(t2-t1));
putText(img, temp, Point(10,30), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 0, 0, 255));
}