Reading Geo tiff Latitude and Longitude [duplicate] - c#

I have acquired Digital Elevation Maps(Height Map of Earth) of some area. My aim was to create Realistic Terrains.
Terrain Generation is no problem. I have practiced that using VC# & XNA framework.
The problem is that those Height Map Files are in GeoTIFF format which i don't know how to read. Nor do i have previous experience with reading any image files so that i could experiment something using little tips-bits available on internet about reading GeoTIFF files. So far i have been unsuccessful.
The geoTIFF files I have are 3601 x 3601 files.
Each file has two version, a decimal & num valued files.
Each file has data of every second of longitude & latitude of
Geo-Coords along with Height Map i.e Lon, Lat, height from sea level
How to read these file :)
The files I have are from ASTER G-DEM Version-2 LINK TO OFFICIAL DESCRIPTION according to them GeoTIFF is pretty standard which is because some GeoTIFF Visualizers I dwonloaded are showing me the correct data.
I am gonna be using C#. I would appreciate if we talk in relation to this language.
E D I T
okay i got the libtiff and this what i have done,
using (Tiff tiff = Tiff.Open(#"Test\N41E071_dem.tif", r))
{
int width = tiff.GetField(TiffTag.IMAGEWIDTH)[0].ToInt();
int height = tiff.GetField(TiffTag.IMAGELENGTH)[0].ToInt();
double dpiX = tiff.GetField(TiffTag.XRESOLUTION)[0].ToDouble();
double dpiY = tiff.GetField(TiffTag.YRESOLUTION)[0].ToDouble();
byte[] scanline = new byte[tiff.ScanlineSize()];
ushort[] scanline16Bit = new ushort[tiff.ScanlineSize() / 2];
for (int i = 0; i < height; i++)
{
tiff.ReadScanline(scanline, i); //Loading ith Line
MultiplyScanLineAs16BitSamples(scanline, scanline16Bit, 16,i);
}
}
private static void MultiplyScanLineAs16BitSamples(byte[] scanline, ushort[] temp, ushort factor,int row)
{
if (scanline.Length % 2 != 0)
{
// each two bytes define one sample so there should be even number of bytes
throw new ArgumentException();
}
Buffer.BlockCopy(scanline, 0, temp, 0, scanline.Length);
for (int i = 0; i < temp.Length; i++)
{
temp[i] *= factor;
MessageBox.Show("Row:"+row.ToString()+"Column:"+(i/2).ToString()+"Value:"+temp[i].ToString());
}
}
where i am displaying the message box, i am displaying the corresponding values, Am i doing it Right, i am asking this cuz this is my maiden experience with images & 8\16 bit problem. I think unlike the official tutorials of libtiff i should be using short instead of ushort because the images i am using are "GeoTIFF, signed 16 bits"

There are some SDKs out there usable from C# to read GeoTIFF files:
http://www.bluemarblegeo.com/global-mapper/developer/developer.php#details (commercial)
http://bitmiracle.com/libtiff/ (free)
http://trac.osgeo.org/gdal/wiki/GdalOgrInCsharp (free?)
UPDATE:
The spec for GeoTIFF can be found here - to me it seems that GeoTIFFs can contain different "subtypes" of information which in turn need to be interpreted appropriately...

Here's a guy that did it without GDAL: http://build-failed.blogspot.com.au/2014/12/processing-geotiff-files-in-net-without.html
GDAL is available in NuGet, though.

If the GeoTIFF contains tiles, you need a different approach. This is how to read a GeoTiff that contains 32bit floats with height data:
int buffersize = 1000000;
using (Tiff tiff = Tiff.Open(geotifffile, "r"))
{
int nooftiles = tiff.GetField(TiffTag.TILEBYTECOUNTS).Length;
int width = tiff.GetField(TiffTag.TILEWIDTH)[0].ToInt();
int height = tiff.GetField(TiffTag.TILELENGTH)[0].ToInt();
byte[] buffer = new byte[buffersize];
for (int i = 0; i < nooftiles; i++)
{
int size = tiff.ReadEncodedTile(i, buffer, 0, buffersize);
float[,] data = new float[width, height];
Buffer.BlockCopy(buffer, 0, data, 0, size); // Convert byte array to x,y array of floats (height data)
// Do whatever you want with the height data (calculate hillshade images etc.)
}
}

Related

Plot values of a line from a grayscale image

I am trying to take a grayscale bitmap and extract a single line from it and then graph the gray values. I got something to work, but I'm not really happy with it. It just seems slow and tedious. I am sure someone has a better idea
WriteableBitmap someImg; //camera image
int imgWidth = someImg.PixelWidth;
int imgHeight = someImg.PixelHeight;
Int32Rect rectLine = new Int32Rect(0, imgHeight / 2, imgWidth, 1); //horizontal line half way down the image as a rectangle with height 1
//calculate stride and buffer size
int imgStride = (imgWidth * someImg.Format.BitsPerPixel + 7) / 8; // not sure I understand this part
byte[] buffer = new byte[imgStride * rectLine.Height];
//copy pixels to buffer
someImg.CopyPixels(rectLine, buffer, imgStride, 0);
const int xGraphHeight = 256;
WriteableBitmap xgraph = new WriteableBitmap(imgWidth, xGraphHeight, someImg.DpiX, someImg.DpiY, PixelFormats.Gray8, null);
//loop through pixels
for (int i = 0; i < imgWidth; i++)
{
Int32Rect dot = new Int32Rect(i, buffer[i], 1, 1); //1x1 rectangle
byte[] WhiteDotByte = { 255 }; //white
xgraph.WritePixels(dot, WhiteDotByte, imgStride, 0);//write pixel
}
You can see the image and the plot below the green line. I guess I am having some WPF issues that make it look funny but that's a problem for another post.
I assume the goal is to create a plot of the pixel value intensities of the selected line.
The first approach to consider it to use an actual plotting library. I have used oxyplot, it works fine, but is lacking in some aspects. Unless you have specific performance requirements this will likely be the most flexible approach to take.
If you actually want to render to an image you might be better of using unsafe code to access the pixel values directly. For example:
xgraph.Lock();
for (int y = 0; y < imgHeight; y++){
var rowPtr = (byte*)(xgraph.BackBuffer + y * xgraph.BackBufferStride);
for(int x = 0; x < imgWidth; x++){
rowPtr[x] = (byte)(y < buffer[i] ? 0 : 255);
}
}
self.Unlock(); // this should be placed in a finally statement
This should be faster than writing 1x1 rectangles. It should also write columns instead of single pixels, and that should help making the graph more visible. You might also consider allowing arbitrary image height and scale the comparison value.
If you want to plot the pixel values along an arbitrary line, and not just a horizontal one. You can take equidistant samples along the line, and use bilinear interpolation to sample the image.

How do I get a partial image from a raw byte array of colors?

So I want to grab a partial image from a byte array of colors. The image is a unity logo that is 64x64 pixels. I want to grab a third of the image (Unity Logo). How would I traverse the byte array to get this image?
Unity Byte Array
assuming each byte is a single pixel (which is only true for 8-bit depth images), the bytes 0-63 are the first row, 64-127 are the second row, etc etc.
meaning that to find out the position of a pixel in the one-dimensional array, based on its two-dimensional coordinates in the image itself, you do
int oneDimPos = (y*64) + x;
if each pixel were 3 bytes (24-bit color depth), the conversion from 2dimensional to 1dimensional coordinates would be:
int oneDimPos = (y * 64 * 3) + (x * 3);
(so the most generic equation is:
int oneDimPos = (y * imageWidth * colorDepth) + (x * colorDepth);
and you need to keep this in mind and adjust the code accordingly. or even better, use this most generic version, and actually read the image width and its color depth from the asset you're using as source.
BEWARE: if the image is anything else than 8bits per pixel, this equation will, naturally, only give you the first, starting bit belonging to that pixel, and you still need to take care to actually also read the other ones that belong to that pixel
i'm gonna finish the answer assuming 8bit color depth, for simplicity, as well as so that you can't just copypaste the answer, but also have to understand it and re-shape it according to your specific needs ;)
)
meaning you can now do classic two nested loops for x and y:
List<byte> result = new List(); //i'm going to use list so i can just .Add each byte instead of having to calculate and allocate the final size in advance, and having to mess around with recalculating the index from the source array into the destination one, because i'm lazy
for(int x=0; x < 22; x++){ //no way for you to grab precise third since that boundary is in the middle of a pixel for an image 64pixels wide
for(int y = 0; y < 64; y++){ //we go all the way to the bottom
result.Add(sourceAsset.bytes[(y*64) + x]);
}
}
//now just convert the list to actual byte array
byte[] resultBytes = result.ToArray();
The original issue that I was having was not exactly the same as the question. I wanted to simplify it by having a byte array that everyone could take a look at. The byte array from Unity's website wasn't exactly what I was getting.
So I have 3 x 1080p portrait screen (1080 x 1920 pixels) with RGBA channels. I grabbed a screenshot from this and got a 24,883,200 size byte array.
Note, 3 * width(1080) * height(1920) * channels(4) = 24,883,200.
byte[] colors = new byte[24883200]; // Screenshot of 3x1080p screen.
byte[] leftThird = new byte[colors.Length / 3];
Array.Copy(colors, 0, leftThird, 0, colors.Length / 3); // Grab the first third of array
This is an issue because the colors array is read from top to bottom, left to right. So instead, you should read a portion of the 3 x 1080 x 4 channels.
int width = 1080 * 4; // 4 channels of colors (RGBA)
int fullWidth = width * 3; // Three screens
int height = 1920;
byte[] leftScreen = new byte[screenShotByteArray.Length / 3];
for(int i = 0; i < height; i++)
{
Array.Copy(screenShotByteArray, (i * fullWidth) + (offset * 4), leftScreen, i * width, width);
}

On printing mono chrome bitmap image one extra vertical line is also getting printed

I am printing the mono chorme bit map image on thermal printer where i am able to print the image but at rightmost, one vertical line is getting printed. (The line is from Top right to bottom right with nearly 2mm thick)
Bitmap image = new Bitmap(imagePath, false);
int imageDepth = System.Drawing.Bitmap.GetPixelFormatSize(image.PixelFormat);
Rectangle monoChromeBitmapRectangle = new Rectangle(0, 0, image.Width, image.Height);
BitmapData monoChromebmpData = null;
int stride = 0;
monoChromebmpData = image.LockBits(monoChromeBitmapRectangle, ImageLockMode.ReadOnly, resizedImage.PixelFormat);
IntPtr ptr = monoChromebmpData.Scan0;
stride = monoChromebmpData.Stride;
int numbytes = stride * image.Height;
byte[] bitmapFileData = new byte[numbytes];
Marshal.Copy(ptr, bitmapFileData, 0, numbytes);
image.UnlockBits(monoChromebmpData);
//Invert bitmap colors
for (int i = 0; i < bitmapFileData.Length; i++)
{
bitmapFileData[i] ^= 0xFF;
}
StringBuilder hexaDecimalImageDataString = new StringBuilder(bitmapFileData.Length * 2);
foreach (byte b in bitmapFileData)
hexaDecimalImageDataString.AppendFormat("{0:X2}", b);
return hexaDecimalImageDataString;
Here i am converting the mono chrome bitmap image to byte array and from byte array to hexadecimal string.
i googled in forums but this kind of error is not discussed. (May be i am doing silly mistake)
Can any one suggest where exactly i am making the mistake.
Thanks in advance.
Cheers,
Siva.
Your are returning monoChromebmpData.Stride * image.Height bytes, i.e. each line in the image will be exactly monoChromebmpData.Stride * 8 pixels wide - but probably the original image has a pixel width that is less than that, hence the extra vertical line on the right.
Try something like this:
byte[] masks = new byte[]{0xff, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f};
int byteWidth = (image.Width+7)/8;
int nBits = imageWidth % 8;
byte[] actualBitmapFileData = new byte[byteWidth*image.Height];
int yFrom = 0;
for (int y=0; y<image.Height; y++) {
for (int x=0; x<byteWidth-1; x++) {
actualBitmapFileData[y*byteWidth + x] = (bitmapFileData[yFrom + x] ^ 0xFF);
}
int lastX = byteWidth - 1;
actualBitmapFileData[y*byteWidth + lastX] = (bitmapFileData[yFrom + lastX] ^ 0xFF) & masks[nBits];
yFrom += stride;
}
it creates an actualBitmapFileData array for bitmapFileData with of the correct size.
Note that the last byte of every line would contain only nBits pixels - and so needs to be 'masked' to clear out the extra bit not corresponding with any pixel. This is done by & masks[nBits], where masks is an array of 8 bytes with the 8 masks to use. The actual values of the mask depend on how the printer works: you might need to set the extra bits to 0 or to 1, and the extra bits can be the most-significant or the least-significant ones. The mask values used above assume that the most significant bits are rendered to the right, and that the masked bits should be set to 0. Depending on how the printer works it might be necessary to swap the bits and/or set the masked bits to 1 instead than zero (complementing the mask and using | instead than &)
For performance reasons each horizontal row in a Bitmap is buffered to a DWORD boundary (see this answer for more details). So if your Bitmap's width multiplied by it's bits-per-pixel(bpp) is not divisible by 32 (DWORD = 32bits) then it's padded with extra bits. So a 238x40 1bpp Bitmap has a memory foot print of 8 DWORDs per row or 256 bits.
The BitmapData object's Stride property is the number of bytes that each row of your bitmap consumes in memory. When you capture the Byte Array, you're capturing that padding as well.
Before you convert the byte array to hex you need to trim the buffer off the end. The following function should do that nicely.
public static byte[] TruncatePadding(byte[] PaddedImage, int Width, int Stride, int BitsPerPixel)
{
//Stride values can be negative
Stride = Math.Abs(Stride);
//Get the actual number of bytes each row contains.
int shortStride = (int)Math.Ceiling((double)(Width*BitsPerPixel/8));
//Figure out the height of the image from the array data
int height = PaddedImage.Length / Stride;
if (height < 1)
return null;
//Allocate the new array based on the image width
byte[] truncatedImage = new byte[shortStride * height];
//Copy the data minus the padding to a new array
for(int i = 0; i < height; i++)
Buffer.BlockCopy(PaddedImage,i*Stride,truncatedImage,i*shortStride,shortStride);
return truncatedImage;
}
The comments from MiMo and MyItchyChin helped me alot on resolving the issue.
The problem is getting the extra line at the end. So technically, on printing the each row of image, last few byte information is incorrect.
The reason for getting this problem is, the image size could be anything, but whne it sends to printer, the byte width should be divisible by eight. In my case my printer expects the bytewidth as input so i must be careful on passing the image.
Assume i have image 168x168 size.
byteWidth = Math.Ceiling(bitmapDataWidth / 8.0);
so the byteWidth is 21 here, As per printer expectation i did Left shift operation to 24 which is diviseble by 8, so virtually i increased the size of image by 3bytes and then started reading the byte information. The line i am talking about is that extra 3 bytes. Since no data is there, the black line is getting printed.
I wrote the logic in such a way, where byte array doesnot effect with shift operations hence it worked for me.
Early days for me in image processing, So please ignore, if i made a silly mistake and explaining the solution here.

Algorithm to detect an image in another image with some noise

I'm searching for the best library to search for identical area in two different images, all images being compressed in JPEG, with a lot of noise. I'm having a hard time finding one. The problem is if you zoom a jpeg, you'll see that it looks like a Monet, I mean, the noise contains a color palette that have no direct link with the original image. So instead of searching for an identical array in the image, I need to find the 'most similar array'.
These images come from random screenshot over a googlemap similar websites, and the images cannot be in another format than jpeg.
I tried a lot of manual way.
One of my method is:
Transforming my two images in smaller images
Changing them in 4bpp images, or even less colors
Taking a small part of image 1
Searching for the byte[] array version of a cropped part of image 1 in image 2
Not searching for identical, but for similar matches.
This algorithm works, but I'm doing everything in one dimension array, and it is very slow.
Is there existing libraries that would do this algorithm directly?
My algorithm is:
// Where SRC is the bigger image in which I search
// Offset is where in my small image I start to search
// Len is how long is my searched array
// Size is the size of the bigger image in which I'm searching.
// private Point simpleSearch(byte[] src, int offset, int len, byte[] search, Size size)
{
byte[] ddd = new byte[len];
Array.Copy(search, offset, ddd, 0, len);
int lowest = 100000000;
int locmatch = 0;
for (int i = 0; i < src.Length - len; i++)
{
int thed = 0;
for (int a = 0; a < len; a++)
{
int diff = Math.Abs(src[i + a] - ddd[a]);
thed += diff;
}
thed = thed / len;
if (thed < lowest)
{
lowest = thed;
locmatch = i-len;
}
}
int yy = (locmatch / size.Width);
int xx = locmatch - (yy * size.Width);
Point p = new Point(xx, yy);
return p;
}
Yep correlation or spectrum signature are ways to tell how similar two image regions are. But I think what you really want here is an algorithm to efficiently search the overlapping region.
Correspondence problem is a well defined problem in computer vision that tries to figure out which parts of an image correspond to which parts of another image. There are RANSAC based algorithms.
There's also a quad-tree algorithm that brings the complexity down to logarithm order.

Reading monochrome bitmap pixel colors

I don't know a better title, but I'll describe the problem.
A piece of hardware we use has the ability to display images.
It can display a black and white image with a resolution of 64 x 256.
The problem is the format of the image we have to send to the device.
It is not a standard bitmap format, but instead it is simply an array of
bytes representing each pixel of the image.
0 = black, 1 = white.
So if we had an image with the size: 4 x 4 the byte array might look something like:
1000 0100 0010 0001
And the image would look like:
Bitmap http://www.mediafire.com/imgbnc.php/6ee6a28148d0170708cb10ec7ce6512e4g.jpg
The problem is that we need to create this image by creating a monochrome bitmap
in C# and then convert it to the file format understood by the device.
For example, one might to display text on the device. In order to do so he would
have to create a bitmap and write text to it:
var bitmap = new Bitmap(256, 64);
using (var graphics = Graphics.FromImage(bitmap))
{
graphics.DrawString("Hello World", new Font("Courier", 10, FontStyle.Regular), new SolidBrush(Color.White), 1, 1);
}
There are 2 problems here:
The generated bitmap isn't monochrome
The generated bitmap has a different binary format
So I need a way to:
Generate a monochrome bitmap in .NET
Read the individual pixel colors for each pixel in the bitmap
I have found that you can set the pixel depth to 16, 24, or 32 bits, but haven't found monochrome and I have no idea how to read the pixel data.
Suggestions are welcome.
UPDATE: I cannot use Win32 PInvokes... has to be platform neutral!
FOLLOW UP: The following code works for me now. (Just in case anybody needs it)
private static byte[] GetLedBytes(Bitmap bitmap)
{
int threshold = 127;
int index = 0;
int dimensions = bitmap.Height * bitmap.Width;
BitArray bits = new BitArray(dimensions);
//Vertically
for (int y = 0; y < bitmap.Height; y++)
{
//Horizontally
for (int x = 0; x < bitmap.Width; x++)
{
Color c = bitmap.GetPixel(x, y);
int luminance = (int)(c.R * 0.3 + c.G * 0.59 + c.B * 0.11);
bits[index] = (luminance > threshold);
index++;
}
}
byte[] data = new byte[dimensions / 8];
bits.CopyTo(data, 0);
return data;
}
I'd compute the luminance of each pixel a then compare it to some threshold value.
y=0.3*R+0.59G*G+0.11*B
Say the threshold value is 127:
const int threshold = 127;
Bitmap bm = { some source bitmap };
byte[,] buffer = new byte[64,256];
for(int y=0;y<bm.Height;y++)
{
for(int x=0;x<bm.Width;x++)
{
Color c=source.GetPixel(x,y);
int luminance = (int)(c.R*0.3 + c.G*0.59+ c.B*0.11);
buffer[x,y] = (luminance > 127) ? 1 : 0;
}
}
I don't know C#. There are possibly many ways to do it. Here is a simple way.
Create a blank black bitmap image of size equal to your device requirement. Draw on it whatever you wish to draw like text, figures etc.
Now threshold the image i.e. set the pixel of image below an intensity value to zero else set it to. e.g. set all intensity values > 0 to 1.
Now convert to the format required by your device. Create a byte array of the size (64 * 256)/8. Set the corresponding bits to 1 where the corresponding pixel values in earlier bitmap are 1, else reset them to 0.
Edit: Step 3. Use bitwise operators to set the bits.
You shouldn't use GetPixel method of your bitmap to convert entire bitmap from one format to another! This will be ineffective. Instead you should use LockBits method to get access to a copy of image buffer and convert it into desired format. I'm not completely sure about converting it to monochrome but there is Format1bppIndexed value in PixelFormat enumeration which may help you.
You may try to supply a pixelformat in the constructor:
var bitmap = new Bitmap(256, 64, PixelFormat.Format1bppIndexed);
When I did draw monochrome bitmaps on other platforms I sometimes had
to disable antialiasing or the rendered text would not show up:
graphics.SmoothingMode=SmoothingMode.None;
YMMV.
Bitmap has a GetPixel method that you can use. This will let you draw on the Bitmap and later convert it to the format that you need.
Bitmaps in Windows forms (ie, accessed through Graphics.FromImage) are 24 bpp (maybe 32? It's too early and I honestly forget). Nonetheless, GetPixel returns a Color object, so the bit depth of the bitmap is immaterial. I suggest you write your code like this:
MyBitmapFormat ToMyBitmap(Bitmap b)
{
MyBitmapFormat mine = new MyBitmapFormat(b.Width, b.Height);
for (int y=0; y < b.Height; y++) {
for (int x=0; x < b.Width; x++) {
mine.SetPixel(x, y, ColorIsBlackish(b.GetPixel(x, y)));
}
}
}
bool ColorIsBlackish(Color c)
{
return Luminance(c) < 128; // 128 is midline
}
int Luminance(c)
{
return (int)(0.299 * Color.Red + 0.587 * Color.Green + 0.114 * Color.Blue);
}
This process is called simple thresholding. It's braindead, but it will work as a first cut.
thanks for the above code - I'm trying to convert a monochrome image into a 2d array where 1-black 0-white however I'm having some trouble - I used your code to load an 8x8 bmp image, and am outputting its contents to a textbox by using
myGrid =GetLedBytes(myBmp);
for (int x = 1; x < 8; x++)
{
textBox1.Text = textBox1.Text + Convert.ToString(myGrid[x])+ " ";
}
however I get this as a result in the textbox:
225 231 231 231 231 129 255
how do I get it so it's 0's and 1's?
This chap has some code that creates a mono bitmap. The SaveImage sample is the one of interest.

Categories