Android平台下使用OpenCV灰度化图片的两种方式
2016-07-07 16:58
597 查看
在OpenCV中灰度化图像是比较常用的操作之一,这篇文章介绍了两种方法对图像进行灰度化并显示出来:
1.通过灰度化公式 Y(亮度)=0.299*R+0.587*G+0.114*B 对图片每个像素操作,从而得到灰度化的图片
2.通过调用cvtColor函数来灰度化图像
方法1:
Java核心代码部分,大体意思就是拿到图片像素数组,传入native层处理,结果返回Java层并显示,其中OpenCVHelper.gray()为native方法
native核心代码,这个完全是套用公式,这里不再赘述
方法2:
讲道理,调用OpenCV提供给我我们的API应该更方便代码量更少,但是这里有几个小问题需要简单说明一下,先上代码。
Java层代码:
native层代码:
问题1:为什么在Java层注释掉了一部分代码,貌似是Bitmap缩放问题。
我们知道Android手机的DPI都是不一样的,当然他们的缩放比例也是不一样的,详细的说明可百度mdpi、hdpi、xhdpi、xxhdpi。不同dpi对应不同的屏幕尺寸,但是如果都堆弃在drawable中都会采用默认的mdpi对图片进行处理,像我使用的nexus 5 为 xxhdpi,因此图片的长宽分别扩大了三倍。虽说这样也能正常把图片灰度化,但是无疑增大了内存使用,利弊自行斟酌。
问题2:为什么在native层图片先转换成灰度图再转换成ARGB?
感谢Daniil Osokin解决我的问题,开始我也是只转换一次的,但是灰度图是单通道的,每个像素仅用一个char表示,但是Android中并不支持单通道的灰度图,因此我们拿到灰色的图片的Mat后,还需要再次转换成ARGB,这样传导Java层才可以解析成Android支持的Bitmap。
文章最后上一张转化后的灰度图,让大家乐呵乐呵^_^
1.通过灰度化公式 Y(亮度)=0.299*R+0.587*G+0.114*B 对图片每个像素操作,从而得到灰度化的图片
2.通过调用cvtColor函数来灰度化图像
方法1:
Java核心代码部分,大体意思就是拿到图片像素数组,传入native层处理,结果返回Java层并显示,其中OpenCVHelper.gray()为native方法
Bitmap bitmap = ((BitmapDrawable) getResources().getDrawable(R.drawable.food)).getBitmap(); int w = bitmap.getWidth(), h = bitmap.getHeight(); int[] pix = new int[w * h]; bitmap.getPixels(pix, 0, w, 0, 0, w, h); //灰度算法 int[] resultPixes = OpenCVHelper.gray(pix, w, h); Bitmap result = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); result.setPixels(resultPixes, 0, w, 0, 0, w, h); imageView.setImageBitmap(result);
native核心代码,这个完全是套用公式,这里不再赘述
JNIEXPORT jintArray JNICALL Java_yu_myself_opencv_jni_OpenCVHelper_gray( JNIEnv *env, jclass obj, jintArray buf, int w, int h) { jint *cbuf; cbuf = env->GetIntArrayElements(buf, JNI_FALSE); if (cbuf == NULL) { return 0; } Mat imgData(h, w, CV_8UC4, (unsigned char *) cbuf); uchar* ptr = imgData.ptr(0); for(int i = 0; i < w*h; i ++){ //计算公式:Y(亮度) = 0.299*R + 0.587*G + 0.114*B //对于一个int四字节,其彩色值存储方式为:BGRA int grayScale = (int)(ptr[4*i+2]*0.299 + ptr[4*i+1]*0.587 + ptr[4*i+0]*0.114); ptr[4*i+1] = grayScale; ptr[4*i+2] = grayScale; ptr[4*i+0] = grayScale; } int size = w * h; jintArray result = env->NewIntArray(size); env->SetIntArrayRegion(result, 0, size, cbuf); env->ReleaseIntArrayElements(buf, cbuf, 0); return result; }
方法2:
讲道理,调用OpenCV提供给我我们的API应该更方便代码量更少,但是这里有几个小问题需要简单说明一下,先上代码。
Java层代码:
//屏幕缩放比例 //DisplayMetrics dm = new DisplayMetrics(); //getWindowManager().getDefaultDisplay().getMetrics(dm); //float scale = dm.density; Bitmap bitmap = ((BitmapDrawable) getResources().getDrawable( R.drawable.food)).getBitmap(); //获得实际尺寸的Bitmap //bitmap = Bitmap.createScaledBitmap(bitmap, (int) (bitmap.getWidth() / scale), (int) (bitmap.getHeight() / scale), false); int w = bitmap.getWidth(), h = bitmap.getHeight(); int[] pix = new int[w * h]; bitmap.getPixels(pix, 0, w, 0, 0, w, h); //传入正常尺寸的像素数组 int[] resultPixes = OpenCVHelper.canny(pix, w, h); Bitmap result = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); result.setPixels(resultPixes, 0, w, 0, 0, w, h); imageView.setImageBitmap(result);
native层代码:
JNIEXPORT jintArray JNICALL Java_yu_myself_opencv_jni_OpenCVHelper_canny( JNIEnv *env, jclass obj, jintArray buf, int w, int h){ jint *cbuf; cbuf = env->GetIntArrayElements(buf, JNI_FALSE); if (cbuf == NULL) { return 0; } Mat srcImage(h, w, CV_8UC4, (unsigned char *) cbuf); Mat grayImage; cvtColor(srcImage, grayImage, COLOR_BGRA2GRAY); cvtColor(grayImage, grayImage, COLOR_GRAY2BGRA); jint* ptr = grayImage.ptr<jint>(0); int size = w * h; jintArray result = env->NewIntArray(size); env->SetIntArrayRegion(result, 0, size, ptr); env->ReleaseIntArrayElements(buf, cbuf, 0); return result; }
问题1:为什么在Java层注释掉了一部分代码,貌似是Bitmap缩放问题。
我们知道Android手机的DPI都是不一样的,当然他们的缩放比例也是不一样的,详细的说明可百度mdpi、hdpi、xhdpi、xxhdpi。不同dpi对应不同的屏幕尺寸,但是如果都堆弃在drawable中都会采用默认的mdpi对图片进行处理,像我使用的nexus 5 为 xxhdpi,因此图片的长宽分别扩大了三倍。虽说这样也能正常把图片灰度化,但是无疑增大了内存使用,利弊自行斟酌。
问题2:为什么在native层图片先转换成灰度图再转换成ARGB?
感谢Daniil Osokin解决我的问题,开始我也是只转换一次的,但是灰度图是单通道的,每个像素仅用一个char表示,但是Android中并不支持单通道的灰度图,因此我们拿到灰色的图片的Mat后,还需要再次转换成ARGB,这样传导Java层才可以解析成Android支持的Bitmap。
文章最后上一张转化后的灰度图,让大家乐呵乐呵^_^
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories