### How To Make SLIC Superpixel Algorithm With C#

SLIC superpixel segmentation is a modern operation for reducing irrelevant detail for shortening computational time in further processing.

Filter by Category

- C# Tutorial(85)
- C# Image Processing(69)
- Morphological Processes(20)
- Image Processing(16)
- Image Restoration and Reconstruction(16)
- Image Segmentation(13)
- C# Data Structures And Algorithms(11)
- Frequency Domain Filtering(8)
- Color Image Processing(8)
- Image Noise(6)
- Grayscale Morphology(5)
- Thresholding(4)
- Sorting Algorithms(4)
- Mean Filters(4)
- Order-Statistic Filters(4)
- Morphological Reconstruction(3)
- Edge Detection(3)
- Simple Lists(2)
- Linked Lists(2)
- Adaptive Filters(2)
- RGB to HSI Color Model(2)
- Tone and Color Corrections(2)
- Landing Pages(1)
- Point Detection(1)
- Line Detection(1)
- Social Games(1)
- Region Growing Segmentation(1)
- Region Splitting And Merging(1)
- Region Segmentation With K Means Clustering(1)
- Region Segmentation Using Superpixels(1)
- C# Arrays(1)
- C# Basics(1)
- Sorted Lists(1)
- Stacks(1)
- Queues(1)
- Bandreject Filters(1)
- Bandpass filters(1)
- Notch Filters(1)
- Intensity Slicing and Color Coding(1)
- Color Slicing(1)
- Histogram Processing Color Images(1)
- Color Image Smoothing And Sharpening(1)
- Using Color In Image Segmentation(1)
- Digital Image Watermarking(1)

Back to Latest Articles
###
How To Make SLIC Superpixel Algorithm With C#

###
How To Make K Means Clustering Algorithm With C#

###
How To Make Region Splitting And Merging Algorithm – C#

###
How To Make Region Growing Algorithm With C#

###
How To Make Adaptive Thresholding Algorithm With C#

###
How To Make Multilevel Thresholding Algorithm With C#

###
How To Make Otsu Thresholding Algorithm With C#

###
How To Make A Basic Global Thresholding Algorithm – C#

###
How To Make Canny Edge Detection Algorithm With C#

###
How To Make Marr Hildreth Edge Detection Algorithm In C#

Region Segmentation Using Superpixels

SLIC superpixel segmentation is a modern operation for reducing irrelevant detail for shortening computational time in further processing.

Region Segmentation With K Means Clustering

K means clustering is a optimization method of partitioning an image by measuring Euclidean distances between pixels and cluster means.

Region Splitting And Merging

Region splitting and merging is a texture segmentation operation, where we use descriptors such as local mean intensity and standard deviation

Region Growing Segmentation

Region growing segmentation is a process, with which we can extract regions from image based on the properties of pixels inside them.

Thresholding

Adaptive thresholding operation computes thresholds for each pixel locally and therefore segments images more accurately.

Thresholding

Multilevel thresholding is an extension of Otsu's method of thresholding, which basically works for an arbitrary number of thresholds.

Thresholding

Otsu thresholding is a global thresholding method, with which we find optimal threshold intensity to ensure the maximum separability.

Thresholding

This tutorial demonstrates how to get optimal threshold value for basic global thresholding operation for segmentation in image processing.

Edge Detection

Canny edge detection process is an edge detection based segmentation operation in image processing for accurately extracting edges.

Edge Detection

Marr hildreth edge detection process is one of the earliest sophisticated edge detection based segmentation operations in image processing.

How To Make SLIC Superpixel Algorithm With C#

**Simple linear iterative clustering or SLIC** is a superpixel segmentation method for reducing irrelevant image data. Furthermore, the idea behind it is to replace standard pixel grid with a grid of regions. This way we create an image with less primitive units while preserving a descent amount of detail.

Each region, or superpixel, holds perceptually more meaningful image information than individual pixels. Therefore, since we reduce irrelevant detail, their purpose is to shorten computational time for further processing.

However, like any other image processing operation, this one also depends on the problem we’re trying to solve.

For example, it’s not acceptable for images, where we need to detect detail on pixel-level resolution, like the ones we use in medical examinations. But, it works well for those where small loss of detail doesn’t affect final results.

