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.
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.
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
- 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.
- Add RSIMGControl.dll to the toolbar through choose items.
- Drag the control named as
RSPicburebox
to the dedicated form.
- 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();
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();
ofd.Filter = "regular digital image|*.jpg;*.png;*.bmp*|
remote sensing image|*.tif;*.img;*.int";
if (ofd.ShowDialog() == DialogResult.OK)
{
OSGeo.GDAL.Gdal.AllRegister();
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:
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.