文章目录
前言
近期,由于老师的要求,我们需要实现将Android Studio摄像头获取的视频实时传输到服务端,而在手机端实时显示。我们决定采用Opencv与Socket实现该功能,网上相关教程较少,因此我们决定写篇文章用于记录一下。
一、如何在Android Studio上部署OpenCv
关于OpenCV在Android Studio上部署,网上已经有许多教程了,我们采用直接接入OpenCV的java SDK的方式。(感谢这位大佬的细致介绍)
1.下载opencv
进入OpenCV的官网下载opencv,在界面中选择Android,我下载的是OpenCV4.2.0

2.Android Studio创建项目
在Android 项目右上角选择SDK Manager - Android SDK - SDK Tools,确保下载了CMake, NDK。


鉴于以后可能会使用ncnn的原因,我们采用native c++的方式创建了项目。

此后的选择与参考了大佬的步骤
3.配置OpenCV
创建了项目后,点击File->New->Import Module,

引入Opencv - android中的java文件夹,我的路径如下
opencv-4.2.0-android-sdk\OpenCV-android-sdk\sdk
出现黄色警报后可以勾选import选项并更改名称为opencv:

选择Finish后导入了作为Module的OpenCV,此时选择build.gradle(注意,一定是OpenCV的build.gradle),接下来更改
apply plugin: 'com.android.application'
改为:
apply plugin: 'com.android.library'
并删除这一行
defaultConfig {
applicationId “org.opencv”
}
为了避免不必要的错误,尽可能调整app的build.gradle与opencv的build.gradle中
compileSdkVersion 29
buildToolsVersion “29.0.2”
此时,将app 的build.gradle中的
externalNativeBuild {
cmake {
cppFlags “-std=c++14”
}
}
更改为
externalNativeBuild {
cmake {
arguments "-DANDROID_STL=c++_shared"
}
用于连接opencv的共享库。
在最后
dependencies{}
之中加入
implementation project( ':opencv')
对应数值相同,如果仍可能出错,则应调整自己下载的OpenCV或SDK,点击Sync now,等待同步成功。
接下来应在AndroidMainifest.xml中申请摄像头与网络权限。
<uses-sdk tools:overrideLibrary="android.support.compat, android.arch.lifecycle" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-feature
android:name="android.hardware.camera"
android:required="false" />
<uses-feature
android:name="android.hardware.camera.autofocus"
android:required="false" />
<uses-feature
android:name="android.hardware.camera.front"
android:required="false" />
<uses-feature
android:name="android.hardware.camera.front.autofocus"
android:required="false" />
在Andorid 项目目录
app\src\main
下创建文件夹,其名为(为与后续步骤一致,因此此处位置可以按我的方式放置)
jniLibs
并将下载的opencv-android中的libs文件复制到此文件夹下,其目录结构为

由于动态链接库*.so文件在cmke默认下是并不是按照以上的路径寻找的,因此需要在cpp文件夹下的CMakeLists.txt下加入
set_target_properties(libopencv_java4 PROPERTIES IMPORTED_LOCATION
${
CMAKE_SOURCE_DIR}/../jniLibs/libs/${
ANDROID_ABI}/libopencv_java4.so)
其中CMAKE_SOURCE_DIR表示了CMakeList.txt所在的文件夹,同时加入
add_library(libopencv_java4 SHARED IMPORTED)
target_link_libraries( # Specifies the target library.
libopencv_java4 # 链接opencv的so
# Links the target library to the log library
# included in the NDK.
${
log-lib} )
此时opencv已经可以使用了,我们通过以上步骤可实现用JNI的方式引入了OpenCV。
二、用户端代码实现
1.利用Application实现多界面共享Socket
由于Socket在Activity中创建时,其生命周期与Activity生命周期一致,为实现Socket在不同界面的共享,我们采用了Application的方式。自定义一个Class,创建的java class名为MySocket
package com.example.myapplication;
import android.app.Application;
import java.net.Socket;
public class MySocket extends Application {
Socket socket = null;
public Socket getSocket() {
System.out.println(socket);
return socket;
}
public void setSocket(Socket socket) {
this.socket = socket;
}
}
并在AndroidManifest.xml文件中的application标签下添加:
android:name= ".MySocket"
在后续调用中,Application可以将MySocket的生命周期调整与APP生命周期一致,因此可以实现APP与服务器的长连接。
2.更改MainActivity
在此我们并不打算将MainActivitzy作为主界面,而是用来初始化MySocekt,MainActivity的代码如下:
import androidx.appcompat.app.AppCompatActivity;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import java.net.Socket;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Thread myThread=new Thread(){
//创建子线程
@Override
public void run() {
try{
Socket socket = new Socket("127.0.0.1",Integer.parseInt("5050")); //此处可更换自己的服务器IP与端口号
((MySocket)getApplication()).setSocket(socket);//初始化MySocket
System.out.println("ok");
}catch (Exception e){
e.printStackTrace();
}
}
};
myThread.start();//启动线程
setContentView(R.layout.activity_main);
MainActivity.this.startActivity(new Intent(MainActivity.this.getApplicationContext(), StartActivity.class));//此处用于打开主界面
MainActivity.this.finish();
}
}
主要注意Socket的初始化,并且Socket要放在子线程中。
2.创建StartActivity做主界面
本段并没有特别的注意事项,只需要设计一个打开摄像头的按钮即可,以下是activity_start.xml的代码
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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=".StartActivity">
<LinearLayout
android:layout_height="match_parent"
android:layout_width="match_parent"
android:gravity="center"
android:layout_weight="1">
<Button
android:layout_width="280dp"
android:layout_height="32dp"
android:text="测试按钮"
android:id="@+id/camera"
android:textColor="#000"
tools:ignore="InvalidId" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
其界面代码为
package com.example.myapplication;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class StartActivity extends AppCompatActivity {
private Button button;
@Override
protected void onCreate(Bundle savedInstanceState) {
button = findViewById(R.id.camera);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_start);
button.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
Intent intent = new

本文详细介绍了如何在Android Studio中部署OpenCV库,并通过JNI方式接入,实现在Android应用中捕获摄像头视频流,并通过Socket实时传输到服务器。首先,从OpenCV官网下载SDK,然后在Android Studio项目中配置OpenCV模块,包括修改build.gradle文件、添加依赖及设置权限。接着,创建一个Application子类来管理Socket连接,确保长连接在多个界面间共享。在MainActivity中初始化Socket,StartActivity作为主界面,CameraGetActivity用于显示并处理摄像头画面,通过OpenCV的JavaCamera2View获取每一帧图像,Base64编码后通过Socket发送。服务端使用Python的socket和OpenCV接收并显示接收到的图像。最后,文章提供了完整的服务端和客户端代码实现。
最低0.47元/天 解锁文章
3282





