PDA

View Full Version : display mutliple images and sync viewing



Algos
21st December 2014, 19:43
Folks, I can make an application to open an image file and to display it and interact with it (zooming, panning, etc). I usually read pgm, ppm, png or jpg images.

Now, I want to go a step further and make an application that can show mulitple images at the same time. The objective is to display two to four images at the same time and to zoom and pan all of them together (want to send the signals from any image's slot to all the images). What is the best way to do this?

The purpose is to examine a set of images taken with different parameters, each set taken at the same time and a series of such sets taken over a longer time. For example, I may capture 2 images at a time (different exposure setting in each), for every 1 hour. For example, after 10 hours, I will have 20 images, two for each time instance. Later, I want to view the the image pair together and to interact with both using either of the images, and also to move forward and backward in time (to scroll through the sets of images).

Currently, I am writing an application using qgraphicsivew such that I have two such objects and each object displays one image of the set. But I see that I need to treat each object's signals to be sent to both. I am hoping to avoid the tediousness of this when there are four images in a set. Any suggestions on how to start designing this?

Thanks.

d_stranz
21st December 2014, 20:39
I was faced with a similar problem is synchronizing multiple plots of scientific data. Each plot showed the same data, but with different parts highlighted. When the user zoomed in or out of one plot, all the others zoomed to the same state.

The way I did this was to implement a template class I called a "ZoomManager"; it uses as a template parameter any class that has the following methods:



void ZoomTo( double xMin, double xMax ); // Zooms x range, leaving y unchanged (or autoscaling to max y in range)

void ZoomTo( double xMin, double xMax, double yMin, double yMax ); // Zoom to rect


The template class is generic - we use it in both Qt and MFC apps, so it depends only on the STL and Boost libraries. You can easily modify it to be Qt-specific and to remove the Boost dependency.

The way it works is that the app (or MainWindow) has a single instance of ZoomManager for each set of views that must be synchronized. For each of these view, call ZoomManager::AddLink() with a pointer to the view. You can optionally add a back pointer to the ZoomManager instance to each of the views, but this isn't strictly necessary. Call SetDefaultZoom() to tell the zoom manager the full rectangle extents.

In the views, you need to handle the mouse events associated with zooming. Since you are already doing this in a single view, all you need is to add some signals to let the main window (or whoever holds the zoom manager instance) know what is going on. It is also important to move whatever code there is in your event handler that does the zooming to the ZoomTo() methods (and to let the zoom manager handle those calls - otherwise you get double updates).

When one of the zoom manager's zoom or pan methods is called, it relays the zoom region to each of the linked views, so that all views are synchronized.

The zoom manager also implements an optional zoom stack. Each zoom in operation pushes the current zoom level onto the stack, each zoom out pops the stack and restores the previous zoom level.

Source code is attached.

Algos
21st December 2014, 23:38
Thanks for sharing your solution and the code snippet. I will play around with it and let you know if I face any troubles in this.

Algos
5th April 2015, 23:25
In the views, you need to handle the mouse events associated with zooming. Since you are already doing this in a single view, all you need is to add some signals to let the main window (or whoever holds the zoom manager instance) know what is going on. It is also important to move whatever code there is in your event handler that does the zooming to the ZoomTo() methods (and to let the zoom manager handle those calls - otherwise you get double updates).

When one of the zoom manager's zoom or pan methods is called, it relays the zoom region to each of the linked views, so that all views are synchronized.


Finally got to make this work (my pet project, so takes its time). Zooming is working fine. I have a two~four (depends on my config) images showing and I can zoom on any one of them and the others zoom in sync.


However, I have run into issues during panning.

For panning, I have connected the horizontalscrollbar signal my derived graphicsview class thus:

connect(this->horizontalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(panImage(int)));

and the panImage function is the following.

void myGraphicsView::panImage(int nTmp) {
if (nTmp != m_nCurrScrollPos) {
if (NULL != m_pMain) {
//get the panned scene's rectangle
QRectF SceneRectPanned = mapToScene(viewport()->geometry()).boundingRect();
float x1New = SceneRectPanned.left() ;
float x2New = SceneRectPanned.right() ;
float y1New = SceneRectPanned.top() ;
float y2New = SceneRectPanned.bottom() ;

//ZoomXY just required the new rectangle, give it the panned rect to pan the views.
m_pMain->m_pZM->ZoomXY(x1New, x2New, y1New, y2New);
}
m_nCurrScrollPos = nTmp;
}
}
Here, m_pMain is the pointer to my class that shows the images, etc. and also contains the zoomer instance m_pZM.

I seem to be running into recursions. I am pretty sure it is a basic mistake. But what !?


Thanks.