Ostu(大津法)二值化图像简介

来源:互联网 发布:学数据库有前途吗 编辑:程序博客网 时间:2024/06/16 04:27

一、前言

Ostu方法又名最大类间差方法,通过统计整个图像的直方图特性来实现全局阈值T的自动选取,其算法步骤为:

1)  先计算图像的直方图,即将图像所有的像素点按照0~255共256个bin,统计落在每个bin的像素点数量

2)  归一化直方图,也即将每个bin中像素点数量除以总的像素点

3)  i表示分类的阈值,也即一个灰度级,从0开始迭代

4)  通过归一化的直方图,统计0~i 灰度级的像素(假设像素值在此范围的像素叫做前景像素) 所占整幅图像的比例w0,并统计前景像素的平均灰度u0;统计i~255灰度级的像素(假设像素值在此范围的像素叫做背景像素) 所占整幅图像的比例w1,并统计背景像素的平均灰度u1;

5)  计算前景像素和背景像素的方差 g = w0*w1*(u0-u1) (u0-u1)

6)  i++;转到4),直到i为256时结束迭代

7)将最大g相应的i值作为图像的全局阈值

二、实现代码

Ostu算法实现函数为下面中的int getOstu(const Mat& in),其实在opencv中已经在threshold中实现了,下面代码也比较了两者的结果

#include "opencv2/core/core.hpp"#include "opencv2/highgui/highgui.hpp"#include "opencv2/imgproc/imgproc.hpp"using namespace cv;#include <iostream>int getOstu(const Mat & in);int main(){Mat img = imread("id_card.jpg" ,0);Mat img_high_Light = imread("id_card2.jpg" ,0);Mat  dst , dst_HL;if(img.empty()  | img_high_Light.empty()){std::cout<<"Error!!";return -1;}std::cout<<"The return value of getOstu is: "<<getOstu(img);std::cout<<"\n"<<"The return value of opencv threshold is: "<<threshold(img , dst ,0,255,CV_THRESH_OTSU);//opencv已实现的大津法imshow("光照均匀的原图像" ,img);imshow("图像光照均匀的处理结果" , dst);threshold(img_high_Light , dst_HL ,0,255,CV_THRESH_OTSU);imshow("光照不均匀的原图像" ,img_high_Light );imshow("图像光照不均匀的处理结果",  dst_HL);waitKey(0);return 0;}int getOstu(const Mat & in){int rows = in.rows;int cols = in.cols;long size = rows * cols;float histogram[256] = {0};  for( int i = 0; i < rows; ++i) { //获取第 i行首像素指针 const uchar * p = in.ptr<uchar>(i); //对第i 行的每个像素(byte)操作 for( int j = 0; j < cols; ++j ) {histogram[int(*p++)]++; }}int threshold;      long sum0 = 0, sum1 = 0; //存储前景的灰度总和及背景灰度总和  long cnt0 = 0, cnt1 = 0; //前景的总个数及背景的总个数  double w0 = 0, w1 = 0; //前景及背景所占整幅图像的比例  double u0 = 0, u1 = 0;  //前景及背景的平均灰度  double variance = 0; //最大类间方差  double maxVariance = 0;  for(int i = 1; i < 256; i++) //一次遍历每个像素  {    sum0 = 0;  sum1 = 0;   cnt0 = 0;  cnt1 = 0;  w0 = 0;  w1 = 0;  for(int j = 0; j < i; j++)  {  cnt0 += histogram[j];  sum0 += j * histogram[j];  }  u0 = (double)sum0 /  cnt0;   w0 = (double)cnt0 / size;  for(int j = i ; j <= 255; j++)  {  cnt1 += histogram[j];  sum1 += j * histogram[j];  }  u1 = (double)sum1 / cnt1;  w1 = 1 - w0; // (double)cnt1 / size;  variance =  w0 * w1 *  (u0 - u1) * (u0 - u1);  if(variance > maxVariance)   {    maxVariance = variance;    threshold = i;    }   }    return threshold;    }    
三、运行结果

调用函数getOstu和调用threshold所得到的图像全局阈值如下,可看出两者的结果非常接近,如下所示:

当所处理图像光照均匀时,这时的分割效果较好,如下所示



当处理的图像存在高照不均匀时,则ostu处理效果不是很好




0 0
原创粉丝点击