opencv android二值化,OpenCV4Android实现图像二值化

最近在学习OpenCV4Android,需要实现对图像二值化处理,找了很多的资料和文献都没有找到需要的,还好看到了winorlose2000 写的文章,这里表示感谢!接下来贴出自己的源代码,希望和大家交流,不妥之处还请指正啊!

程序调用了OpenCV4Android 2.4.9,低版本应该也可以实现。

使用JNI编程。

xmlns:tools="http://schemas.android.com/tools"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="vertical" >

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:orientation="horizontal"

>

android:id="@+id/bt1"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:background="#4B0082"

android:text="@string/bt1" />

android:id="@+id/bt2"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:background="#000080"

android:text="还原" />

android:id="@+id/tv1"

android:background="#FFF8DC"

android:layout_width="fill_parent"

android:layout_height="wrap_content" />

android:id="@+id/image1"

android:layout_width="wrap_content"

android:layout_height="wrap_content" />

主程序如下:

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

#include

#include

#include

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 > contours;

vector < Vec4i > hierarchy;

findContours(mydata, contours, hierarchy, CV_RETR_CCOMP,

CV_CHAIN_APPROX_SIMPLE);

//事实证明,这样得到的个数不是轮廓的个数

int j = contours.size();

return contours.size();

}

其中返回int类型的程序与实现图像二值化无关,特此说明。

效果如下所示:

0818b9ca8b590ca3270a3433284dd417.png

点击按钮后效果如下:

0818b9ca8b590ca3270a3433284dd417.png

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值