安卓开发04:OpenCV SDK下载及Android Java环境搭建

一、官方网站下载sdk:https://opencv.org
1、悬停Library后点击Releases

安卓开发04:OpenCV SDK下载及Android Java环境搭建_第1张图片

2、点击Android,打开网页后会自动下载

安卓开发04:OpenCV SDK下载及Android Java环境搭建_第2张图片
安卓开发04:OpenCV SDK下载及Android Java环境搭建_第3张图片

打开后得到以下内容

安卓开发04:OpenCV SDK下载及Android Java环境搭建_第4张图片

二、打开Android新建项目进行测试,依次点击File -> New -> New Project
  • 选择Empty Activity,点击Next
    安卓开发04:OpenCV SDK下载及Android Java环境搭建_第5张图片
  • Name栏输入OpenCVTest(命名自定义),点击Finish
    安卓开发04:OpenCV SDK下载及Android Java环境搭建_第6张图片
三、将OpenCV SDK导入项目
  • 将视图切换到Project,右键项目总目录,选择New -> Module
    然后选择Android Library,将模块命名为opencv-test(自定义命名)
    最后点击Finish
    安卓开发04:OpenCV SDK下载及Android Java环境搭建_第7张图片
  • 删除目录下所有内容
    安卓开发04:OpenCV SDK下载及Android Java环境搭建_第8张图片
  • 复制sdk目录下的内容到模块opencv-test
    安卓开发04:OpenCV SDK下载及Android Java环境搭建_第9张图片
  • 打开opencv-test目录下的build.gradle文件,删除图中kotlin那一行,然后点击Sync Now
    安卓开发04:OpenCV SDK下载及Android Java环境搭建_第10张图片
  • 显示BUILD SUCCESSFUL即可
    安卓开发04:OpenCV SDK下载及Android Java环境搭建_第11张图片
四、将opencv-test模块依赖到app模块中
  • 打开app模块下的build.gradle,在dependencies中加入以下内容,点击Sync Now
implementation 'com.rabbitmq:amqp-client:5.12.0'
implementation project(path: ':opencv-test')
  • app模块下的src/main/java的包目录下新建ActivityOpencvTestActivity
public class OpencvTestActivity extends Activity {