The way SLIC segmentation preserves detail is by adhering boundaries of superpixels to shapes of objects and background. Therefore it preserves details of shapes, while reducing color detail of the image overall.

In case we wanted to preserve a lot of detail, we could just increase the amount of superpixels. Since each of them will represent a region of individual pixels, our resulting image would still save up on space and computational time for further processing.

SLIC operation is a modification of k-means clustering, which we already covered in another article. In case you’re not familiar with it, I would suggest you check it out. This tutorial will be a walk in the park if you understand how that works.

First of all, we’re going to represent each pixel with a feature vector, which will hold color and spatial information. Therefore, each vector will hold 5 values, first three for RGB values and last two for horizontal and vertical position.

To begin with the process, we need to **initialize it by choosing starting pixels for superpixel centers**. In order to do that, we need to sample them so we end up with a grid of these points.

Furthermore, we’re going to use the following formula to compute this interval. Or in other words distance between each center in x and y position.

For some context *ntp* represents the number of all pixels in the image and *nsp*

While we’re sampling these starting superpixel centers, we need to **check for the lowest gradient point in 3×3 neighborhood**. Reason for that is so we don’t set our centers on noisy pixels. Therefore, I used Sobel edge detection operation to find those.

Next step is **assigning pixels to their closest centers** by computing pixel distance in a 2sx2s neighborhood around each center.

We’re going to use the following formula to compute distances between superpixel centers and pixels around them.

After we assigned pixels to each center, we need to** update the position and mean color values for each center**.

Next step is to test whether we need to **repeat the process** from assigning pixels again or not. Therefore, we need to compute an error value. We can do that by summing Euclidean distances of all superpixel center values from current and previous steps.

In order to stop looping this whole process, we need to **set a threshold**. So when the error value will be lower or equal to it, algorithm will close the loop. I my case here I set it to error from previous step.

And for our final step we’re going to **set each pixel their respective superpixel color**.

```
public static Bitmap Superpixels(this Bitmap image, int nsp)
{
int w = image.Width;
int h = image.Height;
```` BitmapData image_data = image.LockBits(`

` new Rectangle(0, 0, w, h),`

` ImageLockMode.ReadOnly,`

` PixelFormat.Format24bppRgb);`

` int bytes = image_data.Stride * image_data.Height;`

` byte[] buffer = new byte[bytes];`

` Marshal.Copy(image_data.Scan0, buffer, 0, bytes);`

` image.UnlockBits(image_data);`

` int ntp = buffer.Length / 3;`

` int s = (int)Math.Floor(Math.Sqrt((double)ntp / nsp));`

` int[][] means = new int[nsp][];`

` byte[] result = new byte[bytes];`

` int sp = 0;`

` //compute initial superpixel cluster centers`

` for (int x = s / 2; x < w; x+=s)`

` {`

` for (int y = s / 2; y < h; y+=s)`

` {`

` int position = x * 3 + y * image_data.Stride;`

` //compute lowest gradient`

` int lowest_grad = 99999;`

` for (int i = -1; i <= 1; i++)`

` {`

` for (int j = -1; j <= 1; j++)`

` {`

` int n_pos = position + i * 3 + j * image_data.Stride;`

` int grad = 0;`

` for (int k = -1; k <= 1; k++)`

` {`

` for (int l = -1; l <= 1; l++)`

` {`

` int g_pos = n_pos + k * 3 + l * image_data.Stride;`

` grad += buffer[g_pos] * (Filters.SobelHorizontal[k + 1, l + 1] + Filters.SobelVertical[k + 1, l + 1]);`

` }`

` }`

` if (lowest_grad > grad)`

` {`

` lowest_grad = grad;`

` means[sp] = new int[] { buffer[n_pos], x + i, y + j };`

` }`

` }`

` }`

` for (int c = 0; c < 3; c++)`

` {`

` result[means[sp][1] * 3 + means[sp][2] * image_data.Stride + c] = 255;`

` }`

` if (sp < nsp - 1)`

` {`

` sp++;`

` }`

` }`

` }`

` int[] labels = new int[bytes];`

` double[] distances = new double[bytes];`

