前言:
準備工具:
- win7/win8 環境我是win8環境
- java SDK 6 / 7 我是用的6
- eclipse for java EE IED我是32位版
- ADT插件
- CDT插件
- Android SDK
- Android NDK我的是r8版
- cygwin
- Sequoyah
- opencv for android我用的是2.4.5
android環境搭建:
java SDK安裝:
如果你還沒有JDK的話,可以去這裏下載,接下來的工作就是安裝提示一步一步走。設置環境變量步驟如下:
- 我的電腦->屬性->高級->環境變量->系統變量中添加以下環境變量:
- JAVA_HOME值爲: D:\Program Files\Java\jdk1.6.0_18(你安裝JDK的目錄)
- CLASSPATH值爲:.;%JAVA_HOME%\lib\tools.jar;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\bin;
- Path: 在開始追加 %JAVA_HOME%\bin;
- NOTE:前面四步設置環境變量對搭建Android開發環境不是必須的,可以跳過。
安裝完成之後,可以在檢查JDK是否安裝成功。打開cmd窗口,輸入java –version 查看JDK的版本信息。出現類似下面的畫面表示安裝成功了:
eclipse 安裝:
Android SDK安裝:
在Android Developers下載android-sdk_r05-windows.zip,下載完成後解壓到任意路徑。
- 運行SDK Setup.exe,點擊Available Packages。如果沒有出現可安裝的包,請點擊Settings,選中Misc中的"Force https://..."這項,再點擊Available Packages 。
- 選擇希望安裝的SDK及其文檔或者其它包,點擊Installation Selected、Accept All、Install Accepted,開始下載安裝所選包
- 在用戶變量中新建PATH值爲:Android SDK中的tools絕對路徑(本機爲D:\AndroidDevelop\android-sdk-windows\tools)。
運行 android –h 如果有類似以下的輸出,表明安裝成功:
ADT插件安裝:
- 打開 Eclipse IDE,進入菜單中的 "Help" -> "Install New Software"
- 點擊Add...按鈕,彈出對話框要求輸入Name和Location:Name自己隨便取,Location輸入http://dl-ssl.google.com/android/eclipse。如下圖所示:
完成之後:
- 選擇Window > Preferences...
- 在左邊的面板選擇Android,然後在右側點擊Browse...並選中SDK路徑,本機爲:
D:\AndroidDevelop\android-sdk-windows - 點擊Apply、OK。配置完成。
創建android AVD模擬器:
NDK + Cygwin 環境搭建:
安裝Android NDK:
安裝Cygwin:
由於NDK開發大都涉及到C/C++在GCC環境下編譯、運行,所以在Windows環境下,需要模擬Linux模擬編譯環境,下載地址:
下載後是個setup.exe文件,使用過程如下:
第一步:運行setup程序,第一步圖略,直接點擊Next進入下一步。
第二步:選擇安裝方式,第一次可以採用Direct Connection在線下載安裝,如有現成的離線包,可以選擇離線安裝(Install from Local Directory)。
第四步:設置本地包暫存路徑
暫存目錄默認是放到setup.exe的同級目錄下,下載後名字類似ftp%3a%2f%2fcygwin.mirrors.pair.com%2f這樣格式。
第五步:設置網絡連接方式
第六步:選擇下載站點地址
起初嘗試幾個看哪個速度快就用哪個地址(如果感覺不快就點取消,再次來過)。
第七步:等待加載安裝項載入,選擇安裝項
我們編譯NDK,在默認設置下,只需選擇Devel(點擊列表中Devel,將後面的Default改爲Install,圖中箭頭所示),其它均爲默認狀態。
第八步:等待下載完成
下載完成時間決定於你選擇的安裝包數量及網絡連接速度,比如按照本文默認的選擇方式,可能需要4-5個小時,下載後壓縮包約750M,下載完成後會自動安裝到上文設置的安裝目錄。
安裝完成後,先運行Cygwin一次(Cygwin.bat),以便創建一些用戶環境文件,分別輸入:
make -v
和,
gcc -v
如果檢測成功,會有make和gcc相關版本信息打印出來,如下圖。
可以在cygwin中通過vim修改,也可以在windows安裝目錄中修改 home\<你的用戶名>\.bash_profile 文件中最後添加環境變量
NDKROOT=/cygdrive/e/Andriod/develop/android-ndk-r8
export NDKROOT
其中NDK=/cygdrive/<你的盤符>/<android ndk 目錄> ,"NDK"這個名字隨便起,以後經常用不要太長。
重啓cygwin,輸入:
cd $NDK
可進入ndk對應目錄說明設置OK。
3.用ls命令查看libs/armeabi/下是否生成了so文件,有libhello-jni.so說明ndk運行正常。
$ ls libs/armeabi/
gdb.setup gdbserver libhello-jni.so
也可以到E:\android\android-ndk-r8\samples\hello-jni\libs\armeabi目錄下看有沒有生成的.so文件。
2)導入NDK的hello-jni示例到Eclipse中
1.在Eclipse中新建一個Android工程HelloJni。
在Create Android Project時勾選“Create project from existing source”,Location中填E:\android\android-ndk-r8\samples\hello-jni
2.直接以Android Aplication運行com.example.hellojni.HelloJni項目。要先有.so文件才能運行起來。 os放在工程根目錄下
CDT插件的安裝:
不同eclipse版本要下載對應的包,否則安裝不了。
Help-->About Eclipse 下可以看到自己用的版本,我的是 Version: Helios Service Release 2 即Helios版本
http://www.eclipse.org/downloads/download.php?file=/tools/cdt/releases/helios/dist/cdt-master-7.0.2.zip
cdt-master-7.0.2.zip:這個是CDT的離線安裝包。(由於文件比較大推薦使用離線包,7.0.2的54.8M,8.1.1的103MB)
安裝:Eclipse -> Help -> Install New Software,點擊add。
Name:CDT_版本。
Location:點擊Archive,定位到下載的“cdt-master-7.0.2.zip”文件。
如果Location的下面出現“Duplicate location”錯誤,請到Window -> preferences -> Install/Update -> Avaliable Software Site中找到remove掉。
如果出現缺少eclipse包說明你下載的版本和eclipse版本不匹配,重新下載匹配的重新安裝就可以了。
安裝完成重啓後,在Eclispe中新建一個項目,如果出現了C/C++項目,則表明CDT插件安裝成功了。
安裝Sequoyah插件:
官方網址:http://www.eclipse.org/sequoyah/downloads/
打開上面網址就可以看到具體的安裝說明了
Location:http://download.eclipse.org/sequoyah/updates/2.0/
For Helios SR2 Sequoyah version: http://download.eclipse.org/sequoyah/updates/1.0.2/
注:只是安裝1.0.2的沒有出來“本機開發”的配置所以沒法用,本人重新安裝了2.0的可以了,這個應該直接安裝最新版2.0的就可以了。
在安裝界面不要勾選“Group items by category”複選框,選中出現了列表爲空(There are no categorized items)的情況。
在“window –> preferences ->Android -> 本機開發”中添加NDK的路徑。
重啓後右鍵之前建立的“HelloJni”項目,在“Android Tools”選項中包含“Add Native Support…”選項即成功。
opecnv for android 開發環境搭建:
opencv for android SDK 安裝:
進入官網(http://opencv.org/)下載OpenCV4Android並解壓,其目錄結構如下:
其中,sdk目錄即是我們開發opencv所需要的類庫;samples目錄中存放着若干opencv應用示例(包括人臉檢測等),可爲我們進行android下的opencv開發提供參考;doc目錄爲opencv類庫的使用說明及api文檔等;而apk目錄則存放着對應於各內核版本的OpenCV_2.4.3.2_Manager_2.4應用安裝包。此應用用來管理手機設備中的opencv類庫,在運行opencv應用之前,必須確保手機中已經安裝了OpenCV_2.4.3.2_Manager_2.4_*.apk,否則opencv應用將會因爲無法加載opencv類庫而無法運行。
2.2 將SDK引入工作空間
(1) 選擇一個路徑,新建文件夾做爲工作空間(我在E盤根目錄下新建workspace目錄來做爲工作空間);
(2) 將OpenCV-2.4.3.2-android-sdk中的sdk目錄copy至工作空間,並將其更名爲OpenCV-SDK(是否更改名稱無所謂,這是我個人習慣而已);
(3) 以新建的目錄爲工作空間,打開eclipse;
(4) 將OpenCV-SDK引入到工作空間中,如下圖所示:
使用java API開發android:
創建工程
(1) 打開eclipse,創建android應用工程GrayProcess;
(2) 將測試圖像lena.jpg添加到資源目錄res/drawable-hdpi中;
(3) 在Package Explorer中選擇項目GrayProcess,單擊右鍵在彈出菜單中選擇Properties,然後在彈出的Properties窗口中左側選擇Android,然後點擊右下方的Add按鈕,選擇OpenCV Library 2.4.3並點擊OK,操作完成後,會將OpenCV類庫添加到GrayProcess的Android Dependencies中,如下圖所示:
<resources>
<string name="app_name">GrayProcess</string>
<string name="hello_world">Hello world!</string>
<string name="menu_settings">Settings</string>
<string name="title_activity_main">MainActivity</string>
<string name="str_proc">gray process</string>
<string name="str_desc">image description</string>
</resources>
(2) 佈局文件:main.xml<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<Button
android:id="@+id/btn_gray_process"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/str_proc"/>
<ImageView
android:id="@+id/image_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/str_proc"/>
</LinearLayout>
(3) MainActivity.java
package com.iron.grayprocess;
import org.opencv.android.BaseLoaderCallback;
import org.opencv.android.LoaderCallbackInterface;
import org.opencv.android.OpenCVLoader;
import org.opencv.android.Utils;
import org.opencv.core.Mat;
import org.opencv.imgproc.Imgproc;
import android.os.Bundle;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Bitmap.Config;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
public class MainActivity extends Activity implements OnClickListener{
private Button btnProc;
private ImageView imageView;
private Bitmap bmp;
//OpenCV類庫加載並初始化成功後的回調函數,在此我們不進行任何操作
private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
@Override
public void onManagerConnected(int status) {
switch (status) {
case LoaderCallbackInterface.SUCCESS:{
} break;
default:{
super.onManagerConnected(status);
} break;
}
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
btnProc = (Button) findViewById(R.id.btn_gray_process);
imageView = (ImageView) findViewById(R.id.image_view);
//將lena圖像加載程序中並進行顯示
bmp = BitmapFactory.decodeResource(getResources(), R.drawable.lena);
imageView.setImageBitmap(bmp);
btnProc.setOnClickListener(this);
}
@Override
public void onClick(View v) {
Mat rgbMat = new Mat();
Mat grayMat = new Mat();
//獲取lena彩色圖像所對應的像素數據
Utils.bitmapToMat(bmp, rgbMat);
//將彩色圖像數據轉換爲灰度圖像數據並存儲到grayMat中
Imgproc.cvtColor(rgbMat, grayMat, Imgproc.COLOR_RGB2GRAY);
//創建一個灰度圖像
Bitmap grayBmp = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(), Config.RGB_565);
//將矩陣grayMat轉換爲灰度圖像
Utils.matToBitmap(grayMat, grayBmp);
imageView.setImageBitmap(grayBmp);
}
@Override
public void onResume(){
super.onResume();
//通過OpenCV引擎服務加載並初始化OpenCV類庫,所謂OpenCV引擎服務即是
//OpenCV_2.4.3.2_Manager_2.4_*.apk程序包,存在於OpenCV安裝包的apk目錄中
OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_3, this, mLoaderCallback);
}
}
3.1.3 運行結果
使用 c++ API開發android:
創建工程
步驟如工程一,創建新工程GrayProcess2,將lena.jpg添加到資源文件,並按上面所示將opencv類庫添加到工程中。
編寫上層代碼(java)
(1)Stings.xml
<resources>
<string name="app_name">GrayProcess2</string>
<string name="hello_world">Hello world!</string>
<string name="menu_settings">Settings</string>
<string name="title_activity_main">GrayProcess2</string>
<string name="str_proc">gray process</string>
<string name="str_desc">image description</string>
</resources>
(2)main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<Button
android:id="@+id/btn_gray_process"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/str_proc"/>
<ImageView
android:id="@+id/image_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/str_proc"/>
</LinearLayout>
(3)MainActivity.java
package com.iron.grayprocess2;
import org.opencv.android.BaseLoaderCallback;
import org.opencv.android.LoaderCallbackInterface;
import org.opencv.android.OpenCVLoader;
import android.os.Bundle;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Bitmap.Config;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
public class MainActivity extends Activity implements OnClickListener{
private Button btnProc;
private ImageView imageView;
private Bitmap bmp;
//OpenCV類庫加載並初始化成功後的回調函數,在此我們不進行任何操作
private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
@Override
public void onManagerConnected(int status) {
switch (status) {
case LoaderCallbackInterface.SUCCESS:{
System.loadLibrary("image_proc");
} break;
default:{
super.onManagerConnected(status);
} break;
}
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
btnProc = (Button) findViewById(R.id.btn_gray_process);
imageView = (ImageView) findViewById(R.id.image_view);
//將lena圖像加載程序中並進行顯示
bmp = BitmapFactory.decodeResource(getResources(), R.drawable.lena);
imageView.setImageBitmap(bmp);
btnProc.setOnClickListener(this);
}
@Override
public void onClick(View v) {
int w = bmp.getWidth();
int h = bmp.getHeight();
int[] pixels = new int[w*h];
bmp.getPixels(pixels, 0, w, 0, 0, w, h);
int[] resultInt = ImageProc.grayProc(pixels, w, h);
Bitmap resultImg = Bitmap.createBitmap(w, h, Config.ARGB_8888);
resultImg.setPixels(resultInt, 0, w, 0, 0, w, h);
imageView.setImageBitmap(resultImg);
}
@Override
public void onResume(){
super.onResume();
//通過OpenCV引擎服務加載並初始化OpenCV類庫,所謂OpenCV引擎服務即是
//OpenCV_2.4.3.2_Manager_2.4_*.apk程序包,存在於OpenCV安裝包的apk目錄中
OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_3, this, mLoaderCallback);
}
}
代碼第28行:System.loadLibrary("image_proc")用來當OpenCV類庫初始化完成後加載類庫image_proc。此類庫由我們來生成,用於完成圖像灰度處理的操作,此部分將在下面中說明。
(4) ImageProc.java
package com.iron.grayprocess2;
public class ImageProc {
public static native int[] grayProc(int[] pixels, int w, int h);
}
編寫JNI及C相關代碼
在項目中新建目錄jni,在jni目錄中分別添加文件Android.mk,Application.mk,ImageProc.h,ImageProc.cpp,這四個文件的內容分別如下所示。
(1) Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
include ../OpenCV-SDK/native/jni/OpenCV.mk
LOCAL_SRC_FILES := ImageProc.cpp
LOCAL_MODULE := image_proc
include $(BUILD_SHARED_LIBRARY)
代碼說明:
第一行:指明當前編譯路徑;
第二行:清空變量;
第三行:將OpenCV類庫中的編譯文件包含進來,如此一來在我們的工程中即可使用OpenCV類庫;
第四行:指定需要編譯的C++源文件;
第五行:指定編譯生成的類庫名稱;
第六行:調用命令將源文件編譯爲靜態庫。
注:第三行指定的路徑很關鍵,當opencv類庫與工程路徑相關位置發生改變時,此路徑也要隨之改變。
(2) Application.mk(配置文件)
APP_STL := gnustl_static
APP_CPPFLAGS := -frtti -fexceptions
APP_ABI := armeabi-v7a
APP_PLATFORM := android-8
#include <ImageProc.h>
#include <opencv2/core/core.hpp>
#include <string>
#include <vector>
using namespace cv;
using namespace std;
JNIEXPORT jintArray JNICALL Java_com_iron_grayprocess2_ImageProc_grayProc(JNIEnv* env, jclass obj, jintArray buf, jint w, jint h){
jint *cbuf;
cbuf = env->GetIntArrayElements(buf, false);
if(cbuf == NULL){
return 0;
}
Mat imgData(h, w, CV_8UC4, (unsigned char*)cbuf);
uchar* ptr = imgData.ptr(0);
for(int i = 0; i < w*h; i ++){
//計算公式:Y(亮度) = 0.299*R + 0.587*G + 0.114*B
//對於一個int四字節,其彩色值存儲方式爲:BGRA
int grayScale = (int)(ptr[4*i+2]*0.299 + ptr[4*i+1]*0.587 + ptr[4*i+0]*0.114);
ptr[4*i+1] = grayScale;
ptr[4*i+2] = grayScale;
ptr[4*i+0] = grayScale;
}
int size=w * h;
jintArray result = env->NewIntArray(size);
env->SetIntArrayRegion(result, 0, size, cbuf);
env->ReleaseIntArrayElements(buf, cbuf, 0);
return result;
}
說明:
-
ImageProc.h頭文件可以通過jdk提供的工具javah來生成,具體生成方法在下面
-
JNI中的定義的函數遵循一定的命名規則:Java_包名_類名_方法名,具體參考JNI編程相關知識;
-
ImageProc.cpp中利用彩色值轉換爲灰度值的計算公式,將lena.jpg圖像的每個像素轉換爲灰度值,並返回給應用層。需要注意的是對於ARGB_8888類型的圖像而言,其每一個像素值在int型數據中的存儲序列爲BGRA。還需要注ImageProc.cpp 這個文件 第10行的函數名稱Java_包名_類名_方法名 請修改成.h 文件生成的那個函數名
1.首先當年寫完ImageProc.java 這個保存 以後 eclipse會自動幫你生成 java 的class文件
你可以再工程目錄--》 bin --》classes -》com -------。。。。。 的文件裏找到
比如我的 在E:\work\op\OpenCV-2.4.5-android-sdk\samples\Test2\bin\classes\com\test2\test2 這個路徑下
如圖
2.將classes文件拷貝到e盤根目錄下
然後打開 cmd
e:
cd classes
javah com.test2.test2.ImageProc
然後就會在classes文件裏找到一個 xxx.的頭文件 如圖
你可以將這個頭文件改成任意名字 比如我們上面的ImageProc.h 然後放入工程目錄的jni中
編譯運行方法有兩種
1 配置eclipse自動運行
第一步:轉換工程。點擊“文件 -> 新建 -> 其他”(快捷鍵:Ctrl+N)。選擇“C/C++”下的“Convert to a C/C++ Project(Adds C/C++ Nature)”。進 入“下一步”。
第二步:選中你剛纔建的“HelloJni”工程,下面左邊選“Makefile project”右邊選“Cygwin GCC”。確定後提示的“透視圖”不清楚是什麼,點擊“是”即可。
第三步:在“HelloJni”工程上右鍵,選擇“屬性”。配置“C/C++ Build”和“C/C++ General -> Paths and Symbols”。
C/C++ Build:點擊“C/C++ Build”,在右邊的“Builder Settings”中去掉默認勾選的“Use default build command”複選框。設置Build command爲“
${NDKROOT}/ndk-build.cmd "
C/C++ General -> Paths and Symbols:在Includes下add新的GNU C依賴路徑。此“HelloJni”工程需要“D:\Java\android-ndk-r8\platforms\android-8\arch-arm\usr\include”即可,以後根據不同項目選擇不同的依賴庫。
這裏只要是你cpp文件裏頭文件包含目錄
你可以直接在NDK 和opencv jni那個目錄下搜索頭文件名 然後看看在那個路徑有
配置好後運行就行了
2.手動使用Cygwin 生成os 然後運行
由於程序中涉及到了JNI編程,因此需要用cygwin對其中的C/C++代碼進行編譯。打開cygwin,進入到工程的根目錄中執行命令:$NDKROOT/ndk-build完成相關編譯;之後在eclipse中刷新工程GrayProcess2,運行即可。編譯及運行結果分別如下所示。
到這裏兩種方法都結束了!
有問題請留言
有空會及時回覆的