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類核心原始碼
public class MainActivity extends Activity implements Camera.PreviewCallback, AlgCallBack{
private DisplayView mViewDisplay;
private CustomView mViewCustom;
private Button mBtnCameraOp;
private Button mBtnCameraChange;
private CameraUtil mCameraUtil;
private AlgUtil mAlgUtil;
private int mFrameCount = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
Log.i("zhengxing", "MainActivity::onCreate");
super.onCreate(savedInstanceState);
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
setContentView(R.layout.main);
Log.i("zhengxing", "MainActivity::onCreate set basic info finished");
// 創建兩個SurfaceView
mViewDisplay = (DisplayView)this.findViewById(R.id.display_view);
mViewCustom = (CustomView)this.findViewById(R.id.custom_view);
Log.i("zhengxing", "MainActivity::onCreate create visual toolkits finished");
//初始化camera類和alg類
mCameraUtil = new CameraUtil(mViewDisplay, this);
mAlgUtil = new AlgUtil(getAssets(), this);
Log.i("zhengxing", "MainActivity::onCreate create camera util and alg util finished");
}
// 開始按鈕
public void onBtnStartClick(View view){
Log.i("zhengxing", "MainActivity::onBtnStartClick");
if (mCameraUtil.getCameraState() < 0){
mCameraUtil.openCamera();
Log.i("zhengxing", "MainActivity::onBtnStartClick the camera is closed, open it");
}
}
//停止按鈕
public void onBtnStopClick(View view){
Log.i("zhengxing", "MainActivity::onBtnStopClick");
if (mCameraUtil.getCameraState() >= 0){
mCameraUtil.closeCamera();
Log.i("zhengxing", "MainActivity::onBtnStopClick the camera is open, close it");
}
}
//演算法回呼函式,處理演算法回傳結果
@Override
public void onAlgRet(float[] ret) {
float nAlgType = ret[0];
float nClasss = ret[1];
Log.i("zhengxing", "MainActivity::onAlgRet ret value:" + ret[0] + ';' + ret[1]);
mViewCustom.drawAlgRet(ret);
}
//預覽回呼函式,處理每一幀圖片
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
mFrameCount ++;
Log.i("zhengxing", "MainActivity::onPreviewFrame");
Camera.Size size = camera.getParameters().getPreviewSize();
mAlgUtil.addDataToQueue(data, size.width, size.height);
}
}
3.2、Camera類核心原始碼
public class CameraUtil
{
private Camera mCamera;
private final int mCameraID;
private final SurfaceView mViewDisplay;
private final int mOrientation;
private final Camera.PreviewCallback mPreviewCBack;
public CameraUtil(SurfaceView displayView, Camera.PreviewCallback cameraCBack) {
Log.i("zhengxing", "CameraUtil::CameraUtil");
mCamera = null;
mViewDisplay = displayView;
mCameraID = Camera.CameraInfo.CAMERA_FACING_FRONT;
mOrientation = 0;
mPreviewCBack = cameraCBack;
}
//打開攝像頭
public void openCamera() {
Log.i("zhengxing", "CameraUtil::openCamera");
if(mCamera == null) {
mCamera = Camera.open(mCameraID);
Camera.Parameters parameters = mCamera.getParameters();
//parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
//mCamera.setParameters(parameters);
mCamera.setDisplayOrientation(mOrientation);
mCamera.setPreviewCallback(mPreviewCBack);
try {
mCamera.setPreviewDisplay(mViewDisplay.getHolder());
} catch (IOException e) {
e.printStackTrace();
}
mCamera.startPreview();
}
}
//關閉攝像頭
public void closeCamera() {
Log.i("zhengxing", "CameraUtil::closeCamera");
if (mCamera != null) {
mCamera.setPreviewCallback(null);
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
}
}
3.3、Alg類核心原始碼
class AlgUtil implements Runnable {
private boolean mThreadFlag;
private final ArrayBlockingQueue mQueue;
private final Alg mAlg;
private final int mAlgThreads;
private AlgCallBack mAlgCB;
private final Thread mThread;
public AlgUtil(AssetManager assertManager, AlgCallBack algCallBack) {
Log.i("zhengxing", "AlgUtil::AlgUtil");
mAlgCB = algCallBack;
mAlgThreads = 1;
mQueue = new ArrayBlockingQueue(3);
mAlg = new Alg();
mAlg.Init(assertManager);
mThreadFlag = true;
mThread = new Thread(this);
mThread.start();
}
//將預覽圖片投遞到佇列中(由于演算法處理可能會比較慢,并不是每一幀圖片都做演算法處理)
public boolean addDataToQueue(byte [] bytes, int width, int height) {
Log.i("zhengxing", "AlgUtil::addDataToQueue");
Bitmap bmp = null;
try {
YuvImage image = new YuvImage(bytes, ImageFormat.NV21, width, height, null);
if (image != null) {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
image.compressToJpeg(new Rect(0, 0, width, height), 100, stream);
bmp = BitmapFactory.decodeByteArray(stream.toByteArray(), 0, stream.size());
stream.close();
}
} catch (Exception ex) {
}
Bitmap rgba = bmp.copy(Bitmap.Config.ARGB_8888, true);
Bitmap imgSelect = Bitmap.createScaledBitmap(rgba, 312, 312, false);
rgba.recycle();
return mQueue.offer(imgSelect);
}
//回傳演算法推理結果給上層(Activity)
public void setCallBack(AlgCallBack callBack) {
Log.i("zhengxing", "AlgUtil::setCallBack");
this.mAlgCB = callBack;
}
//執行緒體(所有演算法推理都在執行緒中執行)
@Override
public void run() {
Log.i("zhengxing", "AlgUtil::run");
while (mThreadFlag) {
try {
Bitmap bmp = (Bitmap) mQueue.poll(1000, TimeUnit.MILLISECONDS);
if (bmp != null) {
float[] x = mAlg.Run(bmp);
this.mAlgCB.onAlgRet(x);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
4、總結
這次仰臥起坐APP開發前后經歷了大約一個月的時間,都是在晚上或者周末進行的,雖然很累,但是我也學到了很多東西,從原來完全不了解姿態估計這個領域,以及嚴重低估關鍵點檢測的難度,到后來慢慢學習,整理相關論文,解決一個又一個難點,對我自己來說是一次極大的提升,也是對自己興趣愛好的執著,如果整個程序也讓你也有一點點的識訓,那將是對我極大的鼓勵,【獲取APP原始碼請留言或者添加我的微信,15158106211,備注“仰臥起坐APP”,讓我們一起學習一起進步,】
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/272959.html
標籤:其他
下一篇:對JAVA的一些簡單了解
