您的位置:首页 > 移动开发 > Android开发

Android 腾讯优图开发问题总结

2015-12-02 12:06 615 查看
Android 腾讯优图开发问题总结
接入优图检测人脸失败错误码SDK_IMAGE_FACEDETECT_FAILED -1101
具体表现

提供的getBitmap的问题

Bitmap旋转的问题
优图API正向识别

Android机型兼容性考虑

Android系统兼容性考虑

总结

Android 腾讯优图开发问题总结

马上要提交腾讯优图的第一次比赛的作品了,才匆匆忙忙开始这次项目,期间遇到不少问题,发现网上并没有相关解答,毕竟优图API比较新吧,用的人比较少。我就把我遇到的问题总结一下吧。

接入优图检测人脸失败,错误码SDK_IMAGE_FACEDETECT_FAILED = -1101

具体表现

下载优图Android SDK,里面获取优图官方测试图片文件,检测返回数据正确,使用自己的自拍返回失败(刚开始还以为是自己长得丑检测不出来 TAT)

注:下载优图Android SDK不是类似微信SDK一样给出Jar包和文档,而是直接将接口调用封装到Youtu.java文件中,测试项目用Android Studio创建,这里开发者按照自己的包结构将相关的源文件导入到Eclipse工程中。

提供的
getBitmap()
的问题

以下是下载SDK中MainActivity.java中提供的getBitmap()方法:

[code] private Bitmap getBitmap(String path , int maxWidth, int maxHeight){
        //先解析图片边框的大小
        BitmapFactory.Options ops = new BitmapFactory.Options();
        ops.inJustDecodeBounds = true;
        ops.inSampleSize = 1;
        int oHeight = ops.outHeight;
        int oWidth = ops.outWidth;

        //控制压缩比
        int contentHeight = maxWidth;
        int contentWidth = maxHeight;
        if(((float)oHeight/contentHeight) < ((float)oWidth/contentWidth)){
            ops.inSampleSize = (int) Math.ceil((float)oWidth/contentWidth);
        }else{
            ops.inSampleSize = (int) Math.ceil((float)oHeight/contentHeight);
        }
        ops.inJustDecodeBounds = false;
        Bitmap bm = BitmapFactory.decodeFile(path, ops);
        return bm;
    }


这个方法事实上是控制获取Bitmap的宽高,应该是API的要求,不过经过测试后,并不能很好的进行压缩,比如我的
红米2A
测试机自拍得到的Bitmap是1200 * 1600,调用返回结果仍然是1200 * 1600。这里我们对上述方法进行修改,添加语句:

[code]ops.inJustDecodeBounds = true;// 防止Out Of Memory错误
Bitmap bm = BitmapFactory.decodeFile(path, ops);


获取图片的基本数据。经过测试图片能够得到正确压缩。然而…

Bitmap旋转的问题

优图API正向识别

接上然而…然而仍然返回错误码SDK_IMAGE_FACEDETECT_FAILED = -1101,这回真的是我长得丑没差了吧。。。然而用腾讯优图测试图片中葛大爷的图片居然都能检测出来。。。TAT

言归正传,只有继续调试:

这一次,我把需要检测的Bitmap对象写入SD卡根目录,终于发现问题关键:

腾讯优图的测试图片打开后人像都是正方向,而我用红米2A自拍来的图片是正时针旋转270度的治好劲椎病模式的图片。那么将Bitmap对象旋转-90度或者正270度试试?于是继续修改
getBitmap
方法:

[code]ops.inJustDecodeBounds = false;
bm = BitmapFactory.decodeFile(path, ops);
if (bm != null){
    Matrix m = new Matrix();
    m.setRotate(-90, (float) bm.getWidth() / 2,(float) bm.getHeight() / 2);
    Bitmap bm1 = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(),bm.getHeight(), m, true);
    return bm1;//旋转后的图片
}


Android机型兼容性考虑

我的红米2A测试机终于可以正确识别了,网络良好的情况下识别效率和识别的准确度还挺高的,但是…换了同学的MX4之后就又不行了。按照上述方法接着存图片,发现人家MX4自拍得来照片就是正向的,根本不需要旋转,如何解决这个问题呢?参考:http://blog.csdn.net/zdw890412/article/details/7360354

我们首先获取旋转角度,根据不同的角度进行相应的旋转,如果旋转角度为0,则不旋转,这样,再次修改
getBitmap()
方法,加入判断部分:

