突然接了一个需要接入opencv的需求,作为一个零基础opencv的编程人员,心里怂的一逼。然后各种百度,接着就发现了,网上的资料真的是一大堆的坑,缺这缺那的,没有一个是真正可以让项目跑的起来的。心态爆炸,好在自己去看了一下opencv的文档,总算整出来一个可以正常跑起来的项目,分享开大家,让大家少走的弯路。废话不多说了开始吧:
首先我们需要去opencv的官网获取我们的SDK,网址:https://opencv.org/
鉴于opencv官网在没有搭梯子的情况下,下载速度慢,且容易连接失败,博主这里已经有个资源,大家可以去下载就好:https://download.csdn.net/download/weixin_40600325/13985088
目前博主的opencv的版本是4.5.1的,下载完后我们解压到指定的文件夹后打开这个路径
这里面的SDK就是我们需要的东西,想必各位对怎么接入SDK应该已经非常熟悉了吧,但是!请大家先不要着急,我们还要做一件事件,不然后面就都是坑。
首先我们可以先去百度百科搜索opencv,然后我们会看到这样的介绍:
看到了吗?,Opencv是由一系列c函数和少量C++类构成的,这一句话大家想到了什么?我们Android和C、C++交互需要做什么?没错,需要我们的NDK开发,而做NDK开发,就需要安装几个插件,我们先把插件安装好。如果有安装过的同学可以忽略该步骤,那么我们需要安装的插件如下:
NDK和CMake,有的同学可以能还需要LLDB,由于博主的Android studio是最新的版本的,所以只需要Android这两个插件。
安装完后,我们先创建一个项目,名字随意,但是必须是要支持C、C++的项目。如下:
新版的Android studio创建C项目选择的是图中的Native C++这个项,旧版的博主记得是可以直接勾选的支持C++的,都一样,反正就是创建这样一个项目,这个超级重要,避免后面很多的坑。接着我们打开我们创建的项目后,找到下图的文件夹,然后拷贝下来。
一定要把,这个CPP文件夹拷贝下来,或者你也可以直接在该项目做你接入opencv的项目,但是如果你是想加入旧项目中的话,这个文件夹就要拷贝下来。
接着就是重头戏了,我们现在可以关闭这个支持C的项目,又或者你可以用这个项目来做接入Opencv,如下步骤都是适合的。
打开需要接入opencv的项目。
引入我们的解压后得到的Opencv文件夹下的的sdk文件夹下的名为Java的项目作为新的Module,有点绕口,路径是类似这样的:D:\androidProject\OpenCV-android-sdk\sdk\java。
引入后,我们把我们之前拷贝的CPP文件夹放到我们这个项目里,也是在Main文件夹下。
接着我们去我们解压后得到的Opencv文件下找到native的路径:E:\androidProject\OpenCV-android-sdk\sdk\native\libs
然后我们把这个文件夹下面的文件都复制到我们项目的libs文件夹下:
复制到这里来:
同时把我们刚才复制的CPP文件也拷贝到该项目下的main的文件夹下:
最后,我们在App的gradle文件夹下加上这三段代码:
至此,我们最最重要的步骤完成了,只要你是跟着我步骤走的,你就可以避免网络上绝大多数的坑,列如:需要安装OpenCV Manager这样的坑,还有缺失C++_shared的坑。
到这里我们就可以把解压后的Opencv文件下的Java文件导入到我们的项目里面了,路径如下:
E:\androidProject\OpenCV-android-sdk\sdk\java
然后把导入后的JavaModule文件下的gradle改成如下的代码:
这样你就可以避免你的报错,比如:applicationId不能在library情况下设置,导入的module是项目之类的错误。
接着最好确认一下你的setting文件是不是这样的:
都没有问题后,我们就可以好好的使用我们的opencv写一下简单的代码了,因为我们已经接入好opencv了。
在写入代码之前,记得要引入一下我们的C++库,在我们的类里面写入这几行代码:
因为博主的是opencv4的版本,所以引入的是opencv_java4,如果是3点几的版本就引入opencv_java3。
接下来就是博主Demo的代码,就贴出来给大家参考一下:
首先是XML的:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:orientation="vertical">
<ImageView
android:layout_width="match_parent"
android:layout_height="200dp"
android:id="@+id/img"
android:layout_marginTop="100dp"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="导入图片"
android:layout_gravity="center"
android:layout_marginTop="20dp"
android:id="@+id/Import_img"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="50sp"
android:layout_gravity="center"
android:text="灰度化图片"
android:id="@+id/Change_img"/>
</LinearLayout>
然后是main类的代码:
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import org.opencv.android.BaseLoaderCallback;
import org.opencv.android.LoaderCallbackInterface;
import org.opencv.android.OpenCVLoader;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.content.ContentResolver;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import org.opencv.android.OpenCVLoader;
import org.opencv.android.Utils;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.imgproc.Imgproc;
import java.io.FileNotFoundException;
public class MainActivity extends AppCompatActivity {
static {
System.loadLibrary("opencv_java4");
System.loadLibrary("native-lib");
}
private Button Import_img;
private Button Change_img;
private ImageView img;
private Bitmap bitmap;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Import_img = findViewById(R.id.Import_img);
img= findViewById(R.id.img);
Change_img=findViewById(R.id.Change_img);
Import_img.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//intent可以应用于广播和发起意图,其中属性有:ComponentName,action,data等
Intent intent=new Intent();
intent.setType("image/*");
//action表示intent的类型,可以是查看、删除、发布或其他情况;我们选择ACTION_GET_CONTENT,系统可以根据Type类型来调用系统程序选择Type
//类型的内容给你选择
intent.setAction(Intent.ACTION_GET_CONTENT);
//如果第二个参数大于或等于0,那么当用户操作完成后会返回到本程序的onActivityResult方法
startActivityForResult(intent, 1);
}
});
Change_img.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Bitmap bit = bitmap.copy(Bitmap.Config.ARGB_8888, false);
Mat src = new Mat(bit.getHeight(), bit.getWidth(), CvType.CV_8UC(3));
Utils.bitmapToMat(bit, src);
Imgproc.cvtColor(src, src, Imgproc.COLOR_BGR2GRAY);
Utils.matToBitmap(src, bitmap);
Message message=new Message();
message.what=1;
handler.sendMessage(message);
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
//用户操作完成,结果码返回是-1,即RESULT_OK
if(resultCode==RESULT_OK){
//获取选中文件的定位符
Uri uri = data.getData();
Log.e("uri", uri.toString());
//使用content的接口
ContentResolver cr = this.getContentResolver();
try {
//获取图片
bitmap = BitmapFactory.decodeStream(cr.openInputStream(uri));
img.setImageBitmap(bitmap);
} catch (FileNotFoundException e) {
Log.e("Exception", e.getMessage(),e);
}
}else{
//操作错误或没有选择图片
Log.i("MainActivtiy", "operation error");
}
super.onActivityResult(requestCode, resultCode, data);
}
@Override
public void onResume()
{
super.onResume();
if (!OpenCVLoader.initDebug()) {
// Log.d("test", "Internal OpenCV library not found. Using OpenCV Manager for initialization");
// OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION, this, mLoaderCallback);
} else {
// Log.d("test", "OpenCV library found inside package. Using it!");
// mLoaderCallback.onManagerConnected(LoaderCallbackInterface.SUCCESS);
}
}
Handler handler=new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
switch (msg.what)
{
case 1:img.setImageBitmap(bitmap);break;
}
}
};
//openCV4Android 需要加载用到
private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
@Override
public void onManagerConnected(int status) {
switch (status) {
case LoaderCallbackInterface.SUCCESS: {
Log.i("test", "OpenCV loaded successfully");
// mOpenCvCameraView.enableView();
// mOpenCvCameraView.setOnTouchListener(ColorBlobDetectionActivity.this);
}
break;
default: {
super.onManagerConnected(status);
}
break;
}
}
};
}
最后,如果有什么问题欢迎留言一起探讨,谢谢各位。