找回密码
 立即注册

虹软人脸识别 - ArcFace Go应用套件接入说明

本帖最后由 一二三亖 于 2020-7-23 09:43 编辑

昨天看了虹软的发布会,得知应用套件要开源了,晚上看到在官网上线了,随后下载下来打算试一试。
但是运行工程的过程中,它报错了。。。查看错误信息,说的是缺少类(详细说明看下方)
咨询了下虹软小助手,表示这两个类确实是需要自己实现的
晚上加班把这个做出来了,不得不说虹软开放了应用套件,确实省去了很多研发时间,当天晚上就跑通了
下面把类实现分享在这里,给有需要的人做个参考。。

导航:
-- 获取ArcFaceGo包
-- 运行ArcFaceGo工程
-- 安装及使用

(这个编辑器不是很好用,不过勉强可以看虹软人脸识别
一、获取ArcFaceGo包
进入虹软ArcFaceGo官方页面https://ai.arcsoft.com.cn/product/arcfacego.html,按照步骤获取`ArcFaceGo_Source_3.1.1.zip`,其中包含ArcFaceGo源码及相关文档信息。

二、运行ArcFaceGo工程
2.1 获取工程
解压`ArcFaceGo_Source_3.1.1.zip`,解压后进入`sourcecode`目录,解压其中的`ArcFaceGo.zip`获取工程

2.2 编译工程
2.2.1  查看编译报错
使用Android Studio打开工程,并执行`Build`,会提示报错,有两个类里有类不存在,需要自己实现:






2.2.2 实现Camera1Engine类
  1. <font size="2">package com.arcsoft.arcfacesingle.libutil;

  2. import android.graphics.ImageFormat;
  3. import android.graphics.SurfaceTexture;
  4. import android.hardware.Camera;
  5. import android.util.Pair;

  6. import com.arcsoft.asg.libcommon.contract.ICameraEngine;

  7. import java.io.IOException;
  8. import java.util.ArrayList;
  9. import java.util.Collections;
  10. import java.util.LinkedHashSet;
  11. import java.util.List;

  12. /**
  13. * ICameraEngine的实现
  14. */
  15. public class Camera1Engine extends ICameraEngine {

  16.     private static final int COUNT_CAMERA_ONE = 1;
  17.     private static final int COUNT_CAMERA_TWO = 2;
  18.     private Camera camera;
  19.     private boolean usePreAlloc;

  20.     @Override
  21.     public void setUsePreAlloc(boolean usePreAlloc) {
  22.         this.usePreAlloc = usePreAlloc;
  23.     }

  24.     @Override
  25.     public void onPreviewFrame(byte[] data, Camera camera) {
  26.         super.onPreviewFrame(data, camera);
  27.         if (usePreAlloc) {
  28.             camera.addCallbackBuffer(data);
  29.         }
  30.     }

  31.     @Override
  32.     public void startCamera(SurfaceTexture surfaceTexture, int cameraId, int previewRotation, int previewWidth,
  33.                             int previewHeight, int bufferCount, int bufferSize) throws IOException {
  34.         camera = Camera.open(cameraId);
  35.         camera.setDisplayOrientation(previewRotation);
  36.         Camera.Parameters parameters = camera.getParameters();
  37.         parameters.setPreviewFormat(ImageFormat.NV21);
  38.         parameters.setPreviewSize(previewWidth, previewHeight);
  39.         List<String> supportedFocusModes = parameters.getSupportedFocusModes();
  40.         if (supportedFocusModes != null && supportedFocusModes.size() > 0) {
  41.             if (supportedFocusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
  42.                 parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
  43.             } else if (supportedFocusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) {
  44.                 parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
  45.             } else if (supportedFocusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
  46.                 parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
  47.             }
  48.         }
  49.         camera.setParameters(parameters);
  50.         camera.setPreviewTexture(surfaceTexture);
  51.         if (usePreAlloc) {
  52.             for (int i = 0; i < bufferCount; i++) {
  53.                 camera.addCallbackBuffer(new byte[bufferSize]);
  54.             }
  55.             camera.setPreviewCallbackWithBuffer(this);
  56.         } else {
  57.             camera.setPreviewCallback(this);
  58.         }
  59.         camera.startPreview();
  60.     }

  61.     @Override
  62.     public void setPreviewTexture(SurfaceTexture surfaceTexture) {
  63.         try {
  64.             if (camera != null) {
  65.                 camera.setPreviewTexture(surfaceTexture);
  66.             }
  67.         } catch (Exception e) {
  68.             e.printStackTrace();
  69.         }
  70.     }

  71.     @Override
  72.     public void releaseCamera() {
  73.         if (camera != null) {
  74.             if (usePreAlloc) {
  75.                 camera.setPreviewCallbackWithBuffer(null);
  76.             } else {
  77.                 camera.setPreviewCallback(null);
  78.             }
  79.             camera.stopPreview();
  80.             camera.release();
  81.             camera = null;
  82.         }
  83.     }

  84.     @Override
  85.     public List<Integer> getCameraPositionList() {
  86.         List<Integer> cameraPosList = new ArrayList<>();
  87.         int cameraPosBack = Camera.CameraInfo.CAMERA_FACING_BACK;
  88.         int cameraPosFront = Camera.CameraInfo.CAMERA_FACING_FRONT;
  89.         int cameraCount = Camera.getNumberOfCameras();
  90.         if (cameraCount == COUNT_CAMERA_ONE) {
  91.             cameraPosList.add(cameraPosBack);
  92.         } else if (cameraCount >= COUNT_CAMERA_TWO) {
  93.             cameraPosList.add(cameraPosBack);
  94.             cameraPosList.add(cameraPosFront);
  95.         }
  96.         return cameraPosList;
  97.     }

  98.     @Override
  99.     public List<Pair<Integer, Integer>> getCameraPreviewSizeList() {
  100.         List<Camera.Size> commonSizeList = new ArrayList<>();
  101.         int cameraPosBack = Camera.CameraInfo.CAMERA_FACING_BACK;
  102.         int cameraPosFront = Camera.CameraInfo.CAMERA_FACING_FRONT;
  103.         int cameraCount = Camera.getNumberOfCameras();
  104.         if (cameraCount == COUNT_CAMERA_ONE) {
  105.             try {
  106.                 Camera backCamera = Camera.open(cameraPosBack);
  107.                 commonSizeList = backCamera.getParameters().getSupportedPreviewSizes();
  108.                 backCamera.release();
  109.             } catch (Exception e) {
  110.                 e.printStackTrace();
  111.             }
  112.         } else if (cameraCount >= COUNT_CAMERA_TWO) {
  113.             List<Camera.Size> backSizeList;
  114.             try {
  115.                 Camera.CameraInfo cameraInfo2 = new Camera.CameraInfo();
  116.                 Camera.getCameraInfo(cameraPosBack, cameraInfo2);
  117.                 Camera backCamera = Camera.open(cameraPosBack);
  118.                 backSizeList = backCamera.getParameters().getSupportedPreviewSizes();
  119.                 backCamera.release();
  120.             } catch (Exception e) {
  121.                 backSizeList = new ArrayList<>();
  122.             }
  123.             List<Camera.Size> frontSizeList;
  124.             try {
  125.                 Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
  126.                 Camera.getCameraInfo(cameraPosFront, cameraInfo);
  127.                 Camera frontCamera = Camera.open(cameraPosFront);
  128.                 frontSizeList = frontCamera.getParameters().getSupportedPreviewSizes();
  129.                 frontCamera.release();
  130.             } catch (Exception e) {
  131.                 frontSizeList = new ArrayList<>();
  132.             }
  133.             if (frontSizeList.size() > 0 && backSizeList.size() > 0) {
  134.                 for (Camera.Size rgbPreviewSize : frontSizeList) {
  135.                     for (Camera.Size irPreviewSize : backSizeList) {
  136.                         if (irPreviewSize.width == rgbPreviewSize.width && irPreviewSize.height == rgbPreviewSize.height) {
  137.                             commonSizeList.add(irPreviewSize);
  138.                         }
  139.                     }
  140.                 }
  141.             } else if (frontSizeList.size() > 0) {
  142.                 commonSizeList = frontSizeList;
  143.             } else if (backSizeList.size() > 0) {
  144.                 commonSizeList = backSizeList;
  145.             }
  146.         }
  147.         Collections.sort(commonSizeList, ((size, t1) -> {
  148.             int leftWidth = size.width;
  149.             int rightWidth = t1.width;
  150.             return leftWidth - rightWidth;
  151.         }));
  152.         List<Camera.Size> sizeList = new ArrayList<>(new LinkedHashSet<>(commonSizeList));
  153.         List<Pair<Integer, Integer>> cameraPairList = new ArrayList<>();
  154.         if (sizeList.size() > 0) {
  155.             for (Camera.Size size : sizeList) {
  156.                 int sizeWidth = size.width;
  157.                 int sizeHeight = size.height;
  158.                 Pair<Integer, Integer> sizePair = new Pair<>(sizeWidth, sizeHeight);
  159.                 cameraPairList.add(sizePair);
  160.             }
  161.         }
  162.         return cameraPairList;
  163.     }
  164. }</font>
复制代码

2.2.3 实现ImageUtils类
  1. <font size="2">package com.arcsoft.arcfacesingle.libutil;

  2. import android.content.Context;
  3. import android.graphics.Bitmap;
  4. import android.graphics.BitmapFactory;
  5. import android.graphics.Canvas;
  6. import android.graphics.ImageFormat;
  7. import android.graphics.Matrix;
  8. import android.graphics.Rect;
  9. import android.graphics.YuvImage;
  10. import android.graphics.drawable.Drawable;
  11. import android.text.TextUtils;
  12. import android.util.Base64;
  13. import android.util.Pair;

  14. import androidx.annotation.DrawableRes;
  15. import androidx.core.content.ContextCompat;

  16. import java.io.BufferedOutputStream;
  17. import java.io.ByteArrayOutputStream;
  18. import java.io.File;
  19. import java.io.FileInputStream;
  20. import java.io.FileOutputStream;
  21. import java.io.IOException;
  22. import java.io.InputStream;
  23. import java.io.OutputStream;

  24. /**
  25. * 图片管理工具类
  26. */
  27. public final class ImageUtils {
  28.     private static final int FACE_DETECT_IMAGE_WIDTH_LIMIT = 4;
  29.     private static final int FACE_DETECT_IMAGE_HEIGHT_LIMIT = 2;

  30.     private ImageUtils() {
  31.         throw new UnsupportedOperationException("无法初始化!");
  32.     }

  33.     /**
  34.      * 判断bitmap是否为空
  35.      *
  36.      * @param src Bitmap对象
  37.      * @return bitmap是否为空
  38.      */
  39.     private static boolean isEmptyBitmap(final Bitmap src) {
  40.         return src == null || src.getWidth() == 0 || src.getHeight() == 0;
  41.     }


  42.     /**
  43.      * 根据压缩格式将Bitmap转换为压缩后的图像数据
  44.      *
  45.      * @param bitmap Bitmap对象
  46.      * @param format 压缩格式
  47.      * @return 压缩后的图像数据
  48.      */
  49.     public static byte[] bitmap2Bytes(final Bitmap bitmap, final Bitmap.CompressFormat format) {
  50.         if (bitmap == null) {
  51.             return null;
  52.         }
  53.         ByteArrayOutputStream baos = new ByteArrayOutputStream();
  54.         bitmap.compress(format, 100, baos);
  55.         return baos.toByteArray();
  56.     }

  57.     /**
  58.      * 将图片文件转换为Bitmap
  59.      *
  60.      * @param file 图片文件
  61.      * @return Bitmap对象
  62.      */
  63.     public static Bitmap getBitmap(final File file) {
  64.         if (file == null) {
  65.             return null;
  66.         }
  67.         return BitmapFactory.decodeFile(file.getAbsolutePath());
  68.     }

  69.     /**
  70.      * 根据最大宽高,将文件转换为Bitmap
  71.      *
  72.      * @param filePath  文件路径
  73.      * @param maxWidth  最大宽度
  74.      * @param maxHeight 最大高度
  75.      * @return Bitmap对象
  76.      */
  77.     public static Bitmap getBitmap(final String filePath, int maxWidth, int maxHeight) {
  78.         if (isSpace(filePath)) {
  79.             return null;
  80.         }
  81.         BitmapFactory.Options options = new BitmapFactory.Options();
  82.         options.inJustDecodeBounds = true;
  83.         BitmapFactory.decodeFile(filePath, options);
  84.         options.inSampleSize = calculateInSampleSize4(options, maxWidth, maxHeight);
  85.         options.inJustDecodeBounds = false;
  86.         return BitmapFactory.decodeFile(filePath, options);
  87.     }

  88.     /**
  89.      * 根据最大宽高,将压缩图像数据转换为Bitmap
  90.      *
  91.      * @param imageBytes 压缩的图像数据,如jpeg/png等
  92.      * @param maxWidth   最大宽度
  93.      * @param maxHeight  最大高度
  94.      * @return Bitmap对象
  95.      */
  96.     public static Bitmap getBitmap(final byte[] imageBytes, int maxWidth, int maxHeight) {
  97.         if (imageBytes == null || imageBytes.length == 0) {
  98.             return null;
  99.         }
  100.         BitmapFactory.Options options = new BitmapFactory.Options();
  101.         options.inJustDecodeBounds = true;
  102.         BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length, options);
  103.         options.inSampleSize = calculateInSampleSize4(options, maxWidth, maxHeight);
  104.         options.inJustDecodeBounds = false;
  105.         return BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length, options);
  106.     }

  107.     /**
  108.      * 根据最大宽高,将图片文件转换为Bitmap
  109.      *
  110.      * @param filePath  图片文件路径
  111.      * @param maxWidth  最大宽度
  112.      * @param maxHeight 最大高度
  113.      * @return Bitmap对象
  114.      */
  115.     public static Bitmap decodeFileWithThreshold(final String filePath, int maxWidth, int maxHeight) {
  116.         Bitmap tempBitmap = getBitmap(filePath, maxWidth, maxHeight);
  117.         if (tempBitmap != null) {
  118.             if (tempBitmap.getWidth() > maxWidth || tempBitmap.getHeight() > maxHeight) {
  119.                 Bitmap scaleBitmap = resizeImage(tempBitmap, maxWidth, maxHeight);
  120.                 if (!tempBitmap.isRecycled()) {
  121.                     tempBitmap.recycle();
  122.                 }
  123.                 return scaleBitmap;
  124.             }
  125.             return tempBitmap;
  126.         }
  127.         return null;
  128.     }

  129.     /**
  130.      * 根据最大宽高,将图片数据转换为Bitmap
  131.      *
  132.      * @param imgBytes  图片数据,可以是JPEG/PNG等格式的压缩数据
  133.      * @param maxWidth  最大宽度
  134.      * @param maxHeight 最大高度
  135.      * @return Bitmap对象
  136.      */
  137.     public static Bitmap decodeFileWithThreshold(byte[] imgBytes, int maxWidth, int maxHeight) {
  138.         Bitmap tempBitmap = getBitmap(imgBytes, maxWidth, maxHeight);
  139.         if (tempBitmap != null) {
  140.             if (tempBitmap.getWidth() > maxWidth || tempBitmap.getHeight() > maxHeight) {
  141.                 Bitmap scaleBitmap = resizeImage(tempBitmap, maxWidth, maxHeight);
  142.                 if (!tempBitmap.isRecycled()) {
  143.                     tempBitmap.recycle();
  144.                 }
  145.                 return scaleBitmap;
  146.             }
  147.             return tempBitmap;
  148.         }
  149.         return null;
  150.     }

  151.     /**
  152.      * 根据资源ID获取Bitmap
  153.      *
  154.      * @param resId 资源ID
  155.      * @return Bitmap对象
  156.      */
  157.     public static Bitmap getBitmap(@DrawableRes final int resId, Context context) {
  158.         Drawable drawable = ContextCompat.getDrawable(context, resId);
  159.         if (drawable == null) {
  160.             return null;
  161.         }
  162.         Canvas canvas = new Canvas();
  163.         Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
  164.         canvas.setBitmap(bitmap);
  165.         drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
  166.         drawable.draw(canvas);
  167.         return bitmap;
  168.     }

  169.     public static int calculateInSampleSize4(BitmapFactory.Options options, int reqWidth, int reqHeight) {
  170.         int sampleSize = 1;
  171.         int picWidth = options.outWidth;
  172.         int picHeight = options.outHeight;
  173.         if (picWidth > reqWidth || picHeight > reqHeight) {
  174.             final int widthRatio = picWidth / reqWidth;
  175.             final int heightRatio = picHeight / reqHeight;
  176.             sampleSize = Math.max(heightRatio, widthRatio);
  177.         }
  178.         return sampleSize;
  179.     }


  180.     /**
  181.      * 保存图片
  182.      *
  183.      * @param src     Bitmap对象
  184.      * @param file    要保存的file路径
  185.      * @param format  图片格式
  186.      * @param recycle 是否回收bitmap
  187.      * @return 是否保存成功
  188.      */
  189.     public static boolean save(final Bitmap src, final File file, final Bitmap.CompressFormat format, final int quality, final boolean recycle) {
  190.         if (isEmptyBitmap(src)) {
  191.             return false;
  192.         }
  193.         if (!createFileByDeleteOldFile(file)) {
  194.             if (recycle && !src.isRecycled()) {
  195.                 src.recycle();
  196.             }
  197.             return false;
  198.         }
  199.         OutputStream os;
  200.         FileOutputStream fileOutputStream = null;
  201.         boolean ret = false;
  202.         try {
  203.             fileOutputStream = new FileOutputStream(file);
  204.         } catch (Exception e) {
  205.             e.printStackTrace();
  206.         } finally {
  207.             if (fileOutputStream != null) {
  208.                 os = new BufferedOutputStream(fileOutputStream);
  209.                 ret = src.compress(format, quality, os);
  210.                 try {
  211.                     os.flush();
  212.                     os.close();
  213.                 } catch (Exception e) {
  214.                     e.printStackTrace();
  215.                 }
  216.                 try {
  217.                     fileOutputStream.close();
  218.                 } catch (Exception e) {
  219.                     e.printStackTrace();
  220.                 }
  221.                 if (recycle && !src.isRecycled()) {
  222.                     src.recycle();
  223.                 }
  224.             }
  225.         }
  226.         return ret;
  227.     }

  228.     public static boolean save(final Bitmap src, final File file, final Bitmap.CompressFormat format) {
  229.         return save(src, file, format, 100, false);
  230.     }

  231.     public static boolean save(final Bitmap src, final File file, final int quality, final Bitmap.CompressFormat format) {
  232.         return save(src, file, format, quality, true);
  233.     }

  234.     public static boolean save(final Bitmap src, final String filePath, final Bitmap.CompressFormat format, final boolean recycle) {
  235.         return save(src, getFileByPath(filePath), format, 100, recycle);
  236.     }

  237.     public static boolean save(final Bitmap src, final String filePath, final Bitmap.CompressFormat format) {
  238.         return save(src, getFileByPath(filePath), format, 100, false);
  239.     }

  240.     /**
  241.      * 对文件进行base64编码,获取编码后的字符串信息
  242.      *
  243.      * @param path 文件路径
  244.      * @return base64编码后的文件内容
  245.      */
  246.     public static String image2Base64(String path) {
  247.         if (TextUtils.isEmpty(path)) {
  248.             return null;
  249.         }
  250.         InputStream is = null;
  251.         byte[] data;
  252.         String result = null;
  253.         try {
  254.             is = new FileInputStream(path);
  255.             data = new byte[is.available()];
  256.             int ret = is.read(data);
  257.             result = Base64.encodeToString(data, Base64.DEFAULT);
  258.             data = null;
  259.         } catch (IOException e) {
  260.             e.printStackTrace();
  261.         } finally {
  262.             if (null != is) {
  263.                 try {
  264.                     is.close();
  265.                 } catch (IOException e) {
  266.                     e.printStackTrace();
  267.                 }
  268.             }

  269.         }
  270.         return result;
  271.     }

  272.     /**
  273.      * 对Bitmap进行压缩,以30的质量压缩为jpeg格式数据,再进行base64编码,获取编码后的字符串信息
  274.      *
  275.      * @param bitmap Bitmap对象
  276.      * @return base64编码后的文件内容
  277.      */
  278.     public static String bitmapToBase64(Bitmap bitmap) {
  279.         // 要返回的字符串
  280.         String reslut = null;
  281.         ByteArrayOutputStream baos = null;
  282.         try {
  283.             if (bitmap != null) {
  284.                 baos = new ByteArrayOutputStream();
  285.                 //压缩只对保存有效果bitmap还是原来的大小
  286.                 bitmap.compress(Bitmap.CompressFormat.JPEG, 30, baos);
  287.                 baos.flush();
  288.                 baos.close();
  289.                 // 转换为字节数组
  290.                 byte[] byteArray = baos.toByteArray();
  291.                 // 转换为字符串
  292.                 reslut = Base64.encodeToString(byteArray, Base64.DEFAULT);
  293.             } else {
  294.                 return null;
  295.             }
  296.         } catch (IOException e) {
  297.             e.printStackTrace();
  298.         } finally {
  299.             try {
  300.                 if (baos != null) {
  301.                     baos.close();
  302.                 }
  303.             } catch (IOException e) {
  304.                 e.printStackTrace();
  305.             }
  306.         }
  307.         return reslut;
  308.     }


  309.     /**
  310.      * 将base64编码的图像数据解码为Bitmap对象
  311.      *
  312.      * @param base64String base64编码的图像数据
  313.      * @return Bitmap对象
  314.      */
  315.     public static Bitmap base64ToBitmap(String base64String) {
  316.         Bitmap bitmap = null;
  317.         byte[] decode = null;
  318.         try {
  319.             decode = Base64.decode(base64String, Base64.DEFAULT);
  320.         } catch (Exception e) {
  321.         }
  322.         if (decode != null && decode.length != 0) {
  323.             try {
  324.                 bitmap = BitmapFactory.decodeByteArray(decode, 0, decode.length);
  325.             } catch (Exception e) {
  326.             }
  327.         }

  328.         return bitmap;
  329.     }


  330.     /**
  331.      * 将nv21数据转Bitmap
  332.      *
  333.      * @param nv21   NV21数据
  334.      * @param width  NV21图像宽度
  335.      * @param height NV21图像高度
  336.      * @return 转换后的bitmap对象
  337.      */
  338.     public static Bitmap nv21ToBitmap(byte[] nv21, int width, int height) {
  339.         Bitmap bitmap = null;
  340.         try {
  341.             YuvImage image = new YuvImage(nv21, ImageFormat.NV21, width, height, null);
  342.             ByteArrayOutputStream stream = new ByteArrayOutputStream();
  343.             image.compressToJpeg(new Rect(0, 0, width, height), 100, stream);
  344.             bitmap = BitmapFactory.decodeByteArray(stream.toByteArray(), 0, stream.size());
  345.             stream.close();
  346.         } catch (IOException e) {
  347.             e.printStackTrace();
  348.         }
  349.         return bitmap;
  350.     }

  351.     /**
  352.      * 根据旋转角度、是否镜像处理Bitmap
  353.      *
  354.      * @param b            bitmap对象
  355.      * @param rotateDegree 旋转角度
  356.      * @param mirror       是否镜像
  357.      * @return 处理后的Bitmap对象
  358.      */
  359.     public static Bitmap getRotateBitmap(Bitmap b, float rotateDegree, boolean mirror) {
  360.         Matrix matrix = new Matrix();
  361.         if (mirror) {
  362.             if (rotateDegree == 90 || rotateDegree == 270) {
  363.                 matrix.postScale(1, -1);
  364.             } else {
  365.                 matrix.postScale(-1, 1);
  366.             }
  367.         }
  368.         matrix.postRotate(rotateDegree);
  369.         int width = b.getWidth();
  370.         int height = b.getHeight();
  371.         if (width % 4 != 0) {
  372.             width = width >> 2 << 2;
  373.         }
  374.         if (height % 4 != 0) {
  375.             height = height >> 2 << 2;
  376.         }
  377.         return Bitmap.createBitmap(b, 0, 0, width, height, matrix, true);
  378.     }

  379.     /**
  380.      * 旋转Bitmap
  381.      *
  382.      * @param src     原bitmap
  383.      * @param degrees 旋转角度
  384.      * @param px      旋转中心点的x坐标
  385.      * @param py      旋转中心点的y坐标
  386.      * @return Bitmap对象
  387.      */
  388.     public static Bitmap rotate(final Bitmap src, final int degrees, final float px, final float py) {
  389.         return rotate(src, degrees, px, py, false);
  390.     }

  391.     /**
  392.      * 旋转Bitmap
  393.      *
  394.      * @param src     原bitmap
  395.      * @param degrees 旋转角度
  396.      * @param px      旋转中心点的x坐标
  397.      * @param py      旋转中心点的y坐标
  398.      * @param recycle 是否回收bitmap
  399.      * @return 旋转后的bitmap
  400.      */
  401.     public static Bitmap rotate(final Bitmap src, final int degrees, final float px, final float py, final boolean recycle) {
  402.         if (isEmptyBitmap(src)) {
  403.             return null;
  404.         }
  405.         if (degrees == 0) {
  406.             return src;
  407.         }
  408.         Matrix matrix = new Matrix();
  409.         matrix.setRotate(degrees, px, py);
  410.         Bitmap ret = Bitmap.createBitmap(src, 0, 0, src.getWidth(), src.getHeight(), matrix, false);
  411.         if (recycle && !src.isRecycled() && ret != src) {
  412.             src.recycle();
  413.         }
  414.         return ret;
  415.     }

  416.     /**
  417.      * 将图片文件转换为Bitmap对象
  418.      * TODO: 未理解size参数的概念,可自行理解ArcFaceGo再修改该函数
  419.      *
  420.      * @param srcPath 图片文件
  421.      * @param size
  422.      * @return Bitmap对象
  423.      */
  424.     public static Bitmap getImagePng(String srcPath, int size) {
  425.         return BitmapFactory.decodeFile(srcPath);
  426.     }

  427.     /**
  428.      * 根据最大宽高等比缩放Bitmap
  429.      *
  430.      * @param bitmap    原Bitmap
  431.      * @param maxWidth  最大宽度
  432.      * @param maxHeight 最大高度
  433.      * @return 等比缩放后的Bitmap对象
  434.      */
  435.     public static Bitmap resizeImage(Bitmap bitmap, int maxWidth, int maxHeight) {
  436.         int bitmapWidth = bitmap.getWidth();
  437.         int bitmapHeight = bitmap.getHeight();
  438.         float scale = Math.min((float) maxWidth / bitmapWidth, (float) maxHeight / bitmapHeight);
  439.         Matrix matrix = new Matrix();
  440.         matrix.postScale(scale, scale);
  441.         return Bitmap.createBitmap(bitmap, 0, 0, bitmapWidth, bitmapHeight, matrix, false);
  442.     }

  443.     /**
  444.      * 确保Bitmap宽度是4的倍数,并且高度是2的倍数
  445.      *
  446.      * @param bm Bitmap对象
  447.      * @return 宽度是4的倍数,并且高度是2的倍数的Bitmap
  448.      */
  449.     public static Bitmap setBitmap4Align(Bitmap bm) {
  450.         Bitmap newBitmap;
  451.         int width = bm.getWidth();
  452.         int height = bm.getHeight();
  453.         int newWidth = width;
  454.         int newHeight = height;
  455.         if (newWidth % FACE_DETECT_IMAGE_WIDTH_LIMIT != 0) {
  456.             newWidth = newWidth >> 2 << 2;
  457.         }
  458.         if (newHeight % FACE_DETECT_IMAGE_HEIGHT_LIMIT != 0) {
  459.             newHeight = newHeight & ~1;
  460.         }
  461.         // 计算缩放比例.
  462.         float scaleWidth = ((float) newWidth) / width;
  463.         float scaleHeight = ((float) newHeight) / height;
  464.         // 取得想要缩放的matrix参数.
  465.         Matrix matrix = new Matrix();
  466.         matrix.postScale(scaleWidth, scaleHeight);
  467.         // 得到新的图片.
  468.         newBitmap = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, true);
  469.         return newBitmap;
  470.     }

  471.     /**
  472.      * 缩放Bitmap对象
  473.      *
  474.      * @param bitmap    Bitmap对象
  475.      * @param newWidth  新的宽度
  476.      * @param newHeight 新的高度
  477.      * @return 缩放后的Bitmap对象
  478.      */
  479.     public static Bitmap zoomImg(Bitmap bitmap, int newWidth, int newHeight) {
  480.         int width = bitmap.getWidth();
  481.         int height = bitmap.getHeight();
  482.         float scaleWidth = ((float) newWidth) / width;
  483.         float scaleHeight = ((float) newHeight) / height;
  484.         Matrix matrix = new Matrix();
  485.         matrix.postScale(scaleWidth, scaleHeight);
  486.         return Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
  487.     }

  488.     /**
  489.      * 获取图片宽高
  490.      *
  491.      * @param imgPath 图片文件路径
  492.      * @return 图片宽高
  493.      */
  494.     public static Pair<Integer, Integer> getImageOption(String imgPath) {
  495.         BitmapFactory.Options options = new BitmapFactory.Options();
  496.         options.inJustDecodeBounds = true;
  497.         BitmapFactory.decodeFile(imgPath, options);
  498.         return new Pair<>(options.outWidth, options.outHeight);
  499.     }

  500.     /**
  501.      * 判断字符串是否为空格类字符串
  502.      *
  503.      * @param str 待判断的字符串
  504.      * @return 是否为空格类字符串
  505.      */
  506.     public static boolean isSpace(final String str) {
  507.         if (str == null) {
  508.             return true;
  509.         }
  510.         for (int i = 0, len = str.length(); i < len; ++i) {
  511.             if (!Character.isWhitespace(str.charAt(i))) {
  512.                 return false;
  513.             }
  514.         }
  515.         return true;
  516.     }

  517.     /**
  518.      * 创建文件
  519.      *
  520.      * @param file 文件
  521.      * @return 是否创建成果
  522.      */
  523.     public static boolean createFileByDeleteOldFile(final File file) {
  524.         if (file == null) {
  525.             return false;
  526.         }
  527.         if (file.exists() && !file.delete()) {
  528.             return false;
  529.         }
  530.         if (!createDirOrDirExist(file.getParentFile())) {
  531.             return false;
  532.         }
  533.         try {
  534.             return file.createNewFile();
  535.         } catch (IOException e) {
  536.             return false;
  537.         }
  538.     }

  539.     /**
  540.      * 查看文件夹是否存在,如果不存在,则创建文件夹
  541.      *
  542.      * @param file 文件夹对象
  543.      * @return 最终是否存在
  544.      */
  545.     public static boolean createDirOrDirExist(final File file) {
  546.         return file != null && (file.exists() ? file.isDirectory() : file.mkdirs());
  547.     }

  548.     /**
  549.      * 将文件路径转换为文件对象
  550.      *
  551.      * @param path 文件路径
  552.      * @return 文件对象
  553.      */
  554.     public static File getFileByPath(final String path) {
  555.         return isSpace(path) ? null : new File(path);
  556.     }

  557.     /**
  558.      * 将输入流转换为Bitmap对象
  559.      *
  560.      * @param inputStream 输入流
  561.      * @param maxWidth    最大宽度
  562.      * @param maxHeight   最大高度
  563.      * @param chunkSize   临时buffer大小
  564.      * @return Bitmap对象
  565.      * @throws IOException 读取inputStream时可能出现的异常
  566.      */
  567.     public static Bitmap getBitmap(final InputStream inputStream, int maxWidth, int maxHeight, int chunkSize)
  568.             throws IOException {
  569.         if (inputStream == null) {
  570.             return null;
  571.         }
  572.         BitmapFactory.Options options = new BitmapFactory.Options();
  573.         options.inJustDecodeBounds = true;

  574.         byte[] data = inputStream2ByteArr(inputStream, chunkSize);

  575.         BitmapFactory.decodeByteArray(data, 0, data.length, options);

  576.         options.inSampleSize = ImageUtils.calculateInSampleSize4(options, maxWidth, maxHeight);
  577.         options.inJustDecodeBounds = false;

  578.         return BitmapFactory.decodeByteArray(data, 0, data.length, options);
  579.     }

  580.     /**
  581.      * 将输入流转换为字节数组
  582.      *
  583.      * @param inputStream 输入流
  584.      * @param chunkSize   临时buffer的大小
  585.      * @return 字节数组
  586.      * @throws IOException 读取输入流时可能会产生的异常
  587.      */
  588.     private static byte[] inputStream2ByteArr(InputStream inputStream, int chunkSize) throws IOException {
  589.         ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
  590.         byte[] buff = new byte[chunkSize];
  591.         int len;
  592.         while ((len = inputStream.read(buff)) != -1) {
  593.             outputStream.write(buff, 0, len);
  594.         }
  595.         outputStream.flush();
  596.         outputStream.close();
  597.         return outputStream.toByteArray();
  598.     }

  599.     /**
  600.      * 按人脸检测结果截取bitmap
  601.      *
  602.      * @param rect   人脸位置
  603.      * @param orient 人脸角度,详见ArcFace文档
  604.      * @param bitmap 原bitmap
  605.      * @return 裁剪后的bitmap
  606.      */
  607.     public static Bitmap getFaceRegisterCropBitmap(Rect rect, int orient, Bitmap bitmap) {
  608.         if (rect == null || bitmap == null) {
  609.             return null;
  610.         }
  611.         int length = Math.max(rect.width(), rect.height()) / 2;
  612.         int wPadding = Math.min(Math.min(rect.left, bitmap.getWidth() - rect.right), length);
  613.         int width = rect.width() + 2 * wPadding;
  614.         int x = rect.left - wPadding;
  615.         int tPadding = Math.min(rect.top, length);
  616.         int y = rect.top - tPadding;
  617.         int bPadding = Math.min(bitmap.getHeight() - rect.bottom, length);
  618.         int height = rect.height() + tPadding + bPadding;
  619.         if ((width & 0b11) != 0) {
  620.             width &= ~0b11;
  621.         }
  622.         if ((height & 1) != 0) {
  623.             height &= ~1;
  624.         }
  625.         Matrix matrix = new Matrix();
  626.         if (orient == 2) {
  627.             matrix.setRotate(90);
  628.         } else if (orient == 4) {
  629.             matrix.setRotate(180);
  630.         } else if (orient == 3) {
  631.             matrix.setRotate(270);
  632.         }

  633.         return Bitmap.createBitmap(bitmap, x, y, width, height, matrix, true);
  634.     }

  635.     /**
  636.      * 将图像信息转换为Bitmap对象
  637.      *
  638.      * @param imgArray 图像数据,可以是JPG\PNG等格式
  639.      * @return Bitmap对象
  640.      */
  641.     public static Bitmap getBitmap(byte[] imgArray) {
  642.         return BitmapFactory.decodeByteArray(imgArray, 0, imgArray.length);
  643.     }

  644.     /**
  645.      * 将输入流转换为Bitmap对象
  646.      *
  647.      * @param inputStream 输入流
  648.      * @return Bitmap对象
  649.      */
  650.     public static Bitmap getBitmap(InputStream inputStream) {
  651.         return BitmapFactory.decodeStream(inputStream);
  652.     }
  653. }</font>
