Skip to content

Commit 9a503cf

Browse files
author
ig-14
committed
Fix video rotation: compensate for 90deg counter-clockwise camera rotation
- Rotate display 90deg clockwise in CameraWidgetQt6 and CameraWidgetQt6.5 backends to fix display orientation - Rotate snapshots 90deg clockwise in SnapshotManager to fix aspect ratio validation - Ensures display and inference snapshots match raw frame orientation
1 parent 3eef51e commit 9a503cf

File tree

3 files changed

+57
-6
lines changed

3 files changed

+57
-6
lines changed

SerialPrograms/Source/CommonFramework/VideoPipeline/Backends/CameraWidgetQt6.5.cpp

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,15 @@ CameraVideoDisplay::CameraVideoDisplay(QWidget* parent, CameraVideoSource& sourc
225225
this->setMinimumSize(80, 45);
226226
m_view->setFixedSize(this->size());
227227
m_view->setScene(&m_scene);
228-
m_video.setSize(this->size());
228+
// After 90° clockwise rotation, width and height are swapped
229+
m_video.setSize(QSize(this->height(), this->width()));
230+
// Set transform origin to center before rotating
231+
m_video.setTransformOriginPoint(this->height() / 2.0, this->width() / 2.0);
232+
// Rotate 90 degrees clockwise to compensate for counter-clockwise rotation
233+
m_video.setRotation(90.0);
234+
// Position at center of scene
235+
m_video.setPos(this->width() / 2.0 - this->height() / 2.0,
236+
this->height() / 2.0 - this->width() / 2.0);
229237
m_scene.setSceneRect(QRectF(QPointF(0, 0), this->size()));
230238
m_scene.addItem(&m_video);
231239
source.set_video_output(m_video);
@@ -242,7 +250,12 @@ void CameraVideoDisplay::resizeEvent(QResizeEvent* event){
242250
auto scope_check = m_sanitizer.check_scope();
243251
m_view->setFixedSize(this->size());
244252
m_scene.setSceneRect(QRectF(QPointF(0, 0), this->size()));
245-
m_video.setSize(this->size());
253+
// After rotation, dimensions are swapped: set size with swapped width/height
254+
m_video.setSize(QSize(this->height(), this->width()));
255+
// Update transform origin and position after rotation
256+
m_video.setTransformOriginPoint(this->height() / 2.0, this->width() / 2.0);
257+
m_video.setPos(this->width() / 2.0 - this->height() / 2.0,
258+
this->height() / 2.0 - this->width() / 2.0);
246259
}
247260

248261

SerialPrograms/Source/CommonFramework/VideoPipeline/Backends/CameraWidgetQt6.cpp

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
#include <iostream>
1212
#include <QCamera>
1313
#include <QPainter>
14+
#include <QImage>
15+
#include <QTransform>
1416
#include <QMediaDevices>
1517
#include <QVideoSink>
1618
//#include "Common/Cpp/Exceptions.h"
@@ -213,11 +215,34 @@ void CameraVideoDisplay::paintEvent(QPaintEvent* event){
213215
return;
214216
}
215217

216-
QRect rect(0, 0, this->width(), this->height());
217-
QVideoFrame::PaintOptions options;
218-
QPainter painter(this);
218+
// Convert to image to bypass Qt's automatic rotation based on camera metadata
219+
// This ensures the display matches the raw frame orientation used for inference
220+
QImage image = frame.toImage();
221+
if (image.isNull()){
222+
// Fallback to frame.paint() if conversion fails
223+
QRect rect(0, 0, this->width(), this->height());
224+
QVideoFrame::PaintOptions options;
225+
QPainter painter(this);
226+
frame.paint(&painter, rect, options);
227+
m_source.report_rendered_frame(current_time());
228+
return;
229+
}
219230

220-
frame.paint(&painter, rect, options);
231+
QPainter painter(this);
232+
233+
// Rotate 90 degrees clockwise to compensate for counter-clockwise rotation
234+
painter.save();
235+
236+
// Transform: move to center, rotate 90° clockwise, move back
237+
painter.translate(this->width() / 2.0, this->height() / 2.0);
238+
painter.rotate(90.0);
239+
240+
// Draw image centered, but with dimensions swapped due to rotation
241+
// After 90° rotation, image width becomes height and vice versa
242+
QRect imageRect(-this->height() / 2.0, -this->width() / 2.0, this->height(), this->width());
243+
painter.drawImage(imageRect, image);
244+
245+
painter.restore();
221246
m_source.report_rendered_frame(current_time());
222247
}
223248

SerialPrograms/Source/CommonFramework/VideoPipeline/Backends/SnapshotManager.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
*
55
*/
66

7+
#include <QTransform>
78
#include "Common/Cpp/Concurrency/ReverseLockGuard.h"
89
#include "Common/Cpp/Concurrency/AsyncTask.h"
910
#include "CommonFramework/Tools/GlobalThreadPools.h"
@@ -34,6 +35,18 @@ SnapshotManager::SnapshotManager(Logger& logger, QVideoFrameCache& cache)
3435

3536
QImage SnapshotManager::frame_to_image(const QVideoFrame& frame){
3637
QImage image = frame.toImage();
38+
39+
// If Qt applied rotation metadata (90° counter-clockwise), the dimensions will be swapped.
40+
// We need to rotate the image 90° clockwise to restore the original orientation,
41+
// matching what we do in the display layer.
42+
// This ensures snapshots used for inference match the raw frame orientation.
43+
if (image.height() > image.width()){
44+
// Dimensions are swapped, indicating rotation was applied. Rotate 90° clockwise.
45+
QTransform transform;
46+
transform.rotate(90.0);
47+
image = image.transformed(transform);
48+
}
49+
3750
QImage::Format format = image.format();
3851
if (format != QImage::Format_ARGB32 && format != QImage::Format_RGB32){
3952
image = image.convertToFormat(QImage::Format_ARGB32);

0 commit comments

Comments
 (0)