How to flip image from QCamera? - c++

In QT Creator how we can filp the images from camera. I googled a lot but I didn't get a proper solution.
Following is my code.
mCamera = new QCamera;
mViewfinder = new QCameraViewfinder;
mLayout = new QVBoxLayout(ui->graphicsView);
mLayout->addWidget(mViewfinder);
mCamera->setViewfinder(mViewfinder);
mViewfinder->show();
mCamera->start();
I tried QCamera::FrontFace and QCamera::BackFace in constructor argument in QCamera like below
mCamera = new QCamera(QCamera::FrontFace);
and
mCamera = new QCamera(QCamera::BackFace );
But both have no difference.
In Python
video=cv2.flip(self.frame,1)
will solve the problem,
Any idea how to solve this ..
I am using Windows 10

QCamera::FrontFace and QCamera::BackFace are just positions of the camera. To achieve what you want, you should flip every image.
Create QCameraImageCapture and connect to its imageCaptured() signal.
auto imageCapture = new QCameraImageCapture( mCamera );
connect(imageCapture, &QCameraImageCapture::imageCaptured, [&](int id, const QImage &preview){
QImage flipped = preview.mirrored();
// do what you want with flipped image
})
Documentation says that mirrored(bool horizontal = false, bool vertical = true)
Returns a mirror of the image, mirrored in the horizontal and/or the vertical direction depending on whether horizontal and vertical are set to true or false.
UPDATE:
I found the camera and tested the code and realized that I forgot one important thing. You need to use a timer by which QCameraImageCapture will capture the image.
Create QTimer and connect to QTimer::timeout() signal:
connect (&timer, &QTimer::timeout, [&](){
camera->searchAndLock();
imageCapture->capture();
camera->unlock();
});
And after that start the timer. To show flipped image you can use just QLabel class with label->setPixmap(QPixmap::fromImage(flipped)) method.

Hai I changed my code as per the answer of #Allocse and its work for me
My full code will be
mCamera = new QCamera;
mCamera->start();
imageCapture = new QCameraImageCapture( mCamera );
connect (&timer, &QTimer::timeout, [&](){
mCamera->searchAndLock();
imageCapture->capture();
mCamera->unlock();
});
connect(imageCapture, &QCameraImageCapture::imageCaptured, [&](int id, const QImage &preview){
QImage flipped = preview.mirrored(true,false);
ui->videoFrame->setPixmap(QPixmap::fromImage(flipped));
});
timer.start();
Note :-mCamera and imageCapture should be declared in class decleration

Related

Image Streaming using QGraphicsView

I am trying to display images from a CameraLink Camera into a QGraphicsView.
I am using a ring buffer which get() and set() functions and two threads that consume or produce the images in this ring buffer.
This part works because I already had a successfull streaming using a QWidget. I want to use a QGraphicsView because I want to draw over those incoming images
I have a display class which is promoted to QGraphicsView, everytime an image is produced, a signal is emitted from the consumer thread to the following function:
void display::drawImage(ImageBW* image)
{
firstImage = image;
QRect rect;
rect.setHeight(1000);
rect.setWidth(2000);
QApplication::postEvent(this->viewport(),new QPaintEvent(rect));
}
I have reimplemented the painEvent of the QGraphicsview class:
void display::paintEvent(QPaintEvent *event)
{
if(firstImage)
_drawImage();
event->setAccepted(true);
}
and the drawing function is:
void display::_drawImage()
{
int w, h;
if(img)
{
delete img;
img = NULL;
}
w = firstImage->getSizeX();
h = firstImage->getSizeY();
unsigned char * udata = (unsigned char *)firstImage ->getData();
img = new QImage(udata,w, h,QImage::Format_Grayscale8);
pix_img = QPixmap::fromImage(*img);
scene->clear();
scene->addPixmap(pix_img);
scene->setSceneRect(pix_img.rect());
scene->update();
update(); // I have tried here also setScene(scene)
}
In the above code, firstImage is an ImageBW* variable. ImageBW is where the image data from camera is stored.
I have also tried with QGraphicsItem and addItem() function but i get no Image.
'scene' is initialized on the producer of this class and also the 'setScene(scene);' command is there.
The program stucks after a while so that probably means that this code produces stackoverflow.
Please I have tried everything i can think of, any help would be greatly appreciated.
Thanks in advance

QtChart - C++ - Saving a chart which wasn't displayed

