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

一般而言在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 等工具;

如图所示:

在搜索框里分别搜索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文件。

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

从转换灰度图的耗时来说,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项目开发有一定的帮助。

(0)

相关推荐

  • Android-如何将RGB彩色图转换为灰度图方法介绍

    实例:RGB2Grey 项目运行效果图:          源代码: [java] public class MainActivity extends Activity { /* (non-Javadoc)     * @see android.app.Activity#onCreate(android.os.Bundle)     */     @Override     public void onCreate(Bundle savedInstanceState) {         sup

  • JavaScript实现256色转灰度图

    一幅完整的图像,是由红色.绿色.蓝色三个通道组成的.红色.绿色.蓝色三个通道的缩览图都是以灰度显示的.用不同的灰度色阶来表示" 红,绿,蓝"在图像中的比重.通道中的纯白,代表了该色光在此处为最高亮度,亮度级别是255. 灰度化方法:         1.浮点算法:Gray = R*0.299 + G*0.587 + B*0.114         2.整数方法:Gray = (R*299 + G*587 + B*114 + 500) / 1000         3.移位方法:Gray

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

    一般而言在Android上使用JAVA实现彩图转换为灰度图,与J2ME上的实现方法类似,不过遇到频繁地转换或者是大图转换时,就必须使用NDK来提高速度了.本文主要通过JAVA和NDK这两种方式来分别实现彩图转换为灰度图,并给出速度的对比,供大家参考. 先来简单地介绍一下Android的NDK使用步骤: 以NDK r4为例,或许以后新版的NDK的使用方法略有不同. 1.下载支持C++的android-ndk-r4-crystax,支持C++的话可玩性更强. 2.下载cygwin,选择ftp://m

  • 如何在Android Studio下进行NDK开发

    在AS中进行NDK开发之前,我们先来简单的介绍几个大家都容易搞懵的概念: 1. 到底什么是JNI,什么是NDK? 2. 何为"交叉编译"? 先看什么是JNI?JNI的全称就是Java Native Interface,即java本地开发接口.可能大家和我一样,一听到接口什么的就犯懵:"我也知道这是java本地开发接口的意思,但它具体是个什么意思我还是搞不明白."其实JNI它就是一种协议,一说协议,那它就是对某种东西的一个规范和约束,说的好听一点就是标准化.如果你想用

  • Android提高Service优先级的方法分析

    本文实例讲述了Android提高Service优先级的方法.分享给大家供大家参考,具体如下: Android 系统对于内存管理有自己的一套方法,为了保障系统有序稳定的运信,系统内部会自动分配,控制程序的内存使用.当系统觉得当前的资源非常有限的时候,为了保 证一些优先级高的程序能运行,就会杀掉一些他认为不重要的程序或者服务来释放内存.这样就能保证真正对用户有用的程序仍然再运行.如果你的 Service 碰上了这种情况,多半会先被杀掉.但如果你增加 Service 的优先级就能让他多留一会,我们可以

  • android实现Uri获取真实路径转换成File的方法

    本文实例讲述了android实现Uri获取真实路径转换成File的方法.分享给大家供大家参考.具体实现方法如下: Uri uri = data.getData(); String[] proj = { MediaStore.Images.Media.DATA }; Cursor actualimagecursor = managedQuery(uri,proj,null,null,null); int actual_image_column_index = actualimagecursor.g

  • Android ndk获取手机内部存储卡的根目录方法

    如下所示: jclass envcls = env->FindClass("android/os/Environment"); //获得类引用 if (envcls == nullptr) return 0; //找到对应的类,该类是静态的返回值是File jmethodID id = env->GetStaticMethodID(envcls, "getExternalStorageDirectory", "()Ljava/io/File;&

  • Android中Uri和Path之间的转换的示例代码

    Android中Uri和Path之间的转换 原因 调用系统拍照应用,拍照后要保存图片,那么我们需要指定一个存储图片路径的Uri.这就涉及到如何将file path转换为Uri.有时候我们还需要根据照片的路径得到照片的media Uri,那么又该如何转换呢? Android Uri to Path 现在遇到的常规Uri有两种: 媒体文件的Uri是content://, 表示这是一个数据库数据.去数据库查询正常返回. 其他的文件Uri是file://, 表示这个是一个文件.这个uri是通过Uri.f

  • python-OpenCV 实现将数组转换成灰度图和彩图

    主要步骤 1.生成普通python数组(bytearray(),os.urandom()) 2.转换成numpy数组(numpy.array()) 3.通过reshape将数组转换到所需的维数 4.以图像的形式显示出来(cv.imshow()) 代码 import os import cv2 as cv import numpy as np # Make an array of 120000 random bytes randomByteArray = bytearray(os.urandom(

  • python opencv实现灰度图和彩色图的互相转换

    目录 opencv灰度图和彩色图互相转换 注意: 附:python将灰度图转换为RGB彩色图 总结 opencv灰度图和彩色图互相转换 如果摄像头本来就得到3维度红外图那就不用处理直接可以用: import cv2 cap = cv2.VideoCapture(0) ret, image_np = cap.read() 直接转成单通道的灰度图看看能不能用: #如果后面不写0,那就是默认彩色的 # 第一种方式 image = cv2.imread('***/timg4.jpg',0) #第二种方式

  • Android开发实现读取excel数据并保存为xml的方法

    本文实例讲述了Android开发实现读取excel数据并保存为xml的方法.分享给大家供大家参考,具体如下: 前阵子,公司请外面人翻译了一些android中values中的一些strings,然而保存的都是excel格式,如果单纯的将excel中的数据粘贴到指定的xml中的话,工作量非常的大,于是,自己写了个简单的demo,将excel中的数据读取并保存为xml对应的数据,下面的demo和图片展示: 1.数据保存在BeanValue中,包括key和value,方便后续数据读取 package c

  • Android开发实现在Wifi下获取本地IP地址的方法

    本文实例讲述了Android开发实现在Wifi下获取本地IP地址的方法.分享给大家供大家参考,具体如下: 代码核心介绍: WifiManager类提供了对设备Wifi功能的管理,包括Wifi开关的打开和关闭,IP地址获取等等,早期的Android版本甚至支持对于IP的设置.在这里仅介绍其简单的一个小应用--获取IP地址. 首先先添加Uses-Permission:CHANGE_WIFI_STATE,WAKE_LOCK和ACCESS_WIFI_STATE.代码如下(AndroidManifest.

随机推荐