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 的互转
效果图
工程文件下载:下载地址