zl程序教程

您现在的位置是:首页 >  移动开发

当前栏目

Android提高之使用NDK把彩图转换灰度图的方法

Android转换方法 使用 提高 ndk 灰度 彩图
2023-06-13 09:15:41 时间

一般而言在Android上使用JAVA实现彩图转换为灰度图,与J2ME上的实现方法类似,不过遇到频繁地转换或者是大图转换时,就必须使用NDK来提高速度了。本文主要通过JAVA和NDK这两种方式来分别实现彩图转换为灰度图,并给出速度的对比,供大家参考。

先来简单地介绍一下Android的NDK使用步骤:

以NDKr4为例,或许以后新版的NDK的使用方法略有不同。
1、下载支持C++的android-ndk-r4-crystax,支持C++的话可玩性更强。

2、下载cygwin,选择ftp://mirrors.kernel.org这个镜像,搜索 DevelInstall安装gcc和make等工具;

如图所示:

在搜索框里分别搜索gcc和make,必须是DevelInstall栏的。

3、Cygwin安装目录下,找到home/username的目录下的.bash_profile文件,打开文件在最后加上:
   NDK=/cygdrive/d:cygwin/android-ndk-r4-crystax
  exportNDK
PS:假设安装在D:/cygwin/android-ndk-r4-crystax。
4、运行cygwin,通过cd命令去到NDK/samples/例子目录/,运行$NDK/ndk-build来编译该目录下的Android.mk

以下是个人习惯

5、安装Eclipse的CDT,官方下载cdt安装包,解压缩后把plugins和feagures复制覆盖到eclipse文件夹下即可

6、去到系统属性->环境变量->Path添加"D:/cygwin/bin"(假设cygwin安装在D:下)和"D:/cygwin/android-ndk-r4-crystax",重启计算机,然后就可以在Eclipse里面建立基于cygwin的C/C++工程了,先通过这一步来验证NDK的程序能够编译成功,然后再通过第4步来生成SO文件。

接下来看看本文程序运行的效果:

从转换灰度图的耗时来说,NDK的确比JAVA所用的时间短不少。

main.xml源码如下:

<?xmlversion="1.0"encoding="utf-8"?>
-<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="fill_parent"android:layout_height="fill_parent">
<Buttonandroid:layout_height="wrap_content"android:layout_width="fill_parent"android:id="@+id/btnJAVA"android:text="使用JAVA转换灰度图"/>
<Buttonandroid:layout_height="wrap_content"android:layout_width="fill_parent"android:id="@+id/btnNDK"android:text="使用NDK转换灰度图"/>
<ImageViewandroid:id="@+id/ImageView01"android:layout_width="fill_parent"android:layout_height="fill_parent"/>
</LinearLayout>

主程序testToGray.java的源码如下:

packagecom.testToGray;
importandroid.app.Activity;
importandroid.graphics.Bitmap;
importandroid.graphics.Bitmap.Config;
importandroid.graphics.drawable.BitmapDrawable;
importandroid.os.Bundle;
importandroid.view.View;
importandroid.widget.Button;
importandroid.widget.ImageView;
publicclasstestToGrayextendsActivity{
/**Calledwhentheactivityisfirstcreated.*/
ButtonbtnJAVA,btnNDK;
ImageViewimgView;
@Override
publicvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
this.setTitle("使用NDK转换灰度图---hellogv");
btnJAVA=(Button)this.findViewById(R.id.btnJAVA);
btnJAVA.setOnClickListener(newClickEvent());

btnNDK=(Button)this.findViewById(R.id.btnNDK);
btnNDK.setOnClickListener(newClickEvent());
imgView=(ImageView)this.findViewById(R.id.ImageView01);
}
classClickEventimplementsView.OnClickListener{
@Override
publicvoidonClick(Viewv){
if(v==btnJAVA)
{
longcurrent=System.currentTimeMillis();
Bitmapimg=ConvertGrayImg(R.drawable.cat);
longperformance=System.currentTimeMillis()-current;
//显示灰度图
imgView.setImageBitmap(img);
testToGray.this.setTitle("w:"+String.valueOf(img.getWidth())+",h:"+String.valueOf(img.getHeight())
+"JAVA耗时"+String.valueOf(performance)+"毫秒");
}
elseif(v==btnNDK)
{
longcurrent=System.currentTimeMillis();
//先打开图像并读取像素
Bitmapimg1=((BitmapDrawable)getResources().getDrawable(R.drawable.cat)).getBitmap();
intw=img1.getWidth(),h=img1.getHeight();
int[]pix=newint[w*h];
img1.getPixels(pix,0,w,0,0,w,h);
//通过ImgToGray.so把彩色像素转为灰度像素
int[]resultInt=LibFuns.ImgToGray(pix,w,h);
BitmapresultImg=Bitmap.createBitmap(w,h,Config.RGB_565);
resultImg.setPixels(resultInt,0,w,0,0,w,h);
longperformance=System.currentTimeMillis()-current;
//显示灰度图
imgView.setImageBitmap(resultImg);
testToGray.this.setTitle("w:"+String.valueOf(img1.getWidth())+",h:"+String.valueOf(img1.getHeight())
+"NDK耗时"+String.valueOf(performance)+"毫秒");
}
}
}

