Mac環境下opencv for android筆記

hjm_1fb1990發表於2017-08-12

想不到時隔一年,又要接觸NDK了。。。
首先按照在Android Studio中安裝OpenCV mac環境/Linux環境小試了一把。

JNI Tip
jni的資料夾名必須是作者截圖中的jniLibs(因為這個是Gradle預設的JNI資料夾),不然System.loadLibrary方法會報錯。也可以用另一個屬性 jniLibs.srcDirs = ['libs']設定,這樣的話就把JNI檔案放到與src同級的libs資料夾。
另外,只需要複製要支援的cpu架構的資料夾。如果只需要呼叫opencv中封裝好的JNI介面,資料夾中只保留opencv_java.so這個檔案。

opencv 初始化
呼叫OpenCVLoader.initAsync()的話會檢測 OpenCVManager 這個程式有沒有安裝,沒有就會引導使用者安裝。OpenCVManager裡包含的是你要呼叫的各種so檔案,一應俱全。
但這樣顯然會影響使用者體驗,所以推薦另一個初始化方法OpenCVLoader.initDebug()
這個方法基本等同於System.loadLibrary("opencv_java")
opencv_java是我們上一步放到jniLibs下的libopencv_java.so檔案, 包含了所有opencv封裝的JNI介面。
如果你還需要使用其他so檔案,可以使用 System.loadLibrary繼續載入。這樣,初始化的邏輯就搞清楚了。初始化可以在onResume(),或者static 程式碼塊裡執行。

基本資料結構和概念解釋

  • Size
    opencV的Imgproc有很多模糊函式, 它們都需要傳入Size引數。引數名為ksize, 是kernel size的縮寫,即濾波器模板(核)的尺寸。建構函式 Size(w,h) w 為畫素寬度, h為畫素高度。Size(3,3)就是3*3的核。像Size和blockSize這種,邊長還是設定成2,5,7等奇數比較好理解。雖然有時候2*2也可以設定,但不知道和3*3有啥區別。

  • Scalar
     public Scalar</font>(double v0) {
        val = new double[] { v0, 0, 0, 0 };
         }
      以上面單個引數的構造方法為例,可以看出是一個size為4的一維陣列。應用舉例:
      //與一維陣列相乘,所以結果是第一個通道(ARGB的話就是alpha通道)的值被放大一百倍,其他通道的值變為0
     Core.multiply(mat1, new Scalar(100), mat1);
  • Sobel
     //這個建構函式的dx指的是x方向求導的階數,dy指的是y方向求導的階數。ddepth指的是輸出影象的深度。
     public static void Sobel(Mat src, Mat dst, 
     int ddepth, int dx, int dy, int ksize,
      double scale, double delta);
  • Mat
    Mat即矩陣(Matrix)的縮寫, 是儲存影象畫素資訊的矩陣。它主要包含兩部分:矩陣頭和一個指向畫素資料的矩陣指標。程式碼示例:

    //構造一個3*3卷積核,8位無符號整型單通道。
    Mat kernel= new Mat( 3, 3, CvType.CV_8UC1);
    //前兩個參數列示操作起始座標,為(0,0),之後的引數為填充資料[0,-1, 0,-1, 5,-1, 0,-1, 0]
    //因為是單通道,所以9個數剛好能填滿。如果是4通道,就需要9*4才能填滿。
    kernel. put( 0, 0, 0,-1, 0,-1, 5,-1, 0,-1, 0);

    得到的卷積核如下
0 -1 0
-1 5 -1
0 -1 0

霍夫變換
參考文章霍夫變換 確定影象上直線位置
以檢測直線為例,
通過定義理解:
笛卡爾座標系的點(X, Y)對應著經過它的無數條直線,這無數條直線在p-θ平面上(p軸代表直線截距,θ代表直線夾角)上可以用一條直線表示。把笛卡爾座標系的大量的點都對映到p-θ平面上,就有了大量直線。如果p-θ平面上存在大量直線在某個點相交,就說明笛卡爾座標系包含一條直線,直線的斜率和截距對應著此點的p和θ。

通過公式理解:
其實,笛卡爾座標系的直線公式轉化一下,也能得出結論,就是個相對的思維。
用y = kx+b表示笛卡爾座標系的任意一條直線,這樣x, y, k, b 都是未知數了。
而b 和k 通過三角函式可以轉化成p和θ,
暫且用b = f(p,θ)和 k = g(p,θ)
這樣,直線y = kx+b上的點,雖然每一個點都能在p-θ平面上對映無數條直線,但必定每個點對映的直線必定有一條是
f(p,θ) = y- g(p,θ)x
笛卡爾座標系裡,確定y = kx+b的引數值,只需要兩個在這條直線上的不同的點的座標(x0,y0), (x1,y1)
把同樣的(x0,y0), (x1,y1)帶入到方程f(p,θ) = y- g(p,θ)x,就可以求出p, θ的值了。所以,笛卡爾座標系的直線就對應著p-θ平面上的一個點。

在檢測圓的過程中,發現Imgproc.HoughCircles方法居然會改變輸入的Mat, 也就是第一個引數。而且如果採用new Mat()的方法生成Mat, 並且不是第一個Mat, 就可能會影響之前的Mat。而呼叫Mat.zeros方法就不會影響。暫時當作opencv4Android的一個bug吧,C++版本應該沒這麼明顯的bug。

相關文章