基于yolov5的手掌特效app(安卓)

1.前言:

今天给大家分享一个好玩的项目app,该app和上一个博客的效果有点类似,不同的是在该博客中加入了目标检测部分。首先来看一下效果预览:

手掌特效app

2.简介:

介绍一下主要流程,首先使用yolov5训练一个识别手掌的模型,然后准备好需要播放的特效视频。获取摄像头画面进行目标检测,检测到手掌正面以后,在手掌的矩形框内播放特效视频。

3.训练模型

使用yolov5训练模型网上教程有很多,这里不再详细叙述。使用的数据集是本人使用手机拍摄的,一共400张左右,一共分为3个类别,分别是拳头;正面;反面。数据集已经标注完成。如有需要可前往下载
数据集下载地址:
链接:https://pan.baidu.com/s/1BgJsbswReeKHTWrpGDMviQ
提取码:mk9o

4.特效视频

使用的特效视频是直接在快手和抖音上面下载的。部分特效视频如下所示:
螺旋丸特效视频:

5.代码

Mainactivity.java代码:

package com.myapp.handfire2;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.camera.core.Camera;
import androidx.camera.core.CameraControl;
import androidx.camera.core.CameraSelector;
import androidx.camera.core.ImageAnalysis;
import androidx.camera.core.ImageCapture;
import androidx.camera.core.ImageProxy;
import androidx.camera.core.Preview;
import androidx.camera.lifecycle.ProcessCameraProvider;
import androidx.camera.view.PreviewView;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import android.annotation.SuppressLint;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.ImageFormat;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.YuvImage;
import android.media.MediaPlayer;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.os.Message;
import android.os.SystemClock;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.Spinner;
import android.widget.TextView;

import com.google.common.util.concurrent.ListenableFuture;
import com.myapp.handfire2.databinding.ActivityMainBinding;

import org.jetbrains.annotations.NotNull;

import java.io.ByteArrayOutputStream;
import java.nio.ByteBuffer;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;


public class MainActivity extends AppCompatActivity {

    // Used to load the 'native-lib' library on application startup.
    static {
        System.loadLibrary("native-lib");
    }

    private ActivityMainBinding binding;

    public static MyRenderer myRenderer;
    private GLSurfaceView glSurfaceView;
    private Spinner spinner;

    private Myview myview;

    private final String[] REQUIRED_PERMISSIONS = new String[]{"android.permission.CAMERA", "android.permission.WRITE_EXTERNAL_STORAGE"};
    private int REQUEST_CODE_PERMISSIONS = 1001;

    PreviewView pvCameraPreview;
    private Yolov5n Yolov5Net=new Yolov5n();
    private int[] texiao={R.raw.chuizi,R.raw.fire,R.raw.hunhuan,R.raw.qianniao,R.raw.wanzi,R.raw.wanzi2};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        boolean init=Yolov5Net.Init(getAssets());


        binding = ActivityMainBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());
        myview=binding.view;
        spinner=binding.spin;

        spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                myRenderer.start(texiao[position]);

            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) {


            }
        });

        glSurfaceView=binding.glview;
        glSurfaceView.setEGLContextClientVersion(2);
        //背景透明
        glSurfaceView.setEGLConfigChooser(8,8,8,8,16,0);
        glSurfaceView.getHolder().setFormat(PixelFormat.TRANSLUCENT);
        glSurfaceView.setZOrderOnTop(true);
        MyRenderer.myMediaPlayer = new MediaPlayer();



        myRenderer=new MyRenderer(this);
        glSurfaceView.setRenderer(myRenderer);
        //myRenderer.start(texiao[0]);
