Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,15 @@ CameraVideoDisplay::CameraVideoDisplay(QWidget* parent, CameraVideoSource& sourc
this->setMinimumSize(80, 45);
m_view->setFixedSize(this->size());
m_view->setScene(&m_scene);
m_video.setSize(this->size());
// After 90° clockwise rotation, width and height are swapped
m_video.setSize(QSize(this->height(), this->width()));
// Set transform origin to center before rotating
m_video.setTransformOriginPoint(this->height() / 2.0, this->width() / 2.0);
// Rotate 90 degrees clockwise to compensate for counter-clockwise rotation
m_video.setRotation(90.0);
// Position at center of scene
m_video.setPos(this->width() / 2.0 - this->height() / 2.0,
this->height() / 2.0 - this->width() / 2.0);
m_scene.setSceneRect(QRectF(QPointF(0, 0), this->size()));
m_scene.addItem(&m_video);
source.set_video_output(m_video);
Expand All @@ -242,7 +250,12 @@ void CameraVideoDisplay::resizeEvent(QResizeEvent* event){
auto scope_check = m_sanitizer.check_scope();
m_view->setFixedSize(this->size());
m_scene.setSceneRect(QRectF(QPointF(0, 0), this->size()));
m_video.setSize(this->size());
// After rotation, dimensions are swapped: set size with swapped width/height
m_video.setSize(QSize(this->height(), this->width()));
// Update transform origin and position after rotation
m_video.setTransformOriginPoint(this->height() / 2.0, this->width() / 2.0);
m_video.setPos(this->width() / 2.0 - this->height() / 2.0,
this->height() / 2.0 - this->width() / 2.0);
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#include <iostream>
#include <QCamera>
#include <QPainter>
#include <QImage>
#include <QTransform>
#include <QMediaDevices>
#include <QVideoSink>
//#include "Common/Cpp/Exceptions.h"
Expand Down Expand Up @@ -213,11 +215,34 @@ void CameraVideoDisplay::paintEvent(QPaintEvent* event){
return;
}

QRect rect(0, 0, this->width(), this->height());
QVideoFrame::PaintOptions options;
QPainter painter(this);
// Convert to image to bypass Qt's automatic rotation based on camera metadata
// This ensures the display matches the raw frame orientation used for inference
QImage image = frame.toImage();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You cannot call QImage::toImage() here because this is the main Qt thread. It's too expensive and it will overload the main thread on higher resolutions and on multi-Switch programs.

QPainter is different because it renders the QVideoFrame directly to the screen with hardware acceleration.

if (image.isNull()){
// Fallback to frame.paint() if conversion fails
QRect rect(0, 0, this->width(), this->height());
QVideoFrame::PaintOptions options;
QPainter painter(this);
frame.paint(&painter, rect, options);
m_source.report_rendered_frame(current_time());
return;
}

frame.paint(&painter, rect, options);
QPainter painter(this);

// Rotate 90 degrees clockwise to compensate for counter-clockwise rotation
painter.save();

// Transform: move to center, rotate 90° clockwise, move back
painter.translate(this->width() / 2.0, this->height() / 2.0);
painter.rotate(90.0);

// Draw image centered, but with dimensions swapped due to rotation
// After 90° rotation, image width becomes height and vice versa
QRect imageRect(-this->height() / 2.0, -this->width() / 2.0, this->height(), this->width());
painter.drawImage(imageRect, image);

painter.restore();
m_source.report_rendered_frame(current_time());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*
*/

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

QImage SnapshotManager::frame_to_image(const QVideoFrame& frame){
QImage image = frame.toImage();

// If Qt applied rotation metadata (90° counter-clockwise), the dimensions will be swapped.
// We need to rotate the image 90° clockwise to restore the original orientation,
// matching what we do in the display layer.
// This ensures snapshots used for inference match the raw frame orientation.
if (image.height() > image.width()){
// Dimensions are swapped, indicating rotation was applied. Rotate 90° clockwise.
QTransform transform;
transform.rotate(90.0);
image = image.transformed(transform);
}

QImage::Format format = image.format();
if (format != QImage::Format_ARGB32 && format != QImage::Format_RGB32){
image = image.convertToFormat(QImage::Format_ARGB32);
Expand Down
Loading