mountakis's picture

Image viewer with zoom and pan capabilities

I am not familiar with opengl and I haven’t installed yet OpenTK. I use c# for computer vision tasks and I am wondering how easy can it can be to create a picturebox (Image viewer) with zooming and panning capabilities, while at the same time to draw points and lines on the image.
Thanks in advance for your help.


Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
the Fiddler's picture

It is not hard, either with OpenTK and without. Using OpenTK.GLControl is going to be a little harder than a plain old PictureBox (not much), but it is going to give you much better performance if you want real-time zomming, panning and other effects (drawing over the images).

I assume that you are going to stream a camera feed, analyze it and display it on screen with an information overlay (i.e. edge detection etc)? In that case OpenGL is the way to go - plain GDI+ just won't be fast enough.

You'll have to give some more information about your application, if you want more specific advice.

Edit: Of course, feel free to post here if you encounter any problems or don't know how to do something in OpenGL/OpenTK.

mountakis's picture

Thanks for your response!
Concerning the computer vision application that I’m implementing, it has to do, as you said, with image processing, but also 3D model reconstruction. More precisely, from a set of overlapping images, the goal is to calibrate them automatically (using corresponding image points) and finally to reconstruct in 3D space the observed object. Most of the application’s functions have been implemented in c, c++, and Matlab. Yet, a GUI where the user can measure points and lines on the images, or observe the automatically extracted ones, is a demand. For this purpose, I’m already using visual studio 2008, where the program interface is in c#, while the main functions are in c++ (in the same solution). Recently, I have also incorporated some opencv routines (emgu – wrapper for opencv) and I found it very interesting.
Unfortunately, the source images are in high and, sometimes, very high resolution (15000 x 15000 pixel), which makes things more difficult for a viewer to handle. In such cases, I suppose that it is better to use the image pyramid technique (image in different resolutions) so the viewer shows the image that corresponds to the current zoom factor. This is one of the first things I will try to implement in OpenTK and I would appreciate any help with some examples.
Finally, I believe that using openGL in this application is probably the most appropriate solution, since the final product is a 3D model that has to be further analyzed.
Thanks again…

the Fiddler's picture

Sounds like a very interesting project.

What kind of hardware will the viewer run on? Do you need to maintain compatibility with older hardware or IGPs (e.g. intel chips), or are you free to specify minimum requirements?

Some random points that may be helpful:

Graphics hardware is typically limited to 2048x0248, 4096x4096 or (very recently) 8096x8096 textures, so the first thing is to design a system that tiles the source image into an array of textures.

Are the images static? If yes, you can simply go ahead and draw these tiles at the desired zoom level: anything built in the last ten years should be able to handle that without even breaking a sweat. If the source images change however, you are bound to hit a bottleneck in texture updates: to maintain acceptable performance, you'll have to cascade them (i.e. update the most important regions first) and possibly implement an asynchronous update method (using pixel buffer objects, or even a second OpenGL context in a different thread).

For a viewer, you'll want to use GLControl class. Simply drag and drop it onto a Form and use it as any other Windows.Form component (check out our WinForms+OpenGL tutorial for more details).

This blog post shows how to create and fill an OpenGL texture with data.

Don't hesitate to search around and ask on the forums if you encounter any roadblocks!

mountakis's picture

It has been a long time since my previous message, but recently I tried OpenTK and thanks to the help and the comments of Fiddler, I finally was able to handle images in the glControl. The result is very satisfactory since zoom and pan are performed very fast and smoothly (it is even faster than zooming the same image in irfanview!). One can zoom in and out (to the location of the mouse) using the wheel button, and pan with the middle button. The code simply changes the vertices (GL.Vertex2) of the glCcontrol space, that are mapped to the four vertices (GL.TexCoord2) in the image space, according to some mouse events.
So, my first question is, if this is the best way (wrt performance) to handle images. Isn’t it also possible by changing the GL.Viewport?
Of course, the largest image I can view with this way (as Fiddler had mentioned) is 8096 x 8096 pixels, so soon I’ll have to figure out the image tiles.
The second question has to do with drawing on top of the image. In a specific line of the code, the program has to wait until the user plots four points on the image (using cross symbol) and then continue to the next lines. I know that this is not an OpenGL question, but if you have any good idea I would be grateful.

Thanks again Fiddler for your help

the Fiddler's picture
mountakis wrote:

So, my first question is, if this is the best way (wrt performance) to handle images. Isn’t it also possible by changing the GL.Viewport?

The typical approach is to keep the vertices intact and change the modelview matrix:

GL.MatrixMode(MatrixMode.Modelview);
GL.LoadIdentity();
GL.Scale(2, 2, 1);  // Scales the model to double-size in the X and Y directions
GL.Translate(X, Y, 0); // Translates the image to (X, Y, 0)

However the amount of data is so small that it doesn't really matter here.

mountakis wrote:

The second question has to do with drawing on top of the image. In a specific line of the code, the program has to wait until the user plots four points on the image (using cross symbol) and then continue to the next lines. I know that this is not an OpenGL question, but if you have any good idea I would be grateful.

One elegant approach is to use events. Use the MouseClick event of the GLControl to detect clicks and raise a different event when you detect 4 clicks in a cross-shaped pattern. Hook these lines of code to the new event - now they will be executed whenever the correct pattern is entered.

// In pseudo-code:
class CrossEventArgs : EventArgs
{
    public Point[] Points = new Point[4];
}
 
// Detects cross-shaped clicks.
// Use it like this:
// CrossDetector cross_detector = new CrossDetector(glControl1);
// Or you can pass any other Control, e.g. the main Form.
class CrossDetector
{
    public event EventHandler<CrossEventArgs> CrossEntered = delegate { };
    ...
 
    public Foo(Control control)
    {
        ...
       control.MouseClick += delegate(object sender, MouseEventArgs e)
       {
           // Save consecutive clicks and detect if they resemble a cross.
           if (cross_detected)
               OnCrossEntered(this, new CrossEventArgs() { Points = ... } );
       };
    }
 
    // Raises the CrossEntered event.
    protected virtual OnCrossEntered(CrossEventArgs e)
    {
        CrossEntered(this, e);
    }
}
 
// Finally, hook the piece of code you wish to execute to the CrossEntered event.
// This piece of code could go in any class, including on its own or in the main Form.
// Wherevere it makes sense.
class Foo
{
    readonly CrossDetector cross_detector;
 
    public Foo(CrossDetector detector)
    {
        cross_detector = detector;
        cross_detector.CrossEntered += delegate(object sender, CrossEventArgs e)
        {
             // The code you wish to execute when a cross is detected.
        };
    }
}

Hope this makes sense.