DICOM slice corrupted when saved as PNG - c#

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.

Related

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.

How to modify tiff creation date in .Net

I am writing a pdf comparison utility. After some investigation it seems like the best way to do this is to convert to tiff and compare from there.
I managed to do this with Ghostscript but am getting a difference in the embedded creation date metadata.
How do I use .Net to modify this?
You can use LibTiff.NET. It is open source. Using this library, you can use the SetField method to modify any one of the many tags in the Tiff file, including the TiffTag.DATETIME flag.
After more investigation, it seems Microsoft does provide a TIFF library with multi-image support. It's in System.Windows.Media.Imaging. To get this namespace reference PresentationCore.
To access the TIFF metadata use this site as a reference: http://www.awaresystems.be/imaging/tiff/tifftags/baseline.html
This code accesses the date field after the GhostScript name you were interested in:
FileInfo fi = new FileInfo(#"C:\Users\Chris\Downloads\PdfVerificationTests.can_use_image_approval_mode.approved.tiff");
FileStream stream = fi.Open(FileMode.Open, FileAccess.ReadWrite,FileShare.None);
TiffBitmapDecoder decoder = new TiffBitmapDecoder(stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
BitmapMetadata bmd = (BitmapMetadata) decoder.Frames[0].Metadata;
string thedateval = (string) bmd.GetQuery("/ifd/{ushort=306}");
BitmapMetadata bmd2 = bmd.Clone();
bmd2.SetQuery("/ifd/{ushort=306}", "2013:05:30 20:07:52");
This code does not write out a modified TIFF, but is all the info you need to do so. Hope this helps as I feel I'm beating a dead horse.
This code will strip all the attributes from a multipage TIFF and leave the image content intact:
FileInfo fi = new FileInfo(#"C:\Users\Chris\Downloads\PdfVerificationTests.can_use_image_approval_mode.approved.tiff");
FileStream stream = fi.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.None);
TiffBitmapDecoder decoder = new TiffBitmapDecoder(stream, BitmapCreateOptions.None, BitmapCacheOption.None);
FileStream stream2 = new FileStream("empty.tif", FileMode.Create);
TiffBitmapEncoder encoder = new TiffBitmapEncoder();
for (int i = 0; i < decoder.Frames.Count(); i++)
{
BitmapSource source = decoder.Frames[i];
int stride = source.PixelWidth * (source.Format.BitsPerPixel / 8);
byte[] data = new byte[stride * source.PixelHeight];
source.CopyPixels(data, stride, 0);
CachedBitmap theSource = (CachedBitmap)BitmapSource.Create(source.PixelWidth, source.PixelHeight, source.DpiX, source.DpiY, source.Format, source.Palette, data, stride);
encoder.Frames.Add(BitmapFrame.Create(theSource));
}
try
{
encoder.Save(stream2);
stream2.Close();
stream.Close();
}
catch
{
}
If the date stamps are fixed size, a fun workaround for this type of problem is to write a FileStream which simply detects and blanks out such date stamps. In fact I've done this before for PDF comparison, on a project I worked on in school. The checksum comparison worked fine with just that, without any conversion to tiff, though in our specific case we were sure all compared PDFs were generated by the same system, so that simplified things a bit.
The basic method is to make a subclass of FileStream with overridden ReadByte and Read functions, which contains the length and expected format of the date stamps. Whenever a read is performed the following happens:
The code reads an extra piece, the size of the datestamp length minus 1 byte, both before and behind the requested data.
Inside that block, a search and replace is performed to clear any found date stamps.
Finally, the original requested piece is returned.
The source code I wrote for the project back in the day is here.
It seams that this ghostscript behavior could be supressed.
-dTIFFDateTime=false
https://www.ghostscript.com/doc/9.22/Devices.htm
... but for this situation I would recommend some diffpdf tools (http://soft.rubypdf.com/software/diffpdf)
D

In C#, how can I know the number of frames of a TIFF file without actually loading the file?

I want to know how many frames a TIFF picture contains. However, to minimize the execution time, I would like to know this information without actually loading the full file. How can I achieve this?
For your information, I am using the following code right now:
FileStream mystream = new FileStream("mypicture.tif", FileMode.Open);
_Image _currentImg = Image.FromStream(mystream );
mystream.Close();
FrameDimension myframeDimensions = new
FrameDimension(_currentImg.FrameDimensionsList[0]);
Int32 numberOfFrames = _currentImg.GetFrameCount(myframeDimensions );

Preserving Image quality

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.

Creating a PNG source from data in memory

Situation:
I am reading a PNG file, encoded with base64 from a server (JSON Format). Works fine.
There is NO direct URL to the ressource (just like: http:... / image.png or simuliar), so i read the data (which is part of a JSON object), decode in from the base64 Encoding and store it in a byte[].
Want i want: Display this PNG on a certain page ( like:
ImageOnPage.Source = myPNG;
)
I cant find a way to make PNG-data to a bitmap. With jpegs i could do something like
using (var stream = new MemoryStream(data, 0, x, true, true)) {
var wbp = new WriteableBitmap(1, 1);
wbp.LoadJpeg(stream);
profileImage.Source = wbp;
}
(sorry, code not testet)
I tried to look around and find the PNG Writer Library - but i still didn't find a way to do something to convert my internal PNG to a useable Bitmap for Setting the Image.Source.
Any help appreciated!

Categories

Resources