目錄
??OpenCV??
??示例代碼??
??測試效果??
??參考博客:??
近期課題需要用Android實時處理視頻,所以做了一些這方面的工作
本文示例代碼地址:??https://github.com/nikolajohn/OpenCVtest??
推薦一個基于Android OpenCV的目標檢測項目:??https://github.com/nikolajohn/OpenCVForAndroid??
OpenCV全稱Open Source Computer VisoVision Library,是一個基于BSD開源協議的跨平臺計算機視覺庫。OpenCV實現了多種實時且高效的計算機視覺和圖像處理通用算法,并且可以利用計算機底層硬件平臺進行硬件加速。
OpenCV的下載
打開OpenCV主頁:??https://opencv.org/??
并選擇發(fā)行的Release版本
這里可以選擇我們需要的OpenCV版本
以OpenCV 3.4.1為例
點擊這里下載OpenCV 3.4.1 for Android
下載完成后,打開壓縮包
我們可以先看一下,這里面都有什么
選擇SDK文件夾
然后選擇java
可以發(fā)現,這和我們自己新建的Android工程目錄下的文件很像
待會兒會提到,這個目錄將以Module的形式加載到我們自己新建的Android項目中
至此,OpenCV 3.4.1 for Android下載完成
配置SDK manager
首先打開桌面上的Android Studio
點擊configure,進入配置選項
選擇SDK manager
打開后,在右邊選擇SDK Tools
SDK Tools的頁面是這樣的
我們選擇CMake和NDK
CMake是一個跨平臺的編譯工具,能夠輸出各種各樣的makefile文件,這個在之后OpenCV編譯階段需要用到
NDK是Android平臺下的一個開發(fā)工具包,使用NDK可以快速地開發(fā)C、C++的以.so為后綴的動態(tài)庫,并自動將.so動態(tài)庫與應用打包成.apk文件,這也是后面需要用到的
選擇好后,點擊Apply應用,即可開始下載
下載之前,會提醒你要下載的版本,點擊確定即可
稍微等待一下,速度還是挺快的
最好翻一下墻
接下來新建Android工程
填寫項目名稱,記得勾選上支持C++,因為我們用到的OpenCV是用C、C++編寫的
SDK版本我們選擇默認即可,一般來說是API 15
接下來的默認Activity,名字可以直接用默認的MainActivity,也可以修改一下
接下來是選擇C++支持相關的一些選項,記得和下圖選擇一樣即可
至此,配置好NDK和C++支持的Android工程新建完成
?
配置OpenCV
進入剛剛新建好的工程中
選擇Import Module導入模塊
選一下路徑,就是我們下載好OpenCV 3.4.1 for Android后提到的那個文件夾
選擇確定即可
點擊Finish后遇到這個報錯
這是我們的項目API版本和剛導入模塊的API版本不一致導致的
我們的項目API版本要求在這里打開
API版本要求如下:
剛導入的Module的API版本要求如下:
API版本要求如下:
把Module里面的API版本要求根據我們自己新建項目的API版本要求修改即可
這時候可能還會有其他的報錯,但是先不用管,把下面的配置工作先做完
接下來導入模塊,首先打開Project Structure
選擇右邊的Dependencies
選擇右邊的小加號,添加Module Dependency
選擇OpenCVLibrary341,就是我們剛剛導入的Module
導入成功
點擊運行,就沒有報錯了
導入動態(tài)庫
筆者曾看過一些其他教程,里面需要我們先在手機上下載OpenCV Manager
然后才能運行我們自己的Android應用程序
這顯然是沒有必要的
OpenCV Manager是OpenCV 用于管理Android下的OpenCV動態(tài)鏈接庫的
通過OpenCV Manager這個東西,可以實現只要在同一個設備上,都可以共享OpenCV的動態(tài)鏈接庫
什么意思呢?
就是說我現在用Android去調用OpenCV
其實我是不能直接用java調用C++的,我的java代碼只能Import其他的java包
也就是說,我的java代碼只能去調剛導入的那個Module里面的包
而Module里面的java代碼也是不能直接調用C++的,而是需要以動態(tài)鏈接庫的形式,間接地調用C++
那么這些動態(tài)鏈接庫怎么來的呢?
第一種方法比較簡單,其實我們之前下載的OpenCV 3.4.1 for Android里面就已經包含了這些動態(tài)鏈接庫
我們只需要把它放進我們的項目里面來就好了
第二種方法就是使用所謂的OpenCV Manager
我先要下載一個OpenCV Manager應用程序,這個OpenCV Manager里面是帶有這些動態(tài)鏈接庫的
然后只要我現在的手機上有這個OpenCV Manager,那么我自己寫應用程序時不需要添加那些動態(tài)鏈接庫,也可以調用之前下載好的那個應用程序里面的動態(tài)鏈接庫了
我比較推薦第一種方法,做法如下:
選擇Directory,新建一個目錄,命名為jniLibs
回到我們剛剛下載的OpenCV 3.4.1 for Android
選擇native
這里面有兩個文件夾
libs里面放的是動態(tài)鏈接庫,文件以.so結尾
staticlibs里面放的是靜態(tài)庫,文件以.a結尾
我們用的是動態(tài)鏈接庫,因此選擇libs文件夾打開
把這個目錄下的所有文件復制一下
這些文件夾的名字表示不同的處理器架構
回到Android Studio
直接在剛剛新建好的目錄下粘貼即可
點擊運行即可
至此,動態(tài)鏈接庫的導入完成
示例代碼
一個簡單的示例程序,測試我們寫的代碼能否調用OpenCV
JavaActivity
package cn.edu.zju.myopencv;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
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.InputStream;
public class JavaActivity extends AppCompatActivity {
// Used to load the 'native-lib' library on application startup.
static {
System.loadLibrary("native-lib");
}
private double max_size = 1024;
private int PICK_IMAGE_REQUEST = 1;
private ImageView myImageView;
private Bitmap selectbp;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_java);
staticLoadCVLibraries();
myImageView = (ImageView)findViewById(R.id.imageView);
myImageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
Button selectImageBtn = (Button)findViewById(R.id.select_btn);
selectImageBtn.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// makeText(MainActivity.this.getApplicationContext(), "start to browser image", Toast.LENGTH_SHORT).show();
selectImage();
}
private void selectImage() {
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent,"選擇圖像..."), PICK_IMAGE_REQUEST);
}
});
Button processBtn = (Button)findViewById(R.id.process_btn);
processBtn.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// makeText(MainActivity.this.getApplicationContext(), "hello, image process", Toast.LENGTH_SHORT).show();
convertGray();
}
});
}
private void staticLoadCVLibraries() {
boolean load = OpenCVLoader.initDebug();
if(load) {
Log.i("CV", "Open CV Libraries loaded...");
}
}
private void convertGray() {
Mat src = new Mat();
Mat temp = new Mat();
Mat dst = new Mat();
Utils.bitmapToMat(selectbp, src);
Imgproc.cvtColor(src, temp, Imgproc.COLOR_BGRA2BGR);
Log.i("CV", "image type:" + (temp.type() == CvType.CV_8UC3));
Imgproc.cvtColor(temp, dst, Imgproc.COLOR_BGR2GRAY);
Utils.matToBitmap(dst, selectbp);
myImageView.setImageBitmap(selectbp);
}
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == PICK_IMAGE_REQUEST && resultCode == RESULT_OK && data != null && data.getData() != null) {
Uri uri = data.getData();
try {
Log.d("image-tag", "start to decode selected image now...");
InputStream input = getContentResolver().openInputStream(uri);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(input, null, options);
int raw_width = options.outWidth;
int raw_height = options.outHeight;
int max = Math.max(raw_width, raw_height);
int newWidth = raw_width;
int newHeight = raw_height;
int inSampleSize = 1;
if(max > max_size) {
newWidth = raw_width / 2;
newHeight = raw_height / 2;
while((newWidth/inSampleSize) > max_size || (newHeight/inSampleSize) > max_size) {
inSampleSize *=2;
}
}
options.inSampleSize = inSampleSize;
options.inJustDecodeBounds = false;
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
selectbp = BitmapFactory.decodeStream(getContentResolver().openInputStream(uri), null, options);
myImageView.setImageBitmap(selectbp);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
相應的layout
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_java"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="cn.edu.zju.myopencv.JavaActivity"
android:orientation="vertical"
>
<Button
android:id="@+id/select_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="選擇圖片" />
<Button
android:id="@+id/process_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="處理" />
<ImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
這里都是些很簡單的代碼,主要為了測試功能
大家不用自己打了,直接去github下載即可
地址:??https://github.com/nikolajohn/OpenCVtest??
測試效果
?
本文摘自 :https://blog.51cto.com/u