Fillholes function in Aforge - c#

I need to use Fillholes function of Aforge, it accepts binary image. I manipulated all pixels to black or white pixels using following code in c#:
bitmapimage.SetPixel(i, j, Color.FromArgb(255,255,255)); // for white pixel
bitmapimage.SetPixel(i, j, Color.FromArgb(0,0,0)); // for black pixel
But when I apply fillholes function to bitmap image, I get this exception:
"Source pixel format is not supported by the filter"
Kindly anyone help why I am getting this exception ... is bitmap image not converted to Binary by all using setpixel?

Just changing the pixel colors will not change the pixel format of your image.
You first need to make sure that you have a gray scale image using some gray scale filter, then make sure that the gray scale image is binary through some threshold filter. Once the image has been pre-processed using these steps, you may apply the FillHoles filter.
AForge.NET offers helper classes to merge several filters, so you can combine all three filters into one total filter using the FiltersSequence class.
Assuming that your original Bitmap image is named bitmap, you can then apply the fill holes filter for example like this:
var filter = new FiltersSequence(Grayscale.CommonAlgorithms.BT709,
new Threshold(100), new FillHoles());
var newBitmap = filter.Apply(bitmap);

AForge FillHoles Class
The filter allows to fill black holes in white object in a binary image. It is possible to specify maximum holes' size to fill using MaxHoleWidth and MaxHoleHeight properties.
The filter accepts binary image only, which are represented as 8 bpp images.
Sample usage:
C#
// create and configure the filter
FillHoles filter = new FillHoles( );
filter.MaxHoleHeight = 20;
filter.MaxHoleWidth = 20;
filter.CoupledSizeFiltering = false;
// apply the filter
Bitmap result = filter.Apply( image );
The above was found at http://www.aforgenet.com/framework/docs/html/68bd57bd-1fd6-6c4e-4500-ed4726bc836e.htm
You have to convert your bitmapImage to a binary image represented as an 8 bpp image. Here is one way to do it.
UnmanagedImage grayImage = null;
if (image.PixelFormat == PixelFormat.Format8bppIndexed)
{
grayImage = bitmapImage;
}
else
{
grayImage = UnmanagedImage.Create(image.Width, image.Height, PixelFormat.Format8bppIndexed);
}

Related

