图像处理实验2:直方图均衡

本文介绍如何使用OpenCV计算灰度及彩色图像的归一化直方图,并实现直方图均衡化处理,包括灰度图像和彩色图像的均衡化。

要求

  1. 计算灰度图像的归一化直方图。
    具体内容:利用 OpenCV 对图像像素进行操作,计算归一化直方图.并在
    窗口中以图形的方式显示出来
  2. 灰度图像直方图均衡处理
    具体内容:通过计算归一化直方图,设计算法实现直方图均衡化处理。
  3. 彩色图像直方图均衡处理
    具体内容: 在灰度图像直方图均衡处理的基础上实现彩色直方图均衡
    处理。

过程

tips

通过使用数值乘以布尔值实现了对不同情况的统一处理。
plot_poly(hist_image,npdfs[i],Scalar(255*(0==i),255*(1==i),255*(2==i)));

二维vector初始化

大致如下

vector<vector<float>> name(rows, vector<float>(cols, value));

画图

不要使用int类型的bin_width,否则取整时所产生的误差会被放大多倍。

代码

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

#include <string>
#include <iostream>

using namespace cv;
using namespace std;

void calc_hist(Mat &I, vector<int> &hist)
{
    CV_Assert(I.depth() == CV_8U);
    CV_Assert(I.channels() == 1);

    for (auto it = I.begin<uchar>(), end = I.end<uchar>(); it != end; ++it)
        hist[*it]++;
    
    CV_DbgAssert(accumulate(hist.begin(), hist.end(), 0) == I.cols * I.rows);
}


void calc_hist(Mat &I, vector<float> &hist_prob)
{
    CV_Assert(I.depth() == CV_8U);
    CV_Assert(I.channels() == 1);

    int counts = I.cols * I.rows;
    vector<int> hist(256, 0);

    calc_hist(I, hist);

    for (int i = 0; i < 256; ++i)
        hist_prob[i] = (float)hist[i] / counts;

    CV_DbgAssert(accumulate(hist_prob.begin(), hist_prob.end(), 0) == 1);
}

void plot_poly(Mat &I, vector<float> points, const Scalar color)
{
    int width = I.cols, height = I.rows, pts_num = points.size();
    float max_y_point =  *max_element(points.begin(), points.end());

    for (size_t i = 1; i < points.size(); ++i)
        //Round operator should be done at last.
        line(I,
            Point(cvRound((float)(i-1) / pts_num * width), height - cvRound(points[i-1] / max_y_point * height)),
            Point(cvRound((float)(i) / pts_num * width), height - cvRound(points[i] /max_y_point * height)),
            color, 2, 8, 0);
}

void hist_equ_transform(vector<float> foo, Mat &lut)
{
    for (size_t i = 1; i < foo.size(); ++i)
        foo[i] += foo[i-1];
    uchar *p = lut.ptr();
    for (size_t i = 0; i < 256; ++i)
        p[i] = (uchar)(foo[i] * 255);
}

void hist_equ(Mat &src, Mat &dst, vector<float> &opdf, vector<float> &npdf)
{
    // calc_hist(src, opdf);
    Mat lut(1, 256, CV_8U);
    hist_equ_transform(opdf, lut);
    LUT(src, lut, dst);
    calc_hist(dst, npdf);
}

int main(int argc, char const *argv[])
{
    String image_name((argc>1)?(argv[1]):("img_test.jpg"));
    Mat image, image_gray, image_dst;
    image = imread(image_name, IMREAD_COLOR);
    if (image.empty()) {
        cout << "Cannot read image: " << image_name << std::endl;
        return -1;
    }   
    cvtColor(image, image_gray, CV_BGR2GRAY);

    namedWindow("image", CV_WINDOW_AUTOSIZE);
    namedWindow("hist", CV_WINDOW_AUTOSIZE);

    vector<float> opdf(256, 0.0), npdf(256, 0.0);
    Mat hist_img(480, 640, CV_8UC3, Scalar(0, 0, 0));

    calc_hist(image_gray, opdf);
    plot_poly(hist_img, opdf, Scalar(255, 255, 255));
    imshow("hist", hist_img);
    imshow("image", image_gray);
    waitKey();

    hist_equ(image_gray, image_dst, opdf, npdf);
    plot_poly(hist_img, npdf, Scalar(128, 128, 128));
    imshow("hist", hist_img);
    imshow("image", image_dst);
    waitKey();

    Mat hist_image(480, 640, CV_8UC3, Scalar(0, 0, 0));

    vector<Mat> bgr_planes;
    split(image, bgr_planes);
    vector<vector<float>> opdfs(3, vector<float>(256, 0.0));
    auto npdfs = opdfs;

    for (size_t i = 0; i < opdfs.size(); ++i) {
        calc_hist(bgr_planes[i], opdfs[i]);
        plot_poly(hist_image,opdfs[i],Scalar(255*(0==i),255*(1==i),255*(2==i)));
    }
    imshow("hist", hist_image);
    imshow("image", image);
    waitKey();

    for (size_t i = 0; i < npdfs.size(); ++i) {
        hist_equ(bgr_planes[i], bgr_planes[i], opdfs[i], npdfs[i]);
        plot_poly(hist_image,npdfs[i],Scalar(255*(0==i),255*(1==i),255*(2==i)));
    }
    merge(bgr_planes, image_dst);
    imshow("hist", hist_image);
    imshow("image", image_dst);
    waitKey();

    return 0;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值