A. Android中調用OpenCV庫來提取圖片的SIFT特徵,出現Cannot create OpenGL context,急!!求大神幫忙
第一種:在安裝了SDK和Elipse支持ADT的前提下
1.安裝 NDK, 下載android-ndk-r8e-windows-x86.zip, 解壓至本地(android-ndk-r8e-windows-x86_64.zip解壓後不包含prebuilt文件夾,sample中的hello-jni運行報錯)
2.配置環境變數$NDKROOT=android-ndk的文件夾路徑
3.eclipse安裝CDT插件,Eclipse->help->Install software,在"available software sites"中選擇相應的CDT路徑,安裝
4.下載最新的OpenCV for Anroid庫OpenCV-2.4.4-android-sdk.zip ,解壓至本地
5.編譯生成openCV的jar庫文件
1)eclipse中導入OpenCV-2.4.4-android-sdk\sdk\java文件夾
2)添加openCV Library工程的C++工程屬性,右鍵project名稱->New->other->C/C++->Convert to a C/C++Project(Adds C/C++ Nature)
3)為project 配置ndk built路徑。右鍵project->Properties->C/C++ build, 設置Build command: ${NDKROOT}/ndk-build.cmd; behavior選項中的不勾clean
4)編譯工程, /bin文件夾下生成opencv library - 2.4.4.jar
6. 在目標Adnroid應用程序中添加對opencv library - 2.4.4.jar 的引用,便可以調用相應的open CV庫函數了
第二種:在源碼下編譯,包含openCV jar包和.so庫文件
將.jar文件和.so文件放在指定的文件夾中,如project/libs文件夾下, 修改android.mk文件如下,指定相應的靜態庫和.so庫文件
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_STATIC_JAVA_LIBRARIES := opencv #指定靜態庫名
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := 目標apk名稱
WITH_DEXPREOPT := false
LOCAL_CERTIFICATE := platform
include $(BUILD_PACKAGE)
include $(CLEAR_VARS)
LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES := opencv:libs/opencvlibrary.jar #指定靜態庫名對應的庫文件路徑
LOCAL_PREBUILT_LIBS := libopencv_java:libs/armeabi-v7a/libopencv_java.so #指定.so文件對應的路徑
LOCAL_MODULE_TAGS := optional
include $(BUILD_MULTI_PREBUILT)
include $(callall-makefiles-under,$(LOCAL_PATH))
B. android中如何用opencv處理傾斜校正的問題,求源代碼
#include "cv.h"
#include "highgui.h"
#include "cxcore.h"
#include "cvcam.h"
//圖像的像素直接提取
#define _I(img,x,y) ((unsigned char*)((img)->imageData + (img)->widthStep*(y)))[(x)]
//亞像素級灰度值
#define _IF(image,x,y) ( ((int)(x+1)-(x))*((int)(y+1)-(y))*_I((image),(int)(x),(int)(y)) + ((int)(x+1)-(x))*((y)-(int)(y))*_I((image),(int)(x),(int)(y+1)) + ((x)-(int)(x))*((int)(y+1)-(y))*_I((image),(int)(x+1),(int)(y)) + ((x)-(int)(x))*((y)-(int)(y))*_I((image),(int)(x+1),(int)(y+1)) )//插值後的像素值(IN表示interpolation),x、y可以為小數
void callback(IplImage* image);
void main()
{
int ncams = cvcamGetCamerasCount( );//返回可以訪問的攝像頭數目
HWND mywin;
cvcamSetProperty(0, CVCAM_PROP_ENABLE, CVCAMTRUE);
cvcamSetProperty(0, CVCAM_PROP_RENDER, CVCAMTRUE);
mywin = (HWND)cvGetWindowHandle("cvcam window");
cvcamSetProperty(0, CVCAM_PROP_WINDOW, &mywin);
cvcamSetProperty(0, CVCAM_PROP_CALLBACK, callback);
//cvcamGetProperty(0, CVCAM_VIDEOFORMAT,NULL);
cvNamedWindow( "徑向矯正1", 1 );//創建窗口
cvNamedWindow( "徑向矯正2", 1 );//創建窗口
cvcamInit( );
cvcamStart( );
cvWaitKey(0);
cvcamStop( );
cvcamExit( );
cvDestroyWindow( "徑向矯正1" );//銷毀窗口
cvDestroyWindow( "徑向矯正2" );//銷毀窗口
}
void callback(IplImage* image)
{
IplImage* Show1 = cvCreateImage( cvSize(320,240), IPL_DEPTH_8U, 1);
IplImage* Show2 = cvCreateImage( cvSize(420,340), IPL_DEPTH_8U, 1);
IplImage* ImageC1 = cvCreateImage( cvSize(320,240), IPL_DEPTH_8U, 1);
//轉換為灰度圖
cvCvtColor( image, ImageC1, CV_RGB2GRAY);
cvFlip( ImageC1, NULL, 0);
double *mi;
double *md;
mi = new double[3*3];
md = new double[4];
CvMat intrinsic_matrix,distortion_coeffs;
//攝像機內參數
cvInitMatHeader(&intrinsic_matrix,3,3,CV_64FC1,mi);
//鏡頭畸變參數
cvInitMatHeader(&distortion_coeffs,1,4,CV_64FC1,md);
/////////////////////////////////////////////////
////////////////////////////320*240 120度廣角鏡頭
//參數由matlab獲得
double fc1,fc2,cc1,cc2,kc1,kc2,kc3,kc4;
fc1 = 667.23923/2.5;
fc2 = 669.78156/2.5;
cc1 = 429.96933/2.5;
cc2 = 351.48350/2.5;
kc1 = -0.40100;
kc2 = 0.19463;
kc3 = 0.00508;
kc4 = -0.00051;
cvmSet(&intrinsic_matrix, 0, 0, fc1);
cvmSet(&intrinsic_matrix, 0, 1, 0);
cvmSet(&intrinsic_matrix, 0, 2, cc1);
cvmSet(&intrinsic_matrix, 1, 0, 0);
cvmSet(&intrinsic_matrix, 1, 1, fc2);
cvmSet(&intrinsic_matrix, 1, 2, cc2);
cvmSet(&intrinsic_matrix, 2, 0, 0);
cvmSet(&intrinsic_matrix, 2, 1, 0);
cvmSet(&intrinsic_matrix, 2, 2, 1);
cvmSet(&distortion_coeffs, 0, 0, kc1);
cvmSet(&distortion_coeffs, 0, 1, kc2);
cvmSet(&distortion_coeffs, 0, 2, kc3);
cvmSet(&distortion_coeffs, 0, 3, kc4);
////////////////////////////320*240 120度廣角鏡頭
/////////////////////////////////////////////////
//矯正畸變(opencv)
cvUndistort2( ImageC1, Show1, &intrinsic_matrix, &distortion_coeffs);
//矯正畸變
for (int nx=0; nx<420; nx++)
{
for (int ny=0; ny<340; ny++)
{
double x=nx-50;
double y=ny-50;
double xx=(x-cc1)/fc1;
double yy=(y-cc2)/fc2;
double r2=pow(xx,2)+pow(yy,2);
double r4=pow(r2,2);
double xxx=xx*(1+kc1*r2+kc2*r4)+2*kc3*xx*yy+kc4*(r2+2*xx*xx);
double yyy=yy*(1+kc1*r2+kc2*r4)+2*kc4*xx*yy+kc3*(r2+2*yy*yy);
double xxxx = xxx*fc1+cc1;
double yyyy = yyy*fc2+cc2;
if (xxxx>0 && xxxx<320 && yyyy>0 && yyyy<240)
{
_I(Show2,nx,ny) = (int)_IF(ImageC1,xxxx,yyyy);
}
else
{
_I(Show2,nx,ny) = 0;
}
}
}
//畫線
cvLine( Show1, cvPoint(0,10), cvPoint(320,10), cvScalar(255,255,255),3 );
cvLine( Show1, cvPoint(0,230), cvPoint(320,230), cvScalar(255,255,255),3 );
cvLine( Show1, cvPoint(10,0), cvPoint(10,240), cvScalar(255,255,255),3 );
cvLine( Show1, cvPoint(310,0), cvPoint(310,240), cvScalar(255,255,255),3 );
cvLine( Show1, cvPoint(0,0), cvPoint(320,240), cvScalar(255,255,255),3 );
cvLine( Show1, cvPoint(0,240), cvPoint(320,0), cvScalar(255,255,255),3 );
cvLine( Show1, cvPoint(0,10), cvPoint(320,10), cvScalar(0,0,0) );
cvLine( Show1, cvPoint(0,230), cvPoint(320,230), cvScalar(0,0,0) );
cvLine( Show1, cvPoint(10,0), cvPoint(10,240), cvScalar(0,0,0) );
cvLine( Show1, cvPoint(310,0), cvPoint(310,240), cvScalar(0,0,0) );
cvLine( Show1, cvPoint(0,0), cvPoint(320,240), cvScalar(0,0,0) );
cvLine( Show1, cvPoint(0,240), cvPoint(320,0), cvScalar(0,0,0) );
//顯示
cvShowImage("徑向矯正1", Show1);
cvShowImage("徑向矯正2", Show2);
cvWaitKey(1);
cvReleaseImage( &Show1 );
cvReleaseImage( &Show2 );
cvReleaseImage( &ImageC1 );
}
來自: http://www.eyesourcecode.com/t/41983/1/1
C. 如何在Android中使用OpenCV
如何在Android程序中使用OpenCV
有兩種方式(重點講後面一種):
1.使用OpenCV Java API。
OpenCV安裝路徑"F:OpenCV-2.3.1-android-bin"下有兩個文件夾,
將文件夾"OpenCV-2.3.1"拷貝到你的Eclipse工作空間所在的目錄,也就是在你的項目的上一級目錄中,然後導入到工作空間中,在Package Explorer中選擇你的項目,單機右鍵在彈出菜單中選擇Properties,然後在彈出的Properties窗口中左側選擇Android,然後點擊右下方的Add按鈕,選擇OpenCV-2.3.1並點擊OK,
此時,展開你的項目樹,你可以看到新加了一個OpenCV-2.3.1_src目錄,如下圖,那麼就是正確添加了OpenCV Java API,否則就是你放置OpenCV-2.3.1的目錄路徑不正確。
然後就可以在你的Java源文件中導入OpenCV的API包,並且使用OpenCV API了,OpenCV API的包的形式如下:
Org.opencv.(OpenCV模塊名).(OpenCV類名)
例如:
Org.opencv.core.Mat
2.利用JNI編寫C++ OpenCV代碼,通過Android NDK創建動態庫(.so)
新建一個工作空間,例如"TestOpenCV",在Window->Preferences中設置好Android SDK的路徑。
然後新建一個Android項目,Build Target選擇Android2.2,命名為"HaveImgFun",活動名改為HaveImgFun,Package name中填寫com.testopencv.haveimgfun,最後點擊finish。
如同使用OpenCV Java API那樣,將OpenCV-2.3.1文件夾拷貝到與工作空間同一級目錄中;另外,將"F:OpenCV-2.3.1-android-binsamples"下的includeOpenCV.mk文件拷貝到和項目HaveImgFun同一級目錄中:
(上面這個各個文件夾和文件的放置很重要,因為OpenCV-2.3.1下的OpenCV.mk中有很多相對路徑的指定,如果不是這樣放置,在NDK生成動態庫時可能會報文件或文件夾無法找到的錯誤)
選擇Package Explorer中你的項目,右鍵選擇new->folder,新建一個名為jni的文件夾,用來存放你的c/c++代碼。
然後把res->layout下的main.xml的內容改為下面所示:
1 <?xml version="1.0" encoding="utf-8"?>
2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 android:orientation="vertical"
4 android:layout_width="fill_parent"
5 android:layout_height="fill_parent"
6 >
7 <Button android:layout_height="wrap_content"
8 android:layout_width="fill_parent"
9 android:id="@+id/btnNDK"
10 android:text="使用C++ OpenCV進行處理" />
11 <Button android:layout_height="wrap_content"
12 android:layout_width="fill_parent"
13 android:id="@+id/btnRestore"
14 android:text="還原" />
15 <ImageView android:id="@+id/ImageView01"
16 android:layout_width="fill_parent"
17 android:layout_height="fill_parent" />
18 </LinearLayout>
上面的代碼就是一個線性布局裡麵包含2個按鈕加上一個顯示圖像的ImageView
在文件夾src下的com.testopencv.haveimgfun包中新建一個類用於包裝使用了opencv c++代碼的動態庫的導出函數,類名為LibImgFun。
Eclipse會為你創建一個新的文件LibImgFun.java,將裡面的內容改為:
1 package com.testopencv.haveimgfun;
2 public class LibImgFun {
3 static {
4 System.loadLibrary("ImgFun");
5 }
6 /**
7 * @param width the current view width
8 * @param height the current view height
9 */
10 public static native int[] ImgFun(int[] buf, int w, int h);
11 }
從上面的代碼可以得知,我們的動態庫名字應該為「libImgFun.so」,注意"public static native int[] ImgFun(int[] buf, int w, int h)"中的native關鍵字,表明這個函數來自native code。static表示這是一個靜態函數,這樣就可以直接用類名去調用。
在jni文件夾下建立一個"ImgFun.cpp"的文件,內容改為下面所示:
1 #include <jni.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <opencv2/opencv.hpp>
5 using namespace cv;
6
7 extern "C"
8 {
9 JNIEXPORT jintArray JNICALL Java_com_testopencv_haveimgfun_LibImgFun_ImgFun(JNIEnv* env, jobject obj, jintArray buf, int w, int h);
10 JNIEXPORT jintArray JNICALL Java_com_testopencv_haveimgfun_LibImgFun_ImgFun(JNIEnv* env, jobject obj, jintArray buf, int w, int h){
11
12 jint *cbuf;
13 cbuf = env->GetIntArrayElements(buf, false);
14 if(cbuf == NULL)
15 {
16 return 0;
17 }
18
19 Mat myimg(h, w, CV_8UC4, (unsigned char*)cbuf);
20 for(int j=0;j<myimg.rows/2;j++)
21 {
22 myimg.row(j).setTo(Scalar(0,0,0,0));
23 }
24
25 int size=w * h;
26 jintArray result = env->NewIntArray(size);
27 env->SetIntArrayRegion(result, 0, size, cbuf);
28 env->ReleaseIntArrayElements(buf, cbuf, 0);
29 return result;
30 }
31 }
上面的代碼中#include <jni.h>是必須要包含的頭文件,#include <opencv2/opencv.hpp>是opencv要包含的頭文件。
動態庫要導出的函數如下聲明:
JNIEXPORT jintArray JNICALL Java_com_testopencv_haveimgfun_LibImgFun_ImgFun(JNIEnv* env, jobject obj, jintArray buf, int w, int h);
JNIEXPORT 和JNICALL是必須要加的關鍵字
jintArray就是int[],這里返回類型要麼為空,要麼為jni中定義的類型,事實上就是CC++類型前面加上j,如果是數組,則在後面加上Array。
函數名的命名規則如下:
Java_(包路徑)_(類名)_(函數名) (JNIEnv *env, jobject obj, 自己定義的參數...)
包路徑中的"."用"_"(下劃線)代替,類名就是上麵包裝該動態庫函數的類的名字,最後一個才是真正的函數名;JNIEnv *env和jobject obj這兩個參數時必須的,用來調用JNI環境下的一些函數;後面就是你自己定義的參數。在這里,jintArray buf代表了傳進來的圖像的數據,int w是圖像的寬,int h是圖像的高。
這個函數的功能是將傳進來的圖像的上半部分塗成黑色。
然後再在jni下新建兩個文件"Android.mk"文件和"Application.mk"文件,這兩個文件事實上就是簡單的Makefile文件。
其中將Android.mk的內容改為如下所示:
LOCAL_PATH:=$(callmy-dir)
include$(CLEAR_VARS)
include../includeOpenCV.mk
ifeq("$(wildcard$(OPENCV_MK_PATH))","")
#trytoloadOpenCV.mkfromdefaultinstalllocation
include$(TOOLCHAIN_PREBUILT_ROOT)/user/share/OpenCV/OpenCV.mk
else
include$(OPENCV_MK_PATH)
endif
LOCAL_MODULE:=ImgFun
LOCAL_SRC_FILES:=ImgFun.cpp
include$(BUILD_SHARED_LIBRARY)
Application.mk的內容改為如下所示:
APP_STL:=gnustl_static
APP_CPPFLAGS:=-frtti-fexceptions
APP_ABI:=armeabiarmeabi-v7a
其中APP_ABI指定的是目標平台的CPU架構。(經過很多測試,android2.2必須指定為armeabi,android2.2以上的使用armeabi-v7a,如果沒有設置對,很有可能安裝到android虛擬機失敗,當然你同時如上面寫上也是可以的)
上面的步驟完成後,就可以使用NDK生成動態庫了,打開cygwin,cd到項目目錄下:
輸入$NDK/ndk-build命令,開始創建動態庫。
這時候刷新Eclipse的Package Explorer會出現兩個新的文件夾obj和libs。
現在,只剩最後一步完成這個測試程序。
將一張圖片,例如"lena.jpg"放到項目res->drawable-hdpi目錄中並刷新該目錄。
然後將HaveImgFun.java的內容改為下面所示:
1 package com.testopencv.haveimgfun;
2
3 import android.app.Activity;
4 import android.graphics.Bitmap;
5 import android.graphics.Bitmap.Config;
6 import android.graphics.drawable.BitmapDrawable;
7 import android.os.Bundle;
8 import android.widget.Button;
9 import android.view.View;
10 import android.widget.ImageView;
11
12 public class HaveImgFun extends Activity{
13 /** Called when the activity is first created. */
14 ImageView imgView;
15 Button btnNDK, btnRestore;
16
17 @Override
18 public void onCreate(Bundle savedInstanceState) {
19 super.onCreate(savedInstanceState);
20 setContentView(R.layout.main);
21
22 this.setTitle("使用NDK轉換灰度圖");
23 btnRestore=(Button)this.findViewById(R.id.btnRestore);
24 btnRestore.setOnClickListener(new ClickEvent());
25 btnNDK=(Button)this.findViewById(R.id.btnNDK);
26 btnNDK.setOnClickListener(new ClickEvent());
27 imgView=(ImageView)this.findViewById(R.id.ImageView01);
28 Bitmap img=((BitmapDrawable) getResources().getDrawable(R.drawable.lena)).getBitmap();
29 imgView.setImageBitmap(img);
30 }
31
32 class ClickEvent implements View.OnClickListener{
33 public void onClick(View v){
34 if(v == btnNDK){
35 long current=System.currentTimeMillis();
36 Bitmap img1=((BitmapDrawable) getResources().getDrawable(R.drawable.lena)).getBitmap();
37 int w=img1.getWidth(),h=img1.getHeight();
38 int[] pix = new int[w * h];
39 img1.getPixels(pix, 0, w, 0, 0, w, h);
40 int[] resultInt=LibImgFun.ImgFun(pix, w, h);
41 Bitmap resultImg=Bitmap.createBitmap(w, h, Config.RGB_565);
42 resultImg.setPixels(resultInt, 0, w, 0, 0,w, h);
43 long performance=System.currentTimeMillis()-current;
44 imgView.setImageBitmap(resultImg);
45 HaveImgFun.this.setTitle("w:"+String.valueOf(img1.getWidth())+",h:"+String.valueOf(img1.getHeight())+"NDK耗時"+String.valueOf(performance)+" 毫秒");
46 } else if(v == btnRestore){
47 Bitmap img2=((BitmapDrawable) getResources().getDrawable(R.drawable.lena)).getBitmap();
48 imgView.setImageBitmap(img2);
49 HaveImgFun.this.setTitle("使用OpenCV進行圖像處理");
50 }
51 }
52 }
53 }
點擊全部保存,OK,現在可以選擇一個Android虛擬機運行看一下效果,配置好Run Configuration然後點擊Run,得到下面的結果:
D. 如何在mac系統上使用opencv for android
一、安裝OpenCV for MAC
1. 首先下載opencv for mac安裝源文件,解壓縮
2. 安裝cmake程序。下載cmake的dmg文件安裝即可。
3. 通過終端進入存放解壓後的opencv文件夾,編譯安裝opencv,使用命令如下:
>sudo cmake -G "Unix Makefiles"
>sudo make -j8
>sudo make install
4. 經過步驟3則OpenCV已經被Compile完成,並且相應的lib文件存放在「/usr/local/lib」文件夾,h文件存放在「/usr/local/include」。
至此,opencv for Mac 安裝完畢。
二、在MAC下使用OpenCV
1. 使用終端編譯。新建DisplayImage.cpp文件,代碼如下
#include <cv.h>
#include <highgui.h>
using namespace cv;
int main( int argc, char** argv )
{
Mat image;
image = imread( argv[1], 1 );
if( argc != 2 || !image.data )
{
printf( "No image data \n" );
return -1;
}
namedWindow( "Display Image", CV_WINDOW_AUTOSIZE );
imshow( "Display Image", image );
waitKey(0);
return 0;
}
2. 新建CMakeLists.txt文件,代碼如下:
project( DisplayImage )
find_package( OpenCV REQUIRED )
add_executable( DisplayImage DisplayImage )
target_link_libraries( DisplayImage ${OpenCV_LIBS} )
3. 編譯兩個文件
cd <DisplayImage_directory>
cmake .
make
4. 運行編譯好的結果
./DisplayImage lena.jpg
三、在XCode中使用OpenCV
1. 創建一個空的command line工程。
2. 在main.cpp中粘貼以下代碼:
//
// main.cpp
// Created by Jason Yank on 13-05-08.
// Copyright (c) 2013年 Jason Yank. All rights reserved.
//
#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv/cvaux.hpp>
#include <fstream>
using namespace std;
#define BYTE unsigned char
int main(int argc, const char * argv[])
{
// insert code here...
#if 1
//get the image from the directed path
IplImage* img = cvLoadImage("/Users/jasonyank/1.jpg", 1);
//NSLog(img);
//create a window to display the image
cvNamedWindow("picture", 1);
//show the image in the window
cvShowImage("picture", img);
//wait for the user to hit a key
cvWaitKey(0);
//delete the image and window
cvReleaseImage(&img);
cvDestroyWindow("picture");
#endif
//return
return 0;
}
3. 添加lib文件:右鍵點擊工程名,選擇「Add files to..」,在文件選擇對話框彈出來時輸入「/」,在彈出的路徑框中輸入:/usr/local/lib,全選該文件夾下的全部dylib文件,添加至工程。
5. 添加lib文件查找支持: 點擊工程名文件,進入「Build Settings」選項卡,在「Library Search Paths」欄中輸入「/usr/local/lib」
6. 添加頭文件:點擊工程名文件,進入「Build Settings」選項卡,在「Header Search Paths」欄中輸入:「/usr/local/include /usr/local/include/opencv」
7. 編譯運行整個工程,運行成功~~
四、在Eclipse中使用OpenCV
1. 按照正常的步驟,使用eclipse建立一個Mac C++工程,包含一個cpp文件,代碼如xcode中的代碼相同即可。
2. 右擊工程名, 選擇「Properties」,在屬性配置頁中選擇,點擊C/C++ Build, 在下拉選項中選擇 Settings. 在右邊的選項卡中選擇 Tool Settings。
3. 在GCC C++ Compiler選項列表中選擇Includes,在Include paths(-l)中添加安裝好的opencv的頭文件存放目錄:/usr/local/include/
4. 在MacOS X C++Linker選項列表中選擇Library,在Library search path (-L)中添加安裝好的opencv Lib文件存放目錄:/usr/local/lib/
5. 在MacOS X C++Linker選項列表中選擇Library, 在Libraries(-l) 中依次點擊「+」號,添加需要使用的Lib文件(通常情況下,使用前三個):
opencv_core opencv_imgproc opencv_highgui opencv_ml opencv_video opencv_features2d opencv_calib3d opencv_objdetect opencv_contrib opencv_legacy opencv_flann
6. 重新build all工程,大功告成~~*^_^*