Graphics is blank when trying to turn anti-aliasing off for a bitmap (C#)

What I'm trying to do:
Since in my bitmaps there are some unwanted white edges around the picture that result from anti-aliasing as pointed out from another user from stackoverflow.
I'm trying to convert an image that's inputted into a bitmap, convert bitmap into a Graphics object so that I can set the Smooth Mode to none, and then finally convert that Graphics object to a bitmap so that it can be copied by the user after setting it to the clipboard. I'm not sure if this is a good way of getting rid anti-aliasing in bitmaps but I'm definitely interested in improvements and suggestions.
The issue I'm facing:
The result of the image after is completely blank and does not contain any of the pixels that are previously found in the original bitmap. Here's the result:
This issue applies to all pictures no matter what their format is.
My code:
public PicGen(PictureBox pictureBox)
{
Clipboard.Clear();
Bitmap firstImage = new(pictureBox.Image, pictureBox.Width, pictureBox.Height);
RectangleF cloneRect = new RectangleF(0, 0, firstImage.Width, firstImage.Height);
System.Drawing.Imaging.PixelFormat format = firstImage.PixelFormat;
Bitmap cloneBitmap = firstImage.Clone(cloneRect, format);
Graphics AntiARemover = Graphics.FromImage(cloneBitmap);
AntiARemover.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None;
Bitmap finalImg = new(52, 52, AntiARemover);
Clipboard.SetImage(finalImg);
Color backColorBottom = firstImage.GetPixel(0, 0);
firstImage.ReplaceColor(backColorBottom, Color.FromArgb(54, 57, 63));
Bitmap finalImg = new(52, 52, AntiARemover);
From the documentation for this bitmap constructor:
The new Bitmap that this method creates takes its horizontal and vertical resolution from the DpiX and DpiY properties of g, respectively.
If you want create a new image with the content from another you need to call one of the DrawImage methods. You should also dispose your graphics object, and any temporary bitmaps you may use.
using var finalImg = new Bitmap(52,52);
using var graphics = Graphics.FromImage(finalImg);
graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None;
graphics.DrawImage(cloneBitmap)
However, edge artifacts typically occur when combining two images using an alpha channel, see Premultiplied alpha. In your example I can only see one input image, so I'm really not sure what it is you are actually trying to do. If you need to convert to premultiplied alpha you can use the following code to convert the color for each pixel
premultiplied.R = (byte)(straight.R * straight.A / 255);
premultiplied.G = (byte)(straight.G * straight.A / 255);
premultiplied.B = (byte)(straight.B * straight.A / 255);
premultiplied.A = straight.A;

How can I convert a gif image file from Bit depth 24 to Bit depth 8?

Tried this
var test = System.IO.Directory.GetFiles(#"D:\Downloaded Images\New folder",
"*.gif", SearchOption.AllDirectories).OrderBy(x => x).ToArray();
for (int i = 0; i < test.Length; i++)
{
Bitmap orig = new Bitmap(test[i]);
Bitmap clone = new Bitmap(orig.Width, orig.Height,
System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
using (Graphics gr = Graphics.FromImage(clone))
{
gr.DrawImage(orig, new Rectangle(0, 0, clone.Width, clone.Height));
}
}
If I change this line to 24 it will work fine but the images are already Bit depth 24
System.Drawing.Imaging.PixelFormat.Format24bppRgb
When I change the line to 8
System.Drawing.Imaging.PixelFormat.Format8bppIndexed
I'm getting exception
On the line
using (Graphics gr = Graphics.FromImage(clone))
System.Exception: 'A Graphics object cannot be created from an image that has an indexed pixel format.'
There is no Format8bppRgb option.
There’s no Format8bppRgb option because 8-bit images are either grayscale without color, or color with a palette and therefore always indexed.
If your goal is to make an identical copy of the original 8-bit image, you can use the Clone() method like this:
System.Drawing.Bitmap orig = new System.Drawing.Bitmap(GifFile);
System.Drawing.Bitmap clone = orig.Clone(new System.Drawing.Rectangle(0, 0, orig.Width, orig.Height), System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
However, if your goal is to use Graphics to draw other objects on the bitmap, you can convert the 8-bit image to 24-bit, draw on it, then convert it back to 8-bit. It is explained in Microsoft documentation here that Graphics.FromImage does not work if "the image has an indexed pixel format" like 8-bit.
Converting to 24-bit is fairly easy, but converting back to 8-bit can be tricky because you will need to create a suitable palette and match the colors to it so as not to lose too many of the original colors or change the appearance of the image.
If you want to use Graphics drawing without changing from 8-bit, you can use a professional imaging SDK like LEADTOOLS (disclosure: I work for its vendor). Here’s the code that does that:
System.Drawing.Bitmap orig = new System.Drawing.Bitmap(GifFile);
Leadtools.RasterImage LEADClone = Leadtools.Drawing.RasterImageConverter.ConvertFromImage(orig, Leadtools.Drawing.ConvertFromImageOptions.None);
Leadtools.Drawing.RasterImageGdiPlusGraphicsContainer container = new Leadtools.Drawing.RasterImageGdiPlusGraphicsContainer(LEADClone);
container.Graphics.DrawImage(orig, new System.Drawing.Rectangle(0, 0, orig.Width, orig.Height));
The SDK also contains the ColorResolutionCommand Class, which can convert to 8-bits (or any bits-per-pixel) and produce optimized palettes if needed.
If you would like to try LEADTOOLS, you can obtain a free evaluation here

Color tracking using EMGUcv

I am trying to make an colored object tracker which uses a binary image and blob detector to follow the target sort of like this: https://www.youtube.com/watch?v=9qky6g8NRmI . However I can not figure out how the ThresholdBinary() method work and if it is even the right one.
Here is a relevant bit of the code:
cam._SmoothGaussian(3);
blobDetector.Update(cam);
Image<Bgr,byte> binaryImage = cam.ThresholdBinary(new Bgr(145,0,145),new Bgr(0,0,0));
Image<Gray,byte> binaryImageGray = binaryImage.Conver<Gray,byte>();
blobTracker.Process(cam, binaryImageGray);
foreach (MCvBlob blob in blobTracker)
{
cam.Draw((Rectangle)blob, new Bgr(0,0,255),2);
}
When I display the binaryImage I do not even get blobs. I just get a black image.
Typically, the colored blob detection part of such an application works along the lines of:
Convert the image to HSV (hue, saturation, value) color space.
Filter the hue channel for all pixels with a hue value near the target value. Thresholding will typically give you all pixels with a value above or below the threshold. You are interested in the pixels near some target value.
Filter the obtained mask some more, possibly using the saturation/value channels or by removing small blobs. Ideally only the target blob remains.
Some sample code that aims to find a green object (hue ~50) such as the green ball shown in the video:
// 1. Convert the image to HSV
using (Image<Hsv, byte> hsv = original.Convert<Hsv, byte>())
{
// 2. Obtain the 3 channels (hue, saturation and value) that compose the HSV image
Image<Gray, byte>[] channels = hsv.Split();
try
{
// 3. Remove all pixels from the hue channel that are not in the range [40, 60]
CvInvoke.cvInRangeS(channels[0], new Gray(40).MCvScalar, new Gray(60).MCvScalar, channels[0]);
// 4. Display the result
imageBox1.Image = channels[0];
}
finally
{
channels[1].Dispose();
channels[2].Dispose();
}
}

Does making a Bitmap Transparent a smaller image, as in bytes

When building Bitmaps and collectively building a few Bitmaps and combining them into one Bitmap does it help to .MakeTransparent().
And or, before I send the Bitmap to the requesting client if I .MakeTransparent() will it become smaller in size? not width or height, buy in bytes?
In other words will .MakeTransparent() optimize the Bitmap, and if not does anyone get any suggestions on how to optmize a Bitmap before sending to the requesting client over the wire via internet?
The code in question is sheet.MakeTransparent()
internal static Task<Bitmap> GetDoorSecheduleSheetAsync(ShopDrawing.DoorSchedules schedules, RotateFlipType rotate, byte schedulesPerSheet, byte currentI)
{
return Task.Run(() =>
{
var sheet = new Bitmap(DrawingOptions.PAGE_HEIGHT_SIZE, DrawingOptions.PAGE_WIDTH_SIZE);
sheet.SetResolution(150, 150);
byte scheduleCnt = 0;
float prevWidth = 0;
using (Graphics dc = Graphics.FromImage(sheet))
{
dc.Clear(Color.White);
using (Pen pen = new Pen(Color.FromArgb(80, Color.Black), 4))
{
for (; currentI < schedules.Count(); currentI++)
{
if (scheduleCnt > 0)
{
dc.DrawLine(pen, prevWidth, 380/*need constant for start height*/, prevWidth, sheet.Height);
};
using (var doorSchedule = schedules[currentI].Door)
{
dc.DrawImage(doorSchedule, prevWidth + 50, 380/*need constant for start height*/);
prevWidth += doorSchedule.Width + 50;
scheduleCnt++;
}
if (scheduleCnt == schedulesPerSheet)
{
sheet.RotateFlip(rotate);
sheet.MakeTransparent();
return sheet;
}
};
};
};
sheet.MakeTransparent();
sheet.RotateFlip(rotate);
return sheet;
});
}
Thank you!
BMP is uncompressed format with essentially raw bytes (or palette indexes) for each pixel - there is no transformation that will change size of resulting file except changing bit-per-pixel count.
Don't send uncompressed bmp over network - use either loss-less PNG/GIF or (if it works for you) JPG.
As said by Alexei Levenkov sending the raw BMP-Format over the wire is the worst choice.
Calling MakeTransparent() would (if it's not already the case) convert the image format to 32bit (= with alpha cannel), which is most byte hungry - transparency has its costs.
You should save the Bitmap as a i.e. jpeg (if you don't really need transparency) or png (if you really need it) - they're both much more efficient.
Look at this answered question about it: High Quality Image Scaling Library
It shows how to use the .NET built-in image encoders.
When you call the MakeTransparent method the bitmap will be converted to the Format32bppArgb format, as this format supports an alpha channel.
The Format32bppArgb is a format what uses 32 bits per pixel; 8 bits each are used for the alpha, red, green, and blue components. Therefore it could mean a change in size.
But just to have control over what really happens you could zip the bitmap or compress it bye converting it to other formats as PNG o JPG as Alexei Levenkov suggested
Here you can find and example of how to convert PNG to BMP, you can use the same code but exchanging formats
How to convert PNG to BMP at runtime?

Converting from a Format8bppIndexed to a Format24bppRgb in C#/GDI+

Alright, I have an image coming through from an external application in an 8-bit indexed format. I need this image converted to a 24-bit format of the exact same size.
I've tried creating a new Bitmap of the same size and of type Format24bppRgb and then using a Graphics object to draw the 8-bit image over it before saving it as a Bmp. This approach doesn't error out but when I open the resulting image the BMP header has all kinds of funky values. The height and width are HUGE and, in addition, there are funny (and large) values for the compression flags and a few others. Unfortunately my particular requirements are to pass this file off to a specific printer driver that demands a 24-bit image with specific header values (which I'm trying to achieve through GDI+)
Anyone know of an example on "up-converting" an indexed file to a not-indexed 24-bit file? If not an example, which path should I start down to write my own?
-Kevin Grossnicklaus
kvgros#sseinc.com
I used the code below to "up-convert" an image from 8bpp to 24bpp. Inspecting the generated 24bpp file with a hex editor and comparing against the 8bpp file shows no difference in height and width in the two files. That is, the 8bpp image was 1600x1200, and the 24bpp image has the same values.
private static void ConvertTo24(string inputFileName, string outputFileName)
{
Bitmap bmpIn = (Bitmap)Bitmap.FromFile(inputFileName);
Bitmap converted = new Bitmap(bmpIn.Width, bmpIn.Height, PixelFormat.Format24bppRgb);
using (Graphics g = Graphics.FromImage(converted))
{
// Prevent DPI conversion
g.PageUnit = GraphicsUnit.Pixel
// Draw the image
g.DrawImageUnscaled(bmpIn, 0, 0);
}
converted.Save(outputFileName, ImageFormat.Bmp);
}
Everything else in the headers looks reasonable, and the images display identical on my system. What "funky values" are you seeing?
This is my conversion code. Notice the matching of resolution between source image and resulting image.
private void ConvertTo24bppPNG(Stream imageDataAsStream, out byte[] data)
{
using ( Image img = Image.FromStream(imageDataAsStream) )
{
using ( Bitmap bmp = new Bitmap(img.Width, img.Height, PixelFormat.Format24bppRgb) )
{
// ensure resulting image has same resolution as source image
// otherwise resulting image will appear scaled
bmp.SetResolution(img.HorizontalResolution, img.VerticalResolution);
using ( Graphics gfx = Graphics.FromImage(bmp) )
{
gfx.DrawImage(img, 0, 0);
}
using ( MemoryStream ms = new MemoryStream() )
{
bmp.Save(ms, ImageFormat.Png);
data = new byte[ms.Length];
ms.Position = 0;
ms.Read(data, 0, (int) ms.Length);
}
}
}
}
It seems odd that you're creating a Bitmap of the same width and height as your input, yet the generated BMP is much larger. Can you post some code?
The problem is probably the difference between the Vertical- and HorizontalResolution of your source image and your output image. If you load a 8bpp indexed bitmap with a resolution of 72 DPI, and then create a new 24bpp bitmap (default resolution will be 96 DPI... at least it is on my system) and then use Graphics.DrawImage to blit to the new bitmap, your image will appear slightly zoomed in and cropped.
Having said that, I don't know off the top of my head how to properly create the output Bitmap and/or Graphics object to scale properly when saved. I suspect it will have something to do with creating the images using a common scale like inches instead of pixels.

Categories