# Easy 2D Signal-to-Noise Ratio (SNR) calculation for images to find stars without extracting the background noise (C++)

Calculation of a SNR for stars

This article shows how to calculate the 2D signal-to-noise ratio (SNR). Furthermore, it demonstrates how the $SNR$ can be used to decide if there is a potential star in the image.

Long story short – I was looking for a way to detect more or less reliably if a user selected a region which contains a star. I wanted to be able to clearly distinguish between the following two images:

### Solution with the CImg library

After a long journey I finally ended up with the following solution. It is based on the CImg library which in a way calculates the Signal-to-noise ratio (SNR):

CImg <uint16_t> image;
...
double q = image.variance(0) / image.variance_noise(0);
double qClip = (q > 1 ? q : 1);
double snr = std::sqrt(qClip - 1);

For the two images above the code gives the following results:

~/snr$./snr no_star.fits SNR: 0.0622817 ~snr$ ./snr test_star.fits
SNR: 1.5373

For many people this is where the journey ends. But for some of you it may just begin :). Follow me into the rabbit hole and find out why the solution shown above actually worksâ€¦

# Night sky image processing – Part 7: Automatic Star Recognizer

In the parts 1-6 of my “Night sky image processing” Series I wrote about the different stages of night sky image processing. In this article I want to put all the pieces together and develop an “automatic star recognizer” which takes an astro-image as input and outputs a list of the recognized stars with their HFD and FWHM values.

### The star recognizer processing pipeline

Basically the processing pipeline is as follows:

ROI = Region of interest

In order to achieve this I use most of the concepts I have looked into earlier:

As input I used this FITS image for testing.

# Night sky image processing – Part 5: Measuring FWHM of a star using curve fitting – A Simple C++ implementation

In Part 4 of my “Night sky image processing” Series I wrote about star centroid determination with sub-pixel accuracy. Based on this centroid position the FWHM determination of the star takes place. The FWHM (Full Width Half Maximum) value is a measurement for the star width. In this part I write about the so called curve-fitting which is helpful to determine the FWHM value from such an image. Note that for the following calculation and implementation I do not consider the sub-pixel determination of the centroid.

### Determination of the FWHM

Let’s say we want to determine the FWHM in x-direction (red line). There is of course also one in y-direction. Basically, what happens is:

1. Extract the pixel line through the centroid in x direction (those gray-level values usually form a Gaussian distribution: $$y(t)|_{b, p, c, w} = b + p \cdot e^{-\frac{1}{2} \cdot \big(\frac{t – c}{w}\big)^2}$$ We define a “data-point” as (x,y)=(pixel x-position, pixel gray-level value).
2. Based on those (x,y) data-points determine the 4 parameters of a Gaussian curve so that the Gaussian curve and the data-points fit “as good as possible”. As fitting algorithm we use the so called “Levenberg-Marquart” algorithm. It tries to minimize the quadratic error between the data-points and the curve.
3. The result is a Gaussian curve i.e. a parameter set which describes the curve (c=center, p=peak, b=base and the w=mean width). One of those parameters – the mean width is the FWHM value.

# Night sky image processing – Part 4: Calculate the star centroid with sub-pixel accuracy

In Part 3 of my “Night sky image processing” Series I wrote about star-clustering. The result of this step was a list of stars and their pixels. The next step is to find the center of each star – the star centroid.

To keep it simple, in this example I apply the algorithm to calculate the star centroid only for one single star which I load from a FITS file. Mohammad Vali Arbabmir et. al.. proposed this algorithm in “Improving night sky star image processing algorithm for star sensors”.

Certainly it is possible to further optimize the implementation shown below. However, to me this is a good compromise between clarity and efficiency. The paper mentioned above will probably help a lot to get a better understanding of the implementation. Generally there are two steps:

### Step 1: Calculation of the intensity weighted center (IWC) (to get an idea of where star center might be)

The calculation of IWC is based on the center of gravity CoG. The CoG is the same calculation as in physics but in this context just applied to an image. Each pixel brightness value has a weight – the brighter the “heavier”. For example to get the “center” x position $x_{cog}$ (this is the x position where the image has in x-direction the “brightest” value in mean. “In mean” means that all pixel values are considered). This directly leads to the following formulas for $x_{cog}$ and $y_{cog}$:

$$x_{cog} = \frac{\sum_{x=0}^{N-1}\sum_{y=0}^{M-1} x \cdot I(x,y) }{\sum_{x=0}^{N-1}\sum_{y=0}^{M-1}I(x,y)}$$

$$y_{cog} = \frac{\sum_{x=0}^{N-1}\sum_{y=0}^{M-1} y \cdot I(x,y) }{\sum_{x=0}^{N-1}\sum_{y=0}^{M-1}I(x,y)}$$

The only thing that changes between the two formulas is $x$ and $y$. The denominator just normalized the expression so that a valid position comes out. In addition, $N$ is the image width, $Y$ is the image height and $I(x,y)$ is the pixel value at position $(x,y)$.

Now, the only difference in the calculation of IWC is that each pixel value is additionally weighted with it’s own value:

# Night sky image processing – Part 3: Star clustering

Star clustering

This article is about finding all the pixels which belong to a star – also known as star clustering. A short C++ implementation based on CImg is shown below. In Part 2 of my “Night sky image processing” Series I was writing about thresholding. The result of the thresholding is a binary image. In this context it means the “1” pixels belong to stars, the “0” pixels belong to the background. I used Otsu’s method to calculate an according threshold value.

### Introduction to star clustering

The binary image is now further examined in a process called clustering. In simple words the pixels which belong together (i.e. the neighbours) are grouped together. The result of this clustering process is a list of pixel groups which belong together – i.e. a list of stars and the pixels belonging to each star.

The implemented algorithm is based on the paper “Improving night sky star image processing algorithm for star sensors from Mohammad Vali Arbabmir et. al. However, in detail it is slightly different. My implementation assumes that the supplied image cannot be modified during the process. Hence I am using a set to put all white pixels into. To me this is a good compromise between memory consumption, performance and simplicity. However, the implementation can be further improved with respect to runtime performance when one would used a 2D array for the white pixels instead of a set.

### The algorithm

The clustering algorithm is relatively straight forward: