opencv笔记 | 直方图

图像直方图处理
本文介绍了图像直方图的概念及其在图像处理中的应用,包括如何使用OpenCV计算和绘制直方图,以及直方图均衡化的实现方法。

直方图

reference

图像直方图

直方图处理

直方图变换

opencv直方图

直方图

  • 图像直方图是反映一个图像像素分布的统计表,其实横坐标代表了图像像素的种类,可以是灰度的,也可以是彩色的。纵坐标代表了每一种颜色值在图像中的像素总数或者占所有像素个数的百分比。
  • 图像是由像素构成,因为反映像素分布的直方图往往可以作为图像一个很重要的特征。在实际工程中,图像直方图在特征提取、图像匹配等方面都有很好的应用。

直方图均衡化

  • 直方图均衡化是将原图像的直方图通过变换函数变为均匀的直方图,然后按均匀直方图修改原图像,从而获得一幅灰度分布均匀的新图像。

opencv计算直方图

void calcHist(const Mat* images, int nimages, const int* channels, InputArray mask, OutputArray hist, int dims, const int* histSize, const float** ranges, booluniform=true, bool accumulate=false );

/*
const Mat* images:为输入图像的指针。

int nimages:要计算直方图的图像的个数。此函数可以为多图像求直方图,我们通常情况下都只作用于单一图像,所以通常nimages=1const int* channels:图像的通道,它是一个数组,如果是灰度图像则channels[1]={0};如果是彩色图像则channels[3]={0,1,2};如果是只是求彩色图像第2个通道的直方图,则channels[1]={1};

IuputArray mask:是一个遮罩图像用于确定哪些点参与计算,实际应用中是个很好的参数,默认情况我们都设置为一个空图像,即:Mat()。

OutArray hist:计算得到的直方图

int dims:得到的直方图的维数,灰度图像为1维,彩色图像为3维。

const int* histSize:直方图横坐标的区间数。如果是10,则它会横坐标分为10份,然后统计每个区间的像素点总和。

const float** ranges:这是一个二维数组,用来指出每个区间的范围。

后面两个参数都有默认值
uniform参数表明直方图是否等距,
最后一个参数与多图像下直方图的显示与存储有关。
*/

demo学习

#include "opencv2/opencv.hpp"
#include "opencv2/opencv_modules.hpp"
#include "opencv2/highgui/highgui.hpp"
#include<iostream>
using namespace cv;
using namespace std;


/*
    计算直方图的函数
    返回的是直方图的矩阵形式
    输入的是图像
*/