[code]        Bitmap bm = null;
        try {
            ExifInterface exifInterface = new ExifInterface(path);
            int result = exifInterface.getAttributeInt(
                    ExifInterface.TAG_ORIENTATION,
                    ExifInterface.ORIENTATION_UNDEFINED);
            int rotate = 0;
            switch (result) {
            case ExifInterface.ORIENTATION_ROTATE_90:
                rotate = 90;
                break;
            case ExifInterface.ORIENTATION_ROTATE_180:
                rotate = 180;
                break;
            case ExifInterface.ORIENTATION_ROTATE_270:
                rotate = 270;
                break;
            default:
                break;
            }
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inPreferredConfig = Bitmap.Config.RGB_565;
            options.inJustDecodeBounds = true;
            BitmapFactory.decodeFile(path, options);
            //...
            //压缩代码略
            //...
            options.inJustDecodeBounds = false;
            bm = BitmapFactory.decodeFile(path, options);
            if (rotate > 0) {
                Matrix matrix = new Matrix();
                matrix.setRotate(rotate, (float) options.outWidth / 2,
                        (float) options.outHeight / 2);
                Bitmap rotateBm = Bitmap.createBitmap(bm, 0, 0,
                        options.outWidth, options.outHeight, matrix, true);
                if(rotateBm !=null){
                    bm.recycle();
                    bm=rotateBm;
                }
            }
            return bm;


至此基本上大功告成。在HTC one 801e 手机上测试,发现根本获取不了Bitmap对象,返回空指针错误。

Android系统兼容性考虑

测试了很多机型,红米2A,三星Note3,魅族MX4,都是没有问题的,唯独用到HTC one时就崩溃了,返回空指针错误。HTC还真是傲娇。。

怀疑是系统没有找到图片文件,我们知道调用系统相册将返回Uri数据,我们获取图片需要图片的路径,在腾讯优图的测试源码中, 提供了
uri2Path(Uri uri)
方法,用来获取图片路径,通过打印发现HTC one 801e返回的
image/jpeg
这个是Uri中的一个字段,但是到了Android的高版本以后,Uri的结构发生了一些变化,所以用老方法获取的Uri的位置得到的字段向下兼容,到了高版本就不行了,参考:http://blog.csdn.net/wblyuyang/article/details/45223813

重写
uri2Path(Uri uri)
方法:

[code]@SuppressLint("NewApi")
public String uri2Path(final Context context, final Uri uri) {
        final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;

        // DocumentProvider
        if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
            // ExternalStorageProvider
            if (isExternalStorageDocument(uri)) {
                final String docId = DocumentsContract.getDocumentId(uri);
                final String[] split = docId.split(":");
                final String type = split[0];

                if ("primary".equalsIgnoreCase(type)) {
                    return Environment.getExternalStorageDirectory() + "/"
                            + split[1];
                }
            }
            // DownloadsProvider
            else if (isDownloadsDocument(uri)) {

                final String id = DocumentsContract.getDocumentId(uri);
                final Uri contentUri = ContentUris.withAppendedId(
                        Uri.parse("content://downloads/public_downloads"),
                        Long.valueOf(id));

                return getDataColumn(context, contentUri, null, null);
            }
            // MediaProvider
            else if (isMediaDocument(uri)) {
                final String docId = DocumentsContract.getDocumentId(uri);
                final String[] split = docId.split(":");
                final String type = split[0];

                Uri contentUri = null;
                if ("image".equals(type)) {
                    contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
                } else if ("video".equals(type)) {
                    contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
                } else if ("audio".equals(type)) {
                    contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
                }

                final String selection = "_id=?";
                final String[] selectionArgs = new String[] { split[1] };

                return getDataColumn(context, contentUri, selection,
                        selectionArgs);
            }
        }
        // MediaStore (and general)
        else if ("content".equalsIgnoreCase(uri.getScheme())) {
            return getDataColumn(context, uri, null, null);
        }
        // File
        else if ("file".equalsIgnoreCase(uri.getScheme())) {
            return uri.getPath();
        }

        return null;
    }

    public static String getDataColumn(Context context, Uri uri,
            String selection, String[] selectionArgs) {

        Cursor cursor = null;
        final String column = "_data";
        final String[] projection = { column };

        try {
            cursor = context.getContentResolver().query(uri, projection,
                    selection, selectionArgs, null);
            if (cursor != null && cursor.moveToFirst()) {
                final int column_index = cursor.getColumnIndexOrThrow(column);
                return cursor.getString(column_index);
            }
        } finally {
            if (cursor != null)
                cursor.close();
        }
        return null;
    }

    public static boolean isExternalStorageDocument(Uri uri) {
        return "com.android.externalstorage.documents".equals(uri
                .getAuthority());
    }

    public static boolean isDownloadsDocument(Uri uri) {
        return "com.android.providers.downloads.documents".equals(uri
                .getAuthority());
    }

    public static boolean isMediaDocument(Uri uri) {
        return "com.android.providers.media.documents".equals(uri
                .getAuthority());
    }


OK,这次可以开心的听听音乐,谢谢博客了。在我所拥有的的测试条件下(红米2A,魅族MX4,三星Note3,HTC one 801e),皆可以完成腾讯优图API的正确接入。

总结

由于这次使用腾讯优图的API接入开发,不仅仅考虑自己的测试,还需要考虑APP的兼容性问题,主要考虑以下几点:

不同机型自拍保存图片方向(与不同厂商摄像头调教有关)

高低版本Android系统的兼容性问题

不得不说,现在Android开发很多东西都特别混乱,增加了开发难度。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: