Android如何使用OpenCV
Tags: Opencv, Android

Image-manipulations

而主要可以先看這個這個project

ImageManipulationsActivity.java

再透過

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);

}

主要是會帶入得到幾個callback

public interface CvCameraViewListener2 {



public void onCameraViewStarted(int width, int height);



public void onCameraViewStopped();



public Mat onCameraFrame(CvCameraViewFrame inputFrame);

};

最重要就是當相機初始化後，會在onCameraFrame得到每一個frame的資料

可以看到會傳入

CvCameraViewFrame inputFrame

透過 rgba()得到mat要被處理的物件

Mat rgba = inputFrame.rgba();

而下面定義了一個叫做

Mat rgbaInnerWindow;

主要是他透過主畫面取得一個子畫面

接著會透過處理rgbaInnerWindow，來看測試結果

這非常方便，有點就是取得該區塊進行處理，也不需要寫回，因為它直接就是by reference的方式處理該區塊

透過

int rows = (int) sizeRgba.height;

int cols = (int) sizeRgba.width;



int left = cols / 8;

int top = rows / 8;



int width = cols * 3 / 4;

int height = rows * 3 / 4; rgbaInnerWindow = rgba.submat(top, top + height, left, left + width);

取得中間的區塊Mat

而下面就會根據使用者選擇的mode進行影像處理

譬如我選擇了Canny

case ImageManipulationsActivity.VIEW_MODE_CANNY:

rgbaInnerWindow = rgba.submat(top, top + height, left, left + width);

Imgproc.Canny(rgbaInnerWindow, mIntermediateMat, 80, 90);

Imgproc.cvtColor(mIntermediateMat, rgbaInnerWindow, Imgproc.COLOR_GRAY2BGRA, 4);

rgbaInnerWindow.release();

break;

就會這樣處理影像

可以看到就這麼簡單

canny (來源,目的)

Imgproc.Canny(rgbaInnerWindow, mIntermediateMat, 80, 90);

會存入mIntermediateMat，由於他結果是一個黑白影像，所以需要透過

Imgproc.cvtColor(mIntermediateMat, rgbaInnerWindow, Imgproc.COLOR_GRAY2BGRA, 4);

將gray轉為bgra的影像，也就是rgbaInnerWindow中，

在進行release後就會寫回影像中

rgbaInnerWindow.release();

參考

接著我們加入找舉行的api

Imgproc.findContours(mIntermediateMat,matOfPointList,mHierarchy,Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);

找輪廓找框

https://kknews.cc/news/464lal2.html

形態學

開放、封閉

Erosion

Dilation

怎麼在Android使用呢?

由於Sample都是使用camera當範例，我們希望透過讀取一張圖片來處理，於是乎你可以在layout 中增加一個ImageView，然後再BaseLoaderCallback的onManagerConnected成功的時候進行處理

private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {

@Override

public void onManagerConnected(int status) {

if (status == LoaderCallbackInterface.SUCCESS){

onOpenCvInitSuccess();

}else{

super.onManagerConnected(status);

}

}

};

我們就會執行

onOpenCvInitSuccess()

在這邊進行讀取讀片後顯示在ImageView，而openCv支援直接從resource讀取到mat中

Mat mat = Utils.loadResource(getApplicationContext(),R.drawable.f202);

之後就可以開始處理這張影像了

進行邊緣化

mIntermediateMat = mat.clone();

mRgba = mat.clone();

Imgproc.Canny(mat, mIntermediateMat, 80, 100);

然後開始膨脹處理，主要把斷點連接

Imgproc.erode(mIntermediateMat,mIntermediateMat,Imgproc.getStructuringElement(Imgproc.MORPH_CROSS, new Size(1,1)));

然後進行侵蝕，把膨脹處恢復

Imgproc.dilate(mIntermediateMat,mIntermediateMat,Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(2,2)));

接著就可以把影像轉成Bitmap讓ImageView顯示

Imgproc.cvtColor(mIntermediateMat, mRgba, Imgproc.COLOR_GRAY2RGBA, 4);

Bitmap bm = Bitmap.createBitmap(mRgba.cols(), mRgba.rows(),Bitmap.Config.ARGB_8888);

Utils.matToBitmap(mRgba, bm);

imageView.setImageBitmap(bm);

大概就這麼簡單

繼續不斷的侵蝕

遮罩

Mat strElement = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(3, 3), new Point(-1, -1));

Java Docs

參考