Image Processing With GoLang

Explanations and implementations of image processing algorithms in GoLang

Damitha Dayananda
6 min readJun 18, 2020

Main focus of this article is implementing the following image processing algorithms in Golang.

  1. Upside down
  2. Rotating by angle
  3. Rotating by angle with three shear matrix
  4. Converting image into grayscale image
  5. Blur image filter using box blur matrix
  6. Blur image filter using gaussian matrix
  7. Edge detection using sobel operator

All the codes in this article can be found here (https://github.com/damithadayananda/golang-example/tree/master/image-processing)

When talking Image processing lots of developers used to use python and it’s so matured libraries like OpenCv, Pillow and etc. But Golang also has its own way to image processing, One of good thing in Golang is it’s powerful standard packages, when come to images, image package (https://golang.org/pkg/image/) consists all ground level tools that need to play with images.

First thing first, Before going to directly implementing algorithms it’s necessary to clear the ground, this section is for importing files, converting image into tensor and recreating back image by using tensor.

Importing image file

Like any other file, it’s possible to open a image file also, But when it need to decode opened image file into Image type. It’s necessary to import required package for decoding, for example if want to decode a “jpeg” type image file before decode function call for example decode a png file

import(

_”image/png”

)

codes for image file opening

Converting image into tensor

For the easiness of further manipulation, I have converted image.Image into three dimensional array as follows all other further manipulations are performed on top of this tensor(https://en.wikipedia.org/wiki/Tensor).

Convert tensor back to image

After manipulating tensor by applying particular algorithm on it, final step is recreating image back, since I have passed the address of the tensor(variable pixels) into function and then I can use same pixels variable to recreate image

Good news !!. Boring part is over let’s start fun part, but first easy thing let’s start with upside down image

  1. Upside down image

Let’s take a look at our tensor(pixels variable) which holds all pixels data of our image

var pixels [][]color.Color

This is a three dimensional array, so this can illustrate in three dimensional plane. So only thing we have to do in upside down image is take the mirror image value of x plane, in simply reversing y axis values.

Golang implementation of upside down image

(original images get from — https://www.timeout.com/london/film/portrait-of-a-lady-on-fire)

2. Greyscaling image

There are several algorithms to convert color image to grayscale image.

  1. Lightness method

Idea of this method is get the new pixel value by averaging most prominent and least prominent colors. (max(R, G, B) + min(R, G, B)) / 2

  1. Average method

Simply getting average value of three colours as the new pixel value. (R + G + B) / 3

  1. Luminosity method

This is a more sophisticated derivation of average method. Way of calculating the new pixel value is 0.21 R + 0.72 G + 0.07 B.

Golang implementation of luminosity method

3. Image rotating with rotation matrix

Let’s see how image pixels move when rotating

Rotated coordinates of point (x1,y1) from angle a is,

Proof of this equation can be found here (https://en.wikipedia.org/wiki/Rotation_(mathematics)#/media/File:Coordinate_system_rotation_svg.svg). Our goal is to implement this in golang

When calculating new coordinates with above rotation matrix, results are floating numbers, so It’s required to round the results. As a results of this rounding it’s possible to several original image points fall into one new image point and finally data lost, This scenario is called aliasing and since aliasing final image contains black dots.

Golang implementation of simple image rotation

In this implementation I just pushed calculations that possible to perform in concurrently in to new goroutine. Even Though goroutine is a thousands time lightweight compared to java thread increasing running goroutines count up to very high level(>1000) may cause to decreasing performance. So such kind of situations can be handle with worker pool(https://gobyexample.com/worker-pools). Anyway in three shear rotation matrix implementations I have implemented this concept.

Note the black dots in after image this is because of aliasing problem

4. Rotation image with three shear matrix

There are several techniques out there to deal with aliasing problems, using three shear matrix instead of a simple rotation matrix is one of interesting method. In this approach new coordinates are calculated in a three step process. Three shear matrix

Golang implementation of three shear matrix rotation

There shear matrix algorithm implementation is bit more cost cpu power because lots of floating point number multiplications are there. So I decide to use more golang concurrent processing techniques in this implementation and as I promised in simple rotation section here I have used worker pool concept in the code while getting away from waitGroup. Anyway it’s a bit more code If you are not really interesting in reading code please free to skip code section.

Image filtering

Image filtering is a technique used for modifying or enhancing an image like highlighting certain features of remove. Image filtering includes smoothing, sharpening, and edge enhancement. Filtering can be applied in either

  • Spatial domain
  • Frequency domain

The spatial filter is just moving the filter mask from point to point in an image. The filter mask may be 3x3 matrix, 5x5 matrix or 7x7 matrix

Examples for spatial domain filters are,

  • Smoothing filters like for blurring or noise reduction
  • Averaging filter
  • Weighted average filter

Frequency filters process images in frequency domain. The image is fourier transformed, multiplied with the filter function and then re-transformed into spatial domain. Smoother images in spatial domain can be obtained by Attenuating high frequencies, and attenuating low frequencies enhance the edge. Example for frequency domain filters are.

  • Low pass filter
  • High pass filter
  • Band pass filter

5. Blur image using box blur kernel

Box kernel is a 3x3 matrix. It will apply to image pixels and calculate kind of average value of neighbour pixels to get new pixel value as follows

Golang implementation of box kernel filter

In this implementation spartialFilter(pixels *[][]color.Color,kernel *mat.Dense) is a common function. By passing image reference and particular kernel it’s possible to calculate any kernel applied final image pixels.

6. Blur image using gaussian kernel

In gaussian kernel only difference is kernel, now it’s a 5x5 matrix

Golang implementation of gaussian kernel

Here also same spartialFilter(pixels *[][]color.Color,kernel *mat.Dense) will be used only difference is function call which will be as follows.

7. Edge detection

There are lots of techniques out there to detect edges in images like

  • Prewitt operator
  • Sobel operator
  • Robinson compass masks
  • Krisch compass masks
  • Laplacian operator

Here we are going to implement sobel operator in Golang. Sobel use two kernels(one for each direction)

Golang implementation of sobel operator

One of very important thing we want to focus on this implementation reducing information lost in data conversion as much possible unless we will land in some weird result.

References

https://www.johndcook.com/blog/2009/08/24/algorithms-convert-color-grayscale/

https://www.tutorialspoint.com/dip/concept_of_edge_detection.htm

https://www.codingame.com/playgrounds/2524/basic-image-manipulation/filtering

https://homepages.inf.ed.ac.uk/rbf/HIPR2/freqfilt.html

http://datagenetics.com/blog/august32013/index.html

--

--

Damitha Dayananda

Electrical Engineer interesting in web development, power electronic design and android application development — — — — damithadayananda@gmail.com — — — -