opencv 绘制直方图 并 重写鼠标事件 得到百分比,像素值

opencv 绘制直方图 并 重写鼠标事件 得到百分比,像素值


提示:以下是本篇文章正文内容,下面案例可供参考

一、获取直方图

获取直方图博文

二、通过重写鼠标事件获取百分比及像素值

1. cpp文件

#include "histogramview.h"

HistogramView::HistogramView(QWidget *parent)
    :QWidget(parent)
{
    this->init_view();
    this->init_connect();
    this->setMouseTracking(true);
    this->m_label->setMouseTracking(true);
}

void HistogramView::init_view()
{
    this->resize(300,260);
    this->setWindowTitle("直方图");
    this->m_title = new QLabel("通道",this);
    this->m_title->setGeometry(30,8,40,30);

    this->m_label = new QLabel(this);
    this->m_label->setGeometry(15,0,256,256);

    this->m_button = new QComboBox(this);
    this->m_button->setGeometry(120,10,70,25);
    this->m_button->addItem("明度");
    this->m_button->addItem("蓝色");
    this->m_button->addItem("绿色");
    this->m_button->addItem("红色");

    this->m_totalpixelname = new QLabel("总像素数:",this);
    this->m_totalpixelname->setGeometry(170,190,60,30);

    this->m_totalpixeldata = new QLabel(this);
    this->m_totalpixeldata->setGeometry(240,190,40,30);

    this->m_colorname = new QLabel("颜色值",this);
    this->m_colorname->setGeometry(15,190,60,30);

    this->m_color = new QLabel(this);
    this->m_color->setGeometry(85,190,60,20);

    this->m_pixelname = new QLabel("像素值",this);
    this->m_pixelname->setGeometry(15,210,60,30);

    this->m_pixel = new QLabel(this);
    this->m_pixel->setGeometry(85,210,60,30);

    this->m_percentagename = new QLabel("百分比",this);
    this->m_percentagename->setGeometry(15,230,60,30);

    this->m_percentag = new QLabel(this);
    this->m_percentag->setGeometry(85,230,60,30);
}

void HistogramView::init_connect()
{
    connect(this->m_button,SIGNAL(currentIndexChanged(int)),    //连接两个信号和槽
                this,SLOT(ChangeImage(int)));
}

QImage HistogramView::DrawGrayHistogram(QImage image)
{
    cv::Mat gray;
    cv::Mat src = this->QImage2Mat(image);
    cv::cvtColor(src, gray, CV_BGR2GRAY);
    this->m_Flag = GRAY;
    const int channels[] = { 0 };
    int dims = 1;     //设置直方图维度
    const int histSize[] = { 256 }; //直方图每一个维度划分的柱条的数目
    float pranges[] = { 0, 255 };//每个纬度的取值区间
    const float* ranges[] = { pranges };
    cv::calcHist(&gray, 1, channels, cv::Mat(), this->m_Gray_Hist, dims, histSize, ranges, true, false);
    int scale = 2;
    int hist_height = 256;
    cv::Mat hist_img = cv::Mat::zeros(hist_height, 256 * scale, CV_8UC3); //创建一个黑底的8位的3通道图像,高256,宽256*2
    double max_val;
    float total_pix=src.rows*src.cols;
    cv::minMaxLoc(this->m_Gray_Hist, 0, &max_val, 0, 0);//计算直方图的最大像素值
    //将像素的个数整合到 图像的最大范围内
    //遍历直方图得到的数据
    for (int i = 0; i < 255; i++)
    {
        float bin_val = this->m_Gray_Hist.at<float>(i);   //遍历hist元素(注意hist中是float类型)
        float bin_val2 = this->m_Gray_Hist.at<float>(i+1); //前一个像素值  绘制轮廓型
        int intensity = cvRound(bin_val*hist_height / max_val);  //绘制高度
        int intensity2 = cvRound(bin_val2*hist_height / max_val);
        cv::line(hist_img, cv::Point(i*scale,hist_height - intensity), cv::Point((i + 1)*scale - 1,hist_height - intensity2), cv::Scalar(255, 255, 255));
        //cv::rectangle(hist_img, cv::Point(i*scale, hist_height - 1), cv::Point((i + 1)*scale - 1, hist_height - intensity), cv::Scalar(255, 255, 255));//绘制直方图
    }
    /*for (int i = 0; i < 255; i++)
    {
        float bin_val = this->m_Gray_Hist.at<float>(i);   //遍历hist元素(注意hist中是float类型)
        float bin_val2 = this->m_Gray_Hist.at<float>(i+1); //前一个像素值
        int intensity = cvRound(bin_val*hist_height / max_val);  //绘制高度
        int intensity2 = cvRound(bin_val2*hist_height / max_val);
        cv::line(hist_img, cv::Point(i*scale,hist_height - intensity), cv::Point((i + 1)*scale - 1,hist_height - intensity2), cv::Scalar(255, 255, 255));
    }
    */
    this->m_totalpixeldata->setText(QString("%1").arg(total_pix));
    return this->Mat2QImage(hist_img);
}

QImage HistogramView::DrawBGRHistogram(QImage image, int flag)
{
    if(image.isNull())
        return image;
    cv::Mat src = this->QImage2Mat(image);
    std::vector<cv::Mat> bgr_planes;
    int dims = 1;
    const int histSize[] = { 256 };
    float pranges[] = { 0, 255 };
    const float* ranges[] = { pranges };
    cv::split(src, bgr_planes);
    int scale = 2;
    int hist_height = 256;
    cv::Mat hist_img = cv::Mat::zeros(hist_height, 256 * scale, CV_8UC3); //创建一个黑底的8位的3通道图像,高256,宽256*2
    double max_val;
    //总像素
    float total_pix=src.rows*src.cols;
    switch(flag)
    {
    case BLUE:
        this->m_Flag = BLUE;
        cv::calcHist(&bgr_planes[2], 1,0,cv::Mat(),this->m_Blue_Hist,dims, histSize, ranges, true, false);
        cv::minMaxLoc(m_Blue_Hist,0,&max_val,0,0);
        for (int i = 0; i < 256; i++)
        {
            float bin_val = m_Blue_Hist.at<float>(i);   //遍历hist元素(注意hist中是float类型)
            int intensity = cvRound(bin_val*hist_height / max_val);  //绘制高度
            cv::rectangle(hist_img, cv::Point(i*scale, hist_height - 1), cv::Point((i + 1)*scale - 1, hist_height - intensity), cv::Scalar(255, 255, 255));//绘制直方图
        }
        break;
    case GREEN:
        this->m_Flag = GREEN;
        cv::calcHist(&bgr_planes[1], 1,0,cv::Mat(),this->m_Green_Hist,dims, histSize, ranges, true, false);
        cv::minMaxLoc(this->m_Green_Hist,0,&max_val,0,0);
        for (int i = 0; i < 256; i++)
        {
            float bin_val = this->m_Green_Hist.at<float>(i);   //遍历hist元素(注意hist中是float类型)
            int intensity = cvRound(bin_val*hist_height / max_val);  //绘制高度
            cv::rectangle(hist_img, cv::Point(i*scale, hist_height - 1), cv::Point((i + 1)*scale - 1, hist_height - intensity), cv::Scalar(255, 255, 255));//绘制直方图
        }
        break;
    case RED:
        this->m_Flag = RED;
        cv::calcHist(&bgr_planes[0], 1,0,cv::Mat(),this->m_Red_Hist,dims, histSize, ranges, true, false);
        cv::minMaxLoc(this->m_Red_Hist,0,&max_val,0,0);
        for (int i = 0; i < 256; i++)
        {
            float bin_val = this->m_Red_Hist.at<float>(i);   //遍历hist元素(注意hist中是float类型)
            int intensity = cvRound(bin_val*hist_height / max_val);  //绘制高度
            cv::rectangle(hist_img, cv::Point(i*scale, hist_height - 1), cv::Point((i + 1)*scale - 1, hist_height - intensity), cv::Scalar(255, 255, 255));//绘制直方图
        }
        break;
    }
    this->m_totalpixeldata->setText(QString("%1").arg(total_pix));
    return this->Mat2QImage(hist_img);

}

void HistogramView::SetQImage(QImage image)
{
    this->m_image = image;
    if(this->m_image.isNull())
    {
        qDebug()<<"image is null";
    }
    this->ChangeImage(0);
}

