Preserving Image quality - c#

I have a winform C# desktop application.
I have a constant stream of jpegs coming in.
I am comparing the current image with the previous 1.
By using a 3rd party tool - Emgu - I can create a new image that contains just the differences.
I then convert that image to a memory stream and then to a byte array.
In the receiving application I take this byte array and load the image via a memory stream using these bytes.
The trouble is that the image degrades quite a lot.
If I save the image to the hard drive before converting it to a memory stream on the client side the quality of the image is good.
The problem lies when i load it as a memory stream.
I encode it as jpeg.
If I encode it as a PNG before sending to the server the quality is good again.
The trouble with encoding to PNG the size in the byte array shoots up.
What my intention was all along was to reduce the number of bytes I have to upload to improve response time.
Am I doing something wrong or can this not be done?
This is my code:
Bitmap imgContainingDifference
= GetDiffFromEmgu(CurrentJpegImage, PreviousJpegImage);
using (System.IO.MemoryStream msIn = new System.IO.MemoryStream())
{
holding.Save(msIn, System.Drawing.Imaging.ImageFormat.Jpeg);
data = msIn.ToArray();
}
//test here
using (System.IO.MemoryStream msOut = new System.IO.MemoryStream(_data))
{
Bitmap testIMG = (Bitmap)Image.FromStream(msOut);
}
//result is image is poor/degrades
If I do this instead:
using (System.IO.MemoryStream msIn = new System.IO.MemoryStream())
{
holding.Save(msIn, System.Drawing.Imaging.ImageFormat.Png);
data = msIn.ToArray();
}
using (System.IO.MemoryStream msOut = new System.IO.MemoryStream(_data))
{
Bitmap testIMG = (Bitmap)Image.FromStream(msOut);
}
//Image is good BUT the size of the byte array is
//10 times the size of the CurrentFrame right at the start.
This is what the image looks like when using the kid suggestion from :
I have now tried using a encoder from the kind suggestion from #MagnatLU and I also get the same quality of image if I use FreeImage.Net.

You can set JPEG compression level when encoding your file to value that is the best empirical tradeoff between quality and size.

Related

DICOM slice corrupted when saved as PNG