复制代码

2.2.4 编译apk
将上述两个Java类存放到下方目录,
  1. <font size="2">ArcFaceGo\libutil\src\main\java\com\arcsoft\arcfacesingle\libutil</font>
复制代码
下图红框即为刚刚存放好的Java类,

点击

  1. <font size="2">Build -> Build bundle(s)/APK(s) -> Build APK(s)</font>
复制代码
即可编译APK

三、 安装及使用
3.1 安装
直接点击Android Studio的安装或使用adb install或者其他方式将apk安装到设备中

3.2 使用
将`APP_ID`等信息存放到
  1. <font size="2">sdcard/com_arcsoft_arcfacesingle_charge/activeConfig/activeConfig.txt</font>
复制代码
格式如下(以下为示例数据,非真实数据):
  1. <font size="2">APP_ID:Abvyu5a4ds4vaBhyLSNcp49HW6tuPx3sqWog8i9S41Q7
  2. SDK_KEY:EvvwadsFj7XjL1siCQgSD2qGcmeFsE2bCpgtMJpS4MW3
  3. ACTIVE_KEY:8551-2136-J3HC-E5FH</font>
复制代码
首次打开ArcFaceGo App,会自动进入激活、配置等界面,配置完成后即可使用。
APK的具体使用说明详见压缩包中的`doc/操作指南_Android设备端.pdf`


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

大神点评2

Arc虹小妹 2020-5-25 10:55:18 显示全部楼层
感谢分享
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

0关注

0粉丝

1帖子

最热主题

    热门作者