欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

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

程序员文章站 2022-11-05 15:11:13
一般而言在android上使用java实现彩图转换为灰度图,与j2me上的实现方法类似,不过遇到频繁地转换或者是大图转换时,就必须使用ndk来提高速度了。本文主要通过jav...

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

先来简单地介绍一下android的ndk使用步骤:

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

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

如图所示:

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

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

3、cygwin安装目录下,找到home/username的目录下的.bash_profile文件,打开文件在最后加上:
    ndk=/cygdrive/d:cygwin/android-ndk-r4-crystax
   export ndk
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文件。

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

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

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

main.xml源码如下:

<?xml version="1.0" encoding="utf-8" ?>  
- <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/btnjava" android:text="使用java转换灰度图" />  
<button android:layout_height="wrap_content" android:layout_width="fill_parent" android:id="@+id/btnndk" android:text="使用ndk转换灰度图" />  
<imageview android:id="@+id/imageview01" android:layout_width="fill_parent" android:layout_height="fill_parent" />  
</linearlayout> 

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

package com.testtogray; 
import android.app.activity; 
import android.graphics.bitmap; 
import android.graphics.bitmap.config; 
import android.graphics.drawable.bitmapdrawable; 
import android.os.bundle; 
import android.view.view; 
import android.widget.button; 
import android.widget.imageview; 
public class testtogray extends activity { 
  /** called when the activity is first created. */ 
  button btnjava,btnndk; 
  imageview imgview; 
  @override 
  public void oncreate(bundle savedinstancestate) { 
    super.oncreate(savedinstancestate); 
    setcontentview(r.layout.main); 
    this.settitle("使用ndk转换灰度图---hellogv"); 
    btnjava=(button)this.findviewbyid(r.id.btnjava); 
    btnjava.setonclicklistener(new clickevent()); 
     
    btnndk=(button)this.findviewbyid(r.id.btnndk); 
    btnndk.setonclicklistener(new clickevent()); 
    imgview=(imageview)this.findviewbyid(r.id.imageview01); 
  } 
  class clickevent implements view.onclicklistener{ 
    @override 
    public void onclick(view v) { 
      if(v==btnjava) 
      { 
        long current=system.currenttimemillis(); 
        bitmap img=convertgrayimg(r.drawable.cat); 
        long performance=system.currenttimemillis()-current; 
        //显示灰度图 
        imgview.setimagebitmap(img); 
        testtogray.this.settitle("w:"+string.valueof(img.getwidth())+",h:"+string.valueof(img.getheight()) 
            +" java耗时 "+string.valueof(performance)+" 毫秒"); 
      } 
      else if(v==btnndk) 
      { 
        long current=system.currenttimemillis(); 
        //先打开图像并读取像素 
        bitmap img1=((bitmapdrawable) getresources().getdrawable(r.drawable.cat)).getbitmap(); 
        int w=img1.getwidth(),h=img1.getheight(); 
        int[] pix = new int[w * h]; 
        img1.getpixels(pix, 0, w, 0, 0, w, h); 
        //通过imgtogray.so把彩色像素转为灰度像素 
        int[] resultint=libfuns.imgtogray(pix, w, h); 
        bitmap resultimg=bitmap.createbitmap(w, h, config.rgb_565); 
        resultimg.setpixels(resultint, 0, w, 0, 0,w, h); 
        long performance=system.currenttimemillis()-current; 
        //显示灰度图 
        imgview.setimagebitmap(resultimg); 
        testtogray.this.settitle("w:"+string.valueof(img1.getwidth())+",h:"+string.valueof(img1.getheight()) 
            +" ndk耗时 "+string.valueof(performance)+" 毫秒"); 
      } 
    } 
  } 
   
  /** 
   * 把资源图片转为灰度图 
   * @param resid 资源id 
   * @return 
   */ 
  public bitmap convertgrayimg(int resid) 
  { 
    bitmap img1=((bitmapdrawable) getresources().getdrawable(resid)).getbitmap(); 
     
    int w=img1.getwidth(),h=img1.getheight(); 
    int[] pix = new int[w * h]; 
    img1.getpixels(pix, 0, w, 0, 0, w, h); 
    int alpha=0xff<<24; 
    for (int i = 0; i < h; i++) {  
      for (int j = 0; j < w; j++) {  
        // 获得像素的颜色  
        int color = pix[w * i + j];  
        int red = ((color & 0x00ff0000) >> 16);  
        int green = ((color & 0x0000ff00) >> 8);  
        int blue = color & 0x000000ff;  
        color = (red + green + blue)/3;  
        color = alpha | (color << 16) | (color << 8) | color;  
        pix[w * i + j] = color; 
      } 
    } 
    bitmap result=bitmap.createbitmap(w, h, config.rgb_565); 
    result.setpixels(pix, 0, w, 0, 0,w, h); 
    return result; 
  } 
}

封装ndk函数的java类libfuns.java的源码如下:

package com.testtogray; 
public class libfuns { 
  static { 
    system.loadlibrary("imgtogray"); 
  } 
  /** 
  * @param width the current view width 
  * @param height the current view height 
  */ 
  public static native int[] imgtogray(int[] buf, int w, int h); 
}

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

#include <jni.h> 
#include <stdio.h> 
#include <stdlib.h> 
extern "c" { 
jniexport jintarray jnicall java_com_testtogray_libfuns_imgtogray( 
    jnienv* env, jobject obj, jintarray buf, int w, int h); 
} 
; 
jniexport jintarray jnicall java_com_testtogray_libfuns_imgtogray( 
    jnienv* env, jobject obj, jintarray buf, int w, int h) { 
  jint *cbuf; 
  cbuf = env->getintarrayelements(buf, false); 
  if (cbuf == null) { 
    return 0; /* exception occurred */ 
  } 
  int alpha = 0xff << 24; 
  for (int i = 0; i < h; i++) { 
    for (int j = 0; j < w; j++) { 
      // 获得像素的颜色 
      int color = cbuf[w * i + j]; 
      int red = ((color & 0x00ff0000) >> 16); 
      int green = ((color & 0x0000ff00) >> 8); 
      int blue = color & 0x000000ff; 
      color = (red + green + blue) / 3; 
      color = alpha | (color << 16) | (color << 8) | color; 
      cbuf[w * i + j] = color; 
    } 
  } 
  int size=w * h; 
  jintarray result = env->newintarray(size); 
  env->setintarrayregion(result, 0, size, cbuf); 
  env->releaseintarrayelements(buf, cbuf, 0); 
  return result; 
}

android.mk的源码:

local_path:= $(call my-dir) 
include $(clear_vars) 
local_module  := imgtogray 
local_src_files := imgtogray.cpp 
include $(build_shared_library)

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