Android和OpenCV開發編程(1)圖像灰度化和Canny檢測

開發的基礎是首先配置好各種開發環境,過程很複雜,這裏先不具體介紹了,整個過程中遇到了很多問題,主要步驟參考這幾篇博客

http://blog.csdn.net/pwh0996/article/details/8957764


下面直接介紹同時實現兩個功能的app,這裏採用的是利用C++來實現,至於直接利用JAVA來實現灰度化的過程,可以參考這裏http://blog.csdn.net/yanzi1225627/article/details/16917961

使用java API開發android:

創建工程

        (1) 打開eclipse,創建android應用工程Img;

        (2) 將測試圖像lena.jpg添加到資源目錄res/drawable-hdpi中;

        (3) 在Package Explorer中選擇項目Img,單擊右鍵在彈出菜單中選擇Properties,然後在彈出的Properties窗口中左側選擇Android,然後點擊右下方的Add按鈕,選擇OpenCV Library 2.4.9並點擊OK,操作完成後,會將OpenCV類庫添加到Img的Android Dependencies中.


工程代碼:

(1) 佈局文件:activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:orientation="vertical" 
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >
      <Button 
          android:layout_height="wrap_content" 
          android:layout_width="fill_parent" 
          android:id="@+id/btnNDK" 
          android:text="Canny檢測" />
        <Button 
          android:layout_height="wrap_content"
          android:layout_width="fill_parent"
          android:id="@+id/btnGray" 
          android:text="灰度化" /> 
      <Button 
          android:layout_height="wrap_content"
          android:layout_width="fill_parent"
          android:id="@+id/btnRestore" 
          android:text="還原" /> 
      <ImageView 
          android:id="@+id/ImageView01" 
          android:layout_width="fill_parent"
          android:layout_height="fill_parent" /> 
        
</LinearLayout>
    
2、MainActivity.java文件
package com.iipc.img;

import org.opencv.android.BaseLoaderCallback;
import org.opencv.android.LoaderCallbackInterface;
import org.opencv.android.OpenCVLoader;
import android.app.Activity; 
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.drawable.BitmapDrawable; 
import android.os.Bundle; 
import android.widget.Button; 
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageView;
public class MainActivity extends Activity implements OnClickListener  {
	/** Called when the activity is first created. */
	ImageView imgView;
	 Bitmap resultImg;
	 Bitmap img;
	Button btnNDK, btnRestore,btnGray; 
	  private static final String TAG="MainActivity";
	    //OpenCV類庫加載並初始化成功後的回調函數,在此我們不進行任何操作  
	    private BaseLoaderCallback  mLoaderCallback = new BaseLoaderCallback(this) {  
	        @Override  
	        public void onManagerConnected(int status) {  
	            switch (status) {  
	                case LoaderCallbackInterface.SUCCESS:{  
	                	Log.i(TAG,"成功加載");
	                    System.loadLibrary("Image_proc");  
	                } break;  
	                default:{  
	                    super.onManagerConnected(status);  
	                    Log.i(TAG,"加載失敗");
	                } break;  
	            }  
	        }  
	    };  

	@Override 
	public void onCreate(Bundle savedInstanceState) { 
		super.onCreate(savedInstanceState); 
		setContentView(R.layout.activity_main);
		this.setTitle("應用NDK轉換灰度圖"); 
		btnRestore = (Button) findViewById(R.id.btnRestore); 
		btnNDK = (Button) findViewById(R.id.btnNDK); 
		btnGray = (Button) findViewById(R.id.btnGray); 
		imgView = (ImageView) findViewById(R.id.ImageView01); 
		img = ((BitmapDrawable) getResources().getDrawable( R.drawable.lena)).getBitmap();
		imgView.setImageBitmap(img); 
		btnRestore.setOnClickListener(this); 
		btnNDK.setOnClickListener(this);	
		btnGray.setOnClickListener(this);	
		} 
	
	 public void procSrc2Gray(){
	     int w = img.getWidth();  
	    int h = img.getHeight();  
	    int[] pixels = new int[w*h];       
	     img.getPixels(pixels, 0, w, 0, 0, w, h);  
	     int[] resultInt = LibImgFun.grayProc(pixels, w, h);  
	     resultImg = Bitmap.createBitmap(w, h, Config.ARGB_8888);  
	     resultImg.setPixels(resultInt, 0, w, 0, 0, w, h);  
  }
	  
	@Override
	public void onClick(View v) {
		// TODO Auto-generated method stub
		if (v == btnNDK) { 
		//	long current = System.currentTimeMillis();
			Bitmap img1 = ((BitmapDrawable) getResources().getDrawable( R.drawable.lena)).getBitmap(); 
			int w = img1.getWidth(), h = img1.getHeight(); 
		    int[] pix = new int[w * h]; 
			img1.getPixels(pix, 0, w, 0, 0, w, h); 
			int[] resultInt = LibImgFun.imgFun(pix, w, h);
			Bitmap resultImg = Bitmap.createBitmap(w, h, Config.ARGB_8888);
			resultImg.setPixels(resultInt, 0, w, 0, 0, w, h); 
		//	long performance = System.currentTimeMillis() - current; 
			imgView.setImageBitmap(resultImg); 
		//	MainActivity.this.setTitle("w:" + String.valueOf(img1.getWidth()) + ",h:" + String.valueOf(img1.getHeight()) + "NDK耗時" + String.valueOf(performance) + " 毫秒");
			MainActivity.this.setTitle("OpenCV的Canny檢測圖");
		}
		else if (v == btnGray) {
	 procSrc2Gray();
		imgView.setImageBitmap(resultImg);  
		MainActivity.this.setTitle("OpenCV灰度化");
	}
		else if (v == btnRestore) {
			Bitmap img2 = ((BitmapDrawable) getResources().getDrawable( R.drawable.lena)).getBitmap(); 
			imgView.setImageBitmap(img2);
			MainActivity.this.setTitle("原始圖像");
			}
		
			} 
	
