OpenCV4Android实现图像二值化
2014-11-14 15:05
330 查看
原帖地址:http://vaero.blog.51cto.com/4350852/822997最近在学习OpenCV4Android,需要实现对图像二值化处理,找了很多的资料和文献都没有找到需要的,还好看到了winorlose2000 写的文章,这里表示感谢!接下来贴出自己的源代码,希望和大家交流,不妥之处还请指正啊!程序调用了OpenCV4Android 2.4.9,低版本应该也可以实现。使用JNI编程。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" > <Button android:id="@+id/bt1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="#4B0082" android:text="@string/bt1" /> <Button android:id="@+id/bt2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="#000080" android:text="还原" /> </LinearLayout> <TextView android:id="@+id/tv1" android:background="#FFF8DC" android:layout_width="fill_parent" android:layout_height="wrap_content" /> <ImageView android:id="@+id/image1" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout>主程序如下:
package com.example.bitmapbinary; import org.opencv.android.BaseLoaderCallback; import org.opencv.android.LoaderCallbackInterface; import org.opencv.android.OpenCVLoader; import android.os.Bundle; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Matrix; import android.graphics.Bitmap.Config; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.ImageView; import android.widget.TextView; public class MainActivity extends Activity implements OnClickListener { public Button bt1, bt2; public ImageView imageView1; public TextView textView1; public Bitmap map; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); bt1 = (Button) findViewById(R.id.bt1); bt2 = (Button) findViewById(R.id.bt2); imageView1 = (ImageView) findViewById(R.id.image1); textView1 = (TextView) findViewById(R.id.tv1); textView1.setText("个数:"); bt1.setOnClickListener(this); bt2.setOnClickListener(this); // 灰度化图片,显示 map = BitmapFactory.decodeResource(getResources(), R.drawable.lena0); imageView1.setImageBitmap(map); } public Bitmap rotate(Bitmap ori,int degree){ Matrix matrix = new Matrix(); matrix.postRotate(degree); Bitmap rotateBitmap = Bitmap.createBitmap(ori, 0, 0, ori.getWidth(), ori.getHeight(), matrix, true); if(rotateBitmap != ori) { ori.recycle(); ori = rotateBitmap; } return ori; } @Override public void onClick(View v) { if (v == bt1) { //map=rotate(map,270);//旋转图片而已 int w = map.getWidth(); int h = map.getHeight(); int[] piexl = new int[w * h]; map.getPixels(piexl, 0, w, 0, 0, w, h);// 检索指定坐标点的GRB像素值 int result[] = ImageProc.imgbinary(piexl, w, h); Bitmap resultmap = Bitmap.createBitmap(w, h, Config.ARGB_8888); resultmap.setPixels(result, 0, w, 0, 0, w, h); imageView1.setImageBitmap(resultmap); // show轮廓个数 textView1.setText(w * h + "个数:" + ImageProc.num(piexl, w, h)); } else if (v == bt2) { imageView1.setImageBitmap(map); } } // OpenCV类库加载并初始化成功后的回调函数,在此我们不进行任何操作 private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) { @Override public void onManagerConnected(int status) { switch (status) { case LoaderCallbackInterface.SUCCESS: { System.loadLibrary("bitmapbinary"); } break; default: { super.onManagerConnected(status); } break; } } }; protected void onResume() { super.onResume(); OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_3, this, mLoaderCallback); }; }JNI接口程序bitmapbinary如下:
#include<jni.h> #include <ImageProc.h> #include<opencv2/opencv.hpp> #include <stdlib.h> using namespace cv; int otsu2(jint* colors, int w, int h) { unsigned int pixelNum[256]; // 图象灰度直方图[0, 255] int color; // 灰度值 int n, n0, n1; // 图像总点数,前景点数, 后景点数(n0 + n1 = n) int w0, w1; // 前景所占比例, 后景所占比例(w0 = n0 / n, w0 + w1 = 1) double u, u0, u1; // 总平均灰度,前景平均灰度,后景平均灰度(u = w0 * u0 + w1 * u1) double g, gMax; // 图像类间方差,最大类间方差(g = w0*(u0-u)^2+w1*(u1-u)^2 = w0*w1*(u0-u1)^2) double sum_u, sum_u0, sum_u1; // 图像灰度总和,前景灰度总和, 后景平均总和(sum_u = n * u) int thresh; // 阈值 memset(pixelNum, 0, 256 * sizeof(unsigned int)); // 数组置0 // 统计各灰度数目 int i, j; for (i = 0; i < h; i++) { for (j = 0; j < w; j++) { color = (colors[w * i + j]) & 0xFF; // 获得灰度值 pixelNum[color]++; // 相应灰度数目加1 } } // 图像总点数 n = w * h; // 计算总灰度 int k; for (k = 0; k <= 255; k++) { sum_u += k * pixelNum[k]; } // 遍历判断最大类间方差,得到最佳阈值 for (k = 0; k <= 255; k++) { n0 += pixelNum[k]; // 图像前景点数 if (0 == n0) { // 未获取前景,直接继续增加前景点数 continue; } if (n == n0) { // 前景点数包括了全部时,不可能再增加,退出循环 break; } n1 = n - n0; // 图像后景点数 sum_u0 += k * pixelNum[k]; // 前景灰度总和 u0 = sum_u0 / n0; // 前景平均灰度 u1 = (sum_u - sum_u0) / n1; // 后景平均灰度 g = n0 * n1 * (u0 - u1) * (u0 - u1); // 类间方差(少除了n^2) if (g > gMax) { // 大于最大类间方差时 gMax = g; // 设置最大类间方差 thresh = k; // 取最大类间方差时对应的灰度的k就是最佳阈值 } } return thresh; } JNIEXPORT jintArray JNICALL Java_com_example_bitmapbinary_ImageProc_imgbinary( JNIEnv* env, jclass obj, jintArray buf, jint w, jint h) { //图像灰度化的源程序 jint *cbuf; cbuf = env->GetIntArrayElements(buf, false); if (cbuf == NULL) { return 0; } //threshold(src,myimg,0,255,THRESH_OTSU); int white = 0xFFFFFFFF; // 不透明白色 int black = 0xFF000000; // 不透明黑色 int thresh = otsu2(cbuf, w, h); // OTSU获取分割阀值 int i, j, gray; for (i = 0; i < h; i++) { for (j = 0; j < w; j++) { gray = (cbuf[w * i + j]) & 0xFF; // 获得灰度值(red=green=blue) if (gray < thresh) { cbuf[w * i + j] = white; // 小于阀值设置为白色(前景) } else { cbuf[w * i + j] = black; // 否则设置为黑色(背景) } } } int size = w * h; jintArray result = env->NewIntArray(size);//为其分配空间 env->SetIntArrayRegion(result, 0, size, cbuf);//为result赋值 env->ReleaseIntArrayElements(buf, cbuf, 0); return result; } JNIEXPORT jint JNICALL Java_com_example_bitmapbinary_ImageProc_num(JNIEnv *env, jclass obj, jintArray buf, jint w, jint h) { jint *cbuf; cbuf = env->GetIntArrayElements(buf, false); if (cbuf == NULL) { return 0; } Mat mydata(h, w, CV_8UC1, (unsigned char*) cbuf); vector < vector<Point> > contours; vector < Vec4i > hierarchy; findContours(mydata, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE); //事实证明,这样得到的个数不是轮廓的个数 int j = contours.size(); return contours.size(); }其中返回int类型的程序与实现图像二值化无关,特此说明。效果如下所示:点击按钮后效果如下:
相关文章推荐
- Android OpenCV实现图片叠加,水印
- (4)opencv在android平台上实现 物体跟踪
- 【CNTK/OpenCV/Android】Server+Android+CNN实现移动端图像识别系统
- Android使用OpenCV CamShift实现目标追踪
- [置顶] opencv-android笔记1:android studio 2.3 + opencv-android-sdk 实现 camera预览
- {Android-OpenCV调用CvSmooth实现高斯模糊}
- 基于OpenCV实现的Android移动端口红AR
- Android使用OpenCV实现「人脸检测」和「人脸识别」
- 【转】[Android编程心得] Camera(OpenCV)自动对焦和触摸对焦的实现
- Android使用OpenCV实现「人脸检测」和「人脸识别」
- [Android编程心得] Camera(OpenCV)自动对焦和触摸对焦的实现
- opencv在android预览上实现灰化/感应触屏/边缘检测(3)
- opencv裁剪移并植到android实现游戏中的数字识别
- Android OpenCV实现图片叠加,水印
- Android+OpenCV实现轨迹识别
- Android OpenCV实现图片叠加,水印
- Android上使调用OpenCV 2.4.10 实现二维码区域定位(Z-xing 码)
- opencv在Android上实现物体跟踪(7)
- 【Android】OpenCV实现在Android下的人脸检测(NDK)--两篇论文
- Android下使用jni实现基于opencv与dlib的68关键点检测