科大讯飞开发者平台上对外开放了语音和人脸识别的SDK。现在分享的人脸识别功能。

  讯飞人脸识别的demo中有的在线人脸识别、离线人脸识别和视频检测三个功能。为了更好的理解,我就简单介绍这三个功能的作用。

  人脸识别:主要的功能有人脸注册、人脸检测和人脸验证。在线和离线只是实现的方式不一样,其作用都一样的。

  视频检测:就是开启摄像头,检测摄像头的画面是否是一个人脸。 

  对于这三个功能在它的demo中都很详细,这里就不多说。我现在分享的是先用视频检测功能获取到摄像头数据(某一帧的数据),然后用这张数据去进行人脸识别。

步骤1.集成SDK(见讯飞官方Doc)。

  在看文档时,我并没有看到讯飞给开发者提供的返回的json格式。所以为了偷懒,可以将FaceRect、FaceUtil和ParseResult类拷过来(可以自己打印后解析)。

步骤2.拷贝FaceRect、FaceUtil和ParseResult类到自己的工程里。

步骤3.具体实现;假设已经成功完成了步骤1和步骤2。

  新建一个PreviewActivity用来预览和实现验证功能。这个PreviewActivity的代码大部分都是来自讯飞FaceDemo的com.iflytek.facedemo.VideoDemo类,因为这个类实现了预览和人脸检测功能,这里只需要加上验证功能就可以了。验证有在线和离线,这里就说下在线验证的了。在线验证是要借助com.iflytek.cloud.FaceRequest这个类。照着文档建一个FaceRequest,mFaceRequest = new FaceRequest(this);设置参数之后调用mFaceRequest.sendRequest(mImageData, mRequestListener)就可以了。

  那个这个参数要设置什么参数呢?人脸注册和其他功能需要的参数都不一样(详情见官方文档),但是都需要一个保存了图片数据的byte[]数组。这篇博客最主要的分享的也是怎

么样来获取这个byte[]。

  细心的人也许很容易发现我们在设置相机callback时(mCamera.setPreviewCallback()),可以在onPreviewFrame()回调中获取到一个byte[],但是,这真的是我们需要的那个数

据吗?没错,这个数据确实是相机一帧的数据。但是如果尝试用这个数据来进行处理的话(人脸注册或是验证),你会发现并没有成功,再尝试用这个数据去转成bitmap的话,返

回的null。问题又是在哪呢?

  不要急,答案马上揭晓。我们再留意一下相机的设置。

                     

Parameters params=mCamera.getParameters();
                         params.setPreviewFormat(ImageFormat.NV21);
                         params.setPreviewSize(PREVIEW_WIDTH,PREVIEW_HEIGHT);
                        mCamera.setParameters(params);

发现什么了吗?是的,我们现在采集到的一帧的格式是NV21的,并不是RGB或者ARGB。

  问题已经出来了,那么只要将NV21的数据转RGB就行了。这里有个网上找的方法。

public static int[] convertYUV420_NV21toRGB8888(byte[] data, int width, int height) {
    int size = width * height;
    int offset = size;
    int[] pixels = new int[size];
    int u, v, y1, y2, y3, y4;
    // i percorre os Y and the final pixels
    // k percorre os pixles U e V
    for (int i = 0, k = 0; i < size; i += 2, k += 2) {
        y1 = data[i] & 0xff;
        y2 = data[i + 1] & 0xff;
        y3 = data[width + i] & 0xff;
        y4 = data[width + i + 1] & 0xff;
        u = data[offset + k] & 0xff;
        v = data[offset + k + 1] & 0xff;
        u = u - 128;
        v = v - 128;
        pixels[i] = convertYUVtoRGB(y1, u, v);
        pixels[i + 1] = convertYUVtoRGB(y2, u, v);
        pixels[width + i] = convertYUVtoRGB(y3, u, v);
        pixels[width + i + 1] = convertYUVtoRGB(y4, u, v);
        if (i != 0 && (i + 2) % width == 0)
            i += width;
    }
    return pixels;
}

private static int convertYUVtoRGB(int y, int u, int v) {
    int r, g, b;
    r = y + (int) 1.402f * v;
    g = y - (int) (0.344f * u + 0.714f * v);
    b = y + (int) 1.772f * u;
    r = r > 255 ? 255 : r < 0 ? 0 : r;
    g = g > 255 ? 255 : g < 0 ? 0 : g;
    b = b > 255 ? 255 : b < 0 ? 0 : b;
    return 0xff000000 | (b << 16) | (g << 8) | r;
}

  转出之后再转图片(bitmap)就行了,有部分相机方向不对需要相应的设置图片的方向,图片方向对验证或者注册很重要。旋转图片的方法有很多很多人也知道,这里就不再赘述了。

  在线视频的主要技术是不是就是数据格式呢?哈哈!

  demo传不上,不知道为什么会传不上。