add image rotation and flipping
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
#include <QGroupBox>
|
||||
#include <QDebug>
|
||||
#include <QPixmap>
|
||||
#include <QTransform>
|
||||
#include <gst/video/video.h>
|
||||
|
||||
VideoViewerWidget::VideoViewerWidget(QWidget *parent)
|
||||
@@ -19,10 +20,16 @@ VideoViewerWidget::VideoViewerWidget(QWidget *parent)
|
||||
m_statusLabel(nullptr),
|
||||
m_zoomSlider(nullptr),
|
||||
m_zoomLabel(nullptr),
|
||||
m_rotationCombo(nullptr),
|
||||
m_flipHorizontal(nullptr),
|
||||
m_flipVertical(nullptr),
|
||||
m_pipeline(nullptr),
|
||||
m_appSink(nullptr),
|
||||
m_zoomFactor(1.0),
|
||||
m_busWatchId(0)
|
||||
m_busWatchId(0),
|
||||
m_rotationAngle(0),
|
||||
m_flipHorizontalEnabled(false),
|
||||
m_flipVerticalEnabled(false)
|
||||
{
|
||||
initGStreamer();
|
||||
setupUI();
|
||||
@@ -77,6 +84,30 @@ void VideoViewerWidget::setupUI()
|
||||
zoomLayout->addWidget(m_zoomSlider);
|
||||
zoomLayout->addWidget(m_zoomLabel);
|
||||
|
||||
auto* transformLayout = new QHBoxLayout();
|
||||
transformLayout->addWidget(new QLabel("Rotation:", this));
|
||||
|
||||
m_rotationCombo = new QComboBox(this);
|
||||
m_rotationCombo->addItem("0°", 0);
|
||||
m_rotationCombo->addItem("90°", 90);
|
||||
m_rotationCombo->addItem("180°", 180);
|
||||
m_rotationCombo->addItem("270°", 270);
|
||||
m_rotationCombo->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||
m_rotationCombo->setMinimumWidth(70);
|
||||
connect(m_rotationCombo, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
||||
this, &VideoViewerWidget::onRotationChanged);
|
||||
transformLayout->addWidget(m_rotationCombo);
|
||||
|
||||
m_flipHorizontal = new QCheckBox("Flip H", this);
|
||||
connect(m_flipHorizontal, &QCheckBox::checkStateChanged, this, &VideoViewerWidget::onFlipHorizontalChanged);
|
||||
transformLayout->addWidget(m_flipHorizontal);
|
||||
|
||||
m_flipVertical = new QCheckBox("Flip V", this);
|
||||
connect(m_flipVertical, &QCheckBox::checkStateChanged, this, &VideoViewerWidget::onFlipVerticalChanged);
|
||||
transformLayout->addWidget(m_flipVertical);
|
||||
|
||||
transformLayout->addStretch();
|
||||
|
||||
auto* controlGroup = new QGroupBox("Viewer Controls", this);
|
||||
auto* controlLayout = new QVBoxLayout();
|
||||
|
||||
@@ -88,9 +119,11 @@ void VideoViewerWidget::setupUI()
|
||||
m_sourceType->addItem("TCP H.264 Stream", "tcp");
|
||||
m_sourceType->addItem("MJPEG HTTP Stream", "http");
|
||||
m_sourceType->addItem("Test Pattern", "test");
|
||||
m_sourceType->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLengthWithIcon);
|
||||
m_sourceType->setMinimumContentsLength(15);
|
||||
connect(m_sourceType, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
||||
this, &VideoViewerWidget::onSourceTypeChanged);
|
||||
sourceLayout->addWidget(m_sourceType);
|
||||
sourceLayout->addWidget(m_sourceType, 1);
|
||||
|
||||
auto* formLayout = new QFormLayout();
|
||||
m_hostEdit = new QLineEdit("127.0.0.1", this);
|
||||
@@ -117,9 +150,11 @@ void VideoViewerWidget::setupUI()
|
||||
controlLayout->addLayout(buttonLayout);
|
||||
controlLayout->addWidget(m_statusLabel);
|
||||
controlGroup->setLayout(controlLayout);
|
||||
controlGroup->setMaximumWidth(500);
|
||||
|
||||
mainLayout->addWidget(m_scrollArea, 1);
|
||||
mainLayout->addLayout(zoomLayout);
|
||||
mainLayout->addLayout(transformLayout);
|
||||
mainLayout->addWidget(controlGroup);
|
||||
|
||||
setLayout(mainLayout);
|
||||
@@ -352,6 +387,33 @@ void VideoViewerWidget::onZoomChanged(int value)
|
||||
}
|
||||
}
|
||||
|
||||
void VideoViewerWidget::onRotationChanged(int index)
|
||||
{
|
||||
m_rotationAngle = m_rotationCombo->currentData().toInt();
|
||||
|
||||
if (!m_currentFrame.isNull()) {
|
||||
displayFrame(m_currentFrame);
|
||||
}
|
||||
}
|
||||
|
||||
void VideoViewerWidget::onFlipHorizontalChanged(Qt::CheckState state)
|
||||
{
|
||||
m_flipHorizontalEnabled = (state == Qt::Checked);
|
||||
|
||||
if (!m_currentFrame.isNull()) {
|
||||
displayFrame(m_currentFrame);
|
||||
}
|
||||
}
|
||||
|
||||
void VideoViewerWidget::onFlipVerticalChanged(Qt::CheckState state)
|
||||
{
|
||||
m_flipVerticalEnabled = (state == Qt::Checked);
|
||||
|
||||
if (!m_currentFrame.isNull()) {
|
||||
displayFrame(m_currentFrame);
|
||||
}
|
||||
}
|
||||
|
||||
GstFlowReturn VideoViewerWidget::newSampleCallback(GstAppSink* appsink, gpointer user_data)
|
||||
{
|
||||
static int callbackCount = 0;
|
||||
@@ -453,13 +515,34 @@ void VideoViewerWidget::displayFrame(const QImage& frame)
|
||||
|
||||
m_currentFrame = frame;
|
||||
|
||||
QPixmap pixmap = QPixmap::fromImage(frame);
|
||||
QImage transformedFrame = frame;
|
||||
|
||||
// Apply rotation
|
||||
if (m_rotationAngle != 0) {
|
||||
QTransform rotation;
|
||||
rotation.rotate(m_rotationAngle);
|
||||
transformedFrame = transformedFrame.transformed(rotation, Qt::SmoothTransformation);
|
||||
}
|
||||
|
||||
// Apply flipping
|
||||
if (m_flipHorizontalEnabled || m_flipVerticalEnabled) {
|
||||
Qt::Orientations orientations;
|
||||
if (m_flipHorizontalEnabled) {
|
||||
orientations |= Qt::Horizontal;
|
||||
}
|
||||
if (m_flipVerticalEnabled) {
|
||||
orientations |= Qt::Vertical;
|
||||
}
|
||||
transformedFrame = transformedFrame.flipped(orientations);
|
||||
}
|
||||
|
||||
QPixmap pixmap = QPixmap::fromImage(transformedFrame);
|
||||
if (pixmap.isNull()) {
|
||||
qDebug() << "[VideoViewer] ERROR: Pixmap conversion failed!";
|
||||
return;
|
||||
}
|
||||
|
||||
QSize targetSize = frame.size() * m_zoomFactor;
|
||||
QSize targetSize = transformedFrame.size() * m_zoomFactor;
|
||||
|
||||
QPixmap scaledPixmap = pixmap.scaled(targetSize,
|
||||
Qt::KeepAspectRatio,
|
||||
|
||||
Reference in New Issue
Block a user