Android图像处理简单例子 推荐
2012-05-08 10:11
645 查看
Android图像处理简单例子
简单的图像处理的学习例子,效果感觉不怎么好。关于算法,可以看之前的《图像基本处理算法的简单实现》三篇文章。
有人短我要jni库,直接把工程分享出来得了。之前主要是觉得实现不佳,并且重点再算法,所以没附工程==。
再提示句,该工程没用bitmap.h。如果要直接传bitmap对象,可以看《Android NDK基础样例》的样例3。
内容太少,附点代码&截图^^。
1)JoinImage.java
Java native类,native接口&辅助方法。
2)ImageActivity.java
Activity类,界面&处理逻辑。
3)截图
4)后记
不足之处,多多担待^^。
附件:http://down.51cto.com/data/2360515
简单的图像处理的学习例子,效果感觉不怎么好。关于算法,可以看之前的《图像基本处理算法的简单实现》三篇文章。
有人短我要jni库,直接把工程分享出来得了。之前主要是觉得实现不佳,并且重点再算法,所以没附工程==。
再提示句,该工程没用bitmap.h。如果要直接传bitmap对象,可以看《Android NDK基础样例》的样例3。
内容太少,附点代码&截图^^。
1)JoinImage.java
Java native类,native接口&辅助方法。
public class JoinImage { static { System.loadLibrary("JoinImage"); } /** LOG标识 */ private static final String TAG = "JoinImage"; /** 图像存储路径 */ public static final String PATH = Environment.getExternalStorageDirectory() .toString() + "/" + TAG + "/"; /** * 判断是否有SD卡 */ public static boolean hasSDCard() { return Environment.getExternalStorageState().equals( Environment.MEDIA_MOUNTED) ? true : false; } /** * 保存图像为bitName.png */ public static void saveBitmap(String bitName, Bitmap mBitmap) { // 不存在SD卡直接返回 if (!hasSDCard()) { return; } // 判断并创建图像存储路径 File dirFile = new File(PATH); if (!dirFile.exists()) { dirFile.mkdir(); } // 保存图像为高质量png FileOutputStream fOut = null; try { fOut = new FileOutputStream(PATH + bitName + ".png"); mBitmap.compress(Bitmap.CompressFormat.PNG, 100, fOut); fOut.flush(); fOut.close(); } catch (IOException e) { e.printStackTrace(); } } /** * 缩放Bitmap图像并返回 */ public static Bitmap stretch(Bitmap mBitmap, int newW, int newh) { int w = mBitmap.getWidth(), h = mBitmap.getHeight(); // 获取图像长宽 int[] colors = getColors(mBitmap, w, h); // 获取Bitmap颜色数组 colors = stretch(colors, w, h, newW, newh); // 调用动态库方法缩放图像返回颜色数组 return createBitmap(colors, newW, newh); // 返回由新颜色数组重建的Bitmap } /** * 灰度化Bitmap图像并返回 */ public static Bitmap imgToGray(Bitmap mBitmap) { int w = mBitmap.getWidth(), h = mBitmap.getHeight(); // 获取图像长宽 int[] colors = getColors(mBitmap, w, h); // 获取Bitmap颜色数组 colors = imgToGray(colors, w, h); // 调用动态库方法灰度化颜色数组 return createBitmap(colors, w, h); // 返回由新颜色数组重建的Bitmap } /** * 二值化灰度图像并返回 */ public static Bitmap binarization(Bitmap mBitmap, int methodCode) { int w = mBitmap.getWidth(), h = mBitmap.getHeight(); // 获取图像长宽 int[] colors = getColors(mBitmap, w, h); // 获取Bitmap颜色数组 // 调用动态库方法二值化灰度图像 switch (methodCode) { case 0: colors = binarization(colors, w, h); break; case 1: colors = binarization2(colors, w, h); break; default: throw new IllegalArgumentException("请选择正确的二值方法,现有0或1。"); } return createBitmap(colors, w, h); // 返回由新颜色数组重建的Bitmap } /** * 填充二值化图像并返回 * * 填充方式:背景色点上下左右>=3点为前景色,则将其填充为前景色 */ public static Bitmap filling(Bitmap mBitmap) { int w = mBitmap.getWidth(), h = mBitmap.getHeight(); // 获取图像长宽 int[] colors = getColors(mBitmap, w, h); // 获取Bitmap颜色数组 colors = filling(colors, w, h); // 调用动态库方法膨胀二值化图像 return createBitmap(colors, w, h); // 返回由新颜色数组重建的Bitmap } /** * 膨胀二值化图像并返回 * * 膨胀结构元素:3x3 全 */ public static Bitmap dilation(Bitmap mBitmap) { int w = mBitmap.getWidth(), h = mBitmap.getHeight(); // 获取图像长宽 int[] colors = getColors(mBitmap, w, h); // 获取Bitmap颜色数组 colors = dilation(colors, w, h); // 调用动态库方法膨胀二值化图像 return createBitmap(colors, w, h); // 返回由新颜色数组重建的Bitmap } /** * 腐蚀二值化图像并返回 * * 腐蚀结构元素:3x3 全 */ public static Bitmap erosion(Bitmap mBitmap) { int w = mBitmap.getWidth(), h = mBitmap.getHeight(); // 获取图像长宽 int[] colors = getColors(mBitmap, w, h); // 获取Bitmap颜色数组 colors = erosion(colors, w, h); // 调用动态库方法腐蚀二值化图像 return createBitmap(colors, w, h); // 返回由新颜色数组重建的Bitmap } /** * 腐蚀二值化图像并返回 * * 腐蚀结构元素:3x3 全 */ public static Bitmap erosion(Bitmap mBitmap, int iterations) { int w = mBitmap.getWidth(), h = mBitmap.getHeight(); // 获取图像长宽 int[] colors = getColors(mBitmap, w, h); // 获取Bitmap颜色数组 while (iterations-- > 0) { colors = erosion(colors, w, h); // 调用动态库方法腐蚀二值化图像 } return createBitmap(colors, w, h); // 返回由新颜色数组重建的Bitmap } /** * 细化二值化图像并返回 */ public static Bitmap thinning(Bitmap mBitmap, int methodCode) { int w = mBitmap.getWidth(), h = mBitmap.getHeight(); // 获取图像长宽 int[] colors = getColors(mBitmap, w, h); // 获取Bitmap颜色数组 // 调用动态库方法细化二值化图像 switch (methodCode) { case 0: colors = thinning(colors, w, h); break; case 1: colors = thinning2(colors, w, h); break; default: throw new IllegalArgumentException("请选择正确的细化方法,现有0或1。"); } return createBitmap(colors, w, h); // 返回由新颜色数组重建的Bitmap } /** * 分割细化图像 */ public static void split(Bitmap mBitmap) { int w = mBitmap.getWidth(), h = mBitmap.getHeight(); // 获取图像长宽 int[] colors = getColors(mBitmap, w, h); // 获取Bitmap颜色数组 split(colors, w, h); // 调用动态库方法分割细化图像 } /** * 获取指定索引的分割图像 */ public static Bitmap getSplitBmp(int index) { // 调用动态库方法获取指定索引分割图像颜色数组 int[] colors = getSplitImg(index); if (null == colors) { throw new IllegalStateException("请确认已执行了分割图像,并且索引未越界。"); } // 调用动态库方法获取指定索引分割图像的长宽,并返回由新颜色数组重建的Bitmap return createBitmap(colors, getSplitImgW(index), getSplitImgH(index)); } /** * 获取所有分割图像 */ public static Bitmap[] getSplitBmps() { int num = getSplitNum(); // 调用动态库方法获取分割图像个数 Bitmap bitmap[] = new Bitmap[num]; for (int i = 0; i < num; i++) { bitmap[i] = getSplitBmp(i); } return bitmap; } /** * 解析识别分割图像 * * mBitmap:单个字符的二值化图像 */ public static char analyseImg(Bitmap mBitmap) { int w = mBitmap.getWidth(), h = mBitmap.getHeight(); // 获取图像长宽 int[] colors = getColors(mBitmap, w, h); // 获取Bitmap颜色数组 return analyseImg(colors, w, h); // 调用动态库方法解析识别分割图像 } /** * 二值化身份证号码彩图 */ public static Bitmap binaryCid(Bitmap mBitmap) { int w = mBitmap.getWidth(), h = mBitmap.getHeight(); // 获取图像长宽 int[] colors = getColors(mBitmap, w, h); // 获取Bitmap颜色数组 colors = binaryCid(colors, w, h); // 调用动态库方法二值化彩图身份证号码 return createBitmap(colors, w, h); // 返回由新颜色数组重建的Bitmap } /** * 获取Bitmap颜色数组 */ public static int[] getColors(Bitmap mBitmap, int w, int h) { int[] pix = new int[w * h]; mBitmap.getPixels(pix, 0, w, 0, 0, w, h); return pix; } /** * 由颜色数组重建Bitmap */ public static Bitmap createBitmap(int[] colors, int w, int h) { Bitmap img = Bitmap.createBitmap(w, h, Bitmap.Config.RGB_565); img.setPixels(colors, 0, w, 0, 0, w, h); return img; } public static String getTime() { return String.valueOf(System.currentTimeMillis()); } public void sayHello(String msg) { Log.e("C调用Java", msg); } public static native int[] stretch(int[] buf, int srcW, int srcH, int dstW, int dstH); public static native int[] imgToGray(int[] buf, int w, int h); public static native int[] binarization(int[] buf, int w, int h); public static native int[] binarization2(int[] buf, int w, int h); public static native int[] filling(int[] buf, int w, int h); public static native int[] dilation(int[] buf, int w, int h); public static native int[] erosion(int[] buf, int w, int h); public static native int[] thinning(int[] buf, int w, int h); public static native int[] thinning2(int[] buf, int w, int h); public static native void split(int[] buf, int w, int h); public static native int getSplitNum(); public static native int[] getSplitImg(int index); public static native int getSplitImgW(int index); public static native int getSplitImgH(int index); public static native char analyseImg(int[] buf, int w, int h); public static native int[] locateCid(int[] buf, int w, int h); public static native int[] binaryCid(int[] buf, int w, int h); }
2)ImageActivity.java
Activity类,界面&处理逻辑。
public class ImageActivity extends Activity implements OnClickListener, OnItemClickListener { private Button[] buttons; // 按钮组 private int enabledBtnIndex; // 当前可用按钮索引 private ImageView imageView; // ImageView private Bitmap cardBitmap; // 获取的图像 private GridView gridView; // GridView private Bitmap splitBmps[]; // 分割后的图像 private boolean isSave = false; // 是否保存图像(各处理步骤) private int erosionCount = 1; // 腐蚀次数 @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // 各属性&组件初始化...... } /** * 按钮点击事件 */ @Override public void onClick(View v) { // 先设置当前按钮不可用,避免多次点击 buttons[enabledBtnIndex].setEnabled(false); switch (v.getId()) { case R.id.takeBtn: { // 列表项目 final String[] items = { "330122198102212239", "15210319861215033X", "370305196708031216", "210203196809236015", "411224196902244239" }; // 对应资源id // 图像1、2符合像素要求(宽度>= 1000),后续处理不会过度 // 图像3像素折中(800<宽度<1000),腐蚀2次会过度(固定死2次腐蚀,可测试不完整识别) // 图像4像素过低(宽度<=800),用于测试缩放图像后继续处理效果 // 图像5像素过低且光照较暗不均匀(宽度<=400),用于测试缩放图像及后续处理效果 final int[] ids = { R.drawable.idcard_1, R.drawable.idcard_2, R.drawable.idcard_3, R.drawable.idcard_4, R.drawable.idcard_5 }; // 显示列表对话框 new AlertDialog.Builder(this) .setTitle("选择内置身份证号码") .setItems(items, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { // 获取图像资源 InputStream is = getResources().openRawResource( ids[which]); BitmapDrawable bmpDraw = new BitmapDrawable(is); // 判断图像像素修正图像 cardBitmap = correctBitmap(bmpDraw.getBitmap()); // 设置显示图像 imageView.setImageBitmap(cardBitmap); // 显示ImageView imageView.setVisibility(View.VISIBLE); // 隐藏GridView gridView.setVisibility(View.GONE); // 释放缓存图像 splitBmps = null; // 启用下一按钮 setNextBtnEnabled(); } }) .setPositiveButton("或拍照取像", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // 拍照按钮设为可用 buttons[enabledBtnIndex].setEnabled(true); // 调用自定义相机 Intent intent = new Intent( getApplicationContext(), CameraActivity.class); startActivityForResult(intent, 1); } }).setCancelable(false).show(); break; } case R.id.toGraybtn: { // 灰度化图像(将图像变为灰度图像) cardBitmap = JoinImage.imgToGray(cardBitmap); imageView.setImageBitmap(cardBitmap); // 保存该图像 if (isSave) { JoinImage.saveBitmap("1_gray", cardBitmap); } // 启用下一按钮 setNextBtnEnabled(); break; } case R.id.toBinaBtn: { // 二值化图像(将图像变为纯黑白,灰度值仅有0和255,方便后续处理) cardBitmap = JoinImage.binarization(cardBitmap, 0); imageView.setImageBitmap(cardBitmap); // 保存该图像 if (isSave) { JoinImage.saveBitmap("2_bina", cardBitmap); } // 启用下一按钮 setNextBtnEnabled(); break; } case R.id.toFillBtn: { // 填充图像(算是膨胀的变形,和膨胀作用一致) cardBitmap = JoinImage.filling(cardBitmap); imageView.setImageBitmap(cardBitmap); // 保存该图像 if (isSave) { JoinImage.saveBitmap("3_fill", cardBitmap); } // 启用下一按钮 setNextBtnEnabled(); break; } case R.id.toDilaBtn: { // 膨胀图像(用于填充图像中间可能出现的单个像素点,以防腐蚀后出一个窟窿) cardBitmap = JoinImage.dilation(cardBitmap); imageView.setImageBitmap(cardBitmap); // 保存该图像 if (isSave) { JoinImage.saveBitmap("4_dila", cardBitmap); } // 启用下一按钮 setNextBtnEnabled(); break; } case R.id.toErosBtn: { // 腐蚀图像(2次,使得边缘更平滑,减少细化后突出骨架,同时可去除噪点) // 图像像素比较低时可能会腐蚀过度。现需要图像宽度至少800,过低像素做好缩放至宽度1000。 cardBitmap = JoinImage.erosion(cardBitmap, erosionCount); imageView.setImageBitmap(cardBitmap); // 保存该图像 if (isSave) { JoinImage.saveBitmap("5_eros", cardBitmap); } // 启用下一按钮 setNextBtnEnabled(); break; } case R.id.toThinBtn: { // 细化图像(提取图像的骨架特征,方便分析) cardBitmap = JoinImage.thinning(cardBitmap, 1); imageView.setImageBitmap(cardBitmap); // 保存该图像 if (isSave) { JoinImage.saveBitmap("6_thin", cardBitmap); } // 启用下一按钮 setNextBtnEnabled(); break; } case R.id.toSplitBtn: { // 分割图像(对细化图像进行分割) JoinImage.split(cardBitmap); // 获取所有分割图像 splitBmps = JoinImage.getSplitBmps(); // 添加GirdView数据 gridView.setAdapter(new ImageAdapter(this, splitBmps)); // 隐藏ImageView imageView.setVisibility(View.GONE); // 显示GirdView gridView.setVisibility(View.VISIBLE); // 释放缓存图像 cardBitmap = null; // 保存该图像 if (isSave && null != splitBmps) { for (int i = 0; i < splitBmps.length; i++) { JoinImage.saveBitmap("split_" + i, splitBmps[i]); } } // 启用下一按钮 setNextBtnEnabled(); break; } } } /** * 图像修正并设置腐蚀次数 */ private Bitmap correctBitmap(Bitmap mBitmap) { int w = mBitmap.getWidth(), h = mBitmap.getHeight(); // 获取图像长宽 if (w >= 1500) { erosionCount = 2; // 腐蚀次数置2 int newW = 1000; // 缩放图像至宽度1000 int newH = h * newW / w; // 高度等比例变化 // 缩放图像 Bitmap newBitmap = JoinImage.stretch(mBitmap, newW, newH); // 保存该图像 if (isSave) { JoinImage.saveBitmap("0_stre", newBitmap); } return newBitmap; } else if (w >= 1000) { erosionCount = 2; // 腐蚀次数置2 return mBitmap; } else if (w <= 800) { erosionCount = 2; // 腐蚀次数置2 if (w <= 400) { Log.i("图像修正", "图像像素过低!"); } int newW = 1000; // 缩放图像至宽度1000 int newH = h * newW / w; // 高度等比例变化 // 缩放图像 Bitmap newBitmap = JoinImage.stretch(mBitmap, newW, newH); // 保存该图像 if (isSave) { JoinImage.saveBitmap("0_stre", newBitmap); } return newBitmap; } else { erosionCount = 1; // 腐蚀次数置1 return mBitmap; } } /** * GridView点击事件 */ @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { Toast.makeText(this, "->" + JoinImage.analyseImg(splitBmps[position]), Toast.LENGTH_SHORT).show(); } ...... }
3)截图
4)后记
不足之处,多多担待^^。
附件:http://down.51cto.com/data/2360515
相关文章推荐
- Android图像处理(一) 简单的特效 平移 缩放 等
- 在windowsXP系统中使用Eclipse开发Android动态库so(二):简单图像处理so
- Android图像处理之镜像和简单滤镜效果
- [JavaScript][图形图像]图形图像动画处理利器推荐--raphael.js (付:流程设计器例子)
- Android中的Bitmap、Drawable、Byte[]、String、之间的转换及图像简单处理
- Android L(5.0)源码之图形与图像处理之简单图片——Bitmap
- 使用VS+OpenCV的图像处理简单例子
- 图像基本处理算法的简单实现(一) 推荐
- Android 图像处理(类型转换,比例缩放,倒影,圆角)的小例子
- [Qt]一个简单的Qt Widget多线程处理图像的例子
- Android中的简单图像处理
- **ANDROID**# 第七章图形与图像处理(静态处理) > Bitmap是有像素点构成的点阵图。 ------ ## 使用简单的图片 ---- * 通过Drawable对象进行访问。
- 【Android】图形图像处理之”简单图片“
- Android多媒体高级编程(一)——Camera和简单的图像处理
- 【Android Developers Training】 57. 在UI线程之外处理图像
- [Android] 图像处理整合之处理ColorMatrix和Intend传递路径显示图像
- 奇异值分解(SVD)实现简单的图像降噪处理
- 【Android图像处理】给图片加水印
- python 简单图像处理(8) 直方图均衡化
- 在Windows环境下用mahout做推荐系统简单例子