I am looking for a "clean" way to load rasters to my c# code. By raster I mean any (or at least some) XYZ file that QGis or ArcGis are able to load: .tif, .rrd ...
I am using NetTopologySuite. This library works perfectly for shapefiles, which makes me think there could be a raster reader. I have been trying to focus my research under the NetTopologySuite.IO namespace, which contains quite a few Readers.
I have tagged this post with NetTopologySuite hoping that some c#-savvy knows a bit more than me about this particular library.
I used LibTiff.Net for .tif, but I had no requirement for any other format. The UpperLeft and BottomRight properties are used to position the Image on a world map. I don't deal with the model transform case because it's very complicated and - again - no requirement to do so at the moment.
var imageStreamSource = new FileStream(Filename, FileMode.Open, FileAccess.Read, FileShare.Read);
var decoder = new TiffBitmapDecoder(imageStreamSource, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
var bitmapSource = decoder.Frames[0];
// Draw the Image
Image = bitmapSource.ToBitmap();
using (var tiff = Tiff.Open(Filename, "r"))
{
Height = tiff.GetField(TiffTag.IMAGELENGTH)[0].ToInt();
Width = tiff.GetField(TiffTag.IMAGEWIDTH)[0].ToInt();
// see http://www.remotesensing.org/geotiff/spec/geotiff2.6.html#2.6.1
var modelPixelScaleTag = tiff.GetField(TiffTag.GEOTIFF_MODELPIXELSCALETAG);
var modelTiepointTag = tiff.GetField(TiffTag.GEOTIFF_MODELTIEPOINTTAG);
//var modelTransformTag = tiff.GetField(TiffTag.GEOTIFF_MODELTRANSFORMATIONTAG);
var modelPixelScale = modelPixelScaleTag[1].GetBytes();
var ScaleX = BitConverter.ToDouble(modelPixelScale, 0);
var ScaleY = BitConverter.ToDouble(modelPixelScale, 8) * -1;
if (modelTiepointTag != null)
{
var modelTransformation = modelTiepointTag[1].GetBytes();
var originLon = BitConverter.ToDouble(modelTransformation, 24);
var originLat = BitConverter.ToDouble(modelTransformation, 32);
// origin is the center of the pixel, so offset to
var startLat = originLat + (ScaleY / 2.0);
var startLon = originLon + (ScaleX / 2.0);
UpperLeft = new Position(startLat, startLon);
BottomRight = new Position(startLat + ScaleY * Height, startLon + ScaleX * Width);
}
//else if (modelTransformTag != null)
//{
// this is very complicated
//}
else
{
throw new Exception("Couldn't understand the TIFF format");
}
}
Related
I have c# TensorFlow.NET working in Unity. But it using an image from the file system. I want to be able to use an image from memory (Texture2D).
I tried to follow some examples of people using TensorFlowSharp. But that didn't work.
What am I doing wrong?
Note: with both functions, I am using the same image. The image is 512x512. but the result of both pictures is different.
// Doesn't work
private NDArray FromTextureToNDArray(Texture2D texture) {
Color32[] pixels = texture.GetPixels32();
byte[] floatValues = new byte[(texture.width * texture.height) * 3];
for (int i = 0; i < pixels.Length; i++) {
var color = pixels[i];
floatValues[i * 3] = color.r;
floatValues[i * 3 + 1] = color.g;
floatValues[i * 3 + 2] = color.b;
}
Shape shape = new Shape(1, texture.width, texture.height, 3);
NDArray image = new NDArray(floatValues, shape);
return image;
}
// Works
private NDArray ReadFromFile(string fileName) {
var graph = new Graph().as_default();
// Change image
var file_reader = tf.read_file(fileName, "file_reader");
var decodeJpeg = tf.image.decode_jpeg(file_reader, channels: 3, name: "DecodeJpeg");
var casted = tf.cast(decodeJpeg, TF_DataType.TF_UINT8);
var dims_expander = tf.expand_dims(casted, 0);
using (var sess = tf.Session(graph)) {
return sess.run(dims_expander);
}
}
I ended up using this code from Shaqian: https://github.com/shaqian/TF-Unity/blob/master/TensorFlow/Utils.cs
Add this script to your project and then you could use it like this:
// Get image
byte[] imageData = Utils.DecodeTexture(texture, texture.width, texture.height, 0, Flip.VERTICAL);
Shape shape = new Shape(1, texture.width, texture.height, 3);
NDArray image = new NDArray(imageData, shape);
Use Barracuda as step in between.
var encoder = new Unity.Barracuda.TextureAsTensorData(your_2d_texture);
I am trying to create movie from images.
I am following following links :
https://www.leadtools.com/support/forum/posts/t11084- // Here I am trying option 2 mentioned & https://social.msdn.microsoft.com/Forums/sqlserver/en-US/b61726a4-4b87-49c7-b4fc-8949cd1366ac/visual-c-visual-studio-2017-how-do-you-convert-jpg-images-to-video-in-visual-c?forum=csharpgeneral
void convert()
{
bmp = new Bitmap(320, 240, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
// create sample source object
SampleSource smpsrc = new SampleSource();
ConvertCtrl convertCtrl = new ConvertCtrl();
// create a new media type wrapper
MediaType mt = new MediaType();
double AvgTimePerFrame = (10000000 / 15);
// set the type to 24-bit RGB video
mt.Type = Constants.MEDIATYPE_Video;
mt.SubType = Constants.MEDIASUBTYPE_RGB24;
// set the format
mt.FormatType = Constants.FORMAT_VideoInfo;
VideoInfoHeader vih = new VideoInfoHeader();
int bmpSize = GetBitmapSize(bmp);
// setup the video info header
vih.bmiHeader.biCompression = 0; // BI_RGB
vih.bmiHeader.biBitCount = 24;
vih.bmiHeader.biWidth = bmp.Width;
vih.bmiHeader.biHeight = bmp.Height;
vih.bmiHeader.biPlanes = 1;
vih.bmiHeader.biSizeImage = bmpSize;
vih.bmiHeader.biClrImportant = 0;
vih.AvgTimePerFrame.lowpart = (int)AvgTimePerFrame;
vih.dwBitRate = bmpSize * 8 * 15;
mt.SetVideoFormatData(vih, null, 0);
// set fixed size samples matching the bitmap size
mt.SampleSize = bmpSize;
mt.FixedSizeSamples = true;
// assign the source media type
smpsrc.SetMediaType(mt);
// select the LEAD compressor
convertCtrl.VideoCompressors.MCmpMJpeg.Selected = true;
convertCtrl.SourceObject = smpsrc;
convertCtrl.TargetFile = #"D:\Projects\LEADTool_Movie_fromImage\ImageToVideo_LeadTool\ImageToVideo_LeadTool\Images\Out\aa.avi";
//convertCtrl.TargetFile = "C:\\Users\\vipul.langalia\\Documents\\count.avi";
convertCtrl.TargetFormat = TargetFormatType.WMVMux;
convertCtrl.StartConvert();
BitmapData bmpData;
int i = 1;
byte[] a = new byte[bmpSize];
System.Drawing.Rectangle rect = new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height);
var imgs = GetAllFiles();
foreach (var item in imgs)
{
bmpSize = GetBitmapSize(item);
MediaSample ms = smpsrc.GetSampleBuffer(30000);
ms.SyncPoint = true;
bmpData = item.LockBits(rect, ImageLockMode.ReadWrite, item.PixelFormat);
Marshal.Copy(bmpData.Scan0, a, 0, bmpSize);
item.UnlockBits(bmpData);
ms.SetData(bmpSize, a);
SetSampleTime(ms, i, AvgTimePerFrame);
smpsrc.DeliverSample(1000, ms);
i++;
}
smpsrc.DeliverEndOfStream(1000);
}
byte[] GetByteArrayFroMWritableBitmap(WriteableBitmap bitmapSource)
{
var width = bitmapSource.PixelWidth;
var height = bitmapSource.PixelHeight;
var stride = width * ((bitmapSource.Format.BitsPerPixel + 7) / 8);
var bitmapData = new byte[height * stride];
bitmapSource.CopyPixels(bitmapData, stride, 0);
return bitmapData;
}
private int GetBitmapSize(WriteableBitmap bmp)
{
int BytesPerLine = (((int)bmp.Width * 24 + 31) & ~31) / 8;
return BytesPerLine * (int)bmp.Height;
}
private int GetBitmapSize(Bitmap bmp)
{
int BytesPerLine = ((bmp.Width * 24 + 31) & ~31) / 8;
return BytesPerLine * bmp.Height;
}
It is throwing out of memory exception when execute ms.SetData(bmpSize, a); statement. Plus If I directly pass byte[] by var a = System.IO.File.ReadAllBytes(imagePath); in ms.SetData(bmpSize, a); statement then it will not throw error but video file is not properly created.
Can anybody please help me?
There are a couple of problems with your code:
Are all your images 320x240 pixels? If not, you should resize them to these exact dimensions before delivering them as video samples to the Convert control.
If you want to use a different size, you can, but it should be the same size for all images, and you should modify the code accordingly.
You are setting the TargetFormat property to WMVMux, but the name of the output file has “.avi” extension. If you want to save AVI files, set TargetFormat = TargetFormatType.AVI.
If you still face problems after this, feel free to contact support#leadtools.com and provide full details about what you tried and what errors you’re getting. Email support is free for LEADTOOLS SDK owners and also for free evaluation users.
I'm using ImageProcessor to reduce the resolution or quality of an image, but I'm don't know how to make sure that the image resultant size it's below 5 megabytes. I tried setting the image dimensions to 3840-2160 but I want to use a better option.
Here it's my code:
private static byte[] redimensionImage(ref byte[] photoBytes)
{
var byteCuantity = ConvertBytesToMegabytes(photoBytes.Count());
ISupportedImageFormat format = new JpegFormat();
using (MemoryStream inStream = new MemoryStream(photoBytes))
{
using (MemoryStream outStream = new MemoryStream())
{
// Initialize the ImageFactory using the overload to preserve EXIF metadata.
using (ImageFactory imageFactory = new ImageFactory(preserveExifData: true))
{
// Load, resize, set the format and quality and save an image.
using (var imageProcessor = imageFactory.Load(inStream))
{
var originalHeight = imageProcessor.Image.Size.Height;
var originalWidth = imageProcessor.Image.Size.Width;
//calculate aspect ratio
var aspect = originalWidth / (float)originalHeight;
int newWidth, newHeight;
var dimenssionTooSmall = false;
if (originalWidth <= originalHeight && originalWidth < 100)
{
//calculate new dimensions based on aspect ratio
newHeight = (int)(100 / aspect);
var resizeLayer = new ResizeLayer(new Size(100, newHeight), ResizeMode.Min);
imageProcessor.Resize(resizeLayer);
dimenssionTooSmall = true;
}
else if (originalHeight < originalWidth && originalHeight < 100)
{
//calculate new dimensions based on aspect ratio
newWidth = (int)(100 / aspect);
var resizeLayer = new ResizeLayer(new Size(newWidth, 100), ResizeMode.Min);
imageProcessor.Resize(resizeLayer);
dimenssionTooSmall = true;
}
if (byteCuantity > 1 || dimenssionTooSmall)
{
//format.Quality = 6;
imageProcessor.Resize(new ResizeLayer(new Size(3840, 2160), ResizeMode.Min));
imageProcessor.Format(format);
imageProcessor.Save(outStream);
return outStream.ToArray();
}
else
{
return inStream.ToArray();
}
}
}
}
}
}
Thanks and regards.
Unfortunately there's no way you can really do this without reprocessing unless you're saving as bitmap.
When you save an image there are many compression processes that take place to store the image in each individual format (except bitmap which doesn't compress the image). Without actually going through the process itself you can't predict the file size.
You could potentially create your own lookup tables to act as a guideline by resizing a large sample of images in different formats and collecting the output sizes to give you a rough estimate for future processing.
I asked this on syncfusion foruns, but i figured i would give it a try here also
I worked on a project some time ago, that used Syncfusion for WinRT version 12.2.0.36
it had some pdf manipulation, such as adding images to the pdf. After some effort it was working and the part of the code was something like this
//...
foreach (var image in this.images) //image is type Windows.Ui.Xaml.Controls.Image
{
var bitmap = image.Source as ImageSource;
var index = bitmaps.IndexOf(bitmap);
var signature = signatures.ElementAt(index);
var bytes = await signature.Data.EncodePngToJpeg(); //returns bytes of png image converted to jpg
PdfImage pdfImage;
using (var memoryStream = new MemoryStream(bytes))
{
pdfImage = PdfImage.FromStream(memoryStream);
}
var transform = image.RenderTransform as CompositeTransform;
var x = (image.Margin.Left + transform.TranslateX + horizontalOffset) * 100 / pdfViewer.Zoom - 10;
var y = (image.Margin.Top + transform.TranslateY + verticalOffset) * 100 / pdfViewer.Zoom - 10;
var firstPage = pdfDocument.Pages[pdfViewer.PageNumber - 1];
var pageHeight = firstPage.Size.Height;
var pageWidth = firstPage.Size.Width;
var selpage = pdfViewer.PageNumber;
var pagn = selpage - 1;
if (pagn < 0)
pagn = 0;
var ss = pdfViewer.GetDescendantsOfType<ScrollViewer>();
var hh = ss.ElementAt(3);
float VertOff = (float)hh.VerticalOffset;
float VertOff2 = (VertOff * 100 / pdfViewer.Zoom) - ((pagn) * (pageHeight * 1.325f));
var page = pdfDocument.Pages[pagn];
var graphics = page.Graphics;
var width = image.Width;
var height = image.Height;
//float fWidth = (float)width;
//float fHeight = (float)height;
fWidth = 165f * 0.50f;
fHeight = 110f * 0.50f;
graphics.ScaleTransform(0.75f, 0.75f);
graphics.DrawImage(pdfImage, (float)x, (float)y + VertOff2, fWidth, fHeight); // <-- exception is here
}
what this did was adding a list of images to a pdf document in specific places, and after this code i would save and upload.
then i installed the WinRT trial version (13.1.0.21) and i started to get this exception
A first chance exception of type 'System.NullReferenceException'
occurred in Syncfusion.Pdf.WinRT.DLL System.NullReferenceException' :
{"Object reference not set to an instance of an object."}
with this StackTrace:
at Syncfusion.Pdf.Graphics.PdfBitmap.SetColorSpace() at
Syncfusion.Pdf.Graphics.PdfBitmap.Save() at
Syncfusion.Pdf.Graphics.PdfGraphics.DrawImage(PdfImage image, Single
x, Single y, Single width, Single height) at
Gapp_metro.Pages.PdfPage.d__25.MoveNext()
Did anything changed between versions that might be giving me an error?
Or am i doing something wrong?
Currently Essential PDF Winrt supports the following image formats.
1. Jpeg
2. PNG
3. Tiff
4. Gif
Please try the PNG image without convert it to jpeg, I have attached the sample project for your reference, Please try this and let me know the result.
http://www.syncfusion.com/downloads/support/forum/118851/InsertingImage613405857.zip
Regards,
Karthikeyan.C
I've been having a whale of a time diagnosing a leak in a service which is rendering multiple images to a canvas and then pushing out a bitmap or PNG at the end (and doing this multiple times). On start up the service will rocket up to 600MB+ and then keep on increasing until it's taken almost all that it can get hold of. It will never decrease once started.
I've instrumented and run the service using the VS2012 perf mon and seen that there are large amounts of Byte arrays laying about after processing has been completed. I've tried a GC clear to see if it would wipe them out to no avail. Looking into it using WinDbg I can see that the byte array is being held onto by a long chain of items (mostly WPF objects) which is keeping the image in ram.
I've had a look over MSDN for all the objects that are being used and can't find anything that points out a problem with the way the code is running.
I've put together some sample code that closely follows the service (some bits reduced for bevity). This is called off a thread (set to STA). The only other differece is the service code uses MemoryStreams to load images sourced from a DB rather than the URIs I am using. The streams are disposed of:
public static void TestThread()
{
const int rounds = 50;
const int innerRounds = 50;
var randomiser = new Random(DateTime.Now.Millisecond);
// Simulating some live values
const float scaling = 2.67F;
const int pageWidth = 363;
const int pageHeight = 516;
const int dpi = 96;
// To simulate the live system using multiple images
// This is an list of images of different sizes etc
var imageList = new List<ImageData>
{
new ImageData{Uri = new Uri(#"..."), Height = 2592},
new ImageData{Uri = new Uri(#"..."), Height = 1339},
new ImageData{Uri = new Uri(#"..."), Height = 386},
new ImageData{Uri = new Uri(#"..."), Height = 968},
new ImageData{Uri = new Uri(#"..."), Height = 1952},
new ImageData{Uri = new Uri(#"..."), Height = 1024},
};
var proc = Process.GetCurrentProcess();
for (var i = 0; i < rounds; ++i)
{
var canvas = new Canvas();
canvas.BeginInit();
canvas.SnapsToDevicePixels = false;
canvas.UseLayoutRounding = false;
canvas.Width = pageWidth;
canvas.Height = pageHeight;
canvas.Background = Brushes.White;
for (var j = 0; j < innerRounds; ++j)
{
var img = new Image {Stretch = Stretch.Fill};
var bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
var imageNo = randomiser.Next(0, imageList.Count - 1);
bitmapImage.UriSource = imageList[imageNo].Uri;
int imageHeight = imageList[imageNo].Height;
bitmapImage.DecodePixelHeight = (int) (imageHeight * scaling * 1.8);
bitmapImage.EndInit();
if (bitmapImage.CanFreeze)
{
bitmapImage.Freeze();
}
var opacityMask = new ImageBrush();
var opactityBitmap = new BitmapImage();
opactityBitmap.BeginInit();
opactityBitmap.CacheOption = BitmapCacheOption.OnLoad;
imageNo = randomiser.Next(0, imageList.Count - 1);
opactityBitmap.UriSource = imageList[imageNo].Uri;
int opacityImageHeight = imageList[imageNo].Height; ;
opactityBitmap.DecodePixelHeight = (int)(opacityImageHeight * scaling * 1.8);
opactityBitmap.EndInit();
if (opactityBitmap.CanFreeze)
{
opactityBitmap.Freeze();
}
opacityMask.ImageSource = opactityBitmap;
img.OpacityMask = opacityMask;
img.Source = bitmapImage;
img.Width = pageWidth * scaling;
img.Height = pageHeight * scaling;
Canvas.SetLeft(img, 0);
Canvas.SetTop(img, 0);
canvas.Children.Add(img);
img.Opacity = 50F;
}
canvas.LayoutTransform = null;
var size = new Size(Math.Max(canvas.Width, 5), Math.Max(canvas.Height, 5));
canvas.Measure(size);
canvas.Arrange(new Rect(size));
canvas.EndInit();
var renderTargetBitmap = new RenderTargetBitmap(pageWidth, pageHeight, dpi, dpi, PixelFormats.Default); //xxx
renderTargetBitmap.Render(canvas);
if (renderTargetBitmap.CanFreeze)
{
renderTargetBitmap.Freeze();
}
System.Drawing.Image imageData;
using (var ms = new MemoryStream())
{
var image = new PngBitmapEncoder();
image.Frames.Add(BitmapFrame.Create(renderTargetBitmap));
image.Save(ms);
imageData = System.Drawing.Image.FromStream(ms);
}
var encoder = Encoder.Quality;
var encoderParams = new EncoderParameters(1);
encoderParams.Param[0] = new EncoderParameter(encoder, 100L);
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageDecoders();
var codecInfo = codecs.FirstOrDefault(x => x.FormatID == ImageFormat.Png.Guid);
Byte[] bitmapArray;
using (var ms = new MemoryStream())
{
imageData.Save(ms, codecInfo, encoderParams);
bitmapArray = ms.GetBuffer();
}
var filepath = string.Format(#"C:\temp\{0}.png", i);
imageData.Save(filepath, ImageFormat.Png);
var gcMemory = GC.GetTotalMemory(false) / 1024;
Console.WriteLine("Proc mem = {0}KB, GC = {1}KB", (proc.PrivateMemorySize64 / 1024), gcMemory);
}
Console.WriteLine("Exiting");
}
I'm hoping it's something obvious I'm missing here. Thanks for all your help!