Search code examples
pythonnumpysignalsnoise

How to calculate SNR for dynamic range?


I am an absolute beginner when it comes to coding, so I don't really understand how to go about this. I know this question has been asked before, but I couldn't figure it out after checking those out. I hope someone can help me. Now my ultimate goal is to find out what dynamic range the arri amira actually uses. That is part of our project at uni. (specs say 14+) I have shots ranging from 0,5 to 22 f-stops. I also have a shot with the lens cap on (darkframe, which is not 100% black, because there is noise). All frames are saved as TIFF (that's a requirement in our project). Now I would first have to calculate the p(noise) of the darkframe, right? SNR = P(signal)/p(noise). And then use that value as p(noise) for the other images?

I also don't know how to calculate p(noise). My idea is to compare the darkframe image to a darkframe that is actually completely black. Maybe as an array filled with zeros? I found code that included the calculation of mse values. Would that work with my idea? What I tried was this:

realDarkframe= np.zeros( (1080,1920,3) )
darkframeOfAmira= cv2.imread("image.tif",1)
def snr(img1, img2):
    mse = np.mean( (img1 - img2) ** 2)
    return mse

d=snr(realDarkframe,darkframeOfAmira)
print(d)

that returns the value of 565.7092896412037. Now I don't know what that means. And I also don't know how to calculate p(signal) even if this was correct and the number 565.7092896412037 actually equals p(noise).


Solution

  • The dynamic range of a measurement device (i.e. camera) describes the ratio between the maximum and minimum measurable light intensities. Regarding this, two issues emerge in your implementation.

    1. The dark Frame image that determines the lower bound of the dynamic range should not be plain zeros. This would imply an infinite dynamic range (dividing by zero in the SNR formula). Instead you need to capture a dark shot as you suggest

    "I also have a shot with the lens cap on (darkframe, which is not 100% black, because there is noise)."

    and use this image as a reference. You also need an image captured at maximum intensity (total white - "burnt")

    1. The signal-to-noise computation formula in the code segment is the mean squared error. You should use the formula as described in wikipedia snr = P(signal)/p(noise) = mean(signal^2) / mean(noise^2).

    This code should work:

    darkframeOfAmira = cv2.imread("dark_image.tif",1)
    brightframeOfAmira= cv2.imread("image.tif",1)
    def snr(img1, img2):
        return np.mean(img1 ** 2) / (np.mean(img2 ** 2) + 1e-12)
    
    d=snr(brightframeOfAmira,darkframeOfAmira)
    print(d)