数字图像处理22--OpenCV模糊集合实现图像增强 C++

模糊集合原理

       在计算机编程的时候,常常会使用一种“干脆的”集合。在判断某件事,或者某个变量的时候,常常使用的是布尔值(因为某件事,不是真就是假)。通过一个阈值,去判断这件事,而这样的一个阈值的设定,会产生一个问题。

下图

                                

       当一个人的年龄超过20岁,那么这个人就不再属于年轻人范畴。这样来说,未免有些太过“残忍”,毕竟,20多岁的人还是“比较”年轻的。这里就出现了一个模糊的定义,“比较”年轻,这个集合既不属于年轻,也不属于非年轻,也就是其实年轻与非年轻之间的过度不应该是干脆的,而应该是渐进的过度。

       定义Z为对象集,其中,z表示Z中的一类元素(比如z表示年龄)。Z中的一个模糊集合A主要由一个隶属度(Degree of membership)来表示。对此,模糊集合A是一个由z值和隶属度函数组成的集合,即

                                                             

        当的时候,所有的z是模糊集合A的完全成员;当的时候,所有的z都不是模糊集合A的成员,当的值介于0和1之间,那么此时的z称为模糊集合A的不完全成员。

       下面,还有几个重要的性质。

       对于所有的,模糊集合A的补集(NOT),其隶属度函数如下所示。

                                                            

       对于所有的,模糊集合A与模糊集合B的并集(OR)U,其隶属度函数如下所示。

                                                         

       对于所有的,模糊集合A与模糊集合B的交集(AND)I,其隶属度函数如下所示。

                                                   

       到这里,其实已经可以用模糊集合来做一些事情了。对于一个问题的处理,在使用模糊集合来解决的时候,我们可以参考以下步骤。首先,需要将输入量折算为隶属度,这个过程叫做“模糊化”。然后,使用得到的隶属度来进行计算,或者判断,或者其他更复杂的算法。最后,需要将隶属度再次折算为输出,这个过程称为“去模糊”或者“反模糊”。

        模糊集合为处理不严密信息提供了一种形式。将模糊与模糊隶属度函数之间的关联变量称为fuzification;通常用IF-THEN规则描述有关问题的知识。下面我们寻找一种方法,使用输入和问题的先验知识建立模糊系统的输出。

   通常应用实现步骤为:

 (1)模糊输入:将IF-THEN规则描述的先验知识映射到[0,1]区间,找到每个标量对应的模糊值。

 (2)执行任何需要的模糊逻辑操作(AND、OR、NOT),将所有输出组合到一起;利用一种推断方法,每个规则得到单一输出。

 (3)应用聚合方法将所有规则的输出组合到一起,得到单个的输出模糊集合。

 (4)对最后的输出去模糊化,得到“干脆”标量输出。(可以求模糊集的重心)

一、使用模糊集合进行灰度变换

        使用模糊集合来进行灰度变换,从而增强图像。首先可以在常理下考虑一下,一般的对于动态范围较小的图像,我们一般的处理的方法是灰度拉升,或者直方图均衡。

         这两种的方法的本质就是,让原图较暗的像素更加暗,让原图较亮的像素更加亮。那么,我们规定如下模糊规则

                           R1:IF 一个像素是暗的,THEN 让这个像素更暗;

                           R2:IF 一个像素是灰的,THEN 让他保持是灰的;

                           R3:IF 一个像素是亮的,THEN 让这个像素更亮;

        这个规则就代表了我们的处理方法。当然,IF条件中的像素是暗的(或者灰的,或者是亮的),这个概念都是模糊的。同理THEN结论中的更暗(或者保持灰的,或者更亮)亦是模糊的。为此,我们需要确立一个隶属度函数,从而来判断一个像素对于三个条件的隶属度。

        实际上,隶属度函数的确定是很复杂的,然而,这里我们则尽量想得简单一点。首先,一个像素是暗的(模糊),那么其隶属度函数大致的形状是,

    • 在低于某个值的时候域隶属度为1,
    • 在灰度越过某一个值之后,其隶属度为0,
    • 当然。然后之间进行线性插值,那么,我们就可以得到R1的隶属度函数了。同理,R2与R3也是一样的。

        为了简单起见,我们将THEN结论中的更暗设置为较为简单的函数。

    • 为了让这个像素更黑,其输出都为0。同理,
    • 为了使这个像素保持灰的,我们将其输出设为0.5,
    • 为了使得一个像素更亮,我们将其设置为1。

        根据以上讨论,我们所决定的隶属度函数如下所示。

                             

