Displaying QImage on another QImage?
-
Hi all,
i am making an application which looks like as below.
!http://img198.imageshack.us/img198/817/screenshot1yi.png(Image)!
i am taking a matrix and converting it to QpixMap and adding it to Qgraphicsscene. Now this map is changed after every 4 sec and i call update after every 4 sec and it updates this image. at this level it works perfectly fine. Now i want to add more information on that image. for example in image the white line which shows the path of robot. i am doing it on same image. The problem is that robot path is updated very frequently means after 1/2 second but drawing is done after 4 sec.
So is there any way of updating this path in high frequency. secondly is it possible that i use something else for displaying this white line.
@void MainWindow::paintEvent(QPaintEvent *e)
{my_mutex.lock();
//this part updates the red lines and black background
for(unsigned int y = 0; y < 4000; y++) {
for(unsigned int x = 0; x < 4000; x++) {
unsigned int i = x + (4000 - y - 1) * 4000;
if (data12[i] == 0)
{image->setPixel(x,y,1);
}
else if (data12[i] == 100)
{
//cout<<"i can see this"<<endl;
image->setPixel(x,y,3);
}
else {
image->setPixel(x,y,1);
}
}
}
testvar=false;
my_mutex.unlock();
//this part updates the white lines on same image
for(int i=0; i< pose_x.size(); i++)
{
//cout << "i am in pose drawing "<<endl;
image->setPixel(pose_x.at(i),pose_y.at(i),2);
}
image->setPixel(pose_x.back(),pose_y.back(),4);*pixmap= QPixmap::fromImage(*image);
scene->addPixmap(*pixmap);}@
Thanks in advance.
-
Save the vector information of the white line and redraw it ontop of the image in a QPixmap? Or just buffer the white line in a separate QPixmap and just blit the background and the foreground faster than the background buffer is actually updated.
Further, I stick with my recommendations from "last time":http://qt-project.org/forums/viewthread/17566/.
-
The code you post triggers a WTF or two when I read it...
The issues start at line 4. What is that mutex doing there? You're not trying to redraw from multiple threads, are you? That is not supported and will get you into trouble.
Lines 6 and 7 is where the horror already pointed out by DerManu starts. Really? Iterating point-by-point through a 4000x4000 matrix for painting? Every time an update takes place? You cannot be serious. It is worse enough you do it at all, but doing it every paint is redicule. Just do it when anything has changed. Render into a pixmap and keep that pixmap around for the next paintEvent. Or, better yet, see if you can distill lines from the pixels (once, of course...) and draw these as items in your scene. That will hugely improve your performance.
Then, why are you not really taking advantage of the QGraphicsView? If you want to put multiple objects on top of each other, just create separate items for them (in this case: your walls and your path) and update each of them as needed. No need to render them into the same item. That way, you can take advantage of QGrahpicsViews buffering optimizations.
At the last line, you are adding items to the scene in the paintEvent. Don't. You're changing the item while painting, triggering another paint, etcetera. Further more, you're adding item after item in the view, each one a bitmap of 16MP weighing in about 64MB. You're going to run out of memory fast, even on a multi-GB machine. Who is cleaning up the older items?
recommendations
To summarize my recommendations:- Throw away the MainWindow::paintEvent reimplementation.
- Create two custom -QGraphicsViewItem- QGraphicsItem derived items, one to represent your walls, one for your robot path and add an instance of each to the scene once.
- Update these items when needed: when new data actually comes in. Cache any expensive rendering of underlying data structures inside them so they can paint themselves quickly.
- See if you can optimize the rendering of your items by making them into lines instead of big bitmaps. Should be easy for your robot's path, I think.
-
ok i got it. Regarding the mutex i am not updating it in someother thread but i am getting these pixels values from ROS and saving them in a vector thats why i am using it.
For updating all pixels now i do it for only change pixels. but i am not sure how i am suppose to do distill lines from pixels as you suggested.
now i am cleaning the scene and pixmap before adding the new one in it like this
@scene->clear();
QPixmapCache::clear();
*pixmap= QPixmap::fromImage(*image);
scene->addPixmap(*pixmap);@but still the application causes to slow the system.
From your recommendations what do you mean by QGraphicsViewItem ? i have QImage for walls and i can have QImage for path can these be represented as Item ?
Thanks
-
The actual distilling of the lines would be an image processing task, and is outside of the scope of Qt.
You are really not listening to the suggestions. Why do you clear the scene and the pixmap cache? And from where do you do that?
You only need to update the item representing the walls or the path if and when needed. There is no need to rebuild the entire scene.
I meant [[doc:QGraphicsItem]], not QGraphicsViewItem. Sorry for that confusion. Such an item can be (derived from) a QGraphicsPixmapItem, but it might also be another type. You really should look if you can't at least get the robot path in a different format than a huge bitmap. That seems like a really awkward, inefficient and inflexible representation to me.
-
@Andre Thanks for being patient with newbies. I follow your suggestions but have one problem. After making Walls and Path independent QGraphicsItem. when i call update in both independently why it generates call to paint of the both class and both paint updates themselves.
Thanks
-
I am calling update in both items independently with different frequency depending on the data arrived. Now the path data arrives with very high frequency like once in half second so i call update on it but it also causes map paint to be called since its frequency is once in a 4 second.
-
Of course. If you change the path, the underlying item (the map) needs to be repainted too. After all: they may overlap.
You'll just have to make sure the actual paint is fast enough. Did you reimplement that yet by iterating over your huge matrix only when new data comes in?
-
it is not slowing the system any more but was just wondering about the behaviour of paint.
i am still iterating through the full matrix but i am changing only those pixels which value is change. I am still not sure how to deal with this efficiently.
i am getting this 4000 * 4000 matrix in other software so cant do anything about it. Thanks alot. -
As I said before: the trick is to not iterate over the matrix every time you have to paint, but only do that when the data is changed. You can store the result of your iteration in a pixmap, and paint that pixmap in the paintEvent(). That should speed up your application a lot.
-
Hi Andre;
i am back with another problem not sure to start new thread but as i explained my work here more so continuing from here will be more appropriate.
So actual question is "At the end point of path i want to put an image of robot for which i made some 8x8 pixels image now i have to rotate that image to show the direction of robot whenever it is changed in other system(ROS)."
Now after using the traditional way found on blogs and qt documentation i got one problem the size of image (8x8) increases whenever i rotate other than 90 degree angle . which is very strange for me.
i am doing it in following way.
@
QTransform robot_transform;
QImage *robot;
robot_transform.rotate(angle);
*robot = robot->transformed(robot_transform);@and after that in paint function i paint it.
@painter->drawImage(pose_x.back(),pose_y.back(),*robot);@
Thanks in advance