opencv实现c++的otsu自适应阈值分割的算法描述

阅读: 评论:0

otsu算法选择使类间方差最大的灰度值为阈值,具有很好的效果
算法具体描述见otsu论文,或冈萨雷斯著名的数字图像处理那本书
这里给出程序流程:
1、计算直方图并归一化histogram
2、计算图像灰度均值avgValue.
3、计算直方图的零阶w[i]和一级矩u[i]
4、计算并到最大的类间方差(between-class variance
variance[i]=(avgValue*w[i]-u[i])*(avgValue*w[i]-u[i])/(w[i]*(1-w[i]))
对应此最大方差的灰度值即为要的阈值
5、用到的阈值二值化图像
我在代码中做了一些优化,所以算法描述的某些地方跟程序并不一致
otsu代码,先阈值,继而二值化
// implementation of otsu algorithm
// author: onezeros(@yahoo)
// reference: Rafael C. Gonzalez. Digital Image Processing Using MATLAB
void cvThresholdOtsu(IplImage* src, IplImage* dst)
{
    int height=src->height;
    int width=src->width;
    //histogram
    float histogram[256]= {0};
    for(int i=0; i<height; i++)
    {
        unsigned char* p=(unsigned char*)src->imageData+src->widthStep*i;
        for(int j=0; j<width; j++)
        {
            histogram[*p++]++;
        }
    }
    //normalize histogram
    int size=height*width;
    for(int i=0; i<256; i++)
    {
        histogram[i]=histogram[i]/size;
    }
    //average pixel value
    float avgValue=0;
    for(int i=0; i<256; i++)
    {
        avgValue+=i*histogram[i];
    }
    int threshold;
    float maxVariance=0;
    float w=0,u=0;
    for(int i=0; i<256; i++)
    {栾茂田
        w+=histogram[i];
        u+=i*histogram[i];
        float t=avgValue*w-u;
        float variance=t*t/(w*(1-w));
        if(variance>maxVariance)
        {
            maxVariance=variance;
            threshold=i;
        }
    }
    cvThreshold(src,dst,threshold,255,CV_THRESH_BINARY);
}
更多情况下我们并不需要对每一帧都是用otsu寻阈值,于是可以先到阈值,然后用到的阈值处理后面的图像。下面这个函数重载了上面的,返回值就是阈值。只做了一点改变

// implementation of otsu algorithm
// author: onezeros(@yahoo)
// reference: Rafael C. Gonzalez. Digital Image Processing Using MATLAB
int cvThresholdOtsu(IplImage* src)
{
    int height=src->height;
    int width=src->width;
    //histogram
    float histogram[256]= {0};
    for(int i=0; i<height; i++)
    {
        unsigned char* p=(unsigned char*)src->imageData+src->widthStep*i;
        for(int j=0; j<width; j++)
        {灸除百病
            histogram[*p++]++;
        }
    }
    //normalize histogram
    int size=height*width;
    for(int i=0; i<256; i++)
    {
        histogram[i]=histogram[i]/size;
    }
    //average pixel value
    float avgValue=0;
    for(int i=0; i<256; i++)
    {
        avgValue+=i*histogram[i];
    }
    int threshold;
    float maxVariance=0;
    float w=0,u=0;
    for(int i=0; i<256; i++)
    {
        w+=histogram[i];
        u+=i*histogram[i];
        float t=avgValue*w-u;
        float variance=t*t/(w*(1-w));
        if(variance>maxVariance)
        {
            maxVariance=variance;
            threshold=i;
        }
课堂教学的有效性
    }
    return threshold;
}
我在手的自动检测中使用这个方法,效果很好。
下面是使用上述两个函数的简单的主程序,可以试运行一下,如果处理视频,要保证第一帧时,手要在图像中。
 
#include <cv.h>
#include <cxcore.h>
#include <highgui.h>
#pragma comment(lib,"cv210d.lib")
#pragma comment(lib,"cxcore210d.lib")
#pragma comment(lib,"highgui210d.lib")
#include <iostream>
using namespace std;
int main(int argc, char** argv)
{
#ifdef VIDEO //video process 
    CvCapture* capture=cvCreateCameraCapture(-1);
    if (!capture)
    {
        cout<<"failed to open camera"<<endl;
        exit(0);
    }
    int threshold=-1;
    IplImage* img;
    while (img=cvQueryFrame(capture))
    {
        cvShowImage("video",img);
        cvCvtColor(img,img,CV_RGB2YCrCb);
        IplImage* imgCb=cvCreateImage(cvGetSize(img),8,1);
        cvSplit(img,NULL,NULL,imgCb,NULL);
        if (threshold<0)
        {
            threshold=cvThresholdOtsu(imgCb);
        }
        //cvThresholdOtsu(imgCb,imgCb);
        cvThreshold(imgCb,imgCb,threshold,255,CV_THRESH_BINARY);
        cvErode(imgCb,imgCb);
        cvDilate(imgCb,imgCb);
        cvShowImage("object",imgCb);
        cvReleaseImage(&imgCb);
        if (cvWaitKey(3)==27) //esc
        {
中国文化遗产日            break;
        }
    }
日凌期    cvReleaseCapture(&capture);
#else //single image process  新华门事件
    const char* filename=(argc>=2?argv[1]:"cr.jpg");
    IplImage* img=cvLoadImage(filename,CV_LOAD_IMAGE_GRAYSCALE);
    cvThresholdOtsu(img,img);
    cvShowImage( "src", img );
    char buf[256];
    sprintf_s(buf,256,"%s.otsu.jpg",filename);
    cvSaveImage(buf,img);
    cvErode(img,img);
    cvDilate(img,img);
    cvShowImage( "dst", img );
    sprintf_s(buf,256,"%s.otsu.processed.jpg",filename);

本文发布于:2023-08-16 14:13:17,感谢您对本站的认可!

本文链接:https://patent.en369.cn/xueshu/367595.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:阈值   方差   灰度
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2022 Comsenz Inc.Powered by © 369专利查询检索平台 豫ICP备2021025688号-20 网站地图