Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

A Picturebox Control to Display Both Remote Sensing and Regular Digital Images

0.00/5 (No votes)
26 Feb 2011 1  
A Picturebox control to display both remote sensing and regular digital images

Introduction

Extracting useful land use features, such as buildings, roads, and even vehicles, from remote sensing imagery has long been a focus in the field of digital image analysis. Now many software and web services (e.g., Google Earth, Google Map, ArcMap and Bing Maps) have successfully applied information from remote sensing images to assist the public to solve a wide variety of problems like navigation, urban planning and environment engineering. However, compared with regular digital images, the remote sensing images usually have more bands and in various data types (e.g., byte, integer, float, and double). Due to the specialties of remote sensing images, they are not well supported by regular image viewers. For example, the built-in Picturebox control in Visual Studio is not able to display remote sensing images.

image001.jpgimage002.jpg

Figure 1. Screen-shot of the DEMO GUI

This project created a novel Picturebox control which is capable of displaying both regular and remote sensing digital images. Compared with other open-source projects, such as MapWinGIS and SharpMap, the remote sensing Picturebox control is light in size which contained only limited functions. However, this project provides an image display control for applications using remote sensing images and might be useful to inspire beginners on using Geospatial Data Abstract Library (GDAL) for remote sensing image vision. The control was compiled using both GDAL 1.5 and GDI+. GDAL is a powerful and well designed open source library which provides access to geo-spatial dataset in raster format. Geo-spatial dataset in vector format is supported as well via GDAL’s OGR library. Lots of software, such as Google Earth, ArcGIS, ERDAS, GRASS, and IDRISI, have employed GDAL for displaying and analyzing geospatial dataset. GDI+ is a mature technology which enables applications to use graphics and even formatted text. It has been widely used in Windows-based applications. GDI+ is used in this project to display remote sensing images due to its efficiency in showing 2D images.

Background

The way to render remote sensing image using GDI+ is to create a Bitmap object using data from the corresponding bands. The most straightforward way to create the Bitmap object is to import the remote sensing image data directly into a BitmapData object. However, it is not a wise way to create a Bitmap object by importing the remote sensing data entirely because loading remote sensing images might require huge memory consumption. In this project, I used a tricky way to display the remote sensing images which proved to be able to render remote sensing image in large size. Figure 2 (a) shows the way to render remote sensing images using image pyramid, and figure 2(b) illustrates the way to render remote sensing images with various buffer scales in rows’ and columns’ directions. For memory saving consideration, build pyramids for the remote sensing images display the virtual layers according to memory limitations or control size is a common choice. However, the virtual layers are downscaled with the same rates (i.e., 1/2, 1/4, 1/8, 1/16) in both rows’ and columns’ directions, which usually results in raw and vague displaying effects. In addition, through displaying virtual layers, it could be hard for programmers in the beginner level to adjust the scale wisely while zooming and panning. Compared with building pyramids, scale images using unequal weights can be easily implemented using GDAL (e.g., Band.readraster function). Once the control’s displaying rectangle has been determined, users can import the remote sensing images according to the control’s displaying size. Unsafe codes (pointer) were used to accelerate the data importation process in this project.

image003.jpg

Figure 2. Mechanisms of displaying images using image pyramid and raster scale
public Bitmap RSImg2BitMap(OSGeo.GDAL.Dataset dataset, 
                             Rectangle ExtentRect, int[] displayBands)
        {
            int x1width = ExtentRect.Width;
            int y1height = ExtentRect.Height;

            Bitmap image = new Bitmap(x1width, y1height, 
                                     System.Drawing.Imaging.PixelFormat.Format24bppRgb);
            int iPixelSize = 3;

            if (dataset != null)
            {
                BitmapData bitmapdata = image.LockBits(new 
                                        Rectangle(0, 0, x1width, y1height), 
                                        ImageLockMode.ReadWrite, image.PixelFormat);
                int ch = 0;

                try
                {
                    unsafe
                    {
                        for (int i = 1; i <= displayBands.Length; ++i)
                        {
                            OSGeo.GDAL.Band band = 
				dataset.GetRasterBand(displayBands[i - 1]);
                            int[] buffer = new int[x1width * y1height];
                            band.ReadRaster(0, 0, __Geodataset.RasterXSize, 
                                __Geodataset.RasterYSize, buffer, 
				x1width, y1height, 0, 0);
                            int p_indx = 0;

                            if ((int)band.GetRasterColorInterpretation() == 5) 
                                ch = 0;
                            if ((int)band.GetRasterColorInterpretation() == 4) 
                                ch = 1;
                            if ((int)band.GetRasterColorInterpretation() == 3) 
                                ch = 2;
                            if ((int)band.GetRasterColorInterpretation() != 2)
                            {
                                double maxVal = 0.0;
                                double minVal = 0.0;
                                maxVal = GetMaxWithoutNoData(dataset, 
                                         displayBands[i - 1], -9999.0);
                                minVal = GetMinWithoutNoData(dataset, 
                                         displayBands[i - 1], -9999.0);
                                for (int y = 0; y < y1height; y++)
                                {
                                    byte* row = (byte*)bitmapdata.Scan0 + 
                                                      (y * bitmapdata.Stride);
                                    for (int x = 0; x < x1width; x++, p_indx++)
                                    {
                                        byte tempVal = shift2Byte(buffer[p_indx], 
						maxVal, minVal, -9999.0);
                                        row[x * iPixelSize + ch] = tempVal;
                                    }
                                }
                            }
                            else
                            {
                                double maxVal = 0.0;
                                double minVal = 0.0;
                                maxVal = GetMaxWithoutNoData(dataset, 
                                         displayBands[i - 1], -9999.0);
                                minVal = GetMinWithoutNoData(dataset, 
                                         displayBands[i - 1], -9999.0);
                                for (int y = 0; y < y1height; y++)
                                {
                                    byte* row = (byte*)bitmapdata.Scan0 + 
                                                (y * bitmapdata.Stride);
                                    for (int x = 0; x < x1width; x++, p_indx++)
                                    {
                                        byte tempVal = shift2Byte<int />(buffer[p_indx], 
						maxVal, minVal, -9999.0);
                                        row[x * iPixelSize] = tempVal;
                                        row[x * iPixelSize + 1] = tempVal;
                                        row[x * iPixelSize + 2] = tempVal;
                                    }
                                }
                            }
                            ch++;
                        }
                    }
                }
                finally
                {
                    image.UnlockBits(bitmapdata);
                }
            }
            return image;
        }