Mat histogramCal(const Mat& image){
    int histSize = 255; // 直方图的最大像素
    float range[] = { 0, 256 };
    const float *histRange = { range };
    vector<Mat> bgr; // 存储图像的矩阵
    split(image, bgr);// 将彩色图像分割成,b,g,r分别存储
    bool uniform = true;
    bool accumulate = false;
    Mat b_hist, g_hist, r_hist;
    // 分别计算各个波段的直方图
    calcHist(&bgr[0], 1, 0, Mat(), b_hist, 1, &histSize, &histRange, uniform, accumulate);
    calcHist(&bgr[1], 1, 0, Mat(), g_hist, 1, &histSize, &histRange, uniform, accumulate);
    calcHist(&bgr[2], 1, 0, Mat(), r_hist, 1, &histSize, &histRange, uniform, accumulate);

    // 绘制直方图
    int hist_w = 512, hist_h = 400;
    int bin_w = cvRound((double)hist_w / histSize);
    Mat histImage(hist_h, hist_w, CV_8U, Scalar(0, 0, 0));
    //将结果归一化[0,histImage.rows]
    normalize(b_hist, b_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
    normalize(g_hist, g_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
    normalize(r_hist, r_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());

    for (int i = 1; i < histSize; i++) {
        line(histImage, Point(bin_w*(i - 1), hist_h - cvRound(b_hist.at<float>(i - 1))),
            Point(bin_w*(i), hist_h - cvRound(b_hist.at<float>(i))), Scalar(255, 0, 0));
        line(histImage, Point(bin_w*(i - 1), hist_h - cvRound(g_hist.at<float>(i - 1))),
            Point(bin_w*(i), hist_h - cvRound(g_hist.at<float>(i))), Scalar(0, 255, 0));
        line(histImage, Point(bin_w*(i - 1), hist_h - cvRound(r_hist.at<float>(i - 1))),
            Point(bin_w*(i), hist_h - cvRound(r_hist.at<float>(i))), Scalar(0, 0, 255));
    }

    return histImage;

}

int main(){
    Mat src;
    src = imread("E:\\test\\test.jpg");
    src.convertTo(src, CV_8U);
    cout << src.channels() << endl;
    namedWindow("orgin", WINDOW_AUTOSIZE);
    imshow("origin", src);

    Mat histImage = histogramCal(src);
    namedWindow("hist", WINDOW_AUTOSIZE);
    imshow("hist", histImage);

    // 均衡?
    Mat hist;
    vector<Mat>bgr;
    split(src, bgr);
    equalizeHist(bgr[0], bgr[0]);
    equalizeHist(bgr[1], bgr[1]);
    equalizeHist(bgr[2], bgr[2]);
    // 合并
    Mat dst;
    merge(bgr, dst);
    namedWindow("equalize", WINDOW_AUTOSIZE);
    imshow("equalize", dst);

    Mat equalHist = histogramCal(dst);
    namedWindow("equalhist", WINDOW_AUTOSIZE);
    imshow("equalhist", equalHist);

    waitKey(0);

    return 0;
}

函数学习

split 通道分离
  • 注: opencv中. RGB三个通道是反过来的.
void split(const Mat& src,Mat *mvBegin);
void split(InputArray m, OutputArrayOfArrays mv);  
// 用法很显然,第一个参数为要进行分离的图像矩阵,第二个参数可以是Mat数组的首地址,或者一个vector<Mat>对象

std::vector<Mat> channels;  
Mat aChannels[3];  
//src为要分离的Mat对象  
split(src, aChannels);              //利用数组分离  
split(src, channels);             //利用vector对象分离  

imshow("B",channels[0]);  
imshow("G",channels[1]);  
imshow("R",channels[2]);  
Merge 通道合并
void merge(  
    const vector<cv::Mat>& mv, // 输入的多通道序列(n个单通道序列) 
    cv::OutputArray dst // 输出图像,包含mv  
);


// version1 第一个参数是图像矩阵数组,第二个参数是需要合并矩阵的个数,第三个参数是输出
void merge(const Mat* mv, size_t count, OutputArray dst);  
// version2 第一个参数是图像矩阵向量容器,第二个参数是输出,这种方法无需说明需要合并的矩阵个数,vector对象自带说明
void merge(const vector& mv, OutputArray dst );

std::vector<Mat> channels;  
Mat aChannels[3];  

split(src, channels);              //分离到数组  
split(src, aChannels);             //分离到vector对象  
//do something  
//xxxx  
merge(channels, 3, mergeImg);  
merge(aChannels, mergeImg);  
normalize 矩阵归一化
  • 归一化: 将需要处理的数据经过处理后(通过某种算法)限定在一定范围内.
void normalize(InputArray src,OutputArraydst, double alpha = 1, double beta = 0, intnorm_type = NORM_L2, int dtype = -1, InputArray mask = noArray());
/*
src
    输入数组
dst
    输出数组,支持原地运算
alpha
    range normalization模式的最小值
beta 
    range normalization模式的最大值,不用于norm normalization(范数归一化)模式。
normType
    归一化的类型,可以有以下的取值:
    NORM_MINMAX:数组的数值被平移或缩放到一个指定的范围,线性归一化,一般较常用。
    NORM_INF:此类型的定义没有查到,根据OpenCV 1的对应项,可能是归一化数组的C-范数(绝对值的最大值)
    NORM_L1 :  归一化数组的L1-范数(绝对值的和)
    NORM_L2: 归一化数组的(欧几里德)L2-范数
dtype
    dtype为负数时,输出数组的type与输入数组的type相同;
否则,输出数组与输入数组只是通道数相同,而tpye=CV_MAT_DEPTH(dtype).
mask
    操作掩膜,用于指示函数是否仅仅对指定的元素进行操作。
*/
equalizeHisst 直方图均衡化
  • 直方图均衡化,,用于提高图像的质量
void cv::equalizeHist   (   
        InputArray  src,
        OutputArray dst 
 );
/*
第一个参数表示输入图像,必须为灰度图(8位,单通道图)。
第二个参数表示输出图像
*/

// demo
#include <opencv2/imgproc/imgproc.hpp>  
#include <opencv2/highgui/highgui.hpp>  
#include <iostream>  
#include <stdio.h>  

using namespace cv;  
using namespace std;  
int main()  
{  
    Mat src = imread("D:6.jpg", 1);  
    cvtColor(src, src, CV_BGR2GRAY);  
    Mat dst;  
    equalizeHist(src, dst);  
    imshow("shiyan", dst);  
    waitKey(0);  
    return 0;  
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值