c++ - 如何将openCV中裁剪图像的数据数组转换为Qt中的RGB直方图
问题描述
我有一个由两个 QGraphicsView 组成的界面:一个 QGraphicsView 用于显示来自右摄像头的图像,第二个 QGraphicsView 用于显示来自左摄像头的图像。两个 QGraphicsViews 也用于上传图像(例如从文件),以便可以执行图像处理操作。例如,将图像上传到左侧 QGraphicsView 后,我就可以在图像的特定特征上绘制一个框并提取它。只要我右键单击鼠标按钮,我就会打开一个菜单。我正在努力解决的功能之一是我试图将从绘制的框派生的裁剪图像转换为 RGB 直方图。我正在使用 openCV 将图像转换为一系列数组,并将这些数组传递给 3 个 QLabels 以显示 R、G、B 直方图。但是我无法绘制 RGB 直方图并且可以 抓住错误。我附上 UI 的快照以获取信息:
代码也附在下面:
剪辑场景.h
#ifndef CLIPSCENE_H
#define CLIPSCENE_H
#include <QDialog>
#include <QGraphicsScene>
#include <QGraphicsPixmapItem>
#include "opencv2/imgproc.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/highgui/highgui.hpp"
namespace Ui {
class clipScene;
}
class clipScene : public QDialog
{
Q_OBJECT
public:
explicit clipScene(QWidget *parent = 0);
~clipScene();
void setImage(QImage img);
void setBoundingBox(QRect rect);
private slots:
void on_closeBtn_clicked();
void on_acceptBtn_clicked();
void showEvent(QShowEvent *);
private:
Ui::clipScene *ui;
QImage simg, simgR, simgG, simgB;
QRect srect;
QGraphicsScene *scene;
};
#endif // CLIPSCENE_H
和clipscene.cpp
#include "clipscene.h"
#include "ui_clipscene.h"
using namespace cv;
clipScene::clipScene(QWidget *parent) :
QDialog(parent),
ui(new Ui::clipScene)
{
ui->setupUi(this);
scene = new QGraphicsScene();
ui->graphicsViewClipped->setScene(scene);
ui->redImg->setText("<b>Calculate Graph</b>");
ui->greenImg->setText("<b>Calculate Graph</b>");
ui->blueImg->setText("<b>Calculate Graph</b>");
}
clipScene::~clipScene()
{
delete ui;
}
void clipScene::setImage(QImage img)
{
simg = img;
QGraphicsPixmapItem* item = new QGraphicsPixmapItem(QPixmap::fromImage(simg));
scene->addItem(item);
ui->graphicsViewClipped->show();
cv::Mat input = cv::Mat(simg.height(), simg.width(), QImage::Format_ARGB32, simg.bits(), simg.bytesPerLine());
cv::Mat channel[3];
// Establish the number of bins
int hbins = 30, sbins = 32;
int histSize[] = {hbins, sbins};
// Set the ranges ( for B,G,R) )
float hranges[] = { 0, 180 };
// saturation varies from 0 (black-gray-white) to 255 (pure spectrum color)
float sranges[] = { 0, 256 };
const float* histRange[] = { hranges, sranges };
bool uniform = true; bool accumulate = false;
split(input, channel);
int channels[] = {0, 1}; // Now for one channel (R)
MatND hist;
cv::calcHist(&input, 1, channels, Mat(), hist, 1, histSize, histRange, uniform, accumulate);
// The actual splitting.
double maxVal=0;
minMaxLoc(hist, 0, &maxVal, 0, 0);
int scale = 10;
Mat histImg = Mat::zeros(sbins*scale, hbins*10, CV_8UC3);
for( int h = 0; h < hbins; h++ )
for( int s = 0; s < sbins; s++ )
{
float binVal = hist.at<float>(h, s);
int intensity = cvRound(binVal*255/maxVal);
// The arrays of data in openCV should be used here to draw
// the histogram
}
ui->redImg->setScaledContents(true);
ui->redImg->setPixmap(QPixmap::fromImage(QImage(channel[0].data, channel[0].cols, channel[0].rows, channel[0].step, QImage::Format_ARGB32) \
.scaled(200,200,Qt::KeepAspectRatio,Qt::SmoothTransformation)));
}
我发现了这一点,并且我还在阅读 openCV 文档中的其他材料,但问题仍然存在。关于如何解决这个问题的任何想法?
解决方案
使用这个OpenCV的例子,也来展示下图的用法QChartView
,如下图:
#include <QApplication>
#include <QtCharts>
QT_CHARTS_USE_NAMESPACE
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
static cv::Mat QImageToMat(const QImage & image){
cv::Mat out;
switch(image.format()) {
case QImage::Format_Invalid:
{
cv::Mat empty;
empty.copyTo(out);
break;
}
case QImage::Format_RGB32:
{
cv::Mat view(image.height(),image.width(),CV_8UC4,(void *)image.constBits(),image.bytesPerLine());
view.copyTo(out);
break;
}
case QImage::Format_RGB888:
{
cv::Mat view(image.height(),image.width(),CV_8UC3,(void *)image.constBits(),image.bytesPerLine());
cv::cvtColor(view, out, cv::COLOR_RGB2BGR);
break;
}
default:
{
QImage conv = image.convertToFormat(QImage::Format_ARGB32);
cv::Mat view(conv.height(),conv.width(),CV_8UC4,(void *)conv.constBits(),conv.bytesPerLine());
view.copyTo(out);
break;
}
}
return out;
}
static std::vector<cv::Mat> calculate_histogram(const QImage & image){
cv::Mat src = QImageToMat(image);
std::vector<cv::Mat> bgr_planes;
cv::split(src, bgr_planes );
/// Establish the number of bins
int histSize = 256;
/// Set the ranges ( for B,G,R) )
float range[] = { 0, 256 } ;
const float* histRange = { range };
bool uniform = true; bool accumulate = false;
std::vector<cv::Mat> hist;
for(std::size_t i = 0; i < bgr_planes.size(); ++i){
hist.push_back(cv::Mat());
cv::calcHist( &bgr_planes[i], 1, 0, cv::Mat(), hist[i], 1, &histSize, &histRange, uniform, accumulate );
}
return hist;
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QImage image(":/lena.png");
QChartView *view = new QChartView;
QChart *chart = new QChart;
view->setChart(chart);
const QStringList titles{"Blue", "Green", "Red"};
std::vector<cv::Mat> hist_planes = calculate_histogram(image);
for(std::size_t i = 0; i< 3; ++i){
const cv::Mat mat = hist_planes[i];
QLineSeries *series = new QLineSeries;
series->setColor(QColor(titles[i]));
series->setName(titles[i]);
for(int j=0; j < mat.rows; ++j){
*series << QPoint(j, mat.at<float>(j));
}
chart->addSeries(series);
}
chart->createDefaultAxes();
chart->axisX()->setGridLineVisible(false);
chart->axisY()->setGridLineVisible(false);
QLabel *label = new QLabel;
label->setPixmap(QPixmap::fromImage(image));
QWidget w;
QHBoxLayout *lay = new QHBoxLayout(&w);
lay->addWidget(label);
lay->addWidget(view);
w.show();
return a.exec();
}
在以下链接中,您可以找到完整的示例。
推荐阅读
- android - 如何在 TextInputLayout 中为文本/标题/错误设置差异填充?
- c++ - TSubclassOf<> 不存储类类型
- python - 如何在python3中声明数组
- javascript - 尽管生产环境,IE11 中编译的 Vue 代码的控制台错误
- php - Laravel 路由组不会在 API 中返回数据
- svg - inkscape 扩展 - 隐蔽使用节点到路径节点
- c# - .NET Core 2.1 字符串。创建
- android - 在 travis(排毒)中测试 android.emu.release:-read-only 错误
- ios - 我可以在没有苹果开发者帐户的真实苹果设备上测试我的 Flutter 应用程序吗?如果可以,我该怎么做?
- c++ - C++ 数学特殊函数中的 std::complex<>:技术规范或提案