750 lines
23 KiB
C++
750 lines
23 KiB
C++
#pragma once
|
|
#include <QApplication>
|
|
#include <QWidget>
|
|
#include <QVBoxLayout>
|
|
#include <QLabel>
|
|
#include <QGraphicsView>
|
|
#include <QGraphicsScene>
|
|
#include <QGraphicsPixmapItem>
|
|
#include <QPixmap>
|
|
#include <QWheelEvent>
|
|
#include <QKeyEvent>
|
|
#include <opencv.hpp>
|
|
#include <QMenu>
|
|
#include <QAction>
|
|
#include <QTimer>
|
|
#include <qmessagebox.h>
|
|
#include <qmutex.h>
|
|
#include <uiModule/components/fancyButton.h>
|
|
#include "qscrollbar.h"
|
|
#include "global.h"
|
|
#include <qqueue.h>
|
|
#include <qthread.h>
|
|
#include <qcombobox.h>
|
|
#include <qmap.h>
|
|
#include <qbuffer.h>
|
|
#include <qimagewriter.h>
|
|
#include <qgraphicsproxywidget.h>
|
|
#include <QWaitCondition>
|
|
#include <QImage>
|
|
#include <QMetaType>
|
|
class ImageWidgetManager;
|
|
|
|
// 后台图像处理(压缩 + 颜色空间转换)线程工作对象
|
|
class ImageProcessWorker : public QObject {
|
|
Q_OBJECT
|
|
public:
|
|
explicit ImageProcessWorker(int threshold, QObject* parent = nullptr)
|
|
: QObject(parent), threshold(threshold) {}
|
|
|
|
public slots:
|
|
void process(const cv::Mat& img, const QString& type) {
|
|
if (img.empty()) return;
|
|
QImage qimg = matToQImageWithCompress(img, threshold);
|
|
emit imageReady(type, qimg);
|
|
}
|
|
|
|
signals:
|
|
void imageReady(const QString& type, const QImage& img);
|
|
|
|
private:
|
|
int threshold = 0;
|
|
|
|
QImage matToQImageWithCompress(const cv::Mat& srcIn, int thr) {
|
|
if (srcIn.empty()) return QImage();
|
|
cv::Mat src = srcIn;
|
|
while ((thr > 0) && (src.cols > thr || src.rows > thr)) {
|
|
cv::Mat half;
|
|
cv::resize(src, half, cv::Size(src.cols / 2, src.rows / 2), 0, 0, cv::INTER_AREA);
|
|
src = half;
|
|
}
|
|
cv::Mat display;
|
|
QImage img;
|
|
switch (src.type()) {
|
|
case CV_8UC3:
|
|
cv::cvtColor(src, display, cv::COLOR_BGR2RGB);
|
|
img = QImage(display.data, display.cols, display.rows, display.step, QImage::Format_RGB888).copy();
|
|
break;
|
|
case CV_8UC1:
|
|
img = QImage(src.data, src.cols, src.rows, src.step, QImage::Format_Grayscale8).copy();
|
|
break;
|
|
case CV_8UC4:
|
|
cv::cvtColor(src, display, cv::COLOR_BGRA2RGBA);
|
|
img = QImage(display.data, display.cols, display.rows, display.step, QImage::Format_RGBA8888).copy();
|
|
break;
|
|
default:
|
|
src.convertTo(display, CV_8UC3);
|
|
cv::cvtColor(display, display, cv::COLOR_BGR2RGB);
|
|
img = QImage(display.data, display.cols, display.rows, display.step, QImage::Format_RGB888).copy();
|
|
break;
|
|
}
|
|
return img;
|
|
}
|
|
};
|
|
//单画幅
|
|
class SonGraphicsView : public QGraphicsView{
|
|
public:
|
|
explicit SonGraphicsView(const QString& nameIn)
|
|
: name(nameIn),
|
|
scene(new QGraphicsScene(this)),
|
|
//rectGroup(new QGraphicsItemGroup()),
|
|
imageWidth(1),
|
|
imageHeight(1),
|
|
m_isPan(false),
|
|
rightClicked(false){
|
|
QMutexLocker locker(&mutex);
|
|
setDragMode(QGraphicsView::NoDrag);
|
|
setInteractive(false);
|
|
setEnabled(false);
|
|
setObjectName("SonGraphicsView");
|
|
|
|
//scene->addItem(rectGroup);
|
|
setScene(scene);
|
|
#if switchToTongYongUi == true
|
|
setStyleSheet(R"(
|
|
QGraphicsView#SonGraphicsView {
|
|
background: rgb(32, 36, 40);
|
|
background-repeat: no-repeat;
|
|
background-position: center center;
|
|
border-radius: 10px; /* 圆角半径 */
|
|
}
|
|
)");
|
|
|
|
#else
|
|
setStyleSheet(R"(
|
|
QGraphicsView#SonGraphicsView {
|
|
background: transparent;
|
|
background-image: url(:/icon/icon/waitting.png);
|
|
background-repeat: no-repeat;
|
|
background-position: center center;
|
|
})");
|
|
#endif
|
|
}
|
|
|
|
void setImg(const QPixmap& pixmap) {
|
|
showImg(pixmap);
|
|
}
|
|
|
|
void resetImage() {
|
|
QMutexLocker locker(&mutex);
|
|
scene->clear();
|
|
pixmapItem = nullptr;
|
|
setEnabled(false);
|
|
}
|
|
|
|
|
|
protected:
|
|
void wheelEvent(QWheelEvent* event) override {
|
|
if (scene->items().isEmpty())
|
|
return;
|
|
|
|
QPoint numDegrees = event->angleDelta() / 8;
|
|
if (!numDegrees.isNull()) {
|
|
zoom(numDegrees / 15);
|
|
centerOn(currentPos);
|
|
}
|
|
event->accept();
|
|
}
|
|
|
|
void keyPressEvent(QKeyEvent* event) override {
|
|
// 可以添加快捷键重置视图等操作
|
|
}
|
|
|
|
void mousePressEvent(QMouseEvent* event) override {
|
|
if (event->button() == Qt::LeftButton) {
|
|
togglePan(true, event->pos());
|
|
event->accept();
|
|
}
|
|
else if (event->button() == Qt::RightButton) {
|
|
startPos = mapToScene(event->pos());
|
|
rightClicked = true;
|
|
|
|
//rectItem = new QGraphicsRectItem(QRectF(startPos, QSizeF(0, 0)));
|
|
//rectItem->setPen(QPen(Qt::red, 5, Qt::DashLine));
|
|
//rectGroup->addToGroup(rectItem);
|
|
update();
|
|
}
|
|
else {
|
|
event->ignore();
|
|
}
|
|
}
|
|
|
|
void mouseMoveEvent(QMouseEvent* event) override {
|
|
currentPos = mapToScene(event->pos());
|
|
|
|
/* if (rightClicked && rectItem) {
|
|
QPointF endPos = currentPos;
|
|
qreal width = endPos.x() - startPos.x();
|
|
qreal height = endPos.y() - startPos.y();
|
|
rectItem->setRect(startPos.x(), startPos.y(), width, height);
|
|
}*/
|
|
|
|
if (m_isPan) {
|
|
pan(event->pos());
|
|
event->accept();
|
|
}
|
|
else {
|
|
event->ignore();
|
|
}
|
|
}
|
|
|
|
void mouseReleaseEvent(QMouseEvent* event) override {
|
|
if (event->button() == Qt::LeftButton) {
|
|
togglePan(false);
|
|
event->accept();
|
|
}
|
|
//else if (event->button() == Qt::RightButton) {
|
|
// rightClicked = false;
|
|
// QPointF endPos = mapToScene(event->pos());
|
|
// qreal width = endPos.x() - startPos.x();
|
|
// qreal height = endPos.y() - startPos.y();
|
|
|
|
// deleteAllRect();
|
|
|
|
// if (width != 0 && height != 0) {
|
|
// double scaleRate = getMax(width == 0 ? 1.0 : rect().width() / width,height == 0 ? 1.0 : rect().height() / height);
|
|
// scale(scaleRate, scaleRate);
|
|
// centerOn(startPos + QPointF(width / 2, height / 2));
|
|
// }
|
|
//}
|
|
else {
|
|
event->ignore();
|
|
}
|
|
}
|
|
|
|
private:
|
|
QString name;
|
|
QGraphicsScene* scene = nullptr;
|
|
//QGraphicsItemGroup* rectGroup = nullptr;
|
|
//QGraphicsRectItem* rectItem = nullptr;
|
|
// QLabel* imgLabel = nullptr; // 删除
|
|
QGraphicsPixmapItem* pixmapItem = nullptr;
|
|
|
|
|
|
int imageWidth = 1;
|
|
int imageHeight = 1;
|
|
|
|
QPointF currentPos;
|
|
QPointF startPos;
|
|
bool rightClicked = false;
|
|
|
|
bool m_isPan = false;
|
|
QPoint m_prevPan;
|
|
|
|
QMutex mutex;
|
|
|
|
void showImg(const QPixmap& img) {
|
|
QMutexLocker locker(&mutex);
|
|
setEnabled(true);
|
|
setMouseTracking(true);
|
|
|
|
imageWidth = img.width();
|
|
imageHeight = img.height();
|
|
|
|
if (pixmapItem) {
|
|
scene->removeItem(pixmapItem);
|
|
delete pixmapItem;
|
|
pixmapItem = nullptr;
|
|
}
|
|
|
|
pixmapItem = new QGraphicsPixmapItem(img);
|
|
scene->addItem(pixmapItem);
|
|
|
|
setSceneRect(img.rect());
|
|
fitInView(scene->itemsBoundingRect(), Qt::KeepAspectRatio);
|
|
}
|
|
|
|
void zoom(const QPoint& factor) {
|
|
QRectF FOV = mapToScene(rect()).boundingRect();
|
|
float scaleX = static_cast<float>(imageWidth) / FOV.width();
|
|
float scaleY = static_cast<float>(imageHeight) / FOV.height();
|
|
|
|
double currentScale = transform().m11();
|
|
if ((factor.y() > 0 && currentScale > 10.0) || (factor.y() < 0 && currentScale < 0.1))
|
|
return;
|
|
|
|
scale(factor.y() > 0 ? 1.2 : 0.8, factor.y() > 0 ? 1.2 : 0.8);
|
|
}
|
|
|
|
void togglePan(bool pan, const QPoint& startPos = QPoint()) {
|
|
if (pan == m_isPan)
|
|
return;
|
|
|
|
m_isPan = pan;
|
|
m_prevPan = pan ? startPos : QPoint(0, 0);
|
|
setCursor(pan ? Qt::ClosedHandCursor : Qt::ArrowCursor);
|
|
}
|
|
|
|
void pan(const QPoint& panTo) {
|
|
QPoint delta = panTo - m_prevPan;
|
|
m_prevPan = panTo;
|
|
|
|
horizontalScrollBar()->setValue(horizontalScrollBar()->value() - delta.x());
|
|
verticalScrollBar()->setValue(verticalScrollBar()->value() - delta.y());
|
|
}
|
|
|
|
void deleteAllRect() {
|
|
/*if (!rectGroup)
|
|
return;
|
|
|
|
for (QGraphicsItem* item : rectGroup->childItems()) {
|
|
QGraphicsRectItem* rect = qgraphicsitem_cast<QGraphicsRectItem*>(item);
|
|
if (rect) {
|
|
rectGroup->removeFromGroup(rect);
|
|
scene->removeItem(rect);
|
|
delete rect;
|
|
}
|
|
}*/
|
|
}
|
|
};
|
|
//切换窗口 在切换时用pixmap替换现有的以实现
|
|
class ImageWidget : public QWidget {
|
|
Q_OBJECT
|
|
public:
|
|
QComboBox switchBox;
|
|
QMutex switchViewerMutex;
|
|
|
|
//缩放状态相关
|
|
QPushButton* zoombtn;
|
|
bool isZoomed = false;
|
|
QSize originalSize;
|
|
QPoint originalPosition;
|
|
QGridLayout* parentGridLayout = nullptr;
|
|
int originalRow = -1;
|
|
int originalColumn = -1;
|
|
int originalRowSpan = 1;
|
|
int originalColumnSpan = 1;
|
|
|
|
ImageWidget(QWidget* parent = nullptr) : QWidget(parent) {
|
|
qRegisterMetaType<cv::Mat>("cv::Mat");
|
|
QVBoxLayout* layout = new QVBoxLayout(this);
|
|
setObjectName("ImageWidget");
|
|
setStyleSheet(R"(
|
|
#ImageWidget{
|
|
background: rgb(50, 55, 60);
|
|
})");
|
|
layout->setContentsMargins(2, 2, 2, 2);
|
|
viewer = new SonGraphicsView("");
|
|
this->setMaximumSize(9999, 9999);
|
|
|
|
QPalette palette;
|
|
palette.setColor(QPalette::WindowText, Qt::white);
|
|
QFont font("微软雅黑", 8 , QFont::Bold);
|
|
QWidget* hWidget = new QWidget(this);
|
|
QHBoxLayout* hLayout = new QHBoxLayout(hWidget);
|
|
hWidget->setFixedHeight(16);
|
|
|
|
/* auto spaceItem = new QSpacerItem(100, 1);
|
|
hLayout->addSpacerItem(spaceItem);*/
|
|
|
|
zoombtn = new QPushButton();
|
|
zoombtn->setFixedSize(16, 16);
|
|
zoombtn
|
|
->setStyleSheet(
|
|
R"(
|
|
QPushButton {
|
|
background-color: rgba(0, 0, 0, 0.5);
|
|
border: 1px solid rgba(255, 255, 255, 0.3);
|
|
border-radius: 3px;
|
|
}
|
|
QPushButton:hover {
|
|
background-color: rgba(0, 0, 0, 0.7);
|
|
border: 1px solid rgba(255, 255, 255, 0.5);
|
|
}
|
|
)"
|
|
);
|
|
zoombtn->setIcon(QPixmap(":icon/icon/fullscreen.png"));
|
|
zoombtn->setToolTip("放大窗口");
|
|
hLayout->addWidget(zoombtn);
|
|
connect(zoombtn, &QPushButton::clicked, this, &ImageWidget::toggleZoom);
|
|
|
|
|
|
label = new QLabel(u8"相机标签");
|
|
label->setAlignment(Qt::AlignLeft);
|
|
label->setFont(font);
|
|
label->setPalette(palette);
|
|
label->setFixedHeight(21);
|
|
|
|
switchBox.setFont(font);
|
|
switchBox.setPalette(palette);
|
|
switchBox.setFixedHeight(21);
|
|
switchBox.setFixedWidth(100);
|
|
|
|
connect(&switchBox, &QComboBox::currentTextChanged, [=](QString type)
|
|
{
|
|
switchViewType(type);
|
|
});
|
|
switchBox.hide();
|
|
label->setAlignment(Qt::AlignCenter);
|
|
hLayout->addWidget(label);
|
|
hLayout->addWidget(&switchBox);
|
|
hLayout->setContentsMargins(0, 0, 0, 0);
|
|
|
|
//hLayout->addWidget(switchBtn);
|
|
|
|
layout->addWidget(hWidget);
|
|
layout->addWidget(viewer);
|
|
|
|
viewer->setDragMode(QGraphicsView::ScrollHandDrag);
|
|
viewer->setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
|
|
viewer->setRenderHint(QPainter::Antialiasing);
|
|
viewer->setRenderHint(QPainter::SmoothPixmapTransform);
|
|
viewer->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
|
viewer->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
|
|
|
//view->fitInView(item, Qt::KeepAspectRatio);
|
|
//view->setBackgroundBrush(QBrush(QColor(0, 0, 0)));
|
|
//QPixmap backgroundImage(".//icon//watting.png");
|
|
//QGraphicsPixmapItem* backgroundItem = new QGraphicsPixmapItem(backgroundImage);
|
|
//view->scene->addItem(backgroundItem);
|
|
//
|
|
//setContextMenuPolicy(Qt::CustomContextMenu);
|
|
//(this, &QWidget::customContextMenuRequested, this, &ImageWidget::showContextMenu);
|
|
|
|
// 后台线程初始化
|
|
workerThread = new QThread(this);
|
|
worker = new ImageProcessWorker(uiShowImgCompressThreshold);
|
|
worker->moveToThread(workerThread);
|
|
connect(this, &ImageWidget::requestProcess, worker, &ImageProcessWorker::process, Qt::QueuedConnection);
|
|
connect(worker, &ImageProcessWorker::imageReady, this, &ImageWidget::onImageReady, Qt::QueuedConnection);
|
|
workerThread->start();
|
|
}
|
|
~ImageWidget(){
|
|
if (workerThread) {
|
|
workerThread->quit();
|
|
workerThread->wait();
|
|
}
|
|
}
|
|
void setTitle(const QString& text) {
|
|
label->setText(text);
|
|
}
|
|
void createViewer(QString name){
|
|
map.insert(name, QPixmap());
|
|
switchBox.addItem(name);
|
|
}
|
|
|
|
//设置父网格布局和位置信息
|
|
void setParentGridLayout(QGridLayout* gridLayout, int row, int column, int rowSpan, int columnSpan) {
|
|
parentGridLayout = gridLayout;
|
|
originalRow = row;
|
|
originalColumn = column;
|
|
originalRowSpan = rowSpan;
|
|
originalColumnSpan = columnSpan;
|
|
originalSize = this->size();
|
|
|
|
}
|
|
|
|
void updateZoomButtonVisibility() {
|
|
if (parentGridLayout) {
|
|
int rowCount = parentGridLayout->rowCount();
|
|
int columnCount = parentGridLayout->columnCount();
|
|
|
|
if (rowCount < 3 && columnCount < 3) {
|
|
zoombtn->hide();
|
|
}
|
|
else {
|
|
zoombtn->show();
|
|
}
|
|
}
|
|
}
|
|
|
|
public slots:
|
|
//combobox切换槽
|
|
void switchViewType(QString name)
|
|
{
|
|
QMutexLocker locker(&switchViewerMutex);
|
|
auto& it = map.find(name);
|
|
if (it == map.end())
|
|
{
|
|
QString listName;
|
|
for (auto it = map.begin(); it != map.end(); ++it)listName.append(it.key() + ",");
|
|
qDebug() << u8"未找到对应的viewer,输入:" << name << u8" 现有:"<< listName;
|
|
return;
|
|
}
|
|
if (it.value().isNull() == false)
|
|
viewer->setImg(it.value());
|
|
else
|
|
viewer->resetImage();
|
|
|
|
}
|
|
//void sendImg(QString type,QPixmap resImgInput)
|
|
//{
|
|
// std::string typer = type.toStdString();
|
|
// auto& it = map.find(type);
|
|
// if (it == map.end())
|
|
// {
|
|
// QString listName;
|
|
// for (auto it = map.begin(); it != map.end(); ++it)listName.append(it.key() + ",");
|
|
// qDebug() << u8"未找到对应的viewer,输入:" << type << u8" 现有:" << listName;
|
|
// return;
|
|
// }
|
|
// if (resImgInput.isNull()) {
|
|
// return;
|
|
// }
|
|
// it.value() = resImgInput;
|
|
// QMutexLocker locker(&switchViewerMutex);
|
|
// if (type == switchBox.currentText())
|
|
// showImgOnGraphicsView(resImgInput);
|
|
//}
|
|
////无视当前类型直接显示
|
|
//void showImgOnGraphicsView(QPixmap imageMat) {
|
|
// viewer->setImg(imageMat);
|
|
//}
|
|
void accpectImg(cv::Mat img, QString type){
|
|
auto& it = map.find(type);
|
|
if (it == map.end())
|
|
{
|
|
QString listName;
|
|
for (auto it = map.begin(); it != map.end(); ++it)listName.append(it.key() + ",");
|
|
qDebug() << u8"未找到对应的viewer,输入:" << type << u8" 现有:" << listName;
|
|
return;
|
|
}
|
|
// 异步处理(仅发送到后台线程)
|
|
emit requestProcess(img, type);
|
|
}
|
|
void onImageReady(const QString& type, const QImage& qimg) {
|
|
if (qimg.isNull()) return;
|
|
QPixmap px = QPixmap::fromImage(qimg);
|
|
{
|
|
QMutexLocker locker(&mapMutex);
|
|
map[type] = px;
|
|
}
|
|
if (type == switchBox.currentText()) {
|
|
viewer->setImg(px);
|
|
}
|
|
else if (type == "null") {
|
|
viewer->setImg(px);
|
|
}
|
|
}
|
|
|
|
//缩放
|
|
void toggleZoom() {
|
|
if (!parentGridLayout) return;
|
|
|
|
if (!isZoomed) {
|
|
zoomIn();// 放大
|
|
}
|
|
else {
|
|
zoomOut();//缩小
|
|
}
|
|
}
|
|
// 放大窗口
|
|
void zoomIn() {
|
|
if (isZoomed) return;
|
|
if (!parentGridLayout) return;
|
|
|
|
// 保存原始状态
|
|
originalSize = this->size();
|
|
|
|
// 在网格布局中重新放置,占据更多空间
|
|
parentGridLayout->removeWidget(this);
|
|
|
|
//计算父布局的总行数和总列数
|
|
int maxRowSpan = parentGridLayout->rowCount();// 父布局总行数
|
|
int maxColSpan = parentGridLayout->columnCount();// 父布局总列数
|
|
//放大后的跨度
|
|
int zoomColSize = maxColSpan - 1;
|
|
int zoomRowSize = maxRowSpan - 1;
|
|
if (originalRow >= zoomRowSize -1 || originalColumn >= zoomColSize -1) {
|
|
int x = qMax(0, originalRow - (zoomRowSize - 1));
|
|
int y = qMax(0, originalColumn - (zoomColSize - 1));
|
|
parentGridLayout->addWidget(this, x, y, zoomRowSize, zoomColSize);
|
|
}
|
|
else{
|
|
parentGridLayout->addWidget(this, originalRow, originalColumn, zoomRowSize, zoomColSize);
|
|
}
|
|
|
|
this->raise();
|
|
// 更新按钮状态
|
|
isZoomed = true;
|
|
zoombtn->setIcon(QIcon(":/icon/icon/fullscreen-exit.png"));
|
|
zoombtn->setToolTip("缩小窗口");
|
|
|
|
// 强制更新布局
|
|
parentGridLayout->update();
|
|
this->update();
|
|
}
|
|
// 缩小窗口
|
|
void zoomOut() {
|
|
if (!isZoomed) return;
|
|
|
|
// 恢复原始布局位置
|
|
parentGridLayout->removeWidget(this);
|
|
parentGridLayout->addWidget(this, originalRow, originalColumn, originalRowSpan, originalColumnSpan);
|
|
|
|
//更新按钮状态
|
|
isZoomed = false;
|
|
zoombtn->setIcon(QIcon(":/icon/icon/fullscreen.png"));
|
|
zoombtn->setToolTip("放大窗口");
|
|
|
|
//强制更新布局
|
|
parentGridLayout->update();
|
|
this->update();
|
|
}
|
|
protected:
|
|
void wheelEvent(QWheelEvent* event) override {
|
|
if (event->modifiers() & Qt::ControlModifier) {
|
|
double scaleFactor = 1.15;
|
|
if (event->angleDelta().y() < 0) {
|
|
scaleFactor = 1.0 / scaleFactor;
|
|
}
|
|
|
|
viewer->scale(scaleFactor, scaleFactor);
|
|
event->accept();
|
|
}
|
|
else {
|
|
QWidget::wheelEvent(event);
|
|
}
|
|
}
|
|
private:
|
|
#if switchToTongYongUi == 0
|
|
void paintEvent(QPaintEvent* event) override {
|
|
QWidget::paintEvent(event);
|
|
|
|
QPainter painter(this);
|
|
painter.setPen(QPen(Qt::white, 1));
|
|
painter.drawRect(rect().adjusted(1, 1, -2, -2));
|
|
}
|
|
#else
|
|
void paintEvent(QPaintEvent* event) override {
|
|
QPainter painter(this);
|
|
painter.setRenderHint(QPainter::Antialiasing);
|
|
|
|
int radius = 10; // 圆角半径
|
|
QRect r = rect();
|
|
|
|
// 填充圆角背景
|
|
painter.setBrush(QColor(50, 55, 60));
|
|
painter.setPen(Qt::NoPen);
|
|
painter.drawRoundedRect(r, radius, radius);
|
|
}
|
|
#endif
|
|
int in = 0;
|
|
QLabel* label;
|
|
SonGraphicsView* viewer;
|
|
QMap<QString,QPixmap> map;
|
|
QMutex mapMutex;
|
|
QThread* workerThread = nullptr;
|
|
ImageProcessWorker* worker = nullptr;
|
|
// 压缩: 如果任一边 > threshold 则按 1/2 缩,循环直到满足
|
|
QPixmap matToQPixmapWithCompress(const cv::Mat& srcIn, int threshold) {
|
|
if (srcIn.empty()) return QPixmap();
|
|
cv::Mat src = srcIn;
|
|
while ((threshold > 0) && (src.cols > threshold || src.rows > threshold)) {
|
|
cv::Mat half;
|
|
cv::resize(src, half, cv::Size(src.cols / 2, src.rows / 2), 0, 0, cv::INTER_AREA);
|
|
src = half;
|
|
}
|
|
cv::Mat display;
|
|
QImage img;
|
|
switch (src.type()) {
|
|
case CV_8UC3:
|
|
cv::cvtColor(src, display, cv::COLOR_BGR2RGB);
|
|
img = QImage(display.data, display.cols, display.rows, display.step, QImage::Format_RGB888).copy();
|
|
break;
|
|
case CV_8UC1:
|
|
img = QImage(src.data, src.cols, src.rows, src.step, QImage::Format_Grayscale8).copy();
|
|
break;
|
|
case CV_8UC4:
|
|
cv::cvtColor(src, display, cv::COLOR_BGRA2RGBA);
|
|
img = QImage(display.data, display.cols, display.rows, display.step, QImage::Format_RGBA8888).copy();
|
|
break;
|
|
default:
|
|
src.convertTo(display, CV_8UC3);
|
|
cv::cvtColor(display, display, cv::COLOR_BGR2RGB);
|
|
img = QImage(display.data, display.cols, display.rows, display.step, QImage::Format_RGB888).copy();
|
|
break;
|
|
}
|
|
return QPixmap::fromImage(std::move(img));
|
|
}
|
|
int uiShowImgCompressThreshold = 5000; // 超过该宽或高就压缩
|
|
signals:
|
|
void requestProcess(const cv::Mat& img, const QString& type);
|
|
};
|
|
|
|
//总
|
|
class ImageWidgetManager :public QWidget
|
|
{
|
|
Q_OBJECT
|
|
public:
|
|
ImageWidget* createViewer(QString windowName, std::vector<std::string> viewers, int xPos = -1, int yPos = -1)
|
|
{
|
|
ImageWidget* ImageView = new ImageWidget();
|
|
ImageWidgetList.push_back(ImageView);
|
|
map.insert({ windowName,ImageView });
|
|
ImageView->setTitle(windowName);
|
|
if (xPos == -1 || yPos == -1){
|
|
Layout->addWidget(ImageView);
|
|
}
|
|
else {
|
|
// 指定位置布局
|
|
Layout->addWidget(ImageView, yPos, xPos);
|
|
ImageView ->setParentGridLayout(Layout, yPos, xPos, 1, 1);
|
|
}
|
|
|
|
for (auto& viewer : viewers)
|
|
ImageView->createViewer(QString::fromStdString(viewer));
|
|
return ImageView;
|
|
}
|
|
|
|
void updateAllZoomButtonsVisibility() {
|
|
for (auto* widget : ImageWidgetList) {
|
|
widget->updateZoomButtonVisibility();
|
|
}
|
|
}
|
|
|
|
QGridLayout* Layout = new QGridLayout();
|
|
ImageWidgetManager()
|
|
{
|
|
this->setLayout(Layout);
|
|
Layout->setContentsMargins(0, 0, 0, 0);
|
|
// 设置布局属性,允许窗口缩放
|
|
/*Layout->setColumnStretch(0, 1);
|
|
Layout->setColumnStretch(1, 1);
|
|
Layout->setColumnStretch(2, 1);*/
|
|
}
|
|
~ImageWidgetManager()
|
|
{
|
|
}
|
|
bool showImg(const cv::Mat& img,
|
|
const QString& name,
|
|
const QString& type ="null"){
|
|
if (map.find(name) == map.end()) {
|
|
qCritical() << "图像接收方与现有不符=>" << name;
|
|
return false;
|
|
}
|
|
map[name]->accpectImg(img, type);
|
|
|
|
return true;
|
|
}
|
|
void adjustImageWidget() {
|
|
if (ImageWidgetList.isEmpty()) return;
|
|
std::vector<std::vector<ImageWidget*>> vec(Layout->rowCount(), std::vector<ImageWidget*>(Layout->columnCount(),nullptr));
|
|
for (auto& data : map) {
|
|
vec[data.second->originalRow][data.second->originalColumn] = data.second;
|
|
}
|
|
for (int row = 0; row < vec.size(); row++) {
|
|
for (int col = 0; col < vec[row].size(); col++) {
|
|
if (vec[row][col] == nullptr) {
|
|
if (col > 0) {
|
|
if (vec[row][col - 1] != nullptr) {
|
|
Layout->span
|
|
}
|
|
}
|
|
else {
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// 更新布局
|
|
Layout->update();
|
|
updateAllZoomButtonsVisibility();
|
|
}
|
|
private:
|
|
QMutex mutex;
|
|
QList< ImageWidget*>ImageWidgetList;
|
|
std::unordered_map<QString, ImageWidget*>map;
|
|
};
|
|
|