直方图和滤波器的应用

#include 
#include 
#include 
#include 
using namespace std;

// OpenCV includes
#include "2opencv2/core/utility.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
using namespace cv;

//定义一个图像矩阵存储图像
Mat img;

//绘制直方图
//直方图是变量分布的统计图形表示,它能让我们能够理解数据的密度估计和概率分布
//在灰度图像中,变量值的范围是每个可能的灰度值(0~255),密度是具有该值的图像像素数量
//showHistoCallback函数是用于显示输入图像直方图的回调函数,该函数计算每个通道图像的直方图,并在新图像中显示每个直方图通道的结果
void showHistoCallback(int state, void* userData)
{
    // 创建3个矩阵处理每个输入图像通道,用向量类型变量来存储每个通道
    //split函数将输入图像划分为这3个通道
    vector<Mat> bgr;
    split( img, bgr );
	//定义直方图的区间数,每个可能的像素值对应一个区间
    int numbins= 256;
    // 定义变量(B,G,R)范围 
    float range[] = { 0, 256 } ;
    const float* histRange = { range };
	//创建3个矩阵来存储每个直方图
    Mat b_hist, g_hist, r_hist;
	//calHist函数计算直方图
	//该函数有8个参数,按顺序如下所示:
	//1、输入图像;2、用于计算直方图的输入图像数;3、用于计算直方图的数字通道尺寸;4、可选的掩码矩阵;5、用于存储计算得到的直方图的变量;6、直方图的维度;7、要计算的区间数;8、输入变量的范围
    calcHist( &bgr[0], 1, 0, Mat(), b_hist, 1, &numbins, &histRange );
    calcHist( &bgr[1], 1, 0, Mat(), g_hist, 1, &numbins, &histRange );
    calcHist( &bgr[2], 1, 0, Mat(), r_hist, 1, &numbins, &histRange );

    // 绘制直方图并显示出来
    //创建一个512*300像素大小的彩色图像
    int width= 512;
    int height= 300;
    // Create image with gray base
    Mat histImage( height, width, CV_8UC3, Scalar(20,20,20) );
	//在最小值和最大值之间标准化直方图矩阵,最大值与输出直方图图像的高度相同
    normalize(b_hist, b_hist, 0, height, NORM_MINMAX );
    normalize(g_hist, g_hist, 0, height, NORM_MINMAX );
    normalize(r_hist, r_hist, 0, height, NORM_MINMAX );
	//从区间0到区间1绘制一条线,以此类推。之后计算有多少像素在每个区间之间,然后通过将宽度除以区间数来计算binStep变量。从水平位置i-1到i绘制每条小线,垂直位置是相应的i中的直方图值,并使用彩色通道表示来绘制它
	//cvRound()函数返回跟参数最接近的整数值,即四舍五入
    int binStep=cvRound((float)width/(float)numbins);
    for( int i=1; i< numbins; i++)
    {
        line( histImage,
                Point( binStep*(i-1), height-cvRound(b_hist.at<float>(i-1) ) ),
                Point( binStep*(i), height-cvRound(b_hist.at<float>(i) ) ),
                Scalar(255,0,0)
            );
        line( histImage,
                Point( binStep*(i-1), height-cvRound(g_hist.at<float>(i-1) ) ),
                Point( binStep*(i), height-cvRound(g_hist.at<float>(i) ) ),
                Scalar(0,255,0)
            );
        line( histImage,
                Point( binStep*(i-1), height-cvRound(r_hist.at<float>(i-1) ) ),
                Point( binStep*(i), height-cvRound(r_hist.at<float>(i) ) ),
                Scalar(0,0,255)
            );
    }
    imshow("Histogram", histImage);
}
//均衡图像颜色
//图像均衡,即直方图均衡化,试图获得具有均匀分布值的直方图
//均衡的结果是图像对比度增加。均衡能够使对比度较低的局部区域获得高对比度,从而分散最频繁的强度。当图像非常暗或非常亮,并且背景和前景之间存在非常小的差异时,此法非常有用。
//通过直方图均衡化,可以增加对比度,提升暴露过度或暴露不足的细节
void equalizeCallback(int state, void* userData)
{
	//定义一个存储结果的矩阵
    Mat result;
    //把BGR图像转化为YCrCb
    Mat ycrcb;
    cvtColor( img, ycrcb, COLOR_BGR2YCrCb);
	// 创建矩阵处理每个输入图像通道,用向量类型变量来存储每个通道
    //split函数将输入图像划分为不同的通道矩阵
    vector<Mat> channels;
    split( ycrcb, channels );
    //equalizeHist函数只均衡在Y通道中的直方图
    //equalizeHist(输入矩阵,输出矩阵)
    equalizeHist(channels[0], channels[0]);
    //合并生成的通道
    merge( channels, ycrcb );
    //将ycrcb转化为BGR
    cvtColor( ycrcb, result, COLOR_YCrCb2BGR );
    imshow("Equalized", result);
}
//Lomography效果
void lomoCallback(int state, void* userData)
{
    Mat result;
	//定义E变量并创建1行和256列的lut矩阵
	//通过应用公式并将其保存到lut变量来对所有可能的像素值进行循环
    const double E = std::exp(1.0);
    // Create Lookup table for color curve effect
    Mat lut(1, 256, CV_8UC1);
    for (int i=0; i<256; i++)
    {
        float x= (float)i/256.0;
        lut.at<uchar>(i)= cvRound( 256 * (1/(1 + pow(E, -((x-0.5)/0.1)) )) );
    }
	//split函数按通道分割输入图像并应用lut表变量于红色通道
    vector<Mat> bgr;
    split(img, bgr);
    //LUT(输入图像,查找表的矩阵,输出图像)
    LUT(bgr[2], lut, bgr[2]);
    //合并所计算的通道
    merge(bgr, result);
    //为图像创建黑暗光环
    Mat halo( img.rows, img.cols, CV_32FC3, Scalar(0.3,0.3,0.3) );
    //创建一个内部带有白色圆圈的灰色图像,大小与输入图像相同
    circle(halo, Point(img.cols/2, img.rows/2), img.cols/3, Scalar(1,1,1), -1);
    //可以使用blur滤镜函数对圆光晕图像应用大模糊,以获得平滑效果
    blur(halo, halo, Size(img.cols/3, img.cols/3));
	//将这个光环应用于步骤1的图像,一个简单的方法是将两个图像相乘
	//必须把输入图像从8位图像转换为32位浮点数,因为需要把具有0~1范围值的模糊图像与具有整数值的输入图像相乘
    Mat resultf;
    result.convertTo(resultf, CV_32FC3);
    //转换图像后,只需将每个元素的每个矩阵相乘
    multiply(resultf, halo, resultf);
    //将浮点图像矩阵结果转换为8位图像矩阵
    resultf.convertTo(result, CV_8UC3);
    imshow("Lomograpy", result);

    // Release mat memory
    halo.release();
    resultf.release();
    lut.release();
    bgr[0].release();
    bgr[1].release();
    bgr[2].release();
}
//卡通效果
void cartoonCallback(int state, void* userData)
{
    /** 边缘检测 **/
    //应用中值滤波器从输入图像中去除可能的噪音
    //medianBlur(输入图像,输出图像,内核大小<内核是一个小矩阵,用于对图像应用某些数学运算,例如卷积运算>)
    Mat imgMedian;
    medianBlur(img, imgMedian, 7);
    //消除任何可能的噪音后,用Canny过滤器检测强边缘
    //Canny(输入图像,输出图像,第一阈值,第二阈值,Sobel尺寸光圈,布尔值<用于表示是否需要使用更准确的图像梯度幅度>)
    //第一阈值和第二阈值之间的最小值用于边缘链接,最大值用于查找强边缘的初始段,Sobel尺寸光圈是算法中使用的Sobel滤波器的内核大小
    Mat imgCanny;
    Canny(imgMedian, imgCanny, 50, 150);
	//检测到边缘后用一个小的扩张来连接断开的边缘
    Mat kernel= getStructuringElement(MORPH_RECT, Size(2,2));
    dilate(imgCanny, imgCanny, kernel);
    //若需要将边缘的结果图像与彩色图像相乘,则需要像素值处在0~1范围内
    //将canny边缘检测结果除以255并将边缘反转为黑色
    imgCanny= imgCanny/255;
    imgCanny= 1-imgCanny;
    //将canny8位无符号像素格式转换为浮点矩阵
    Mat imgCannyf;
    imgCanny.convertTo(imgCannyf, CV_32FC3);
	//应用blur滤镜平滑结果线
    blur(imgCannyf, imgCannyf, Size(5,5));

    /** 颜色过滤 **/
    //应用双边滤波器使颜色均质化
    //bilateralFilter有五个参数,如下:
    //1、输入图像;2、输出图像;3、像素邻域直径(如为负数,则从Sigma空间值计算它);4、Sigma色值;5、Sigma坐标空间
    //直径大于5时,bilteral滤镜开始变慢;当Sigma>150时,会出现卡通效果
    Mat imgBF;
    bilateralFilter(img, imgBF, 9, 150.0, 150.0);
    //为了创建更强大的卡通效果,通过乘以和除以像素值将可能的颜色值截断为10
    // truncate colors
    Mat result= imgBF/25;
    result= result*25;
	/** 合并颜色和边缘结果 **/
    //为边缘创建一个三通道图像
    Mat imgCanny3c;
    Mat cannyChannels[]={ imgCannyf, imgCannyf, imgCannyf};
    merge(cannyChannels, 3, imgCanny3c);
	//将颜色结果图像转化为32位浮点图像
    Mat resultf;
    result.convertTo(resultf, CV_32FC3);
    // Multiply color and edges matrices
    multiply(resultf, imgCanny3c, resultf);
    //将图像转换为8位
    resultf.convertTo(result, CV_8UC3);
    imshow("Result", result);
}
int main( int argc, const char** argv )
{
	// 读取图片的绝对路径
	img= imread("/home/audrey/Desktop/workspace/opencv4.5/tutorial/chapter4/lena.jpg");
	//创建窗口
    namedWindow("Input");
    //创建UI按钮
    //createButton函数创建按钮
    //OpenCV中定义了三种按钮类型:QT_CHECKBOX,QT_RADIOBOX,QT_PUSH_BUTTON
    //每个按钮有五个参数,按顺序如下所示:
    //1、按钮名称;2、回调函数;3、传递给回调函数的用户变量数据的指针;4、按钮类型;5、用于复选框和单选框按钮类型的默认初始状态
    createButton("Show histogram", showHistoCallback, NULL, QT_PUSH_BUTTON, 0);
    createButton("Equalize histogram", equalizeCallback, NULL, QT_PUSH_BUTTON, 0);
    createButton("Lomography effect", lomoCallback, NULL, QT_PUSH_BUTTON, 0);
    createButton("Cartonize effect", cartoonCallback, NULL, QT_PUSH_BUTTON, 0);
    //imshow函数显示图像
    //imshow("图像标题",图像矩阵)
    imshow("Input", img);
    waitKey(0);
    return 0;
}

知识补充

直方图和滤波器的应用_第1张图片直方图和滤波器的应用_第2张图片

结果

直方图和滤波器的应用_第3张图片

你可能感兴趣的:(opencv)