/**
*把资源图片转为灰度图
*@paramresID资源ID
*@return
*/
publicBitmapConvertGrayImg(intresID)
{
Bitmapimg1=((BitmapDrawable)getResources().getDrawable(resID)).getBitmap();

intw=img1.getWidth(),h=img1.getHeight();
int[]pix=newint[w*h];
img1.getPixels(pix,0,w,0,0,w,h);
intalpha=0xFF<<24;
for(inti=0;i<h;i++){
for(intj=0;j<w;j++){
//获得像素的颜色
intcolor=pix[w*i+j];
intred=((color&0x00FF0000)>>16);
intgreen=((color&0x0000FF00)>>8);
intblue=color&0x000000FF;
color=(red+green+blue)/3;
color=alpha|(color<<16)|(color<<8)|color;
pix[w*i+j]=color;
}
}
Bitmapresult=Bitmap.createBitmap(w,h,Config.RGB_565);
result.setPixels(pix,0,w,0,0,w,h);
returnresult;
}
}

封装NDK函数的JAVA类LibFuns.java的源码如下:

packagecom.testToGray;
publicclassLibFuns{
static{
System.loadLibrary("ImgToGray");
}
/**
*@paramwidththecurrentviewwidth
*@paramheightthecurrentviewheight
*/
publicstaticnativeint[]ImgToGray(int[]buf,intw,inth);
}

彩图转换为灰度图的ImgToGray.cpp源码:

#include<jni.h>
#include<stdio.h>
#include<stdlib.h>
extern"C"{
JNIEXPORTjintArrayJNICALLJava_com_testToGray_LibFuns_ImgToGray(
JNIEnv*env,jobjectobj,jintArraybuf,intw,inth);
}
;
JNIEXPORTjintArrayJNICALLJava_com_testToGray_LibFuns_ImgToGray(
JNIEnv*env,jobjectobj,jintArraybuf,intw,inth){
jint*cbuf;
cbuf=env->GetIntArrayElements(buf,false);
if(cbuf==NULL){
return0;/*exceptionoccurred*/
}
intalpha=0xFF<<24;
for(inti=0;i<h;i++){
for(intj=0;j<w;j++){
//获得像素的颜色
intcolor=cbuf[w*i+j];
intred=((color&0x00FF0000)>>16);
intgreen=((color&0x0000FF00)>>8);
intblue=color&0x000000FF;
color=(red+green+blue)/3;
color=alpha|(color<<16)|(color<<8)|color;
cbuf[w*i+j]=color;
}
}
intsize=w*h;
jintArrayresult=env->NewIntArray(size);
env->SetIntArrayRegion(result,0,size,cbuf);
env->ReleaseIntArrayElements(buf,cbuf,0);
returnresult;
}

Android.mk的源码:

LOCAL_PATH:=$(callmy-dir)
include$(CLEAR_VARS)
LOCAL_MODULE:=ImgToGray
LOCAL_SRC_FILES:=ImgToGray.cpp
include$(BUILD_SHARED_LIBRARY)

感兴趣的读者可以动手调试一下本文所述代码,相信会对大家进行Android项目开发有一定的帮助。