当前位置:   article > 正文

[开源]基于姿态估计的运动计数APP开发(三)_跳绳 app源码

跳绳 app源码

1、前言:

在上一期中[开源]基于姿态估计的运动计数APP开发(二)中,我们已经完成了仰卧起坐算法的开发和windows的demo开发。本期主要是将该算法一直到android平台上面,实现一个android手机上可以使用的APP。下面的视频是我在西湖边进行的测试,在背景比较干净的情况下,效果还不错哦。【获取APP源码请留言,或者添加我的微信,15158106211,备注“仰卧起坐APP”,让我们一起学习一起进步。】

(CSDN放不了视频,请见谅)

2、模型改进

有的朋友已经发现,上一期的demo中,只有两个关键点,头部和膝盖,而这次的APP有三个关键点,分别是头部,腰部和膝盖。当只有两个关键点的时候,模型很容易出现误识别,会把关键点定位在一些其他东西上面,很少会考虑这是不是属于一个人的特征。而使用了三个关键点之后,一方面更加有利于判断姿势,另一方面也相对于增加了一个监督信号,并且三个关键点都位于人身上,使得模型更容易理解和学习。因此在性能上有一定的提升,主要是降低了误识别率。

3、APP框架

APP主要要Activiry类,两个SurfaceView类,一个Alg类,一个Camera类组成。Alg类主要负责调用算法进行推理,并返回结果。这里我已经将pytorch训练好的模型转换成了NCNN模型,因此实际上是调用的NCNN库的推理功能。Camera类主要负责摄像头的打开和关闭,以及进行预览回调。第一个SurfaceView(DisplayView)主要用于摄像头预览的展示。第二个SurfaceView(CustomView)主要用于绘制一些关键点信息,计数统计信息等。Activity就是最上层的一个管理类,负责管理整个APP,包括创建按钮,创建SurfaceView,创建Alg类,创建Camera类等。

3、主要类源码

3.1、Activity类核心源码

  1. public class MainActivity extends Activity implements Camera.PreviewCallback, AlgCallBack{
  2. private DisplayView mViewDisplay;
  3. private CustomView mViewCustom;
  4. private Button mBtnCameraOp;
  5. private Button mBtnCameraChange;
  6. private CameraUtil mCameraUtil;
  7. private AlgUtil mAlgUtil;
  8. private int mFrameCount = 0;
  9. @Override
  10. protected void onCreate(Bundle savedInstanceState) {
  11. Log.i("zhengxing", "MainActivity::onCreate");
  12. super.onCreate(savedInstanceState);
  13. this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
  14. this.requestWindowFeature(Window.FEATURE_NO_TITLE);
  15. this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
  16. setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
  17. setContentView(R.layout.main);
  18. Log.i("zhengxing", "MainActivity::onCreate set basic info finished");
  19. // 创建两个SurfaceView
  20. mViewDisplay = (DisplayView)this.findViewById(R.id.display_view);
  21. mViewCustom = (CustomView)this.findViewById(R.id.custom_view);
  22. Log.i("zhengxing", "MainActivity::onCreate create visual toolkits finished");
  23. //初始化camera类和alg类
  24. mCameraUtil = new CameraUtil(mViewDisplay, this);
  25. mAlgUtil = new AlgUtil(getAssets(), this);
  26. Log.i("zhengxing", "MainActivity::onCreate create camera util and alg util finished");
  27. }
  28. // 开始按钮
  29. public void onBtnStartClick(View view){
  30. Log.i("zhengxing", "MainActivity::onBtnStartClick");
  31. if (mCameraUtil.getCameraState() < 0){
  32. mCameraUtil.openCamera();
  33. Log.i("zhengxing", "MainActivity::onBtnStartClick the camera is closed, open it");
  34. }
  35. }
  36. //停止按钮
  37. public void onBtnStopClick(View view){
  38. Log.i("zhengxing", "MainActivity::onBtnStopClick");
  39. if (mCameraUtil.getCameraState() >= 0){
  40. mCameraUtil.closeCamera();
  41. Log.i("zhengxing", "MainActivity::onBtnStopClick the camera is open, close it");
  42. }
  43. }
  44. //算法回调函数,处理算法返回结果
  45. @Override
  46. public void onAlgRet(float[] ret) {
  47. float nAlgType = ret[0];
  48. float nClasss = ret[1];
  49. Log.i("zhengxing", "MainActivity::onAlgRet ret value:" + ret[0] + ';' + ret[1]);
  50. mViewCustom.drawAlgRet(ret);
  51. }
  52. //预览回调函数,处理每一帧图片
  53. @Override
  54. public void onPreviewFrame(byte[] data, Camera camera) {
  55. mFrameCount ++;
  56. Log.i("zhengxing", "MainActivity::onPreviewFrame");
  57. Camera.Size size = camera.getParameters().getPreviewSize();
  58. mAlgUtil.addDataToQueue(data, size.width, size.height);
  59. }
  60. }

