opencv之大津法Otsu介绍

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_29540745/article/details/73038357

一、大津法(Otsu)

        所谓大津法(Otsu)就是最大类间差方法,通过统计图像直方图信息来自动确定阈值T,从而来区分前景与背景,说白了就是能自动区分图像前景与背景的二值化。

算法流程描述:

1.遍历图像像素,统计每个像素值出现的次数,即255个bin,统计每个bin像素值的个数;

2.遍历0到255每个像素,以i像素值为当前分类的阈值,在(0~i)范围内计算前景像素平均灰度u0,前景部分像素点数所占比例w0;在(i~155)计算背景像素平均灰度u1,背景部分像素点数所占比例w1;

3.计算当前类间方差varValueI=w0*w1*(u1-u0)*(u1-u0);

4.选择最大类间方差varValueI时的i像素阈值作为区分前景与背景的最佳阈值;

       可喜可贺的是opencv已经把Ostu作为一个阈值分割方法写进了threshold函数;


#include "stdafx.h"
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;

double Otsu(Mat&image) {

	int threshold=0;
	double maxVariance = 0;
	double w0=0,w1=0;//前景与背景像素点所占比例
	double u0=0,u1=0;//前景与背景像素值平均灰度
	double histogram[256]={0};
	double Num=image.cols*image.rows;
	//统计256个bin,每个bin像素的个数
	for(int i=0;i<image.rows;i++){
		const uchar * p = image.ptr<uchar>(i);  
	    for(int j=0;j<image.cols;j++){
			histogram[int(*p++)]++; //cout<<"Histogram[data[i*image.step+j]]++:;"<<histogram[int(*p++)]++<<endl; 
		}
	}
	//前景像素统计
	for(int i=0;i<255;i++){
		w0=0;
		w1=0;
		u0=0;
		u1=0;
		for(int j=0;j<=i;j++){
			w0=w0+histogram[j];//以i为阈值,统计前景像素个数
			u0=u0+j*histogram[j];//以i为阈值,统计前景像素灰度总和
		}
		w0=w0/Num;u0=u0/w0;

	//背景像素统计
		for(int j=i+1;j<=255;j++){
			w1=w1+histogram[j];//以i为阈值,统计前景像素个数
			u1=u1+j*histogram[j];//以i为阈值,统计前景像素灰度总和
		}
		w1=w1/Num;u1=u1/w1;
		double variance=w0*w1*(u1-u0)*(u1-u0); //当前类间方差计算
		 if(variance > maxVariance)     
        {      
            maxVariance = variance;      
            threshold = i;      
        }
	}
	cout<<"threshold:"<<threshold<<endl;
	return threshold;
	}

int main()
{   
    Mat img = imread("D://vvoo//fenge.jpg");
	Mat img1;
	img.copyTo(img1);
	cvtColor(img,img,CV_BGR2GRAY);
	cvtColor(img1,img1,CV_BGR2GRAY);
	double th=Otsu(img);
	cout<<"The return value of getOstu is: "<<th<<endl;  
	cout<<"The return value of opencv threshold is: "<<threshold(img1 , img1 ,0,255,CV_THRESH_OTSU);//opencv已实现的大津法  
	for(int i=0;i<img.rows;i++){
	    for(int j=0;j<img.cols;j++){
			if( img.data[i*img.step + j]<=th)
				img.data[i*img.step + j]=255;
			else
				img.data[i*img.step + j]=0;
		}
	}
	imshow("Ostu_img",img);
	imshow("Opencv_img",img1);
    waitKey(0);  
    return 0;
}

阈值是一样的。

扫描二维码关注公众号,回复: 3847841 查看本文章

1. http://blog.csdn.net/ap1005834/article/details/51452516

猜你喜欢

转载自blog.csdn.net/qq_29540745/article/details/73038357