I'm trying to save a chart to a file, in a QTextDocument in this example :
QTextDocument doc("Frame rate test\n");
QTextCursor cursor(&doc);
cursor.movePosition(QTextCursor::End);
if (getTestFinishedStatus())
{
QPixmap pix = _pFrameRateChart->grab(); //_pFrameRateChart is QChartView
cursor.insertImage(pix.toImage());
}
QTextDocumentWriter docWriter;
docWriter.setFileName("framerate.odf");
docWriter.setFormat("ODF");
docWriter.write(&doc);
The problem is the result isn't same if I'm displaying the chart in an ui.
Here is the result when not displayed :
Here is the result when displayed :
Obviously I would like to have the second result even when I don't add the ChartView to a widget to display it on an ui.
I've tried resizing the QChartView, resizing the QChart, adding the Chart to a temporarly widget and QVBoxLayout then saving it, showing temporarly the QChartView before saving it etc... but didn't managed to get a good result.
I use the following code to render a QGraphivsView on a Pixmap, since QtCharts is based on QGraphivsView, I think this will also work.
Try to render the image instead of trying to grab the pixmap.
void Printer::putProfileImage(QRect profilePlaceholder, QRect viewPort, QPainter *painter, QGraphivsView* profile)
{
int x = profilePlaceholder.x() - viewPort.x();
int y = profilePlaceholder.y() - viewPort.y();
QRect pos(x, y, profilePlaceholder.width(), profilePlaceholder.height());
profile->render(painter, pos);
}
I didn't find any easy way to this, so here's my solution, which is more like a workaround though :
QPixmap ChartView::getChartPixmap()
{
QWidget* w = new QWidget; //creating a temporary widget, which will enable to display the chart
w->resize(REPORT_IMAGE_WIDTH, REPORT_IMAGE_HEIGHT);
QVBoxLayout *vl;
vl = new QVBoxLayout(w);
vl->addWidget(this); //'this' being the QChartView
w->show(); //showing the widget so it is resized and can be grabbed with the correct dimensions
QTest::qWait(500); //we need to wait for a little for the graph to be drawn otherwise you'll still have the same size problem
QPixmap pixmap = w->grab(); //retrieve the pixmap
w->hide(); //hiding the widget
return pixmap;
}
It's working but you'll have a small window opened with the graph for 500 ms.

How to use zoom in/out with Qt Camera?

I'm very new to Qt, I have to create an image capture via webcam and print it, in Qt. I have managed to carry out most of the
required tasks but there is one problem that I have when I see the webcam image I would like to zoom in/out to capture an image, How can I do this ? I
have searched the net without any joy. What I have so far
ui->setupUi(this);
vCam = new QCamera(this);
vCamViewfinder = new QCameraViewfinder(this);
vCamImageCapture = new QCameraImageCapture(vCam, this);
vLayout = new QVBoxLayout;
vMenu = new QMenu("Options",this);
vStart = new QAction("Start", this);
vEnd = new QAction("End",this);
vCapture = new QAction("Capture",this);
vMenu->addActions({ vStart, vEnd, vCapture });
ui->pushButton_camAction->setMenu(vMenu);
vCam->setViewfinder(vCamViewfinder);
vLayout->addWidget(vCamViewfinder);
vLayout->setMargin(0);
ui->graphicsView->setLayout(vLayout);
connect(vStart, &QAction::triggered, [&](){
vCam->start();
});
connect(vEnd, &QAction::triggered, [&](){
vCam->stop();
});
connect(vCapture, &QAction::triggered, [&](){
on_pushButton_camAction_clicked();
});
void VisitorSignIn::on_pushButton_camAction_clicked()
{
QString vImage = "C:/Qt/VisitorsImages/1.jpg";
vCamImageCapture->setCaptureDestination(QCameraImageCapture::CaptureToFile);
QImageEncoderSettings imgEncSet;
imgEncSet.setCodec("image/jpeg");
imgEncSet.setResolution(640, 480);
vCamImageCapture->setEncodingSettings(imgEncSet);
vCam->setCaptureMode(QCamera::CaptureStillImage);
vCam->start();
vCam->searchAndLock();
vCamImageCapture->capture(vImage);
vCam->unlock();
}
Have a look on http://doc.qt.io/qt-5/qcamerafocus.html These Methods allow optical and digital zoom.

QT QGraphicsView rotation

