I am using QT to build a custom component for QML. I want this component to be able to play a WEBM video that contains an alpha channel. However, all of my attempts have resulted in the transparent pixels of the video getting replaced with black ones. This is my code currently:
MyClass::MyClass()
{
m_pixmap = new QPixmap(1920, 1080); // Create a canvas to draw on:
// Create something that can be drawn:
m_painter = new QPainter(m_pixmap);
m_rect = new QRect(0, 0, 1920, 1080);
// Create an area to present on:
m_label = new QLabel();
m_label->setPixmap(*m_pixmap);
m_label->show();
// Play video:
m_videoSink = new QVideoSink();
m_mediaPlayer = new QMediaPlayer();
m_mediaPlayer->setVideoSink(m_videoSink);
m_mediaPlayer->setSource(QUrl::fromLocalFile("path..."));
m_mediaPlayer->setLoops(QMediaPlayer::Infinite);
m_mediaPlayer->play();
// Add a an event for when the video frame changes:
connect(m_videoSink, SIGNAL(videoFrameChanged(QVideoFrame)), this, SLOT(SetFrame(QVideoFrame)));
qDebug() << "Constructed";
}
void MyClass::SetFrame(QVideoFrame frame)
{
frame.paint(m_painter, *m_rect, m_options); //Stores the frame in the m_pixmap
m_label->setPixmap(*m_pixmap);
}
In this example I attempt to use a QMediaPlayer to play the video, then a QVideoSink to extract the currently playing QVideoFrame and paint that to a QPixmap that is finally being displayed in a QLabel.
I have also tried to have the QMediaPlayer directly hooked up to a QVideoWidget.
I know that my WEBM video works as it is displaying as expected when imported in to other programs.
Related
void Editor::DisplayImage(QString(pathOfImage))
{
// QPixmap pix (pathOfImage);
// ui->lbl_DisplayImage->setPixmap(pix);
// ui->lbl_DisplayImage->lower();
// annotationPixmap = QPixmap(pix.size());
// annotationPixmap.fill(Qt::transparent);
ui->lbl_DisplayImage->setPixmap(annotationPixmap);
annotationPixmap = QPixmap(pathOfImage);
clickMouse = false;
}
I am trying to move this pixmap and change the size of the pixmap image. I have tried using labels but they prevent me from drawing over the images and the drawings are always placed behind the image.
Is there a way to manipulate the pixmap?
I have a GUI composed of a QTableView with 18 columns and a QGraphicsView where I upload images using a button. I am able to draw a box on a region of interests (ROI) and as soon as I do that with a mouse right click I open up a small dialog. This dialog is composed of a TabWidget with two pages. The first page has a small QGraphicsView that carries the cropped image (say Image A) captured with the previous box drawn. The second page of the TabWidget has also another QGraphicsView that I use to upload a previously saved .jpg image (say Image B) that is on my Desktop. As soon as I hit ok the information on this dialog will be transferred to the first row of the QTableView. Image A will be stoted in one column (column 17 to be precise) and Image B in an additional column too (column 18 to be precise).
I was able to store the cropped Image A (which was the most difficult part because I had to work on understanding the conversion format between Qt and openCV and vice versa) in the QTableView but not Image B (which I handle as simple image that I saved on my Desktop).
I tried different options: option 1: I created a function with which I handle the image that I upload on the second page of the TabWidget (Image B), option 2: I tried to debug to narrow the problem and it seems that the compiler is not seeing the image I am trying to store.
I am attaching the most important part of the code that are carrying this bug:
In clipscene.h is how I declare the most important variables and functions I use:
class clipScene : public QDialog
{
Q_OBJECT
public:
explicit clipScene(QWidget *parent = 0);
~clipScene();
void setImage(QImage img);
void setClassifiedImage(QImage img);
SelectionData getData();
void setData(SelectionData newdata);
private:
SelectionData returnData;
Ui::clipScene *ui;
QImage simg;
QImage featureClassified;
};
In clipscene.cpp this is the function setClassifiedImage I use to handle Image B
void clipScene::setClassifiedImage(QImage img)
{
featureClassified = img;
QGraphicsPixmapItem* item = new QGraphicsPixmapItem(QPixmap::fromImage(featureClassified));
workingImageScene->addItem(item);
}
In clipscene.cpp using setImage I successfully handle the Qt and openCV conversion of the cropped image
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(), CV_16UC3, simg.bits(), simg.bytesPerLine());
// .....operations...
// .....operations...
}
In clipscene.cpp the following img1 represent the cropped Image A and the img2 represent Image B (that is currently nor stored neither passsed)
void clipScene::on_acceptBtn_clicked()
{
// .....operations...
// This will save the cropped Image A successfully
QPixmap img1;
img1.convertFromImage(simg);
QByteArray img1Array;
QBuffer buffer1(&img1Array);
buffer1.open(QIODevice::WriteOnly);
img1.save(&buffer1, "PNG");
returnData.mSave = img1Array;
// This will save a different Image B
// But here the compiler says that no arguments are being passed
QPixmap img2;
QByteArray img2Array;
QBuffer buffer2(&img2Array);
buffer2.open(QIODevice::WriteOnly);
img2.save(&buffer2, "PNG");
returnData.mClassImg = img2Array;
}
Finally when all information are passed and stored on the QTableView I am able to DoubleClick on one row of the QTableView and the same dialog I used before for manually storing the data will pop up with all information recorded and both images (Image A and Image B).
The part of the code that does this on MainWindow (and where the bug is connected) is below:
void MainWindow::onTableClick(const QModelIndex &index)
{
int row = index.row();
SelectionData currentData;
currentData.mName = index.sibling(row, 1).data().toString();
// ....additional data....
// ....additional data...
currentData.mSave = index.sibling(row, 17).data().toByteArray();
currentData.mClassImg = index.sibling(row, 18).data().toByteArray();
QPixmap iconPix;
if(!iconPix.loadFromData(index.sibling(row, 17).data().toByteArray())) {
}
QPixmap iconPix2;
if(!iconPix2.loadFromData(index.sibling(row, 18).data().toByteArray())) {
}
clipScene d(this);
d.setData(currentData);
d.setImage(iconPix.toImage());
d.setClassifiedImage(iconPix2.toImage());
// ....additional operations....
}
I have been struggling with this problem for some days now and anyone who can shed some light on this or provide a solution on how to solve this would be great.
I am not sure if this is still useful to you but since I had the same problem this might be helpful. I think you are never passing the image to the destination table. Are you ever loading the image? Are you ever doing something like this:
clipscene.h
private:
QList<QGraphicsPixmapItem*> leftClipPix;
clipscene.cpp
void clipScene::load_classifiedImageFromDb(QImage image)
{
clasImg = image;
QGraphicsPixmapItem* item = new QGraphicsPixmapItem(QPixmap::fromImage(image));
leftClipPix.append(item);
workingImageScene->addItem(item);
ui->yourgraphicsView->show();
ui->yourgraphicsView->setSceneRect(QRectF(0, 0, image.width(), image.height()));
}
Also if, as you said, you are trying to upload an image from your Desktop or database, than it may be useful to do something like:
void clipScene::load_classifiedImage()
{
QString dir = QFileDialog::getOpenFileName(this, tr("Open image directory"), "", tr("Images (*.tif *.jpg *.png *.jpeg *.bmp *.gif *.tiff)"));
QImage image;
if(QString::compare(dir, QString()) != 0) {
image = QImage(dir);
QGraphicsPixmapItem* item = new QGraphicsPixmapItem(QPixmap::fromImage(image));
leftClipPix.append(item);
workingImageScene->addItem(item);
}
ui->yourgraphicsView->show();
ui->yourgraphicsView->setSceneRect(QRectF(0, 0, image.width(), image.height()));
clasImg = image;
}
and pass load_classifiedImage() function to a QPushButton
I am struggling with writing a video player which uses OpenCV to read a frame from video and display it in a QWidget.
This is my code:
// video caputre is opened here
...
void VideoPlayer::run()
{
int sleep = 1000 / static_cast<unsigned long>(video_capture_.get(CV_CAP_PROP_FPS));
forever
{
QScopedPointer<cv::Mat> frame(new cv::Mat);
if(!video_capture_.read(*frame))
break;
cv::resize(*frame, *frame, cv::Size(640, 360), 0, 0, cv::INTER_CUBIC);
cv::cvtColor(*frame, *frame, CV_BGR2RGB);
QImage image(frame->data, frame->cols, frame->rows, QImage::Format_RGB888);
emit signalFrame(image); // notifying QWidget to draw an image
msleep(sleep); // wait before we read another frame
}
}
and on the QWidget side, I am just using this image and drawing it in paintEvent.
It just looks to me that parameter sleep doesn't play important role here. As much as I decrease it (to get more FPS) the video is just not smooth.
The only thing here left for me is that I gave up on that approach because it doesn't work, but I wanted to ask here one more time, just to be sure - am I doing something wrong here?
I am writing a program, to display two cameras next to each other. In Qt it is pretty simple with the QCamera. But my Cameras are turned by 90°, so I have to turn the Camera in the porgram too.
The QCamera variable has no command to turn it, so I want to display it in a label, and not in a viewfinder. So I take an Image, turn it and display it in a label.
QImage img;
QPixmap img_;
img = ui->viewfinder->grab().toImage();
img_ = QPixmap::fromImage(img);
img_ = img_.transformed(QTransform().rotate((90)%360));
QImage img2;
QPixmap img2_;
img2 = ui->viewfinder->grab().toImage();
img2_ = QPixmap::fromImage(img2);
img2_ = img2_.transformed(QTransform().rotate((90)%360));
ui->label->setPixmap(img_);
ui->label_2->setPixmap(img2_);
When I start the program there are just two black boxes next to each other.
(In the code there is missing the part where I deklare it, but the camera works fine in the viewfinder so I think there is no problem)
Try this:
img_ = QPixmap::grabWindow(ui->viewfinder->winId(), 0, 0, -1, -1); (for take a snapshot as QPixmap)
or
img = QPixmap::grabWindow(ui->viewfinder->winId(), 0, 0, -1, -1).toImage(); (for take a snapshot as QImage)
You can use the orientation of the camera to correct the image orientation in view finder as described in Qt documentation. Here is the link:
http://doc.qt.io/qt-5/cameraoverview.html
and here is the code found in the documentation:
// Assuming a QImage has been created from the QVideoFrame that needs to be presented
QImage videoFrame;
QCameraInfo cameraInfo(camera); // needed to get the camera sensor position and orientation
// Get the current display orientation
const QScreen *screen = QGuiApplication::primaryScreen();
const int screenAngle = screen->angleBetween(screen->nativeOrientation(), screen->orientation());
int rotation;
if (cameraInfo.position() == QCamera::BackFace) {
rotation = (cameraInfo.orientation() - screenAngle) % 360;
} else {
// Front position, compensate the mirror
rotation = (360 - cameraInfo.orientation() + screenAngle) % 360;
}
// Rotate the frame so it always shows in the correct orientation
videoFrame = videoFrame.transformed(QTransform().rotate(rotation));
It looks like you don't even understand, what you are looking at...
Whats the purpose of pasting stuff like that to forum? Did you read ALL description about this? Its only part of the code that - i see You dont understand, but you try to be smart :)
i am using Qt Creator to implement an application that reads a video and by clicking on a button i will save the frame that is being showed. Then i will process that frame with Opencv.
Having a video being displayed with QmediaPlayer, how can i extract a frame from the video? I should then be able to convert that frame to a Mat image in Matlab.
Thanks
QMediaPlayer *player = new QMediaPlayer();
QVideoProbe *probe = new QVideoProbe;
connect(probe, SIGNAL(videoFrameProbed(QVideoFrame)), this, SLOT(processFrame(QVideoFrame)));
probe->setSource(player); // Returns true, hopefully.
processFrame slot:
void processFrame(QVideoFrame const&) {
if (isButtonClicked == false) return;
isButtonClicked = false;
...
process frame
...
}
QVideoProbe reference
QVideoFrame reference
You can use QVideoFrame::bits() to process image with OpenCV