首页 > 解决方案 > 如何将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 文档中的其他材料,但问题仍然存在。关于如何解决这个问题的任何想法?

标签: c++qtopencvqt5

解决方案


使用这个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();
}

在此处输入图像描述

在以下链接中,您可以找到完整的示例。


推荐阅读