Disclaimer: I am pretty much a beginner with QT.
I've been struggling for some time to rotate a QGraphicsView (no 3D rotation) but, despite what i do, it doesn't work. I have tried:
QTransform transform;
transform.rotate(45);
ui->graphicsView->setTransform(transform);
or more simply:
ui->graphicsView->rotate(45);
These seem like very straightforward ways to do it that should work, but for some reason, whenever i run it, the QGraphicsView doesn't rotate at all. If possible, i'd like some direct and easy to understand code snippets, and/or what i'm doing wrong.
EDIT: This is the code in the widget cpp file i have problems with. It should be a simple timer with an animated hourglass icon. It gets repeated every .5 seconds.
void Widget::timerEvent(QTimerEvent *event)
{
++timeFlag;
++timerFlag;
if (timerFlag < 115){
animateTimer = QString("\":/new/100/timerFrames/timerIconFrame%1.png\"").arg(timerFlag);
QPixmap pix(animateTimer);
pixmapitem.setPixmap(pix);
scene.addItem(&pixmapitem);
ui->graphicsView_2->setScene(&scene);
}
if (timerFlag >= 115 && timerFlag < 119){
//
}
if(timerFlag == 119){
ui->graphicsView_2->setStyleSheet("border-image:url(:/new/100/timerIconPix.PNG);border:0px;}");
}
if(timerFlag == 120){
timerFlag = 0;
}
if (timeFlag==2){
timeFlag = 0;
if(sec>=10){
ui->label_2->setText(QString("%1:%2").arg(min).arg(sec));
} else {
ui->label_2->setText(QString("%1:0%2").arg(min).arg(sec));
}
++sec;
if (sec == 60) {
sec = 0;
++min;
}
}
}
You're merely decorating the QGraphicsView using the style mechanism. You could have used a plain QWidget instead, since you don't use any graphics view functionality. None of the images in the stylesheet are what the view actually displays. The image must be on the scene displayed by the view.
Set the image on a QGraphicsPixmapItem, add that item to a scene, set the scene on the view, and then the transformations will work. You can then keep replacing the pixmap in the timer handler.
Finally, you must also check the timer id in the timerEvent. I assume that you're using a QBasicTimer, say called m_timer, you'd then check as follows:
void Widget::timerEvent(QTimerEvent * ev) {
if (ev->timerId() != m_timer.timerId()) return;
... // rest of the code
}
As you can see, the code that you've not included in the original question was absolutely essential! Without it, the question was wholly off-topic.
You need to implement a QGraphicsView, a QGraphicsScene and then add something that inherits from QGraphicsItem to that scene to rotate.
Here is an example that rotates a QWidget in a QGraphicsView:
QGraphicsView* view = new QGraphicsView(parent);
QGraphicsScene* scene = new QGraphicsScene(view);
view->setScene(scene);
// Widget to rotate - important to not parent it
QWidget* widget = new QWidget();
QProxyWidget proxy_widget = scene_->addWidget(widget);
QPropertyAnimation* animation = new QPropertyAnimation(proxy_widget, "rotation");
animation->setDuration(5000);
animation->setStartValue(0);
animation->setEndValue(360);
animation->setEasingCurve(QEasingCurve::Linear);
animation->start(QAbstractAnimation::DeleteWhenStopped);

Drawing App, How to Erase

(I'm a newbie in AS3) I found a usefull code here http://www.flashandmath.com/advanced/smoothdraw/ and I'm trying to create an Erase button, I'm trying to use .cacheAsBitmap = true; but this work only if there is a mask(I saw this on some AS2 app where you can erase a bitmap then you can redraw).
P.S. I changed the code slightly to change the background now the drawBackgroundfunction look like this:
function drawBackground():void {
//We draw a background with a very subtle gradient effect so that the canvas darkens towards the edges.
var mesh:Shape = new Shape();
var gradMat:Matrix = new Matrix();
gradMat.createGradientBox(700,500,0,0,0);
var bg:Sprite = new Sprite();
mesh.graphics.beginBitmapFill(new lignes(), null, true, false);
//bg.graphics.beginGradientFill("radial",[0xDDD0AA,0xC6B689],[1,1],[1,255],gradMat);
//bg.graphics.drawRect(0,0,700,500);
//bg.graphics.endFill();
mesh.graphics.drawRect(0, 0, 700, 500);
mesh.graphics.endFill();
boardBitmapData.draw(mesh);
mesh.cacheAsBitmap = true;
//We clear out the undo buffer with a copy of just a blank background:
undoStack = new Vector.<BitmapData>;
var undoBuffer:BitmapData = new BitmapData(boardWidth, boardHeight, false);
undoBuffer.copyPixels(boardBitmapData,undoBuffer.rect,new Point(0,0));
undoStack.push(undoBuffer);
}
I just want to create an Erase methode, thanks for your help
Edit: I meant to erase only the clicked area
To clean the Shape Try:
mesh.graphics.clear();
To clean the Shape object. I don't know what else you are doing with the boardBitmapData variable, maybe will be necessary to do something about as well.
clear() - Clears the graphics that were drawn to this Graphics object, and resets fill and line style settings.
You need convert your canvas in bitmap, then use a mask to delete or blend mode ERASE, and to draw again create a new bitmap from the masked bitmap and finally use this as background.