C# Tutorial: How To Apply Erosion To An Image
Erosion is a morphological process, where pixels at an object boundaries are removed. Erosion and dilation are a pair of basic morphological transformations, which are completely...
Filter by Category
Erosion is a morphological process, where pixels at an object boundaries are removed. Erosion and dilation are a pair of basic morphological transformations, which are completely...
Dilation is a simple morphology process which changes pixel intensities based on the change of intensities that occur at object boundaries. This process is used on grayscale...
What is sobel operator? Well, basically it’s 2 kernels, with which we can process an image in a way, that only edges are visible. It is commonly used for grayscale images,...
Contrast stretch or otherwise known as normalization is a process where your image’s intensity is changed in such a way, that dark pixels become darker and light pixels...
Grayscale images are basically black and white images. These images are good for programming, since their pixels hold only intensity values or in other words, shades of gray, they...
Erosion is a morphological process, where pixels at an object boundaries are removed. Erosion and dilation are a pair of basic morphological transformations, which are completely opposite to one another.
When an image is processed it works with a kernel, which is placed on every pixel of the image. When a kernel is over a certain set of pixels, only the center pixel is evaluated for a change in intensity. All other neighboring pixel are just scanning the surface around it for a change in intensity. If they detect there is a change, the center pixel’s intensity is changed to the lowest intensity detected.
Usually we use erosion on binary images, or in other words images which contain only black and white. It works very well with Sobel edge detection filter, which produces such images, where edges od the objects are highlighted in white, while the background is completely black,
It is also very often used in combination with dilation and holes filling processes. While dilation adds pixels to edges, holes filling gives us an ability to whiten in the object. After these two processes we usually use erosion to get rid of that extra layer of pixels on the edges of our object in the image, so it is of the original size again.
First part of the function is dedicated to saving all your image data into an array, where we will read the image in numbers.
private Bitmap ErodeImage(Bitmap srcImage) { int width = srcImage.Width; int height = srcImage.Height; Rectangle canvas = new Rectangle(0, 0, width, height); BitmapData srcData = srcImage.LockBits(canvas, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); int bytes = srcData.Stride * srcData.Height; byte[] pixelBuffer = new byte[bytes]; byte[] resultBuffer = new byte[bytes]; Marshal.Copy(srcData.Scan0, pixelBuffer, 0, bytes); srcImage.UnlockBits(srcData);
Although it is mostly used for binary images, this code works for grayscale aswell.
float rgb; for (int i = 0; i < bytes; i += 4) { rgb = pixelBuffer[i] * .071f; rgb += pixelBuffer[i + 1] * .71f; rgb += pixelBuffer[i + 2] * .21f; pixelBuffer[i] = (byte)rgb; pixelBuffer[i + 1] = pixelBuffer[i]; pixelBuffer[i + 2] = pixelBuffer[i]; pixelBuffer[i + 3] = 255; }
Save processed data into the second array we created for holding the image data.
int kernelSize = 3; int kernelOffset = (kernelSize - 1) / 2; int calcOffset = 0; int byteOffset = 0; for (int y = kernelOffset; y < height - kernelOffset; y++) { for (int x = kernelOffset; x < width - kernelOffset; x++) { byte value = 255; byteOffset = y * srcData.Stride + x * 4; for (int ykernel = -kernelOffset; ykernel <= kernelOffset; ykernel++) { for (int xkernel = -kernelOffset; xkernel <= kernelOffset; xkernel++) { if (kernel[ykernel + kernelOffset,xkernel + kernelOffset] == 1) { calcOffset = byteOffset + ykernel * srcData.Stride + xkernel * 4; value = Math.Min(value, pixelBuffer[calcOffset]); } else { continue; } } } resultBuffer[byteOffset] = value; resultBuffer[byteOffset + 1] = value; resultBuffer[byteOffset + 2] = value; resultBuffer[byteOffset + 3] = 255; } }
Create a new bitmap to which we copy image data from array that holds processed values.
Bitmap result = new Bitmap(width, height); BitmapData resultData = result.LockBits(canvas, ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); Marshal.Copy(resultBuffer, 0, resultData.Scan0, bytes); result.UnlockBits(resultData); return result; }