void HistogramView::ChangeImage(int index)
{
    QImage image;
    switch (index)
    {
    case GRAY:
        image = this->DrawGrayHistogram(this->m_image);
        break;
    case BLUE:
        image = this->DrawBGRHistogram(this->m_image,BLUE);
        break;
    case GREEN:
        image = this->DrawBGRHistogram(this->m_image,GREEN);
        break;
    case RED:
        image = this->DrawBGRHistogram(this->m_image,RED);
        break;
    }
    if(!image.isNull())
    {
        QPixmap I_map = QPixmap::fromImage(image);
        I_map = I_map.scaled(this->m_label->width(), this->m_label->height(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
        this->m_label->setPixmap(I_map);
    }
}

cv::Mat HistogramView::QImage2Mat(QImage image)
{
    cv::Mat mat;
    switch (image.format())
    {
    case QImage::Format_ARGB32:
    case QImage::Format_RGB32:
    case QImage::Format_ARGB32_Premultiplied:
        mat = cv::Mat(image.height(), image.width(), CV_8UC4, (void*)image.constBits(), image.bytesPerLine());
        break;
    case QImage::Format_RGB888:
        mat = cv::Mat(image.height(), image.width(), CV_8UC3, (void*)image.constBits(), image.bytesPerLine());
        cv::cvtColor(mat, mat,cv::COLOR_BGR2RGB);
        break;
    case QImage::Format_Indexed8:
        mat = cv::Mat(image.height(), image.width(), CV_8UC1, (void*)image.constBits(), image.bytesPerLine());
        break;
    }
    return mat;
}

//鼠标的移动事件
void HistogramView::mouseMoveEvent(QMouseEvent *p)
{
    // 用来限制小数的位数
    char f = 'g';
    if(p->pos().x() >= 15 && p->pos().y() >= 65 && p->pos().x() <= 271 && p->pos().y() <= 190)
    {
        switch (this->m_Flag)
        {
        case GRAY:
            if(!this->m_Gray_Hist.empty())
            {
                this->m_color->setText(QString::number(p->pos().x()-15));
                this->m_pixel->setText(QString::number(this->m_Gray_Hist.at<float>(p->pos().x()-15)));
                this->m_percentag->setText(QString("%1 %").arg(QString::number(float(p->pos().x()-15)/256*100,f,4)));
            }
            break;
        case BLUE:
            if(!this->m_Blue_Hist.empty())
            {
                this->m_color->setText(QString::number(p->pos().x()-15));
                this->m_pixel->setText(QString::number(this->m_Blue_Hist.at<float>(p->pos().x()-15)));
                this->m_percentag->setText(QString("%1 %").arg(QString::number(float(p->pos().x()-15)/256*100,f,4)));
            }
            break;
        case GREEN:
            if(!this->m_Green_Hist.empty())
            {
                this->m_color->setText(QString::number(p->pos().x()-15));
                this->m_pixel->setText(QString::number(this->m_Green_Hist.at<float>(p->pos().x()-15)));
                this->m_percentag->setText(QString("%1 %").arg(QString::number(float(p->pos().x()-15)/256*100,f,4)));
            }
            break;
        case RED:
            if(!this->m_Red_Hist.empty())
            {
                this->m_color->setText(QString::number(p->pos().x()-15));
                this->m_pixel->setText(QString::number(this->m_Red_Hist.at<float>(p->pos().x()-15)));
                this->m_percentag->setText(QString("%1 %").arg(QString::number(float(p->pos().x()-15)/256*100,f,4)));
            }
            break;
        default:
            break;
        }
    }
    else
    {
        this->m_color->setText("");
        this->m_pixel->setText("");
        this->m_percentag->setText("");
    }
}

QImage HistogramView::Mat2QImage(cv::Mat mat)
{
    if(mat.type() == CV_8UC1)
    {
        QImage image(mat.cols, mat.rows, QImage::Format_Indexed8);
        image.setColorCount(256);
        for(int i = 0; i < 256; i++)
        {
            image.setColor(i, qRgb(i, i, i));
        }
        uchar *pSrc = mat.data;
        for(int row = 0; row < mat.rows; row ++)
        {
            uchar *pDest = image.scanLine(row);
            memcpy(pDest, pSrc, mat.cols);
            pSrc += mat.step;
        }
        return image;
    }
    else if(mat.type() == CV_8UC3)
    {
        const uchar *pSrc = (const uchar*)mat.data;
        QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_RGB888);
        return image.rgbSwapped();
    }
    else if(mat.type() == CV_8UC4)
    {
        const uchar *pSrc = (const uchar*)mat.data;
        QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_ARGB32);
        return image.copy();
    }
    else
    {
        return QImage();
    }
}

2. .h文件

#ifndef HISTOGRAMVIEW_H
#define HISTOGRAMVIEW_H

#include <QWidget>
#include <QLabel>
#include <QComboBox>
#include <opencv2/opencv.hpp>
#include <QImage>
#include <iostream>
#include <QPixmap>
#include <QObject>
#include <QDebug>
#include <QMouseEvent>
#define GRAY 0
#define BLUE 1
#define GREEN 2
#define RED 3

class HistogramView:public QWidget
{
    Q_OBJECT
public:
    HistogramView(QWidget *parent = 0);
    void init_view();
    void init_connect();
    cv::Mat QImage2Mat(QImage image);
    void mouseMoveEvent(QMouseEvent *p);
    QImage Mat2QImage(cv::Mat mat);
    QImage DrawGrayHistogram(QImage image);
    QImage DrawBGRHistogram(QImage image,int flag);
    void SetQImage(QImage image);

public slots:
    void ChangeImage(int index);

private:
    QComboBox * m_button;
    QLabel * m_title;
    QLabel * m_label;
    QImage   m_image;
    QLabel * m_totalpixelname;
    QLabel * m_totalpixeldata;
    QLabel * m_pixelname;
    QLabel * m_pixel;
    QLabel * m_colorname;
    QLabel * m_color;
    QLabel * m_percentagename;
    QLabel * m_percentag;
    cv::Mat m_Gray_Hist;
    cv::Mat m_Blue_Hist;
    cv::Mat m_Green_Hist;
    cv::Mat m_Red_Hist;
    int m_Flag = -1;
};

总结

注释都在代码里,效果图如下,如果想看Mat跟QImage的互转可以到Mat与QImage 的互转
效果图
请添加图片描述
请添加图片描述
工程文件下载:下载地址

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BigProgrambug

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值