在对图像进行预处理的过程中,经常会遇到对图像进行二值化,比如对图像轮廓进行提取时,是一种比较常规的方法。下面是通过是我通过网上搜集到的OSTU算法动态阈值二值化图像的方法,主要是将1.x接口,修改成了2.x版本的API,并对其中的部分代码进行了修改。

#include "opencv2/opencv.hpp"
#include <iostream>

/**
 *@function OSTU_Region : used to get the threshold for image binary
 */
int OSTU_Region(cv::Mat& image)
{
    assert(image.channels() == 1);
    int width = image.cols ;
    int height = image.rows ;
    int x = 0,y = 0;
    int pixelCount[256] = { 0 };
    float pixelPro[256] = { 0 };
    int i, j, pixelSum = width * height, threshold = 0;

    uchar* data = image.ptr<uchar>(0);

    //count every pixel number in whole image
    for(i = y; i < height; i++)
    {
        for(j = x;j <width;j++)
        {
            pixelCount[data[i * image.step + j]]++;
        }
    }

    //count every pixel's radio in whole image pixel
    for(i = 0; i < 256; i++)
    {
        pixelPro[i] = (float)(pixelCount[i]) / (float)(pixelSum);
    }

    // segmentation of the foreground and background
    // To traversal grayscale [0,255],and calculates the variance maximum grayscale values ​​for the best threshold value
    float w0, w1, u0tmp, u1tmp, u0, u1, u,deltaTmp, deltaMax = 0;
    for(i = 0; i < 256; i++)
    {
        w0 = w1 = u0tmp = u1tmp = u0 = u1 = u = deltaTmp = 0;

        for(j = 0; j < 256; j++)
        {
            if(j <= i)   //background
            {
                w0 += pixelPro[j];
                u0tmp += j * pixelPro[j];
            }
            else        //foreground
            {
                w1 += pixelPro[j];
                u1tmp += j * pixelPro[j];
            }
        }

        u0 = u0tmp / w0;
        u1 = u1tmp / w1;
        u = u0tmp + u1tmp;
        //Calculating the variance
        deltaTmp = w0 * (u0 - u)*(u0 - u) + w1 * (u1 - u)*(u1 - u);
        if(deltaTmp > deltaMax)
        {
            deltaMax = deltaTmp;
            threshold = i;
        }
    }
    //return the best threshold;
    return threshold;
}

/**
 *@function main
 */
int main(int argc, char* argv[])
{
    //--1. load image
    cv::Mat src;
    src = cv::imread(argv[1],1);
    if(!src.data)
    {
        std::cout << "Invalid image file!" << std::endl;
        exit(-1);
    }
    cv::imshow("src",src);

    //--2. use ostu get the threshold and applay binary
    cv::Mat src_gray;
    cv::cvtColor(src, src_gray, CV_BGR2GRAY);
    int threshold = OSTU_Region(src_gray);
    cv::threshold(src_gray,src_gray,threshold,255,CV_THRESH_BINARY);
    cv::imshow("OSTU",src_gray);

    cv::waitKey(0);

    return 0;
}

关于OSTU的算法,它是1979年由日本大津提出的,在最小二乘法原理基础上推导出来的。适用于双峰的直方图。网上有很多类似的算法,上述采用的是最简单,也是最经典的的一种方法而已。

它的基本原理是:

ostu

目前理解还是比较模糊的……大概意思理解而已。

PS:最近正在自学py中,还处于非常迷茫的阶段,求指导,求批斗~

采用OSTU算法对图像进行动态阈值二值化(基于OpenCV)
Tagged on:     

发表评论

电子邮件地址不会被公开。 必填项已用*标注

This site uses Akismet to reduce spam. Learn how your comment data is processed.