二值化函数cvThreshold()参数CV_THRESH_OTSU的疑惑【转】

查看OpenCV文档cvThreshold(),在二值化函数cvThreshold(const CvArr* src, CvArr* dst, double threshold, double max_value, int threshold_type)中,参数threshold_type有5种类型:

  • THRESH_BINARY
  • THRESH_BINARY_INV
  • THRESH_TRUNC
  • THRESH_TOZERO
  • THRESH_TOZERO_INV

问题来了:为什么可以在threshold_type参数中使用CV_THRESH_OTSU,在哪里可以查看这种OTSU,它用的什么方法?经多次验证,二值化的效果很好,且速度很快。
已经有一些同志在使用:
例证1:例证1
例证2:例证2
例证3:例证3

我的遭遇:为了二值化一个比较大的图像(10M,3840*2748),痛苦的看了各种论文,尝试了各种的二值化方法:一维OTSU,快速迭代的一维OTSU,二维的OTSU,快速迭代的二维OTSU。但现实的残酷的!只有二维的OTSU和快速迭代的OTSU可用,但前者处理时间让人难以接受,后者也要500多个ms。        快速迭代的二维OTSU算法是根据吴一全老师的《二维最大类间方差阈值分割的快速迭代算法》(论文下载链接,提取码:fd0b)来实现的。但是令我哭笑不得的是,无意中在网上发现了一种方法threshold_type使用参数使用CV_THRESH_OTSU时,时间却大大的缩短。程序如下(
程序下载链接提取码:fd0b),图像下载  (提取码:24f3)。

/* otsu_2d:二维最大类间方差阈值分割的快速迭代算法   吴一全 */
#include <iostream>
#include <cv.h>
#include <highgui.h>

using namespace std;
double TwoDimentionOtsu(IplImage *image);
int main()
{
        IplImage* srcImage = cvLoadImage( "E:/image_1/14.bmp",0 );
        assert(NULL != srcImage);

        cvNamedWindow("src",0);
        cvShowImage("src",srcImage); 

        clock_t start_time=clock();

        //计算最佳阈值
        double threshold = TwoDimentionOtsu(srcImage);//70,125

        clock_t end_time=clock();
        cout<< "Running time is: "<<static_cast<double>(end_time-start_time)/CLOCKS_PER_SEC*1000<<"ms"<<endl;//输出运行时间

        cout << "threshold=" << threshold << endl;

        IplImage* biImage = cvCreateImage(cvGetSize(srcImage),8,1);
        //对图像二值化
        //cvThreshold(srcImage,biImage,255,255, CV_THRESH_OTSU | CV_THRESH_BINARY);
        cvThreshold(srcImage,biImage,threshold,255, CV_THRESH_BINARY);

        cvNamedWindow("binary",0);
        cvShowImage("binary",biImage);  

        cvWaitKey(0);  

        cvReleaseImage(&srcImage);
        cvReleaseImage(&biImage);  

        cvDestroyAllWindows();  

        return 0;
}
double TwoDimentionOtsu(IplImage *image)
{
        double t0 = 0, s0 = 0, t = 0, s = 0;
        int width = image->width;
        int height = image->height;
        double dHistogram[256][256]={0.0};                                //建立二维灰度直方图
        unsigned long sum0 = 0,sum1 = 0;                                //sum0记录所有的像素值的总和,sum1记录3x3窗口的均值的总和
        uchar* data = (uchar*)image->imageData;
        for(int i=0; i<height; i++)
        {
                for(int j=0; j<width; j++)
                {
                        unsigned char nData1 = data[i * image->widthStep + j];//nData1记录当前点(i,j)的像素值
                        sum0 += nData1;
                        unsigned char nData2 = 0;  //nData2记录以当前点(i,j)为中心三领域像素值的平均值
                        int nData3 = 0;                                        //nData3记录以当前点(i,j)为中心三领域像素值之和,注意9个值相加可能超过一个字节
                        for(int m=i-1; m<=i+1; m++)
                        {
                                for(int n=j-1; n<=j+1; n++)
                                {
                                        if((m>=0)&&(m<height)&&(n>=0)&&(n<width))
                                                nData3 += data[m * image->widthStep + n];
                                }
                        }
                        nData2 = (unsigned char)(nData3/9);    //对于越界的索引值进行补零,邻域均值
                        sum1 += nData2;
                        dHistogram[nData1][nData2]++;
                }
        }

        long N = height*width;                //总像素数
        t = sum0/N;                                        //图像灰度级均值
        s = sum1/N;                                        //邻域平均灰度级的均值

        s0 = s;
        t0 = t;
        for(int j=0; j<256; j++)
                for(int i=0; i<256; i++)
                {
                        dHistogram[i][j] = dHistogram[i][j]/N;  //得到归一化的概率分布
                }

                double w0 = 0.0,w1 = 0.0,u0i = 0.0,u1i = 0.0,u0j = 0.0,u1j = 0.0;

                do
                {
                        t0 = t;
                        s0 = s;
                        w0 = w1 = u0i = u1i = u0j = u1j = 0.0;
                        for (int i = 0,j; i < 256; i++)
                        {
                                for (j = 0; j < s0; j++)
                                {
                                        w0 += dHistogram[i][j];
                                        u0j += dHistogram[i][j] * j;
                                }

                                for (; j < 256; j++)
                                {
                                        w1 += dHistogram[i][j];
                                        u1j += dHistogram[i][j] * j;
                                }

                        }
                        for (int j = 0,i = 0; j < 256; j++)
                        {
                                for (i = 0; i < t0; i++)
                                        u0i += dHistogram[i][j] * i;
                                for (; i < 256; i++)
                                        u1i += dHistogram[i][j] * i;
                        }
                        u0i /= w0;
                        u1i /= w1 ;
                        u0j /= w0;
                        u1j /= w1;

                        t = (u0i + u1i)/2;
                        s = (u0j + u1j)/2;
                }while ( t != t0);//是否可以用这个做为判断条件,有待考究,请高手指点

                return t;//只用t做为阈值,个人也感觉不妥,但没有找到更好的方法,请高手指点

}