//
//        button=binding.btn;
//        button.setOnClickListener(new View.OnClickListener() {
//            @Override
//            public void onClick(View v) {
//                //myRenderer.start("");
//                Log.i("aa","click");
//
//            }
//        });

        pvCameraPreview=binding.preview;

        //获取权限
        if(allPermissionsGranted()){
            startCamera(); //start camera if permission has been granted by user
        } else{
            ActivityCompat.requestPermissions(this, REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS);
        }


    }
    //获取权限函数
    private boolean allPermissionsGranted() {
        for (String permission : REQUIRED_PERMISSIONS) {
            if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
                return false;
            }
        }
        return true;
    }

    /**
     * 开始预览
     */
    private CameraControl cameraControl;
    private Executor executor = Executors.newSingleThreadExecutor();
    private void startCamera() {
        ListenableFuture<ProcessCameraProvider> cameraProviderFuture =
                ProcessCameraProvider.getInstance(this);
        ((ListenableFuture<?>) cameraProviderFuture).addListener(new Runnable() {
            @SuppressLint("RestrictedApi")
            @Override
            public void run() {
                try {

                    ImageAnalysis imageAnalysis = new ImageAnalysis.Builder()
                            //.setBackpressureStrategy(ImageAnalysis.STRATEGY_BLOCK_PRODUCER)//阻塞模式
                            //.setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_YUV_420_888)
                            //.setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_RGBA_8888)
                            .build();
                    imageAnalysis.setAnalyzer(executor, new ImageAnalysis.Analyzer() {
                        @Override
                        public void analyze(@NonNull @NotNull ImageProxy image) {

                            //yuv图像数据转bitmap
                            ImageProxy.PlaneProxy[] planes = image.getPlanes();
                            //cameraX 获取yuv
                            ByteBuffer yBuffer = planes[0].getBuffer();
                            ByteBuffer uBuffer = planes[1].getBuffer();
                            ByteBuffer vBuffer = planes[2].getBuffer();

                            int ySize = yBuffer.remaining();
                            int uSize = uBuffer.remaining();
                            int vSize = vBuffer.remaining();

                            byte[] nv21 = new byte[ySize + uSize + vSize];

                            yBuffer.get(nv21, 0, ySize);
                            vBuffer.get(nv21, ySize, vSize);
                            uBuffer.get(nv21, ySize + vSize, uSize);
                            //获取yuvImage
                            YuvImage yuvImage = new YuvImage(nv21, ImageFormat.NV21, image.getWidth(), image.getHeight(), null);
                            //输出流
                            ByteArrayOutputStream out = new ByteArrayOutputStream();
                            //压缩写入out
                            yuvImage.compressToJpeg(new Rect(0, 0, yuvImage.getWidth(), yuvImage.getHeight()), 50, out);
                            //转数组
                            byte[] imageBytes = out.toByteArray();
                            //生成bitmap
                            Bitmap bmp = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length);

//                            Bitmap rotateBitmap=null;

                            Dector(bmp);

                            image.close();
                        }
                    });
                    //将相机的生命周期和activity的生命周期绑定,camerax 会自己释放
                    ProcessCameraProvider cameraProvider = cameraProviderFuture.get();
                    Preview preview = new Preview.Builder().build();
                    //创建图片的 capture
                    ImageCapture mImageCapture = new ImageCapture.Builder()
                            .setFlashMode(ImageCapture.FLASH_MODE_OFF)
                            .build();
                    //选择前置摄像头
                    CameraSelector cameraSelector = new CameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_BACK).build();
                    // Unbind use cases before rebinding
                    cameraProvider.unbindAll();

                    // Bind use cases to camera
                    //参数中如果有mImageCapture才能拍照,否则会报下错
                    //Not bound to a valid Camera [ImageCapture:androidx.camera.core.ImageCapture-bce6e930-b637-40ee-b9b9-
                    Camera camera = cameraProvider.bindToLifecycle(MainActivity.this, cameraSelector, preview, imageAnalysis,mImageCapture);

                    cameraControl = camera.getCameraControl();
                    cameraControl.setLinearZoom(0.1f);
                   preview.setSurfaceProvider(pvCameraPreview.getSurfaceProvider());
                } catch (ExecutionException e) {
                    e.printStackTrace();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, ContextCompat.getMainExecutor(this));
    }
    private void setFrame() {

    }

    /**
     * 检测函数
     */
    private void  Dector(Bitmap bitmap) {
        // draw objects on bitmap
        Bitmap rgba = bitmap.copy(Bitmap.Config.ARGB_8888, true);
        Yolov5n.Obj[] objects = Yolov5Net.Detect(rgba, false, 0.25f);
        float width = rgba.getWidth();
        float height = rgba.getHeight();
        myview.draws(objects,width,height,true,false);
    }
}

布局代码:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">


    <androidx.camera.view.PreviewView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/preview"
        />


    <android.opengl.GLSurfaceView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/glview"
        />

    <com.myapp.handfire2.Myview
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/view"
        />
    <Spinner
        android:layout_width="100dp"
        android:layout_height="wrap_content"
        android:layout_gravity="right"
        android:id="@+id/spin"
        android:entries="@array/texiao"
        android:background="@mipmap/xia"
        android:alpha="0.7"
        
        />

</FrameLayout>

6.app下载地址及项目下载地址

如果手机端打不开,可以使用电脑试一下。
项目地址:https://gitee.com/mqwdasddqw/HandFire2

app下载地址:https://www.pgyer.com/bjSZ

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值