I'm using SimpleITK to read a DICOM, and save a particular slice as a PNG file. I can write back a new DICOM file to disk fine, and it looks as expected. But whenever I try to save it in any other format, it's greatly corrupted. By that I mean it looks nothing like the input, it's completely garbled.
Here is the code:
var imageReader = new ImageFileReader();
imageReader.SetOutputPixelType(PixelIDValueEnum.sitkUInt8);
var dicomFileNames = ImageSeriesReader.GetGDCMSeriesFileNames(#"D:\Study");
imageReader.SetFileName(dicomFileNames[255]);
var image = imageReader.Execute();
var fileWriter = new ImageFileWriter();
fileWriter.SetFileName("slice.png");
fileWriter.Execute(image);
Getting the image's buffer and using it to create a BitMap suffers the same problem. Reading the DICOM series (my eventual goal) instead of one file, and using the 3D volume and extracting a slice in that manner also has the same issue.
What am I missing?
EDIT: Using PixelIDValueEnum.sitkUInt16 greatly improves the output of ImageFileWriter, although the contrast is off and loses some detail. I still cannot convert the buffer to a BitMap and save that as a PNG, this code still creates corrupted data:
var size = image.GetSize();
var length = (int)(size[0] * size[1]) * 2;
var buffer = image.GetBufferAsUInt16();
var rgbValues = new byte[length];
Marshal.Copy(buffer, rgbValues, 0, length);
var newBitmap = new Bitmap((int)image.GetWidth(), (int)image.GetHeight(), (int)image.GetWidth(), PixelFormat.Format16bppArgb1555, buffer);
newBitmap.Save(#"C:\test.png", ImageFormat.Png);
I have tried every PixelFormat.16bpp* value without success, some data must be getting lost, because the output of the ImageFileWriter is more than 50% larger than when I save the bitmap.
Here is the bad BitMap:
Most medical images are 16 bit deep (short or unsigned short), not 8 bit (sitkUInt8). Try a few other pixel formats. If that does not help, attach an extracted PNG slice - that will allow more/better advice.

Set image resolution

I have array of image bytes and I would like to set resolution. Original image can be JPEG, PNG, BMP. Output - PNG. I am using ImageMagic to convert image and do some manipulations.
using (var image = this.Convert(originalImage, height, width))
using (var stream = new MemoryStream())
{
image.Quality = 90;
image.Write(stream, MagickFormat.Png);
return stream.GetBuffer();
}
I tryed to modify image.GetExifProfile, but has no success (at least for PNG images).
I can't use any comandline tool (like ImageMagic or ExifTool) here.
There are 3 exiff tags I need to modify
XResolution
YResolution
ResolutionUnit
I can successfully achieve this with bitmap, but it also resource overhead (need to create MemoryStream ...).
I have found some Pdf specification, but it will consume time to make it all work.
Does any can point me to right direction?
Thanks.

HttpPostedFileBase to Resized Image

I have the following line of code which takes my HttpPostedFileBase and converts it to an image.
I have messed around with Encoder Parameteres to try and resize the image but can't seem to do this.
What is the best way to resize the image to 250x250?
I would also prefer it to take the middle of the image as 250x250 rectangle rather than somewhere random.
What is the most space efficent way to convert and save the image as it will be going in the database?
Please note that model.Image is of type HttpPostedFileBase.
var image = Image.FromStream(model.Image.InputStream, true, true);
ImageCodecInfo jpgInfo = ImageCodecInfo.GetImageEncoders()
.Where(codecInfo => codecInfo.MimeType == "image/jpeg").First();
using (EncoderParameters encParams = new EncoderParameters(1))
{
encParams.Param[0] = new EncoderParameter(Encoder.Quality, (long)50);
//quality should be in the range [0..100]
using (var ms = new MemoryStream())
{
// Convert Image to byte[]
image.Save(ms, ImageFormat.Jpeg);
byte[] imageBytes = ms.ToArray();
// Convert byte[] to Base64 String
string base64String = Convert.ToBase64String(imageBytes);
image64 = base64String;
}
}
The best way is to use an established library like ImageResizer; that way, you avoid re-inventing the wheel. If you are concerned about space efficiency (file size), use the JPEG format with maximum compression. Note that using JPEG's lossy encoding will drastically reduce image quality. If you want to use a lossless encoding, try PNG. Compressing PNG images is quite difficult in .NET, in my experience. I searched in vain awhile back for a single library that would do it and all I found were thick-client Windows applications.

list(of byte) to Picturebox

I have a jpeg file that is being held as a list(of Byte)
Currently I have code that I can use to load and save the jpeg file as either a binary (.jpeg) or a csv of bytes (asadsda.csv).
I would like to be able to take the list(of Byte) and convert it directly to a Picturebox without saving it to disk and then loading it to the picturebox.
If you are curious, the reason I get the picture file as a list of bytes is because it gets transfered over serial via an industrial byte oriented protocol as just a bunch of bytes.
I am using VB.net, but C# example is fine too.
You could do this:
var ms = new MemoryStream(byteList.ToArray());
pictureBox.Image = Image.FromStream(ms);
The Image class has a FromStream method and you can create a MemoryStream from a byte array. So:
MemoryStream ms = new MemoryStream(byteList.ToArray());
Image image = Image.FromStream(ms);
What you need to do is take the bytes and read them into a stream. You can then use the stream to load the picture box image.
using( MemoryStream ms = new MemoryStream( byteList.ToArray() ) )
{
this.pictureBox1.Image = Image.FromStream( ms );
}

C# How can I watermark a jpeg image?

Using C# how would I watermark an jpeg image that I'm reading into a memory stream and saving to a byte array?
using (MemoryStream imageStream = new MemoryStream())
{
pbPreview.Image.Save(imageStream, ImageFormat.Jpeg);
photoBytes = imageStream.ToArray();
}
Thank you
Please take a look: Watermark Creator and Creating a Watermarked Photograph with GDI+ for .NET
A more detailed explanation here: Build a simple watermarking utility in C#

Categories

Resources