HardBirch

Android提高十六篇之使用NDK把彩图转换灰度图

时间:10-12-23 栏目:安卓入门与提高 作者:张飞不张,文采横飞 评论:55 点击: 16,946 次

        在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源码如下:






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




















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的源码如下:









public static native int[] ImgToGray(int[] buf, int w, int h);
}

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



































Android.mk的源码:






声明: 本文由( 张飞不张,文采横飞 )原创编译,转载请保留链接: Android提高十六篇之使用NDK把彩图转换灰度图

Android提高十六篇之使用NDK把彩图转换灰度图:目前有55 条留言

  1. 0楼
    hmc1985:

    [e02]实在佩服!

    2010-12-23 14:53 [回复]
  2. 0楼
    s278777851:

    果断一楼顶起,。。。。

    2010-12-23 14:53 [回复]
  3. 0楼
    kf156:

    [e01]

    2010-12-23 14:53 [回复]
  4. 0楼
    xuyan87101:

    顶起[e03]

    2010-12-23 14:56 [回复]
  5. [e02]羡慕嫉妒恨啊

    2010-12-23 15:24 [回复]
  6. 来顶你

    2010-12-23 17:44 [回复]
  7. [e01][e01]

    2010-12-24 13:12 [回复]
  8. 0楼
    cankeyyin:

    [e01]

    2010-12-24 20:07 [回复]
  9. 0楼
    aokihu:

    终于看明白了,原来NDK里面使用_来替代. 然后函数名也是完整的包名,前两个参数是系统自动添加的参数,后面的是自定义参数

    2010-12-28 17:16 [回复]
  10. 0楼
    cicade:

    问一个问题,NDK不可以直接处理资源文件并绘制在view上吗,因为感觉img1.getPixels(pix, 0, w, 0, 0, w, h)和Bitmap result=Bitmap.createBitmap(w, h, Config.RGB_565);
    result.setPixels(pix, 0, w, 0, 0,w, h);
    这三行JAVA代码拖累了NDK的速度

    2010-12-28 22:37 [回复]
  11. 0楼
    lllovelhj:

    [e01]

    2010-12-28 22:45 [回复]
  12. 0楼
    hellogv:

    回复 cicade:
    如果不利用Android现有的图像编解码库的话,可以直接取得Pixels的。

    2010-12-28 22:48 [回复]
  13. 0楼
    Jeanth:

    支持楼主

    2010-12-29 10:59 [回复]
  14. 0楼
    zmyde2010:

    [e01]

    2010-12-29 12:37 [回复]
  15. 0楼
    yanghuaixi:

    [e01]

    2010-12-29 14:25 [回复]
  16. 0楼
    cicade:

    回复 hellogv:谢谢博主的回答,“可以直接取得Pixels的”,那可以直接操作View吗(用NDK)
    还有另一个问题,博主有试过用颜色矩阵来做灰度转换吗,效率会不会高点
    最后一个问题,博主的代码是在模拟器里运行的还是真机,是真机的话是什么型号,我好做个参考,谢谢

    2010-12-29 14:49 [回复]
  17. 0楼
    hellogv:

    回复 cicade:
    我用XT720,这篇文章是为了給ASIFT做铺垫而写的,ASIFT本身就包含了LINUX/MAC/WIN通用的PNG解码,编码库,你可以用他来直接解码PNG,效率会块很多,但是会相对繁琐很多。

    2010-12-29 16:11 [回复]
  18. 0楼
    cicade:

    回复 hellogv:虽然还是有些没明白,但还是谢谢博主的热情解答。PS:我试了一下颜色矩阵(ColorMatrix),在模拟器上比像素操作快几百倍

    2010-12-29 22:34 [回复]
  19. 0楼
    fyboyz:

    [e04][e01]

    2010-12-30 10:54 [回复]
  20. 差那么多呢啊 首次差一倍,再次差100多毫秒呢 [e01]

    2011-01-14 13:58 [回复]
  21. 不错 [e01] 做个记号

    2011-01-29 11:44 [回复]
  22. 你好,国威老师。我在编译的时候遇到了一个问题,直接执行第四步不能生成so文件,不知道出了Android.mk,ImgToGray.cpp,LibFuns.java这三个文件之外还需要什么。因为每次都会出现
    make: *** No rule to make target `/AreaCalculate.c', needed by `/cygdrive/e/Jworkplace/workspace/AreaCalculate/obj/local/armeabi/objs/AreaCalculate/AreaCalculate.o'. Stop.之类的错误提示。我找了很久还是没有找到解决办法,还望赐教,谢谢!!!

    2011-02-23 23:41 [回复]
  23. 这回麻烦了,so也生成了,java下的也可以运行,就是一点ndk按键就挂掉,中间就有个o,d这两个文件没有生成,不知道什么原因。整个过程也没有报错,不知道是不是和o,d这两个文件有关系,烦躁中

    2011-02-24 20:45 [回复]
  24. 0楼
    Roymuztang:

    老师你好,我现在编译一直遇到这个问题,请指教一下好吗?谢谢
    make: *** No rule to make target `/ImgToGray.cpp', needed by ……..

    2011-03-13 12:46 [回复]
  25. [e01][e02][e03][e06]

    2011-04-18 17:17 [回复]
  26. 0楼
    ghd2000:

    回复 cicade:楼主想请教你一个问题,如果图片的尺寸过大或者读取多张大图时,在int[] pix = new int[w * h];
    img1.getPixels(pix, 0, w, 0, 0, w, h); 时会出现内存溢出,有什么好的解决办法?

    2011-04-28 13:32 [回复]
  27. [e01][e02][e03][e06]

    2011-04-29 13:12 [回复]
  28. 能否发个源码到我的邮箱:casel.chen@gmail.com 谢谢!

    2011-05-22 19:57 [回复]
  29. 其实在Android手机上将彩色图片转成灰阶图不用这么麻烦,Android内置有API能够实现,比起其他实现方法更加快捷有效。实验下来的数据:w:384,h:512,Time:190 ms

    2011-05-23 10:43 [回复]
  30. 0楼
    hellogv:

    回复 cricket1981:
    本文主要目的是讲解NDK的应用,转灰度图我也不会这样做。。。

    2011-05-23 13:18 [回复]
  31. 0楼
    ccc003:

    为啥我转灰度图用java比ndk快不少呢
    难道说是2.2的关系?

    2011-06-21 20:16 [回复]
  32. 0楼
    ccc003:

    写错了,是2.3[e08]

    2011-06-21 20:30 [回复]
  33. 0楼
    zclovemike:

    老师您好 找不到您书说的第三步home那个啊

    2011-08-12 11:10 [回复]
  34. 0楼
    zclovemike:

    老师没有第三步啊 装了两回了 但是都没有找到啊

    2011-08-12 13:23 [回复]
  35. 0楼
    zclovemike:

    老师给解答一下啊 那个第三步Home里边是空的啊 什么都没有啊 gcc还有make那些都装上了啊 就是那个Home里是空的 为什么啊

    2011-08-15 12:42 [回复]
  36. 0楼
    haojunming:

    老师,问一下,您知道怎么根据一张图片获取它的cmyk值吗?我这里有根据图片的rgb值来转换为cmyk值,但是不知道该怎么样直接获取

    2011-11-23 10:36 [回复]
  37. 0楼
    haojunming:

    问一下,你看在c++里面int型数组是jintArray,我想问一下,string型字符串该怎么表示啊

    2011-11-23 14:07 [回复]
  38. 0楼
    haojunming:

    老师, 问一下,怎么实现提取出一张图片里面的某一种颜色呢,比如说黄色,然后获取这一片黄色区域的所有像素的rgb值。麻烦您了,谢谢啊

    2011-11-29 08:27 [回复]
  39. 0楼
    hellogv:

    [reply]haojunming[/reply]
    先别玩NDK,先多用用JNI就明白了,char[]

    2011-11-29 09:07 [回复]
  40. 0楼
    hellogv:

    [reply]haojunming[/reply]
    这个很简单就是XY轴扫描符合要求的RGB

    2011-11-29 09:08 [回复]
  41. 0楼
    achellies:

    请问一下文章里面演示用的gif动画是用什么做?

    2011-11-29 16:14 [回复]
  42. 0楼
    haojunming:

    [reply]hellogv[/reply]
    好的,知道了一定。

    2011-11-29 17:19 [回复]
  43. 0楼
    haojunming:

    老师,问一下,假如在c语言里面我多次使用java中的集合,当我使用的数量比较多的时候,比如往list里面添加一千,一万个对象时,程序就崩掉了, 这是为什么,c调用java中不可用使用那么多对象吗?还是我没有做内存释放。对于java中的对象该怎么进行内存释放。

    2011-12-06 09:21 [回复]
  44. 0楼
    hellogv:

    [reply]haojunming[/reply]
    jni最安全的传递就是那几个标准类型,不建议传递对象或者指针

    2011-12-06 21:06 [回复]
  45. 0楼
    haojunming:

    [reply]haojunming[/reply]
    老师,我这里有一个问题,您能不能给解决一下。
    http://blog.csdn.net/haojunming/article/details/7057866谢谢啊

    2011-12-09 17:20 [回复]
  46. 0楼
    hellogv:

    [reply]haojunming[/reply]
    介个算法问题。。。要花点脑筋。。。

    2011-12-10 00:04 [回复]
  47. 0楼
    haojunming:

    [reply]hellogv[/reply]
    确实,我想了老半天都没有什么好的办法,您能不能给想一想。谢谢啊

    2011-12-12 09:02 [回复]
  48. 0楼
    haojunming:

    问一下,在做这个代码中使用到了bitmap,可是它多次使用后就报java.lang.OutOfMemoryError: bitmap size exceeds VM budget这个错误,不知道老师你有什么好的办法吗?谢谢啊,刚刚上网查了一些方法,可是都不理想,希望老师帮帮忙

    2011-12-16 16:12 [回复]
  49. 0楼
    hellogv:

    [reply]haojunming[/reply]
    1.看看每次使用后是否释放了,建议你用SoftReference<Bitmap>
    2.看看Bitmap的尺寸是否太大了

    2011-12-17 11:00 [回复]
  50. 0楼
    haojunming:

    [reply]hellogv[/reply]
    我的尺寸是320*240的,对于这个有什么好办法吗

    2011-12-20 08:57 [回复]
  51. 再快也没这个快吧: ColorMatrix

    2011-12-24 17:09 [回复]
  52. 0楼
    liumazi:

    mark

    2012-05-20 06:26 [回复]
  53. 0楼
    shoelace:

    有几个问题需要指教
    计算转化时间的时间包括打开图像,获得像素,以及显示灰度图部分,是不是只计算像素灰度计算这段时间更精确呢?
    第一次转换成灰度图的时候需要700多秒,第二次转换的时候应该转换的还是那个彩色图片,为什么时间会缩短了呢,而且我试验了下,一直使用java方法转换,时间也很不稳定,倒是一直使用Ndk方法很稳定

    2012-06-05 08:40 [回复]
  54. 0楼
    holdc:

    2种实现方法都是很好的示范。但简单比较就无意义了,精确比较才能体现差别,显示位图都是用的java实现,这个时间反而可能是大头

    2012-08-04 11:05 [回复]

发表评论


QQ群互动

Linux系统与内核学习群:194051772

WP建站技术学习交流群:194062106

魔豆之路QR

魔豆的Linux内核之路

魔豆的Linux内核之路

优秀工程师当看优秀书籍

优秀程序员,要看优秀书!

赞助商广告

友荐云推荐