Create your Applications

Preparation

  1. Copy the 5 .dll files (gdal15.dll, gdal_csharp.dll, gdalconst_wrap.dll, gdal_wrap.dll, and gdalconst_csharp.dll) from the DEMO project into your executable bin file folder “..\bin\Debug\”, and add gdal_csharp.dll as reference to your project.

    image004.jpg

  2. Add RSIMGControl.dll to the toolbar through choose items.

    image005.jpg

  3. Drag the control named as RSPicburebox to the dedicated form.

    image006.jpg

  4. Import the necessary libraries:
    using  System;
    using  System.Collections.Generic;
    using  System.ComponentModel;
    using  System.Data;
    using  System.Drawing;
    using  System.Drawing.Imaging;
    using  System.Text;
    using  System.Windows.Forms;
    using  RSIMGControl.control;
    using  OSGeo.GDAL;

Using the Code

There are two ways to display remote sensing images using the RSPicturebox. The easiest way is to set the “ImagePath” property using the following codes:

RSPicturebox rsPicburebox1=new RSPicturebox();
OpenFileDialog ofd = new OpenFileDialog();
//By default, assume that remote sensing images are usually 
//saved in the format of.tif or .img
ofd.Filter = "regular digital image|*.jpg;*.png;*.bmp*|
		remote sensing image|*.tif;*.img;*.int";
if (ofd.ShowDialog() == DialogResult.OK)
{
    rsPicturebox1.ImagePath = ofd.FileName;
}

Another way is to assign OSGeo.GDAL.Dataset to RSIMGControl’s GeoDataset property, which uses the following codes:

RSPicturebox rsPicburebox1=new RSPicturebox();
OpenFileDialog ofd = new OpenFileDialog();
//By default, assume that remote sensing images are 
//usually saved in the format //of .tif or .img
ofd.Filter = "regular digital image|*.jpg;*.png;*.bmp*|
	remote sensing image|*.tif;*.img;*.int";
if (ofd.ShowDialog() == DialogResult.OK)
{
	//Register all the drivers for remote sensing in different formats.
	OSGeo.GDAL.Gdal.AllRegister();
	//Open the image using "ReadOnly" access.
   	OSGeo.GDAL.Dataset dataset = OSGeo.GDAL.Gdal.Open
				(__ImgPath, OSGeo.GDAL.Access.GA_ReadOnly);
    rsPicburebox1.GeoDataset=dataset;
}

RGB bands selection is also important for displaying remote sensing images, since different land use features are stressed with various band combinations. Besides the default setup for multispectral images (e.g., red band is band 1, green band is band 2, and blue band is band 3), users can assign the RGB bands using the following syntaxes:

//2, 3, 4 means band 2, 3, 4 for red, green and blue band, respectively.
int[] displayBands = new int[3] {2,3,4};
rsimgPicburebox1.DisplayBands =displayBands;
rsimgPicburebox1.Invalidate();

If you assign red, green and blue bands all to a same band (e.g., displayBands = new int[3] {1,1,1 };), the remote sensing image is displayed as a grayscale figure. Same as viewing images in Google Earth, you can use mouse wheel to zoom in and out the displaying figure, and also you can pan the image by moving the mouse with right key down.

The RSPicturebox control is capable of displaying images with various types, like byte, int16, int32, float, and even double. For remote sensing images whose pixel values are out of displaying range (0-255), the pixel values are automatically scaled. Users can obtain remote sensing sample images in various data types and formats from the author’s personal website or search from other websites (USGS). It needs to be clarified that the no-data pixels (e.g., pixel value < -9999) are going to be displayed in the color of black. In addition, users are capable of accessing the data of the remote sensing image through using the property of “GeoDataset” and obtaining the current displaying figure using the property of “DispBitMap”.

Points of Interest

Two simple applications such as change display bands and histogram equalization were included in the demo.

History

  • First version: January, 2011

About the Author

I’m now a PHD student majoring in Geospatial Information Science and Engineering at SUNY-ESF. I’m interested in applying geo-spatial dataset to solve cutting edge environmental and social problems.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here