使用输入的隶属度函数,可以得到模糊化后的数据。

        对于一个像素,需要根据规则R1,R2R3,计算出所对应的隶属度,这个过程,称之为模糊化。将一个输入量模糊化,所使用的函数(或者说是对应关系),称之为知识库。 

         模糊化之后,得到一个像素所对应的三个隶属度之后,就可以进行反模糊化了。反模糊化的算法很多,这里使用简单的重心法去进行计算。

                               

        公式中的Udark、Ugray、Ubright由对应的当前像素点,根据右边曲线图来计算获得。 Vd = 0,表示全黑;Vg = 127, 表示中间灰度;Vb = 255,表示白。Vo表示生成的结果图像当前像素值。         

        其中Vd,Vg,Vb为输出的单一值,对于一个像素,需要根据规则R1,R2与R3,计算出所对应的隶属度。得到一个权值衡量后的成熟度估计值,最为输出值。到此,就得到了输出,整个算法的效果如下图所示

 

代码实现:

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
#include <string>

#define throDark 30
#define throMid 100
#define throBright 170

cv::Mat equalize_img( cv::Mat &src_img )
{
    cv::Mat result;
    cv::equalizeHist( src_img, result );
    return result;
}

cv::Mat show_img_histogram( cv::Mat &src_img )
{
    //create 256 subinterval
    //the number of possibles values
    int numbins = 256;

    //set the range for BGR(0-256)
    float range[] = { 0, 256};
    const float* histRange = { range };

    cv::Mat gray_hist;
    cv::calcHist( &src_img, 1, 0, cv::Mat(), gray_hist, 1, &numbins, &histRange );

    //draw histogram
    //draw lines for each channels
    int width = 512;
    int height = 300;

    // Create image with gray base
    cv::Mat histImage( height, width, CV_8UC1, cv::Scalar(20, 20, 20) );

    // Normalize the histograms to height of image
    cv::normalize(gray_hist, gray_hist, 0, height, cv::NORM_MINMAX );

    int binStep= cvRound((float)width/(float)numbins);
    for( int i=1; i< numbins; i++){
        cv::line(
            histImage,
            cv::Point( binStep*(i-1), height-cvRound(gray_hist.at<float>(i-1) ) ),
            cv::Point( binStep*(i), height-cvRound(gray_hist.at<float>(i) ) ),
            cv::Scalar(255,0,0)
            );
    }
    return histImage;
}

double getUdark(double num){
    double tmpUdark;
    if(num <= throDark){
        tmpUdark = 1;
    }else if((num > throDark) && (num <= throMid)){
        tmpUdark  = ((double)(throMid - num)) / ((double)(throMid - throDark));
    }else{
        tmpUdark = 0;
    }
    return tmpUdark;
}

double getUmid(double num){
    double tmpUmid;
    if((num > throDark) && (num < throMid)){
        tmpUmid  = (num - throDark) / (throMid - throDark);
    }else if((num >= throMid) && (num < throBright)){
        tmpUmid  = (throBright - num) / (throBright - throMid);
    }
    else{
        tmpUmid = 0;
    }
    return tmpUmid;
}

double getUbright(double num){
    double tmpUbright;
    if(num <= throMid){
        tmpUbright = 0;
    }else if((num > throMid) && (num <= throBright)){
        tmpUbright  = (num - throMid) / (throBright - throMid);
    }else{
        tmpUbright = 1;
    }
    return tmpUbright;
}

cv::Mat fuzzy_deal( cv::Mat &srcImage )
{
    if (srcImage.empty())
        std::cout << "No data" <<std::endl;

    cv::Mat resultImage = cv::Mat::zeros(srcImage.size(), srcImage.type());
    uchar val = 0;
    double Udark, Umid, Ubright;
    for (int i = 0; i < srcImage.rows; i++){
        for (int j = 0; j < srcImage.cols; j++){
            val = srcImage.at<uchar>(i, j);
            Udark   = getUdark(val);
            Umid    = getUmid(val);
            Ubright = getUbright(val);
            val = (0 * Udark + 127 * Umid + 255 * Ubright) / (Udark + Umid + Ubright);
            resultImage.at<uchar>(i, j) = cv::saturate_cast<uchar>(val);
        }
    }
    return resultImage;
}

int main(int argc , char* argv[])
{
    if(argc < 2){
        std::cerr << "Please input picture!\n" << std::endl;
        return 0;
    }
    cv::Mat image;

    image = cv::imread(argv[1], cv::IMREAD_GRAYSCALE);
    cv::Mat hist1 = show_img_histogram(image);
    imshow( "Histogram1", hist1);
    imshow( "src", image);

    cv::Mat equail = equalize_img(image);
    cv::Mat his = show_img_histogram(equail);
    imshow( "Histogram_deal", his);
    imshow( "Histogram2", equail);

    cv::Mat dst_img = fuzzy_deal(image);
    cv::Mat hist2 = show_img_histogram(dst_img);
    imshow( "Histogram3", hist2);
    imshow("Blur_deal", dst_img);
    cv::waitKey(0);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/cyf15238622067/article/details/87879633