文章目錄
- 0 前言
- 0.1 一定按照老師給的安裝包等去配置環境
- 0.2 運作
- 0.3 修改
- 0.4 資料
- 1 OpenCV概述
- 1.1 什麼是OpenCV
- 1.2 opencv環境的配置
- 1.2.1 OpenCV Android SDK
- 1.2.3.4 添加module dependency
- 1.2.3.5 OpenCV庫的加載
- 1.2.3.6 Make Project
- 2.OpenCV簡單案例
- 2.1 Mat
- 2.1.1 Mat的概念
- 2.1.2 Bitmap和Mat的轉換
- 2.1.3 Mat的位運算和算術運算
- 2.1.4 Mat的release
- 2.1.5 例程練習
- 2.2 顔色轉換
- 2.2.1 圖像色彩模式
- 2.2.2 cvtColor()顔色轉換函數
- 2.2.2.1 轉換灰階圖執行個體
- 2.2.2.2 轉換二值圖執行個體
- 2.2.3 例程練習
- 2.3 幾何圖形繪制
- 2.3.1 直線繪制
- 2.3.2 矩形繪制
- 2.3.3 多邊形繪制
- 2.3.4 圓形繪制
- 2.3.5 文字繪制
0 前言
本文是安卓開發方面純純的新手,最近的項目目的是在android手機上開發一款app,對圖像處理後顯示處理後的圖像。總體功能比較簡單。學習過程中受到b站上上海電子資訊職業技術學院 沈毓駿老師的視訊教程,根據他給的講義寫學習筆記總結如下。大部分内容都來自視訊,喜歡的朋友可以對照老師的視訊和本講義操作。
0.1 一定按照老師給的安裝包等去配置環境
我下載下傳了最新版本的android studio,結果就配置總是出錯。
0.2 運作
老師運作代碼是用的虛拟機,我想在真正的環境上運作。是以就把我的舊手機打開開發者模式,然後去調試的。
0.3 修改
建議直接在老師給的demo程式上做修改~
0.4 資料
老師給的所有資料都可以掃碼擷取。在文末
1 OpenCV概述
1.1 什麼是OpenCV
OpenCV,全稱Open Source Computer VisionLibrary,是基于C/C++編寫的,是BSD開源許可的計算機視覺開發架構,其開源協定允許在學術研究與商業應用開發中免費使用它。OpenCV支援Windows、Linux、Mac OS、iOS與Android作業系統上的應用開發。
OpenCV Android SDK 是OpenCV針對Android平台提供的開發工具包。Android應用開發一般采用Java或者Kotlin語言進行,而OpenCV主要子產品采用C、C++語言編制,因在android環境下可以通過JNI技術,實作JAVA或者Kotlin調用OpenCV算法子產品的目的。
在android開發環境中配置好OpenCV以後,我們可以友善的調用各種API函數對計算機圖像進行各種處理。OpenCV目前可以實作的功能有:
- 圖像處理
- 人機互動
- 圖像分割
- 人臉檢測
- 動作識别
- 運動跟蹤
- 運動分析
等等
1.2 opencv環境的配置
1.2.1 OpenCV Android SDK
OpenCV-Android-SDK是配置OpenCV環境的重要部分。我們可以到OpenCV的官網進行下載下傳,目前最新版本為4.5.0。OpenCV的[官網連結](https://下:
[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-oGHRn(./pic/01.JPG)]
[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖g09248414)(cs.2.dn失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img15)(./picn/31失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-19f./pic/04.JPG)]失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(7817)(./pic/a的修改配置特别麻煩,容易錯。其餘我們可以導入整個SDK包,後期的修改和配置特别簡單,而且可以脫離OpenCV Manage獨立運作。
點選File ->New->import Module。在彈出的對話框中定位到SDK位置。
[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-X0w4cpml-1637809248418)(./pic/06.JPG)]
[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-WewmNAkL-1637809248418)(./pic/07.JPG)]
确定位置後将Ope9248419)(./pic/08.JPG)]
記住app的compile的值。
[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-GrOpdKmF-1637809248419)(./pic/09.JPG)]
然b。
[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-y2zZgHDg-1637809248419)(./pic/10.JPG)]
将該檔案中的compile SDK、minSDK、targetSDK版本号改成和app build.gradle中對應的值相同。
[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-iqB6fxxR-1637809248421)(./pic/11.JPG)]
1.2.3.4 添加module dependency
之前我們已經把opencv作為一個module導入了project。接下來為project添加module dependency。使我們的Android項目可以識别OpenCV。
點選File -> Project structure…。在彈出的對話框的左邊欄中選擇Dependcies。在中間的Modules中選擇app。在右邊的Declared Dependcies中選擇‘+’号。
[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-x1Th0sQ8-1637809248421)(./pic/12.JPG)]
點選‘+’号以後在下拉選項中選擇第三項module dependency。
[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-eX5zcq7s-1637809248422)(./pic/13.JPG)]
在彈出的對話框中把SDK選中,這個SDK就是我們之前導入的OpenCV SDK。這一步是添加依賴。
[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-CasY2y3S-1637809248422)(./pic/14.JPG)]
1.2.3.5 OpenCV庫的加載
可編寫一個子函數在程式開始的時候加載OpenCV庫。
private void iniLoadOpenCV() {
boolean success = OpenCVLoader.initDebug();
if(success) {
Toast.makeText(this.getApplicationContext(), "Loading OpenCV Libraries...", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(this.getApplicationContext(), "WARNING: Could not load OpenCV Libraries!", Toast.LENGTH_LONG).show();
}
}
1.2.3.6 Make Project
以上步驟完成後可以點選build -> Make Project編譯程式,正常的話編譯可以正常通過。
2.OpenCV簡單案例
OpenCV Java API中我們經常會用到這幾個類:
- Mat類主要用來定義Mat對象,切割Mat對象。正常的Bitmap位圖在OpenCV中都需要轉換為Mat。
- Core類主要用于Mat的運算,提供了很多運算功能的靜态函數。
- ImgProc類主要用于圖像的處理,也提供了很多處理功能的靜态函數。
- Utils類主要用于Mat和/bitmap之間的轉換。
OpenCV Java API參考手冊可見官網
https://docs.opencv.org/java/3.0.0/
2.1 Mat
2.1.1 Mat的概念
Android中對圖像是用bitmap格式來進行處理,而OpenCV中是采用Mat格式進行處理。是以我們在Android中使用OpenCV也要将Bitmp轉化為Mat格式。Mat類用于表示一個多元的單通道或者多通道的數組。能夠用來儲存實數或複數的向量、矩陣,灰階或彩色圖像,立體元素,張量以及直方圖。簡而言之,Mat就是用來儲存多元的矩陣的。Mat對象中包含了圖像的各種基本資訊與圖像像素資料。Mat是由頭部與資料部分組成的,其中頭部還包含一個指向資料的指針。我們把Mat可以視作就是圖像矩陣。
2.1.2 Bitmap和Mat的轉換
Bitmap和Mat的轉換方法
ory.decodeResource(getResources(), R.drawable.d01);
Mat src = new Mat();
Utils.bitmapToMat(bp, src);Mat也可以使用以下的代碼直接加載圖檔 srcMat1 = Utils.loadResource(this, R.drawable.d01);
} catch (IOException e) {
e.printStackTrace();
}
Mat也可以轉換為Bitmap在Android UI上進行顯示,轉換代碼如下。
bitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
Utils.matToBitmap(mat, bitmap);
/
2.1.3 Mat的位運算和算術運算
Mat格式的圖像可以直接進行位運算和算術運算。
位運算主要支援按位非、按位與、按位或、按位異或。算術運算主要支援加減乘除。這些運算其實實際上都是矩陣的運算。
相應的OpenCV API如下表。
[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-ndok6yw3-1637809248422)(./pic/15.JPG)]
[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-62SKO37d-1637809248423)(./pic/16.JPG)]
比如要對兩張圖檔進行and運算并輸出結果可以參考以下的代碼。
try {
srcMat1 = Utils.loadResource(this, R.drawable.d01);
srcMat2 = Utils.loadResource(this, R.drawable.d02);
} catch (IOException e) {
e.printStackTrace();
}
Core.bitwise_and(srcMat1, srcMat2, dstMat);
resultBitmap = Bitmap.createBitmap(dstMat.width(), dstMat.height(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(dstMat, resultBitmap);
dstImg.setImageBitmap(resultBitmap);
2.1.4 Mat的release
使用者定義的Mat一般都需要在程式結束時使用release()函數進行記憶體釋放。代碼一般放在OnDestroy()裡,代碼如下。
protected void onDestroy() {
super.onDestroy();
mat.release();
}
2.1.5 例程練習
将兩個原圖進行按位與、按位或、按位異或、算術加、算術減、算術乘、算術除的運算,并檢視結果。
[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-4LgQEq5g-1637809248423)(./pic/17.JPG)]
也可以自己找兩張原圖,注意兩張原圖應尺寸相同。
2.2 顔色轉換
2.2.1 圖像色彩模式
圖像的色彩模式主要有以下幾種:
位圖模式
位圖模式是圖像中最基本的格式,圖像隻有黑色和白色像素,是色彩模式中占有空間最小的,同樣也叫做黑白圖,它包含的資訊量最少,無法包含圖像中的細節,相當于隻有0或者1。
一副彩色圖如果要轉換成黑白模式,則一般不能直接轉換,需要首先将圖像轉換成灰階模式。
灰階模式
灰階模式即使用單一色調來表示圖像,與位圖模式不同,不像位圖隻有0和1,使用256級的灰階來表示圖像,一個像素相當于占用8為一個位元組,每個像素值使用0到255的亮度值代表,其中0為黑色,255為白色,相當于從黑->灰->白的過度,通常我們所說的黑白照片就是這種模式,與位圖模式相比,能表現出一定的細節,占用空間也比位圖模式較大。
RGB模式
RGB模式為我們經常見到的,被稱為真色彩。RGB模式的圖像有3個顔色通道,分布為紅(Red),綠(Green)和藍(Bule),每個都占用8位一個位元組來表示顔色資訊,這樣每個顔色的取值範圍為0~255,那麼就三種顔色就可以有多種組合,
當三種基色的值相等時表現出為灰色,三種顔色都為255即為白色,三種顔色都為0,即為黑色。RGB模式的圖像占用空間要比位圖,灰階圖都要大,但表現出的細節更加明顯。
HSV模式
是根據日常生活中人眼的視覺對色彩的觀察得而制定的一套色彩模式,最接近與人類對色彩的辨認的思考方式,所有的顔色都是用色彩三屬性來描述
- H:(色相):是指從物體反射或透過物體傳播的顔色
- S:(飽和度):是指顔色的強度或純度,表示色相中灰色成分所占的比例
-
V:(亮度):是指顔色對相對明暗程度,通常 100%定義為白色;0%為黑色
[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-ArlvFmVJ-1637809248424)(./pic/18.JPG)]
另外還有CMYK模式、YUV模式等。
2.2.2 cvtColor()顔色轉換函數
OpenCV中主要使用cvtColor()函數進行顔色轉換操作。函數原型如下:
Imgproc.cvtColor(source mat, destination mat1, Color_Conversion_Code);
Color_Conversion_Code提供了豐富的顔色轉換模式。
顔色碼 | 功能 |
COLOR_BGR2RGB | 顔色空間轉換 |
COLOR_BGR2GRAY | BGR轉換到灰階空間 |
COLOR_GRAY2RGB | 灰階轉換到RGB |
COLOR_RGB2HSV | RGB轉換到HSV |
COLOR_RGB2RGBA | 添加alpha通道 |
。。。 | 。。。 |
2.2.2.1 轉換灰階圖執行個體
Bitmap bp = BitmapFactory.decodeResource(getResources(), R.drawable.d01);
Utils.bitmapToMat(bp, src);
Imgproc.cvtColor(src, dst, Imgproc.COLOR_BGRA2GRAY);
Utils.matToBitmap(dst, bp);
iv1.setImageBitmap(bp);
/
轉換效果
原圖
[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-FtfUIwjd-1637809248425)(./pic/19.JPG)]
轉換後
[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-CaqkQQ6Z-1637809248425)(./pic/20.JPG)]
2.2.2.2 轉換二值圖執行個體
圖像二值化就是将圖像上的像素點的灰階值設定為0或255,也就是将整個圖像呈現出明顯的黑白效果的過程。 轉換二值圖的關鍵就是确定一個門檻值,整張圖檔中高于門檻值的點都置為255,低于門檻值的點都置為0,就可以呈現出明顯的二值黑白效果。
門檻值的确定有兩種方法,一種是手動指定,由開發者手動确定一個門檻值,在一些專用場景下可以通過實驗效果調整。
手動閥值法
手動門檻值法所使用的函數的是:Imgproc.threshold()
threshold(Mat src, Mat dst, double thresh, double maxval, int type);
參數 :
- src : Mat 輸入圖像
- dst : Mat 輸出圖像 門檻值操作結果填充在此圖像
- thresh : double 門檻值
- maxval : double 當 type 為 THRESH_BINARY 或 THRESH_BINARY_INV 時的最大值
-
type : int , 門檻值類型。對對象取門檻值的方式
0:THRESH_BINARY : src(x,y) > thresh ? maxval : 0 。 目前像素點的灰階值 > thresh ,目前像素點值為 maxval ,反之為0
1:THRESH_BINARY_INV : src(x,y) > thresh ? 0 : maxval 。 目前像素點灰階值 > thresh , 目前像素點值為 0 反之為 maxval
2:THRESH_TRUNC : src(x,y) > thresh ? threshold : src(x,y)。目前像素點灰階值 > thresh , 設定為thresh ,反之保持不變
3:THRESH_TOZERO : src(x,y) > thresh ? src(x,y) : 0 。 目前像素點灰階值 > thresh , 目前像素點值保持不變,其他情況為0
4:THRESH_TOZERO_INV : src(x,y) > thresh ? 0 : src(x,y) 。 目前像素點灰階值 > thresh , 目前像素點值為0 ,其他情況保持不變
手動門檻值二值化轉換代碼
Imgproc.threshold(src,dst,125,255,Imgproc.THRESH_BINARY);
其中125就是我們自己指定的門檻值。
效果如下
[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-NQJYHzb9-1637809248426)(./pic/21.JPG)]
自動門檻值法
OpenCV中也可以使用算法來自動計算門檻值。OpenCV支援均值算法和高斯均值算法。它不是計算全局圖像的門檻值,而是根據圖像不同區域亮度分布,計算其局部門檻值,是以對于圖像不同區域,能夠自适應計算不同的門檻值,是以被稱為自适應門檻值法。
如果圖像的各處亮度不一緻在進行全局門檻值二值化的時候會得到不太理想的結果。
[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-BdrpH7Gq-1637809248427)(./pic/53.PNG)]
而采用了局部門檻值計算的話是計算某個鄰域(局部)的均值、高斯權重平均(高斯濾波)來确定門檻值。對每個區域來說門檻值是不一樣的。局部門檻值通常會得到較好的二值化效果,上圖如果采用局部門檻值的話可以得到如下的效果。
[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-69i3gRFY-1637809248427)(./pic/54.PNG)]
自動門檻值所使用的函數是Imgproc.adaptiveThreshold(),函數原型如下:
public static adaptiveThreshold(Mat src, Mat dst, double maxValue, int adaptiveMethod, int thresholdType, int blockSize, double C)
參數說明:
- src : Mat 輸入圖像
- dst : Mat 輸出圖像 門檻值操作結果填充在此圖像
- maxValue : double 配置設定給滿足條件的像素的非零值
-
adaptiveMethod : int 自定義使用的門檻值算法,ADAPTIVE_THRESH_MEAN_C 、ADAPTIVE_THRESH_GAUSSIAN_C
ADAPTIVE_THRESH_MEAN_C 時,T(x,y) = blockSize * blockSize【b】
blockSize【b】= 鄰域内(x,y) - C
ADAPTIVE_THRESH_GAUSSIAN_C 時,T(x,y) = blockSize * blockSize【b】
blockSize【b】= 鄰域内(x,y) - C與高斯窗交叉相關的權重總和
- thresholdType : int 門檻值類型,隻能是THRESH_BINARY 、 THRESH_BINARY_INV
- blockSize : int 用來計算門檻值的鄰域尺寸 3,5,7等等,奇數
- C : double 減去平均值或權重平均值的常數,通常情況下,它是正的,但也可能是零或負。
代碼實作:
Imgproc.adaptiveThreshold(src,dst,255, Imgproc.ADAPTIVE_THRESH_MEAN_C, Imgproc.THRESH_BINARY, 13, 5);
效果:
[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-wYS4Xcir-1637809248428)(./pic/22.JPG)]
2.2.3 例程練習
按本節内容,導入一張圖檔,編寫一個轉化灰階圖、二值圖的APP。可以嘗試不同的參數的不同效果。
[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-vicVeX0T-1637809248428)(./pic/23.JPG)]
2.3 幾何圖形繪制
2.3.1 直線繪制
幾何圖形繪制主要使用ImgProc類裡的line、rectangle、polylines、circle、ellipse等函數,也可以使用putText函數繪制文字。圖形繪制函數一般在APP中起到畫面标注的功能。
直線繪制line函數原型
public static void line(Mat img,Point pt1,Point pt2,Scalar color,int thickness);
參數:
- img:需要繪制的圖像Mat。
- pt1: 直線起點坐标。
- pt2: 直線終點坐标。
- color:直線的顔色。
- thickness:直線的寬度。
比如我們要在畫面的左下到右上畫一條紅色的寬度為4的直線,可以這樣調用。
Imgproc.line(src,new Point(0,src.height()),new Point(src.width(),0),new Scalar(255,0,0),4);
2.3.2 矩形繪制
函數原型:
public static void rectangle(Mat img, Point pt1, Point pt2, Scalar color, int thickness);
參數:
- img,需要繪制的圖像Mat
- pt1,矩形左上角
- pt2,矩形右下角
- color,繪制直線的顔色
- thickness,直線寬度。若為負值,表示填充
2.3.3 多邊形繪制
函數原型:
public static void polylines(Mat img, List<MatOfPoint> pts, boolean isClosed, Scalar color, int thickness);
參數:
- img,輸入圖像
- pts,多邊形端點坐标清單
- isClosed,是否閉合
- color,繪制直線的顔色
- thickness,直線寬度
2.3.4 圓形繪制
函數原型:
public static void circle(Mat img, Point center, int radius, Scalar color, int thickness);
參數:
- img,輸入圖像
- center,圓心坐标
- radius,圓半徑
- color,繪制直線的顔色
- thickness,直線寬度。若為負值,表示填充
2.3.5 文字繪制
函數原型:
public static void putText(Mat img, String text, Point org, int fontFace, double fontScale, Scalar color, int thickness);
參數:
- img,輸入圖像
- text,文字内容
- org,文本字元串的左下角位置
- fontFace,字型類型,可取值
- fontScale,字型大小
- color,繪制直線的顔色
- thickness,直線寬度
Imgproc.putText(src,"I`m a cat",new Point(src.width() /2,src.height()/3),2,5,new Scalar(0,255,0),3);