I am currently writing a real-time visualization tool for processing simulation data. The data are two-dimensional data like a pressure/temperature field. Currently, I am using QImage to manipulate the data and QPixmap to display those data but are there any better/faster way? Does QPixmap::fromImage() copy the data from the given image and how costly is that? The source code from my approach looks like this:
int main(int argc, char **argv) {
QApplication app(argc, argv);
QMainWindow* mainWindow = new QMainWindow(0, 0);
mainWindow->setMinimumSize(1024, 768);
mainWindow->show();
QGraphicsScene* scene = new QGraphicsScene();
QGraphicsView* view = new QGraphicsView(scene);
mainWindow->setCentralWidget(view);
QImage* image = new QImage(640, 480, QImage::Format_RGB32);
image->fill(0);
QGraphicsPixmapItem* item = scene->addPixmap(QPixmap::fromImage(*image));
item->setPos(0, 0);
// DO SOME CALCULATION AND SET PIXEL COLOR ON image
item->setPixmap(QPixmap::fromImage(*image));
return app.exec();
Related
I have a problem when use QGraphicsView and QGraphicsBlurEffect in my project. When I put them together, my program does not work normally. I wrote a tiny program to reproduce this problem.
The Widget class is inherited from QGraphicsView.
Widget::Widget(QWidget *parent)
: QGraphicsView(parent)
{
scene = new QGraphicsScene(this);
this->setScene(scene);
label = new QLabel;
QPixmap pixmap = QPixmap("../partly_cloudy.png").scaledToWidth(200);
label->setPixmap(pixmap);
label->setGeometry(100,100, pixmap.width(), pixmap.height());
label->setStyleSheet("border:3px;border-color: rgb(255, 100, 0); border-style:solid;");
/* ********image won't show when adding following comment code********
QGraphicsBlurEffect *blur = new QGraphicsBlurEffect;
blur->setBlurRadius(10);
label->setGraphicsEffect(blur);
******* */
QGraphicsProxyWidget *proxyWidget = new QGraphicsProxyWidget;
proxyWidget->setWidget(label);
proxyWidget->setPos(10,10);
scene->addItem(proxyWidget);
}
and main.cpp is as follows.
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
This is a screenshot when QGraphicsBlurEffect is not used.
However, this is a screenshot when QLabel uses setGraphicsEffect() to bind blur effect.
To solve this problem, I tried to use a QWidget to wrap QLabel. When I did this, QLabel was rendered. However, it seems to be bounded by a rectangle area.
Widget::Widget(QWidget *parent)
: QGraphicsView(parent)
{
scene = new QGraphicsScene(this);
this->setScene(scene);
/* ********/
container = new QWidget;
container->setStyleSheet("border:3px;border-color: blue; border-style:solid;");
/******** */
label = new QLabel(container);
QPixmap pixmap = QPixmap("../partly_cloudy.png").scaledToWidth(200);
label->setPixmap(pixmap);
label->setGeometry(100,100, pixmap.width(), pixmap.height());
label->setStyleSheet("border:3px;border-color: red; border-style:solid;");
QGraphicsBlurEffect *blur = new QGraphicsBlurEffect;
blur->setBlurRadius(10);
label->setGraphicsEffect(blur);
QGraphicsProxyWidget *proxyWidget = new QGraphicsProxyWidget;
proxyWidget->setWidget(container);
proxyWidget->setPos(80,80);
qDebug() << proxyWidget->boundingRect();
scene->addItem(proxyWidget);
this->setSceneRect(0,0,640,480);
}
The screenshot of the result is.
I tried to set proxyWidget position to {0,0}, and it works normally. it seems that the position of effect rectangle will not influenced by proxyWidget position.
By the way, the version of Qt is 5.14.2.
I've searched for a long time on net. But no use. Please help or try to give some ideas how to achieve this.
I am trying to extract the pixel data from every frame, but when I try to get the pixmap it returns null. I thought that the pixmap would return the actual pixel data of what was on the screen, similar to glReadPixels but I think I am mistaken. I think it's meant to access the pixel map of the result of setPixmap.
Is there a way to access the raw pixels rendered on the screen? With the below example, "Hello World" is rendered on the screen and I want the actual pixel data of that label.
QWidget window;
window.resize(1280, 720);
window.show();
window.setWindowTitle(QApplication::translate("toplevel", "Top-Level Widget"));
QLabel *label = new QLabel(QApplication::translate("label", "Hello World"), &window);
label->move(500, 500);
label->raise();
label->show();
QPixmap pixmapVal = label->pixmap(Qt::ReturnByValue);
Cause
QPixmap:
The QPixmap class is an off-screen image representation that can be used as a paint device
In other words, it is a drawing canvas and, as any other canvas, if you have not drawn on it, it would be empty.
On the other hand QLabel serves as a view for the pixmap, not as its content, and when you try to access the pixmap of the label without having set one, it returns null.
Solution
There is of course a way to make a widget, the label in your case, content of the pixmap and access the pixel data. My approach to the this problem would be like this:
Create an empty pixmap with the size of the widget whos pixel content you want to access, e.g.:
QPixmap pixmap(widget->size());
pixmap.fill(Qt::transparent);
Use QWidget::render to render the content of the widget onto the pixmap:
widget->render(&pixmap);
Convert the pixmap to QImage and use QImage::pixel or QImage::pixelColor to access the rgb data of the pixel at (pixelX, pixelY) like this:
pixmap.toImage().pixelColor(pixelX, pixelY);
Example
Here is an example I have prepared for you to demonstrate how the proposed solution could be implemented:
#include "MainWindow.h"
#include <QApplication>
#include <QLabel>
#include <QDebug>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget w;
auto *label = new QLabel(QObject::tr("Hello World"), &w);
label->move(500, 500);
label->raise();
w.setWindowTitle(QObject::tr("Top-Level Widget"));
w.resize(1280, 720);
w.show();
QPixmap pixmap(label->size());
pixmap.fill(Qt::transparent);
label->render(&pixmap);
int pixelX = 10;
int pixelY = 5;
// Access image pixels
qDebug() << pixmap.toImage().pixelColor(pixelX, pixelY);
return a.exec();
}
Result
For the pixel at (10, 5) the example produces the following result:
QColor(ARGB 1, 0, 0, 0.156863)
I acquire images from a camera by using a SDK which returns the data in an unsigned char array. However this SDK doesn't offer functionality to display the data, so I tried to implement this by using Qt 4.8 under Ubuntu 12.04.
At the moment my code looks like this:
#include <QtGui/QApplication>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsPixmapItem>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QGraphicsScene scene;
QGraphicsView view(&scene);
while (..) // condition which breaks after a number of images where grabbed
{
// Get the image from the third party SDK into an unsigned char array
// named pImageBuffer
QImage image ((unsigned char *) pImageBuffer,
GetWidth(),
GetHeight(),
QImage::Format_Indexed8);
QVector<QRgb> colorTable(256);
for(int i=0;i<256;i++)
colorTable[i] = qRgb(i,i,i);
image.setColorTable(colorTable);
QPixmap pixmap = QPixmap::fromImage(image);
QGraphicsPixmapItem *item = new QGraphicsPixmapItem(pixmap);
scene.addItem(item);
view.show();
a.exec();
}
}
This works like expected, the images are displayed properly. However a.exec() blocks the main thread until I close the QtWindow.
Is there any easy way to modify this, so the window stays open all the time and just updates the displayed image? Performance doesn't matter at all at the moment, but I need to keep the code simple.
While a call to QApplication::processEvents will work, it's just a hack and not the best solution.
Ideally the image grabber should run on a separate thread as an object derived from QObect. This object emits signals of the images that it receives, which are received by an object on the main thread.
The receiving object can then set the image on the QGraphicsPixmapItem object.
Note that the code in the question creates a new QGraphicsPixmapItem for every image that is received from the grabber. Assuming you're wanting to create an animated image, you should only be creating and adding a single QGraphicsPixmapItem to the scene.
Using QThread is very easy and if you've not done it before, I suggest you read this article, which clearly explains what to do, with example code.
class ImageGrabber
{
Q_OBJECT
public:
ImageGrabber(QPixmapItem* item) : _item(item)
{
connect( &timer, SIGNAL(timeout()), this, SLOT(grabImage()) )
_timer.start(33); // 33 ms between timeouts.
}
public slots:
void grabImage()
{
// Update image
QImage image(...);
_item->setPixmap( QPixmap::fromImage(image) );
}
private:
QPixmapItem* _item;
QTimer _timer;
};
int main(...)
{
QApplication a(argc,argv);
...
view.show();
QGraphicsPixmapItem* pixmapItem = scene.addPixmap(QPixmap());
ImageGrabber ig(pixmapItem);
return a.exec();
}
Can some one explain me how to make a window in qt according to the shape of some object in an image , for example i have an image of a tree , using that i need to create a window in the shape of a tree ..
After a long search , myself found a good solution , check out this ..
#include <QtGui>
class myMainWindow:public QMainWindow
{
public:
myMainWindow():QMainWindow()
{
setMask((new QPixmap("saturn.png"))->mask());
QPalette* palette = new QPalette();
palette->setBrush(QPalette::Background,QBrush(QPixmap("saturn.png")));
setPalette(*palette);
setWindowFlags(Qt::FramelessWindowHint);
QWidget *centralWidget = new QWidget(this);
QGridLayout *layout = new QGridLayout();
centralWidget->setLayout(layout);
QPushButton* button1 = new QPushButton("Button 1");
button1->setFixedSize(80,50);
layout->addWidget(button1,0,0);
setCentralWidget(centralWidget);
};
~myMainWindow(){};
};
int main(int argc, char **argv)
{
QApplication app(argc, argv);
myMainWindow *window = new myMainWindow();
window->resize(600, 316);
window->show();
return app.exec();
}
Here is a recipe for making a widget with a semi-transparent background colour. Just expand from there by making the background fully transparent, then display the tree image on top of that as a background image. Note that the widget will still behave like a rectangular widget in regards to laying out its child elements, so you probably need to deal with this using some custom layout inside the tree shape.
Start from the docs for QWidget::setMask. It has a version which takes a QBitmap and one that takes a QRegion. This is the fundamental function in getting a transparent widget. The toolkit also includes a clock example using the QRegion version -- I suspect a bitmap is just as easy though.
I'm writing interface with C++/Qt in QtCreator's designer. What element to chose to make as a rect with some background image?
And the second question: how to draw tiled image? I have and image with size (1×50) and I want to render it for the parent width. Any ideas?
mTopMenuBg = QPixmap("images/top_menu_bg.png");
mTopMenuBrush = QBrush(mTopMenuBg);
mTopMenuBrush.setStyle(Qt::TexturePattern);
mTopMenuBrush.setTexture(mTopMenuBg);
ui->graphicsView->setBackgroundBrush(mTopMenuBrush);
QBrush: Incorrect use of
TexturePattern
If you just want to show an image you can use QImage. To make a background with the image tiled construct a QBrush with the QImage. Then, if you were using QGraphicsScene for example, you could set the bursh as the background brush.
Here is an example which fills the entire main window with the tiled image "document.png":
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QMainWindow *mainWindow = new QMainWindow();
QGraphicsScene *scene = new QGraphicsScene(100, 100, 100, 100);
QGraphicsView *view = new QGraphicsView(scene);
mainWindow->setCentralWidget(view);
QImage *image = new QImage("document.png");
if(image->isNull()) {
std::cout << "Failed to load the image." <<std::endl;
} else {
QBrush *brush = new QBrush(*image);
view->setBackgroundBrush(*brush);
}
mainWindow->show();
return app.exec();
}
The resulting app:
Alternatively, it seems that you could use style sheets with any widget and change the background-image property on the widget. This has more integration with QtDesigner as you can set the style sheet and image in QtDesigner.