I try to convert a Image (16bits grayscale) to Bitmap (16bits grayscale).
This example doesn't works (Exception : ArgumentException)
private Mat ToMat16bGrayscale(Image im)
{
Bitmap bmp2 = new Bitmap(im);
}
But this example works :
private Mat ToMat16bGrayscale(Image im)
{
//Cast obligatoire la création ou la copie d'une bitmap ne fonctionne pas ici...
Bitmap bmp = (Bitmap)(im);
Bitmap new_bmp = (Bitmap)bmp.Clone();
}
I want to know why the constructor Bitmap doesn't works with a Image 16bits grayscale and why the cast Image to Bitmap works.
Thanks :)
PixelFormat.Format16bppGrayscale is a white elephant image format. Commodity hardware, the kind you'd find back in your machine, isn't even remotely close to being able to accurately render such a bitmap. Which is RGB-based with 8 bits for each color channel, producing 16 million distinct colors. Only 256 of them are shades of gray. Even worse are commodity LCD monitors, they generally can't do better than make 6 bits of color info distinctive, in effect rendering no more than 64 shades of gray. Mapping 65,536 shades of gray down to 256 or 64 of course causes lots of details to be lost.
It does get used in very specialized applications. One is radiological imaging, displaying X-ray images for example. But they also have extraordinary expensive monitors to display such an image. The non-trivial electrical component is the D/A converter, a 16-bit converter that can run at ~250 MHz costs lots and lots of money. They also use specialized image file formats, DICOM is common, formats that are not otherwise supported by the codecs included with GDI+.
There is significant liability here, always an issue in the USA, when you display such a medical image on commodity hardware then whomever looks at it isn't going to be able to see enough details to properly diagnose, say, an evolving tumor. In itself enough to discourage Microsoft to support pixel format conversions for the pixel format, they do not want to be involved in such a lawsuit.
GDI+ supports storing such an image. You can get to the pixel data with Bitmap.LockBits(). Suitable enough for image processing applications. But any attempt to create a Graphics object for such an image or using Graphics.DrawImage() on such an image will cause an exception. Which is what the Bitmap(Image) constructor does. Look for a vendor like LeadTools for library support.
Related
I have an image https://drive.google.com/file/d/16Xotc-2CJ6HkEJDysfKBkjClkU1OGiyQ/view?usp=sharing that is GrayScale but every library I have tried, ImageMagick, ImageSharp, System.Drawing seem to interpret it as black and white, but when you open it in ImageJ or Photoshop or Incarta or many other software you can clearly see it is grayscale.
can anyone help me find a way to display this image? here is something I've tried but i've tried almost a dozen different things
TiffEncoder encoder = new TiffEncoder();
encoder.PhotometricInterpretation = SixLabors.ImageSharp.Formats.Tiff.Constants.TiffPhotometricInterpretation.BlackIsZero;
SixLabors.ImageSharp.Image image = SixLabors.ImageSharp.Image.Load(mysteryTiff);
PixelTypeInfo pixType = image.PixelType;
// Stretches the image to fit the pictureBox.
Stream stream = new MemoryStream();
image.SaveAsTiff(stream, encoder);
stream.Position = 0;
MagickImage magickImage = new MagickImage(stream);
pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;
pictureBox1.ClientSize = new System.Drawing.Size(1200, 1200);
pictureBox1.Image = magickImage.ToBitmap();
Can anyone display this image correctly. It will display correctly when uploaded to
What you have there, according to the image tag directory, is a 2024x2024 16-bpp greyscale LZW-compressed extended TIFF. It even opens in some software, which proves that it's not malformed. So far so good.
Now here's where it breaks down: 16-bpp greyscale is not supported by a lot of things. The 'why' is mildly convoluted, having to do largely with "but we all use 8 bits per channel, and so does the hardware, so why bother", but the end result isn't: if you want to use anything above 8 bits per channel, you'll either have to find something that will do the work for you or convert the data to 8-bpp at some point.
Even when the file format explicitly support 16-bpp greyscale (TIFF and PNG for instance), most libraries tend not to support either read or write in that format because it is so rarely used that they don't bother to implement it. I ended up writing my own PNG encoder for 16-bpp greyscale images (converted from 12-bpp and 16-bpp XRAY images), but the images aren't viewable in most programs that supposedly support the full PNG standard.
In this case your best option is probably going to be to write a conversion of your own for this type of file. Assuming that the same format (16-bpp, LZW-compressed) is produced by the source application every time, it shouldn't be too difficult to convert the pixel buffer to 8-bpp and save out as TIFF, PNG or whatever you like. You'll lose half of your greyscale (depth) resolution, but for display purposes they're not going to help much anyway. It only really matters when there's a good reason to retain the full range of values.
I've been working on image recognition that grabs the screen using bitmap in winforms at 727, 115 area every 700 milliseconds. The get set pixel method is a way to slow and any other method I have found I don't really know how to use.
Bitmap bitmap = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
Graphics g = Graphics.FromImage(bitmap);
g.CopyFromScreen(896, 1250, 0, 0, bitmap.Size);
Bitmap myPic = Resources.SARCUT;
This creates the image on the area on the screen, and the myPic image is the image needing to be found in a 727, 115 area, as stated before. I've tried using aForge, Emgu, and LockPixel but I couldn't convert the bitmaps to the right format and never got it to work.
Any suggestions?
Bitmap and any image operation, together with rendering, is handled by GDI+ in .NET. The GDI+ albeit being faster than its predecessor GDI, it's still notably slow. Also, you seem to be performing a copy operation and this will always represent a performance hit. If you really need to improve performance you should not use the GDI+ framework, this means you have to operate on bitmaps directly and at a lower level. However, this last statement is very broad because it depends on exactly what you want to accomplish and how. Finally, if you want to compare two images you should avoid doing it pixel by pixel and instead do it byte by byte, it's faster since no indexing format and no value encoding has to be taken into account.
So I am trying nQuant for png compression but having terrible results:
Using the canonical QuantizeImage call
var quantizer = new WuQuantizer();
Bitmap imageToSave = new Bitmap(image);
using (var quantized = quantizer.QuantizeImage(imageToSave))
{
quantized.Save(Path.Combine(imagesPath, imageName + "." + format), format);
}
Processing this
I obtained this
Any Idea how to prevent the quality from degrading so much?
Xialoin Wu's fast optimal color quantizer, which is one of the most effective color quantization methods, provides excellent results. However, low frequency colors in the original image tend to be excluded during the histogram counting process. In particular, the loss of original color increases when it uses a small number of boxes to quantize the image with a small number of colors (i.e. photo containing small red lips). Thus, to complement these disadvantages, a better color quantization algorithm that is effective even when it uses only a small number of colors by using the fast pairwise nearest neighbor based algorithm.
Given the limited number of colors, a severe type of artifact arises in the quantized image in areas of smooth color gradients, in the form of false edges, are clearly visible. To reduce such artifacts, a subsequent dithering step is typically employed after quantization. Dithering distributes quantization errors into neighboring pixels, helping to hide the false edges.
GDI+ supports different compression algorithms via the Encoder.Compression. But that's not "Quality". Each algorithm will compress the image to a different size; where the compression with the least number of bytes may be considered "best", in terms of quality of compression. But, that's not what Encoder.Quality means. Encoder.Quality deals with the degree of loss with lossy compression; something that doesn't apply to PNG. PNG is not a lossy format; Therefore, Quality doesn't apply. Possibly using 3rd party applications to write PNG files.
Please find the following c# open source to achieve better quality without support for the compression of PNG file using GDI+ as mentioned above.
https://github.com/mcychan/nQuant.cs
if I try to create a bitmap bigger than 19000 px I get the error: Parameter is not valid.
How can I workaround this??
System.Drawing.Bitmap myimage= new System.Drawing.Bitmap(20000, 20000);
Keep in mind, that is a LOT of memory you are trying to allocate with that Bitmap.
Refer to http://social.msdn.microsoft.com/Forums/en-US/netfxbcl/thread/37684999-62c7-4c41-8167-745a2b486583/
.NET is likely refusing to create an image that uses up that much contiguous memory all at once.
Slightly harder to read, but this reference helps as well:
Each image in the system has the amount of memory defined by this formula:
bit-depth * width * height / 8
This means that an image 40800 pixels by 4050 will require over 660
megabytes of memory.
19000 pixels square, at 32bpp, would require 11552000000 bits (1.37 GB) to store the raster in memory. That's just the raw pixel data; any additional overhead inherent in the System.Drawing.Bitmap would add to that. Going up to 20k pixels square at the same color depth would require 1.5GB just for the raw pixel memory. In a single object, you are using 3/4 of the space reserved for the entire application in a 32-bit environment. A 64-bit environment has looser limits (usually), but you're still using 3/4 of the max size of a single object.
Why do you need such a colossal image size? Viewed at 1280x1024 res on a computer monitor, an image 19000 pixels on a side would be 14 screens wide by 18 screens tall. I can only imagine you're doing high-quality print graphics, in which case a 720dpi image would be a 26" square poster.
Set the PixelFormat when you new a bitmap, like:
new Bitmap(2000, 40000,PixelFormat.Format16bppRgb555)
and with the exact number above, it works for me. This may partly solve the problem.
I suspect you're hitting memory cap issues. However, there are many reasons a bitmap constructor can fail. The main reasons are GDI+ limits in CreateBitmap. System.Drawing.Bitmap, internally, uses the GDI native API when the bitmap is constructed.
That being said, a bitmap of that size is well over a GB of RAM, and it's likely that you're either hitting the scan line size limitation (64KB) or running out of memory.
Got this error when opening a TIF file. The problem was due to not able to open CMYK. Changed colorspace from RGB to CMYK and didn't get an error.
So I used taglib library to get image file size instead.
Code sample:
try
{
var image = new System.Drawing.Bitmap(filePath);
return string.Format("{0}px by {1}px", image.Width, image.Height);
}
catch (Exception)
{
try
{
TagLib.File file = TagLib.File.Create(filePath);
return string.Format("{0}px by {1}px", file.Properties.PhotoWidth, file.Properties.PhotoHeight);
}
catch (Exception)
{
return ("");
}
}
The GDI+ generic error when saving a bitmap is obviously a common problem according to my research here on SO and the web. Given following simplified snippet:
byte[] bytes = new byte[2048 * 2048 * 2];
for (int i = 0; i < bytes.Length; i++)
{
// set random or constant pixel data, whatever you want
}
Bitmap bmp = new Bitmap(2048, 2048, PixelFormat.Format16bppGrayScale);
BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, 2048, 2048), ImageLockMode.ReadWrite, bmp.PixelFormat);
System.Runtime.InteropServices.Marshal.Copy(bytes, 0, bmpData.Scan0, 8388608);
bmp.UnlockBits(bmpData);
bmp.Save(#"name.bmp");
This results in the 0x80004005 generic error. The usual reason for this are said to be locks on components, but I do not see anything here I. Am I just blind? The path I am saving to exists, of course, only a empty bmp file is created (0B).
Background: I am getting pixel data from a camera driver that I transfer to .NET using a C++/CLI wrapper, so the Bitmap object above is returned by a function call. But since this small example already fails, I guess that there is nothing wrong with the adapter.
Any suggestions are highly appreciated!
Bitmap bmp = new Bitmap(2048, 2048, PixelFormat.Format16bppGrayScale);
GDI+ exceptions are rather poor, you'll have little hope to diagnose the two mistakes. The lesser one is your Save() call, it doesn't specify the ImageFormat you want to save. The default is PNG, not BMP as you hoped.
But the core one is PixelFormat.Format16bppGrayScale. When GDI+ was designed, long before .NET came around, everybody was still using CRTs instead of LCD monitors. CRTs were quite good at displaying a gamut of colors. Although good, there were no mainstream CRTs yet that were capable of display 65536 distinct gray colors. Most of all restricted by the DAC in the video adapter, the chip that converts the digital pixel value to an analog signal for the CRT. A DAC that can convert with 16-bit accuracy at 100 MHz or more wasn't technologically feasible yet. Microsoft gambled on display technology improving to make that possible someday so specified Format16bppGrayScale as a pixel format that might someday be available.
That did not happen. Rather the opposite, LCDs are significantly worse at color resolution. Typical LCD panels can only resolve 6 bits of a color rather than the 8 bits available from the pixel format. Getting to 16-bit color resolution is going to require a significant technological break-through.
So they guessed wrong and, since the pixel format isn't useful, GDI+ doesn't actually have an image encoder that can write a 16bpp grayscale image format. Kaboom when you try to save it to disk, regardless of the ImageFormat you pick.
16bpp grayscale is actually used, radiological imaging uses that pixel format. With very expensive displays to make it actually useful. Such equipment however invariable uses a custom image format to go with that, DICOM is the usual choice. GDI+ doesn't have a codec for it.
You'll need to go shopping for a library that supports the image format that your customer wants. Lead Tools is the thousand pound gorilla in that product segment.
PixelFormat.Format32bppArgb seems to work for me on Ubuntu 20 using GDI.
var bitmapdata = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly,
PixelFormat.Format32bppArgb);
The error I was getting was
System.ArgumentException: 'Parameter is not valid.'
at System.Drawing.SafeNativeMethods.Gdip.CheckStatus(Int32 status)
at System.Drawing.Bitmap.LockBits(Rectangle rect, ImageLockMode flags, PixelFormat format, BitmapData bitmapData)
at System.Drawing.Bitmap.LockBits(Rectangle rect, ImageLockMode flags, PixelFormat format)