Day38 Qchart绘制灰度直方图
1.场景
一个小场景是,点击按钮将显示一张图片,灰度直方图将立即更新该图片的灰度统计结果。主要借助此场景说明直方图的创建步骤。实际应用中,可以在采集图片流时适时发出更新灰度统计信号,即可实时显示当前画面的统计信息,用于指示调节曝光时间。
2.步骤
1.qt的组件中安装qt chart模块
2.Qt ,pro文件中添加chart模块
QT += core gui charts
3.添加模块相关的头文件
#include <QChart>
#include <QChartView>
#include <QtCharts/QChart>
#include <QtCharts/QBarSeries>
#include <QtCharts/QBarSet>
#include <QtCharts/QCategoryAxis>
#include <QtCharts/QValueAxis>
4.初始化画图程序
在界面初始化的时候,画一个直方图的框架,留下数据更新接口,程序运行时,通过信号槽的方式,在槽函数中添加更新直方图数据的代码。现介绍初始化部分。可以将QChart类比为一个画布,它提供了绘制图表所需的各种属性和方法。可以在QChart对象上添加不同类型的图表元素,如曲线、柱状图、饼图等。QChart负责管理和绘制这些图表元素,并提供一些功能,如坐标轴、图例、背景等。而QChartView类则可以看作是一个显示器,它将QChart对象的内容显示在窗口中。QChartView提供了一个图表视图,可以在其中显示QChart对象,并支持用户交互操作,例如缩放、平移、选择等。QChartView还可以设置一些显示属性,如背景颜色、边框样式等。可以将QChart理解为图表的数据和样式的容器,而QChartView则是将这些数据和样式以图形的形式展示出来的视图。通过将QChart对象与QChartView对象结合使用,我们可以在窗口中创建、显示和操作各种类型的图表。QBarSeries包含多个QBarSet对象,每个QBarSet对象代表一个柱子的数据集。QCategoryAxis用于在水平方向上显示类别,例如产品名称。QValueAxis用于在垂直方向上显示值,例如销售量。代码如下:
void MainWindow::initHistogram()
{
grayChart= new QChart();//创建视图
grayChart->setTitle("Histogram");
QChartView* graphicsView = new QChartView(grayChart,ui->widget);//创建表格与视图绑定
graphicsView->setRenderHint(QPainter::Antialiasing);//抗锯齿
QVBoxLayout* layout_bottom_ = new QVBoxLayout(ui->widget);
layout_bottom_->setMargin(0);
layout_bottom_->setSpacing(0);
layout_bottom_->addWidget(graphicsView);
QBarSet * set = new QBarSet("灰度值",this);//柱子
set->setBrush(QBrush(Qt::gray));
set->setPen(QPen(Qt::gray));
//包含关系是:Qchart(QChartView显示)>>QBarSeries>>QBarSet
series = new QBarSeries(grayChart);//柱子族中只有一根柱子(一种柱子)
series->append(set);
series->setBarWidth(1);// 设置柱子宽度
grayChart->addSeries(series);// 向直方图中添加数据系列
grayChart->legend()->setVisible(false); // 显示图例
// 初始化坐标轴画笔和标签字体
QPen pen(Qt::black);
pen.setWidth(2);
QFont font;
font.setBold(true);
font.setPointSize(9);
// 设置横坐标
m_axisX = new QCategoryAxis();//水平方向上显示柱子族
m_axisX->setRange(0, 255);
// 设置x轴刻度标签
for (int i = 0; i <= 255; i+=20) {
m_axisX->append(QString::number(i), i);
}
m_axisX->append("0",0);
m_axisX->append("255",255);
m_axisX->setGridLineVisible(false);
m_axisX->setLabelsPosition(QCategoryAxis::AxisLabelsPositionOnValue);
grayChart->addAxis(m_axisX, Qt::AlignBottom);// 添加坐标轴
series->attachAxis(m_axisX);// 将坐标轴与数据系列绑定
m_axisX->setLinePen(pen);// 设置坐标轴及其网格线
m_axisX->setGridLinePen(pen);
m_axisX->setLabelsFont(font);
// 设置纵坐标
m_axisY = new QValueAxis();//水平方向上显示柱子族的对应数值
m_axisY->setLabelFormat("%d");// 设置坐标轴刻度
m_axisY->setTickCount(2);// 设置纵向刻度数目
m_axisY->setGridLineVisible(false);
grayChart->addAxis(m_axisY, Qt::AlignLeft); // 添加坐标轴
series->attachAxis(m_axisY);// 将坐标轴与数据系列绑定
m_axisY->setLinePen(pen); // 设置坐标轴及其网格线
m_axisY->setGridLinePen(pen);
m_axisY->setLabelsFont(font);
grayChart->setBackgroundBrush(QColor(255, 255, 255));
grayChart->setMargins(QMargins(0, 0, 0, 0)); // 设置边距,以增加边框的宽度
}
5.响应程序
在框架搭好的基础上,写一个槽函数用于更新直方图数据。需要注意,更新数据的时候需要从series中把原来的柱子clear掉,在添加新的柱子,如果试图清楚柱子的内容在更新柱子会出错。下面的程序是接收来自相应信号的QImage对象,然后通过遍历像素统计灰度分布,最后添加柱子对象barset更新直方图。
void MainWindow::doProcessUpdateHistogram(const QImage &img)
{
series->clear();
QBarSet *barSet = new QBarSet("灰度值",this);
QVector<int> newData(256, 0);
barSet->setBrush(QBrush(Qt::gray));
barSet->setPen(QPen(Qt::gray));
series->append(barSet);
QImage image = img.convertToFormat(QImage::Format_Grayscale8);
// 遍历每个像素 统计其灰度值
uchar * imgData = image.bits();
for (int x = 0; x < image.height()*image.width(); x++) {
newData[imgData[x]] = newData[imgData[x]]+1;
}
int y_range = 0;
for (int i = 0; i < 256; ++i) {
barSet->append(static_cast<qreal>(newData[i]));
if(newData[i] > y_range){
y_range = newData[i] ;
}
}
m_axisX->setRange(0, 255);
m_axisY->setRange(0, y_range);//设置纵坐标范围
grayChart->update();
}
3.源码与效果
源码链接