3.2、Camera类核心源码

  1. public class CameraUtil
  2. {
  3. private Camera mCamera;
  4. private final int mCameraID;
  5. private final SurfaceView mViewDisplay;
  6. private final int mOrientation;
  7. private final Camera.PreviewCallback mPreviewCBack;
  8. public CameraUtil(SurfaceView displayView, Camera.PreviewCallback cameraCBack) {
  9. Log.i("zhengxing", "CameraUtil::CameraUtil");
  10. mCamera = null;
  11. mViewDisplay = displayView;
  12. mCameraID = Camera.CameraInfo.CAMERA_FACING_FRONT;
  13. mOrientation = 0;
  14. mPreviewCBack = cameraCBack;
  15. }
  16. //打开摄像头
  17. public void openCamera() {
  18. Log.i("zhengxing", "CameraUtil::openCamera");
  19. if(mCamera == null) {
  20. mCamera = Camera.open(mCameraID);
  21. Camera.Parameters parameters = mCamera.getParameters();
  22. //parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
  23. //mCamera.setParameters(parameters);
  24. mCamera.setDisplayOrientation(mOrientation);
  25. mCamera.setPreviewCallback(mPreviewCBack);
  26. try {
  27. mCamera.setPreviewDisplay(mViewDisplay.getHolder());
  28. } catch (IOException e) {
  29. e.printStackTrace();
  30. }
  31. mCamera.startPreview();
  32. }
  33. }
  34. //关闭摄像头
  35. public void closeCamera() {
  36. Log.i("zhengxing", "CameraUtil::closeCamera");
  37. if (mCamera != null) {
  38. mCamera.setPreviewCallback(null);
  39. mCamera.stopPreview();
  40. mCamera.release();
  41. mCamera = null;
  42. }
  43. }
  44. }

3.3、Alg类核心源码

  1. class AlgUtil implements Runnable {
  2. private boolean mThreadFlag;
  3. private final ArrayBlockingQueue mQueue;
  4. private final Alg mAlg;
  5. private final int mAlgThreads;
  6. private AlgCallBack mAlgCB;
  7. private final Thread mThread;
  8. public AlgUtil(AssetManager assertManager, AlgCallBack algCallBack) {
  9. Log.i("zhengxing", "AlgUtil::AlgUtil");
  10. mAlgCB = algCallBack;
  11. mAlgThreads = 1;
  12. mQueue = new ArrayBlockingQueue(3);
  13. mAlg = new Alg();
  14. mAlg.Init(assertManager);
  15. mThreadFlag = true;
  16. mThread = new Thread(this);
  17. mThread.start();
  18. }
  19. //将预览图片投递到队列中(由于算法处理可能会比较慢,并不是每一帧图片都做算法处理)
  20. public boolean addDataToQueue(byte [] bytes, int width, int height) {
  21. Log.i("zhengxing", "AlgUtil::addDataToQueue");
  22. Bitmap bmp = null;
  23. try {
  24. YuvImage image = new YuvImage(bytes, ImageFormat.NV21, width, height, null);
  25. if (image != null) {
  26. ByteArrayOutputStream stream = new ByteArrayOutputStream();
  27. image.compressToJpeg(new Rect(0, 0, width, height), 100, stream);
  28. bmp = BitmapFactory.decodeByteArray(stream.toByteArray(), 0, stream.size());
  29. stream.close();
  30. }
  31. } catch (Exception ex) {
  32. }
  33. Bitmap rgba = bmp.copy(Bitmap.Config.ARGB_8888, true);
  34. Bitmap imgSelect = Bitmap.createScaledBitmap(rgba, 312, 312, false);
  35. rgba.recycle();
  36. return mQueue.offer(imgSelect);
  37. }
  38. //返回算法推理结果给上层(Activity)
  39. public void setCallBack(AlgCallBack callBack) {
  40. Log.i("zhengxing", "AlgUtil::setCallBack");
  41. this.mAlgCB = callBack;
  42. }
  43. //线程体(所有算法推理都在线程中执行)
  44. @Override
  45. public void run() {
  46. Log.i("zhengxing", "AlgUtil::run");
  47. while (mThreadFlag) {
  48. try {
  49. Bitmap bmp = (Bitmap) mQueue.poll(1000, TimeUnit.MILLISECONDS);
  50. if (bmp != null) {
  51. float[] x = mAlg.Run(bmp);
  52. this.mAlgCB.onAlgRet(x);
  53. }
  54. } catch (InterruptedException e) {
  55. e.printStackTrace();
  56. }
  57. }
  58. }
  59. }

4、总结

这次仰卧起坐APP开发前后经历了大约一个月的时间,都是在晚上或者周末进行的。虽然很累,但是我也学到了很多东西。从原来完全不了解姿态估计这个领域,以及严重低估关键点检测的难度,到后来慢慢学习,整理相关论文,解决一个又一个难点,对我自己来说是一次极大的提升,也是对自己兴趣爱好的执着。如果整个过程也让你也有一点点的收获,那将是对我极大的鼓励。【获取APP源码请留言或者添加我的微信,15158106211,备注“仰卧起坐APP”,让我们一起学习一起进步。】

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/323505
推荐阅读
相关标签
  

闽ICP备14008679号