	   @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_9, this, mLoaderCallback);  
	    }  
	
	}

3、LibImgFun.java文件
package com.iipc.img;

public class LibImgFun {
	public static native int[] imgFun(int[] buf, int w, int h);
	public static native int[] grayProc(int[] buf, int w, int h);
}


4、Android.mk
LOCAL_PATH := $(call my-dir)  
include $(CLEAR_VARS)  
include ../OpenCV-SDK/native/jni/OpenCV.mk  
LOCAL_SRC_FILES  := LibImgFun.cpp  
LOCAL_MODULE     := Image_proc  
include $(BUILD_SHARED_LIBRARY) 

5、 Application.mk(配置文件)
APP_STL := gnustl_static  
APP_CPPFLAGS := -frtti -fexceptions  
APP_ABI := armeabi-v7a  
APP_PLATFORM := android-8  

6、LibImgFun.cpp文件
#include <LibImgFun.h>
#include <opencv2/opencv.hpp>
#include<highgui.h>
#include <string>
#include <vector>
#include<stdio.h>
#include<stdlib.h>
#include<iostream>
using namespace cv;
using namespace std;

//改寫的canny檢測代碼,返回值爲存儲canny檢測圖像數據的int數組jintArray,傳遞的參數存儲原始圖像數據的int數組,以及w和h
JNIEXPORT jintArray JNICALL Java_com_iipc_img_LibImgFun_imgFun(JNIEnv* env, jclass obj, jintArray buf, jint w, jint h){
	jint *cbuf; cbuf = env->GetIntArrayElements(buf, false);//JNI傳遞int數組的方法
	if (cbuf == NULL)
	{
		return 0;
	}
	Mat myimg(h, w, CV_8UC4, (unsigned char*) cbuf);//java中讀入的圖像都是4通道的,所以這裏myimg聲明定義爲CV_8UC4,以一個數組中的數據來建立Mat
	Mat grayimg;
	cvtColor(myimg,grayimg,CV_BGRA2GRAY);//將4通道的彩色圖轉爲灰度圖
	Mat pCannyImage;
	Canny(grayimg,pCannyImage,50,150,3);//canny檢測

	uchar* ptr = myimg.ptr(0);//因爲灰度圖最終以4通道bmp形式顯示,所以將得到的灰度圖grayimg的數據賦值到4通道的imageData中,
	  for(int i = 0; i < w*h; i ++){
	     //得到的canny圖像原本是單通道,但java中顯示bmp時只能4通道或三通道,爲了使顯示的圖像時灰度的,把canny圖像的數據值賦給一個4通道的myimg
	      //對於一個int四字節,其彩色值存儲方式爲:BGRA
	      ptr[4*i+1] = pCannyImage.data[i];
	      ptr[4*i+2] = pCannyImage.data[i];
	      ptr[4*i+0] = pCannyImage.data[i];
	  }

		//以下部分是將得到canny圖像存在數組中,以數組的形式返回
		int size = w * h;
		jintArray result = env->NewIntArray(size);
		env->SetIntArrayRegion(result, 0, size, cbuf);
		env->ReleaseIntArrayElements(buf, cbuf, 0);
		return result;


}



JNIEXPORT jintArray JNICALL Java_com_iipc_img_LibImgFun_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);



Mat grayimg;
cvtColor(imgData,grayimg,CV_BGRA2GRAY);//將4通道的彩色圖轉爲灰度圖
  uchar* ptr = imgData.ptr(0);//因爲灰度圖最終以4通道bmp形式顯示,所以將得到的灰度圖grayimg的數據賦值到4通道的imageData中,
  for(int i = 0; i < w*h; i ++){
      //計算公式:Y(亮度) = 0.299*R + 0.587*G + 0.114*B//去掉了原始程序中轉換的公式
      //對於一個int四字節,其彩色值存儲方式爲:BGRA
      ptr[4*i+1] = grayimg.data[i];
      ptr[4*i+2] = grayimg.data[i];
      ptr[4*i+0] = grayimg.data[i];
  }

	//以下部分是將得到canny圖像存在數組中,以數組的形式返回
	int size = w * h;
	jintArray result = env->NewIntArray(size);
	env->SetIntArrayRegion(result, 0, size, cbuf);
	env->ReleaseIntArrayElements(buf, cbuf, 0);
	return result;


}

7、LibImgFun.h文件
#include <jni.h>


extern "C" {
JNIEXPORT jintArray JNICALL Java_com_iipc_img_LibImgFun_imgFun
  (JNIEnv *, jclass, jintArray, jint, jint);

JNIEXPORT jintArray JNICALL Java_com_iipc_img_LibImgFun_grayProc
  (JNIEnv *, jclass, jintArray, jint, jint);

}


8、結果
1、原圖
2、灰度化


3、Canny檢測




發佈了33 篇原創文章 · 獲贊 41 · 訪問量 17萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章