    ConnectionFactory factory;
    //定义线程池处理上帝视角引起的程序卡死问题
    private final ThreadPoolExecutor threadPoolExecutor = new
            ThreadPoolExecutor(3, 10, 1, TimeUnit.MILLISECONDS, new LinkedBlockingDeque<>());
    private boolean mQuit = false;//当为true的时候退出画图线程
    private boolean closeCompleteFlag = false;//当为true的时候表示通道和连接都关闭
    //播放视频页面(前、后、左、右)
    private SurfaceHolder surfaceHolder;
    private static final String TAG = "opencv启动日志";
    //消费rabbitmq数据的线程
    Runnable basicConsumeRunnable;
    volatile String picture;
    //画图的runnable
    Runnable drawRunnable;
    //全局定义各视角连接和通道,便于退出Activity后关闭
    Connection connection;
    Channel channel;
    //关闭通道和连接的runnable
    Runnable closeRunnable;
    private final String TAG_THREAD = "线程池";
    private static final String TAG_RABBITMQ = "RabbitMQ";

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main_opencv);
        //初始化opencv相关变量
        initOpencv();
        playVideo();
    }

    private void initOpencv() {
        SurfaceView mySurfaceView = findViewById(R.id.surfaceViewTest);
        surfaceHolder = mySurfaceView.getHolder();
        setupConnectionFactory();
    }

    //上帝视角相关函数以及线程的开启和关闭 Start
    @SuppressLint("HandlerLeak")
    private void playVideo() {
        //用于从线程中获取数据,更新ui
        Handler incomingMessageHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                picture = msg.getData().getString("msg");
            }
        };
        //视频号
        basicConsumeRunnable = getBasicConsumeRunnable(incomingMessageHandler);
        threadPoolExecutor.execute(basicConsumeRunnable);
        surfaceHolder.addCallback(new SurfaceHolder.Callback() {
            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
                // TODO Auto-generated method stub
            }
            @Override
            public void surfaceCreated(SurfaceHolder holder) {
                // TODO Auto-generated method stub
                drawRunnable = getDrawRunnable();
                threadPoolExecutor.execute(drawRunnable);
            }
            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {
                // TODO Auto-generated method stub
            }
        });
    }
    
    /**
     * 关闭channel和connection的runnable,网络请求不能在主线程挂起
     *
     * @return 运行的runnable
     */
    private Runnable getCloseRunnable(Channel channel, Connection connection){
        return () -> closeChannelAndConnection(channel, connection);
    }

    //画图线程
    private Runnable getDrawRunnable() {
        return () -> {
            Paint paint = new Paint();
            paint.setAntiAlias(true);
            paint.setStyle(Paint.Style.STROKE);
            //矩形区域:左上角、右下角(坐标)(老铁稳)
            Rect mSrcRect = new Rect(0, 0, 6500, 1080);;
            Rect mDestRect = new Rect(0, 0, 7200, 1080);
            while (!mQuit) {
                // Lock the canvas for drawing
                Canvas canvas = surfaceHolder.lockCanvas();
                if (canvas == null) {
                    Log.i("WindowSurface", "Failure locking canvas");
                    continue;
                }
                if (picture != null) {
                    Bitmap bmp = returnBitMap(picture);
                    // Bitmap scaled = scaleBitmap(bmp, 0.95f);
                    canvas.drawBitmap(Objects.requireNonNull(bmp), mSrcRect, mDestRect, paint);
                }
                // Update graphics
                // All done
                surfaceHolder.unlockCanvasAndPost(canvas);
            }
            Log.d(TAG_THREAD, "画图线程已关闭");
        };
    }

    //消费者线程
    private Runnable getBasicConsumeRunnable(Handler incomingMessageHandler) {
        return () -> basicConsume(incomingMessageHandler);
    }

    //收消息(从发布者那边订阅消息)
    private void basicConsume(final Handler handler) {
        try {
            Log.d(TAG, "basicConsume: 已连接");
            connection = factory.newConnection();
            Log.d(TAG, "basicConsume: 通道已建立");
            channel = connection.createChannel();
            //实现Consumer的最简单方法是将便捷类DefaultConsumer子类化。可以在basicConsume 调用上传递此子类的对象以设置订阅:
            channel.basicConsume("video_6", false, new DefaultConsumer(channel) {
                @Override
                public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                    super.handleDelivery(consumerTag, envelope, properties, body);
                    String msg = new String(body);
                    long deliveryTag = envelope.getDeliveryTag();
                    channel.basicAck(deliveryTag, false);
                    //从message池中获取msg对象更高效
                    Message uiMsg = handler.obtainMessage();
                    Bundle bundle = new Bundle();
                    bundle.putString("msg", msg);
                    uiMsg.setData(bundle);
                    Log.d(TAG, "handleDelivery: msg" + msg);
                    handler.sendMessage(uiMsg);
                }
            });
        } catch (IOException | TimeoutException e) {
            e.printStackTrace();
        }
    }

    //关闭通道和连接
    private void closeChannelAndConnection(Channel channel, Connection connection) {
        //关闭通道
        if (channel != null){
            if (channel.isOpen()) {
                try {
                    channel.close();
                } catch (IOException | TimeoutException e) {
                    e.printStackTrace();
                }
            }
            Log.d(TAG_RABBITMQ, "channel关闭状态:" + !channel.isOpen());
        }

        //关闭连接
        if (connection != null) {
            if (connection.isOpen()) {
                try {
                    connection.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            Log.d(TAG_RABBITMQ, "connection关闭状态:" + !connection.isOpen());
        }

        Log.d(TAG_THREAD, "通道线程已关闭");
        closeCompleteFlag = true;//设置为true表示关闭完成

    }

    //关闭正在运行的所有线程
    private void closeMyActivity() {
        //设置为true可以关闭画图线程
        mQuit = true;
        //关闭channel和connection通道的线程
        closeRunnable = getCloseRunnable(channel, connection);
        threadPoolExecutor.execute(closeRunnable);
        //closeCompleteFlag为true表示通道关闭完成
        while (!closeCompleteFlag) {
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        threadPoolExecutor.shutdownNow();//杀死所有运行结束的线程
        Log.d(TAG_THREAD, "线程池排队数量:" + threadPoolExecutor.getQueue().size());
        Log.d(TAG_THREAD, "正在运行的线程数量:" + threadPoolExecutor.getActiveCount());
        Log.d(TAG_THREAD, "执行完成的线程数量" + threadPoolExecutor.getCompletedTaskCount());
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (!OpenCVLoader.initDebug()) {
            Log.d(TAG, "Internal OpenCV library not found. Using OpenCV Manager for initialization");
            OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_3_0_0, this, mLoaderCallback);
        } else {
            Log.d(TAG, "OpenCV library found inside package. Using it!");
            mLoaderCallback.onManagerConnected(LoaderCallbackInterface.SUCCESS);
        }
    }

    //openCV4Android 需要加载用到
    private final BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
        @Override
        public void onManagerConnected(int status) {
            if (status == LoaderCallbackInterface.SUCCESS) {
                Log.i(TAG, "OpenCV loaded successfully");
            } else {
                super.onManagerConnected(status);
            }
        }
    };

    private Bitmap returnBitMap(String message) {
        byte[] frame = Base64.decode(message.getBytes(), Base64.DEFAULT);
        try{
            Mat mat = Imgcodecs.imdecode(new MatOfByte(frame),Imgcodecs.IMREAD_UNCHANGED);
            Bitmap bmp = Bitmap.createBitmap(mat.width(), mat.height(), Bitmap.Config.ARGB_8888);
            Utils.matToBitmap(mat,bmp);
            return bmp;
        }catch (Exception e){
            return null;
        }
    }

    /**
     * 连接设置
     */
    private void setupConnectionFactory() {
        factory = new ConnectionFactory();
        factory.setHost("47.242.239.206");
        factory.setPort(5672);
        factory.setUsername("zdx19981006");
        factory.setPassword("19981006");
    }

    // 缩放函数
    private Bitmap scaleBitmap(Bitmap origin, float ratio) {
        if (origin == null) {
            return null;
        }
        int width = origin.getWidth();
        int height = origin.getHeight();
        Matrix matrix = new Matrix();
        matrix.preScale(ratio, ratio);
        Bitmap newBM = Bitmap.createBitmap(origin, 0, 0, width, height, matrix, false);
        if (newBM.equals(origin)) {
            return newBM;
        }
        origin.recycle();
        return newBM;
    }

    @Override
    public void onBackPressed() {
        //选择确定会杀死所有线程
        closeMyActivity();
        super.onBackPressed();
    }

    //销毁Activity回调方法
    @Override
    protected void onDestroy() {
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        threadPoolExecutor.shutdownNow();
        Log.d(TAG_THREAD, "线程池排队数量:" + threadPoolExecutor.getQueue().size());
        Log.d(TAG_THREAD, "正在运行的线程数量:" + threadPoolExecutor.getActiveCount());
        Log.d(TAG_THREAD, "执行完成的线程数量" + threadPoolExecutor.getCompletedTaskCount());
        super.onDestroy();
    }
}
  • 对应的xml文件:activity_main_opencv.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical">
    
    <SurfaceView
        android:id="@+id/surfaceViewTest"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" />

</LinearLayout>
  • AndroidManifest.xml中修改主启动类进行测试
<!--测试opencv-->
<activity android:name=".OpencvTestActivity"
    tools:ignore="IntentFilterExportedReceiver">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>
五、启动程序,查看日志
  • 连接手机,打开开发者选项进行调试
  • 点击Logcat,输入opencv启动日志检索日志
  • 出现以下日志即成功集成opencv
    安卓开发04:OpenCV SDK下载及Android Java环境搭建_第12张图片

你可能感兴趣的:(安卓开发,android,java,opencv)