title:
date: 2018-07-16 09:39:40

tags: [图像处理]

图像分割-大津法

算法介绍

最大类间方差法是1979年由日本学者大津提出的,是一种自适应阈值确定的方法,又叫大津法,简称OTSU

算法公式

代码 Opencv249 + vs2010

#include "stdio.h"
#include "cv.h"
#include "highgui.h"
#include "Math.h"

int Otsu(IplImage* src);

int main()
{
    IplImage* img = cvLoadImage("lena.jpg",0); //获取灰度图像img
    IplImage* dst = cvCreateImage(cvGetSize(img), 8, 1);
    int threshold = Otsu(img); //调用大津法求出最佳阈值
    printf("otsu threshold = %d\n", threshold);
    cvThreshold(img, dst, threshold, 255, CV_THRESH_BINARY); //用otsu的阈值二值化

    cvNamedWindow( "img", 1 );
    cvNamedWindow( "dst", 1 );
    cvShowImage("img", img);
    cvShowImage("dst", dst);


    cvWaitKey(-1);

    cvReleaseImage(&img);
    cvReleaseImage(&dst);

    cvDestroyWindow( "img" );
    cvDestroyWindow( "dst" );

    return 0;
}

int Otsu(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 & average pixel value 
    int size = height * width;  
    float u =0;
    for(int i = 0; i < 256; i++)
    {  
        histogram[i] = histogram[i] / size;  
        u += i * histogram[i];  //整幅图像的平均灰度
    }  

    int threshold;    
    float maxVariance=0;  
    float w0 = 0, avgValue  = 0;
    for(int i = 0; i < 256; i++) 
    {  
        w0 += histogram[i];  //假设当前灰度i为阈值, 0~i 灰度像素所占整幅图像的比例即前景比例
        avgValue  += i * histogram[i]; //avgValue/w0 = u0

        float t = avgValue/w0 - u;  //t=u0-u
        float variance = t * t * w0 /(1 - w0);  
        if(variance > maxVariance) 
        {  
            maxVariance = variance;  
            threshold = i;  
        }  
    }  

    return threshold;  
} 

代码2

#include <opencv2/opencv.hpp>  
#include <cv.h>
#include <highgui.h>
#include <cxcore.h>

using namespace std;
using namespace cv;

Mat otsuGray(const Mat src) {
    Mat img = src;
    int c = img.cols; //图像列数
    int r = img.rows; //图像行数
    int T = 0; //阈值
    uchar* data = img.data; //数据指针
    int ftNum = 0; //前景像素个数
    int bgNum = 0; //背景像素个数
    int N = c*r; //总像素个数
    int ftSum = 0; //前景总灰度值
    int bgSum = 0; //背景总灰度值
    int graySum = 0;
    double w0 = 0; //前景像素个数占比
    double w1 = 0; //背景像素个数占比
    double u0 = 0; //前景平均灰度
    double u1 = 0; //背景平均灰度
    double Histogram[256] = {0}; //灰度直方图
    double temp = 0; //临时类间方差
    double g = 0; //类间方差

    //灰度直方图
    for(int i = 0; i < r ; i ++) {
        for(int j = 0; j <c; j ++) {
            Histogram[img.at<uchar>(i,j)]++;
        }
    }
    //求总灰度值
    for(int i = 0; i < 256; i ++) {
        graySum += Histogram[i]*i;
    }

    for(int i = 0; i < 256; i ++) {
        ftNum += Histogram[i];  //阈值为i时前景个数
        bgNum = N - ftNum;      //阈值为i时背景个数
        w0 = (double)ftNum/N; //前景像素占总数比
        w1 = (double)bgNum/N; //背景像素占总数比
        if(ftNum == 0) continue;
        if(bgNum == 0) break;
        //前景平均灰度
        ftSum += i*Histogram[i];
        u0 = ftSum/ftNum;

        //背景平均灰度
        bgSum = graySum - ftSum;
        u1 = bgSum/bgNum;

        g = w0*w1*(u0-u1)*(u0-u1);
        if(g > temp) {
            temp = g;
            T = i;
        }
    }

    for(int i=0; i<img.rows; i++)
    {
        for(int j=0; j<img.cols; j++)
        {
            if((int)img.at<uchar>(i,j)>T)
                img.at<uchar>(i,j) = 255;
            else
                img.at<uchar>(i,j) = 0;
        }
    }
    return img;
}
最后修改:2020 年 07 月 07 日 08 : 22 PM
如果觉得我的文章对你有用,请随意赞赏