输出结果:

 cvThreshold()参数设为CV_THRESH_OTSU,输入结果:

原文地址:https://www.cnblogs.com/huaxingtianxia/p/9052135.html

时间: 2024-09-30 22:23:09

二值化函数cvThreshold()参数CV_THRESH_OTSU的疑惑【转】的相关文章

OpenCV图像的全局阈值二值化函数(OTSU)

cv::threshold(GrayImg, Bw, 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);//灰度图像二值化 CV_THRESH_OTSU是提取图像最佳阈值算法.该方法在类间方差最大的情况下是最佳的,就图像的灰度值而言,OTSU给出最好的类间分离的阈值. OpenCV阈值分割的几种方法(types_c.h中的定义): /* Threshold types */ enum { CV_THRESH_BINARY =0, /* value = valu

MATLAB实现二值化函数

function  bc = binary_conversion(a)  %这是灰度值二值化转换函数,阈值为平均值j=imread(a);             %读取灰度图像   j=double(j);             %将图像转换为小数浮点型(double)[m,n]=size(j);             %获取图像的长宽(m,n)s=sum(sum(j));             %图像像素值求和a=s/(m*n);                  %计算像素平均值a=

opencv2对读书笔记——图像二值化——thresholded函数

opencv中的图像二值化函数threshold函数 其结构 double cv::threshold( //二值化函数 const CvArr* src, //原始图像 CvArr* dst, //输出图像 double threshold, //阈值 double max_value, //最大值 int threshold_type//阈值类型 ); 实例代码 #include "cv.h" #include "highgui.h" int main() {

[转载+原创]Emgu CV on C# (五) —— Emgu CV on 局部自适应阈值二值化

局部自适应阈值二值化 相对全局阈值二值化,自然就有局部自适应阈值二值化,本文利用Emgu CV实现局部自适应阈值二值化算法,并通过调节block大小,实现图像的边缘检测. 一.理论概述(转载自<OpenCV_基于局部自适应阈值的图像二值化>) 局部自适应阈值则是根据像素的邻域块的像素值分布来确定该像素位置上的二值化阈值.这样做的好处在于每个像素位置处的二值化阈值不是固定不变的,而是由其周围邻域像素的分布来决定的.亮度较高的图像区域的二值化阈值通常会较高,而亮度较低的图像区域的二值化阈值则会相适

OpenCV中对图像进行二值化的关键函数——cvThreshold()。

函数功能:采用Canny方法对图像进行边缘检测 函数原型: void cvThreshold( const CvArr* src, CvArr* dst, double threshold, double max_value, int threshold_type ); 函数说明: 第一个参数表示输入图像,必须为单通道灰度图. 第二个参数表示输出的边缘图像,为单通道黑白图. 第三个参数表示阈值 第四个参数表示最大值. 第五个参数表示运算方法. 在OpenCV的imgproc\types_c.h中

OpenCV二值化cvThreshold和自适应二值化cvAdaptiveThreshold及Otsu

阈值化函数: double cvThreshold(constCvArr* src, CvArr* dst, double threshold, double max_value,int threshold_type) 参数:   src –原始数组 (单通道 , 8-bit of 32-bit 浮点数). dst –输出数组,必须与 src 的类型一致,或者为 8-bit. thresh –阈值. max_value –使用 CV_THRESH_BINARY 和 CV_THRESH_BINAR

MATLAB:图像二值化、互补图(反运算)(im2bw,imcomplement函数)

图像二值化.反运算过程涉及到im2bw,imcomplement函数,反运算可以这么理解:原本黑的区域变为白的区域,白的区域变为黑的区域. 实现过程如下: close all; %关闭当前所有图形窗口,清空工作空间变量,清除工作空间所有变量 clear all; clc; J=imread('rice.png');% 读取灰度图像,赋值给J J1=im2bw(J);%将灰度图像转换成二值图像,赋值给J1 J2=imcomplement(J);%求灰度图像的补,即对图像进行求反运算,赋值给J2 J

二值化的cv2 threshold函数

像素高于阈值时,给像素赋予新值,否则,赋予另外一种颜色.函数是cv2.threshold() cv2.threshold(src,thresh,maxval,type[,dst])->retval,dst 作用:用于获取二元值的灰度图像 thresh:阈值,maxval:在二元阈值THRESH_BINARY和逆二元阈值THRESH_BINARY_INV中使用的最大值 返回值retval其实就是阈值 type:使用的阈值类型 例子: #python 3.5.3 蔡军生 #http://edu.cs

【OpenCV入门指南】第四篇 图像的二值化

[OpenCV入门指南]第四篇 图像的二值化 在上一篇<[OpenCV入门指南]第三篇Canny边缘检测>中介绍了使用Canny算子对图像进行边缘检测.与边缘检测相比,轮廓检测有时能更好的反映图像的内容.而要对图像进行轮廓检测,则必须要先对图像进行二值化,图像的二值化就是将图像上的像素点的灰度值设置为0或255,这样将使整个图像呈现出明显的黑白效果.在数字图像处理中,二值图像占有非常重要的地位,图像的二值化使图像中数据量大为减少,从而能凸显出目标的轮廓. <OpenCV入门指南>系