开发的基础是首先配置好各种开发环境,过程很复杂,这里先不具体介绍了,整个过程中遇到了很多问题,主要步骤参考这几篇博客
http://blog.youkuaiyun.com/pwh0996/article/details/8957764
下面直接介绍同时实现两个功能的app,这里采用的是利用C++来实现,至于直接利用JAVA来实现灰度化的过程,可以参考这里http://blog.youkuaiyun.com/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检测