` for (int i = 0; i < bytes; i+=3)`

` {`

` labels[i] = -1;`

` distances[i] = buffer.Length;`

` }`

` double error = new double();`

` double cc = 20;`

` while (true)`

` {`

` int[][] new_means = new int[nsp][];`

` //assign samples to clusters`

` for (int i = 0; i < nsp; i++)`

` {`

` int m_pos = means[i][1] * 3 + means[i][2] * image_data.Stride;`

` int xe = 2 * s + means[i][1];`

` int xs = means[i][1] - 2 * s;`

` int ye = 2 * s + means[i][2];`

` int ys = means[i][2] - 2 * s;`

` for (int x = (xs < 0 ? 0 : xs); x < ((xe < w) ? xe : w); x++)`

` {`

` for (int y = (ys < 0 ? 0 : ys); y < (ye < h ? ye : h); y++)`

` {`

` int position = x * 3 + y * image_data.Stride;`

` double ds = Math.Sqrt(Math.Pow(x - means[i][1], 2) + Math.Pow(y - means[i][2], 2));`

` double dc = Math.Sqrt(Math.Pow(buffer[position] - means[i][0], 2)`

` + Math.Pow(buffer[position + 1] - means[i][0], 2)`

` + Math.Pow(buffer[position + 2] - means[i][0], 2));`

` double distance = dc + (cc / s) * ds;`

` if (distance < distances[position])`

` {`

` distances[position] = distance;`

` labels[position] = i;`

` }`

` }`

` }`

` }`

` //compute new means`

` for (int i = 0; i < nsp; i++)`

` {`

` new_means[i] = new int[3];`

` int samples = 0;`

` for (int x = 0; x < w; x++)`

` {`

` for (int y = 0; y < h; y++)`

` {`

` int position = x * 3 + y * image_data.Stride;`

` if (labels[position] == i)`

` {`

` new_means[i][0] += buffer[position];`

` new_means[i][1] += x;`

` new_means[i][2] += y;`

` samples++;`

` }`

` }`

` }`

` for (int j = 0; j < 3; j++)`

` {`

` new_means[i][j] /= samples;`

` }`

` }`

` //compute error`

` double new_error = 0;`

` for (int i = 0; i < nsp; i++)`

` {`

` new_error += (int)Math.Sqrt(Math.Pow(means[i][0] - new_means[i][0], 2)`

` + Math.Pow(means[i][1] - new_means[i][1], 2)`

` + Math.Pow(means[i][2] - new_means[i][2], 2));`

` means[i] = new_means[i];`

` }`

` if (error < new_error)`

` {`

` break;`

` }`

` else`

` {`

` error = new_error;`

` }`

` }`

` for (int i = 0; i < nsp; i++)`

` {`

` for (int j = 0; j < bytes; j+=3)`

` {`

` if (labels[j] == i)`

` {`

` for (int c = 0; c < 3; c++)`

` {`

` result[j + c] = (byte)means[i][0];`

` }`

` }`

` }`

` }`

` Bitmap res_img = new Bitmap(w, h);`

` BitmapData res_data = res_img.LockBits(`

` new Rectangle(0, 0, w, h),`

` ImageLockMode.WriteOnly,`

` PixelFormat.Format24bppRgb);`

` Marshal.Copy(result, 0, res_data.Scan0, bytes);`

` res_img.UnlockBits(res_data);`

` return res_img;`

` }`

I hope this tutorial helped you understand how superpixel segmentation works.

You can also download the demo project and try it out yourself.

## Comments

Hello,

I’m having trouble getting your code to work, but that’s okay – I’m going to stick with it.

I wanted to point out that your “compute new means” code could be faster. If you set up your new means arrays as well as an array of counters, you’ll increase the storage necessary, but you’ll also be able to iterate over the labels instead of iterating over the superpixels, then iterating over all of the pixels and then finding out if those pixels had been found to be inside that superpixel.

After you do this, you can do the necessary division inside one loop over the superpixels.

This changes it from being a triply-nested for-loop to being 3 single for-loops.

I haven’t gotten to test this yet, but I’ll let you know when I get it working. I had to make significant modifications for my purposes, but the theory and structure remains unchanged.