summaryrefslogtreecommitdiff
path: root/utils/raspberrypi/ctt/ctt_noise.py
blob: 0afcf8f850ccf688068379f2b9b25d463baeb4d6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# SPDX-License-Identifier: BSD-2-Clause
#
# Copyright (C) 2019, Raspberry Pi (Trading) Limited
#
# ctt_noise.py - camera tuning tool noise calibration

from ctt_image_load import *
import matplotlib.pyplot as plt


"""
Find noise standard deviation and fit to model:

    noise std = a + b*sqrt(pixel mean)
"""
def noise(Cam, Img, plot):
    Cam.log += '\nProcessing image: {}'.format(Img.name)
    stds = []
    means = []
    """
    iterate through macbeth square patches
    """
    for ch_patches in Img.patches:
        for patch in ch_patches:
            """
            renormalise patch
            """
            patch = np.array(patch)
            patch = (patch-Img.blacklevel_16)/Img.againQ8_norm
            std = np.std(patch)
            mean = np.mean(patch)
            stds.append(std)
            means.append(mean)

    """
    clean data and ensure all means are above 0
    """
    stds = np.array(stds)
    means = np.array(means)
    means = np.clip(np.array(means), 0, None)
    sq_means = np.sqrt(means)

    """
    least squares fit model
    """
    fit = np.polyfit(sq_means, stds, 1)
    Cam.log += '\nBlack level = {}'.format(Img.blacklevel_16)
    Cam.log += '\nNoise profile: offset = {}'.format(int(fit[1]))
    Cam.log += ' slope = {:.3f}'.format(fit[0])
    """
    remove any values further than std from the fit

    anomalies most likely caused by:
    > ucharacteristically noisy white patch
    > saturation in the white patch
    """
    fit_score = np.abs(stds - fit[0]*sq_means - fit[1])
    fit_std = np.std(stds)
    fit_score_norm = fit_score - fit_std
    anom_ind = np.where(fit_score_norm > 1)
    fit_score_norm.sort()
    sq_means_clean = np.delete(sq_means, anom_ind)
    stds_clean = np.delete(stds, anom_ind)
    removed = len(stds) - len(stds_clean)
    if removed != 0:
        Cam.log += '\nIdentified and removed {} anomalies.'.format(removed)
        Cam.log += '\nRecalculating fit'
        """
        recalculate fit with outliers removed
        """
        fit = np.polyfit(sq_means_clean, stds_clean, 1)
        Cam.log += '\nNoise profile: offset = {}'.format(int(fit[1]))
        Cam.log += ' slope = {:.3f}'.format(fit[0])

    """
    if fit const is < 0 then force through 0 by
    dividing by sq_means and fitting poly order 0
    """
    corrected = 0
    if fit[1] < 0:
        corrected = 1
        ones = np.ones(len(means))
        y_data = stds/sq_means
        fit2 = np.polyfit(ones, y_data, 0)
        Cam.log += '\nOffset below zero. Fit recalculated with zero offset'
        Cam.log += '\nNoise profile: offset = 0'
        Cam.log += ' slope = {:.3f}'.format(fit2[0])
        # print('new fit')
        # print(fit2)

    """
    plot fit for debug
    """
    if plot:
        x = np.arange(sq_means.max()//0.88)
        fit_plot = x*fit[0] + fit[1]
        plt.scatter(sq_means, stds, label='data', color='blue')
        plt.scatter(sq_means[anom_ind], stds[anom_ind], color='orange', label='anomalies')
        plt.plot(x, fit_plot, label='fit', color='red', ls=':')
        if fit[1] < 0:
            fit_plot_2 = x*fit2[0]
            plt.plot(x, fit_plot_2, label='fit 0 intercept', color='green', ls='--')
        plt.plot(0, 0)
        plt.title('Noise Plot\nImg: {}'.format(Img.str))
        plt.legend(loc='upper left')
        plt.xlabel('Sqrt Pixel Value')
        plt.ylabel('Noise Standard Deviation')
        plt.grid()
        plt.show()
    """
    End of plotting code
    """

    """
    format output to include forced 0 constant
    """
    Cam.log += '\n'
    if corrected:
        fit = [fit2[0], 0]
        return fit

    else:
        return fit
if (!compare(Point(50, 100), Point(50, 100), &operator!=, "!=", false)) return TestFail; if (!compare(Point(-50, 100), Point(-50, 100), &operator!=, "!=", false)) return TestFail; if (!compare(Point(50, -100), Point(50, -100), &operator!=, "!=", false)) return TestFail; if (!compare(Point(-50, -100), Point(-50, -100), &operator!=, "!=", false)) return TestFail; if (!compare(Point(-50, 100), Point(50, 100), &operator!=, "!=", true)) return TestFail; if (!compare(Point(50, -100), Point(50, 100), &operator!=, "!=", true)) return TestFail; if (!compare(Point(-50, -100), Point(50, 100), &operator!=, "!=", true)) return TestFail; /* Negation */ if (Point(50, 100) != -Point(-50, -100) || Point(50, 100) == -Point(50, -100) || Point(50, 100) == -Point(-50, 100)) { cout << "Point negation test failed" << endl; return TestFail; } /* Default constructor */ if (Point() != Point(0, 0)) { cout << "Default constructor test failed" << endl; return TestFail; } /* * Size tests */ if (!Size().isNull() || !Size(0, 0).isNull()) { cout << "Null size incorrectly reported as not null" << endl; return TestFail; } if (Size(0, 100).isNull() || Size(100, 0).isNull() || Size(100, 100).isNull()) { cout << "Non-null size incorrectly reported as null" << endl; return TestFail; } /* Test alignDownTo(), alignUpTo(), boundTo() and expandTo() */ Size s(50, 50); s.alignDownTo(16, 16); if (s != Size(48, 48)) { cout << "Size::alignDownTo() test failed" << endl; return TestFail; } s.alignUpTo(32, 32); if (s != Size(64, 64)) { cout << "Size::alignUpTo() test failed" << endl; return TestFail; } s.boundTo({ 40, 40 }); if (s != Size(40, 40)) { cout << "Size::boundTo() test failed" << endl; return TestFail; } s.expandTo({ 50, 50 }); if (s != Size(50, 50)) { cout << "Size::expandTo() test failed" << endl; return TestFail; } s.alignDownTo(16, 16).alignUpTo(32, 32) .boundTo({ 40, 80 }).expandTo({ 16, 80 }); if (s != Size(40, 80)) { cout << "Size chained in-place modifiers test failed" << endl; return TestFail; } /* Test alignedDownTo(), alignedUpTo(), boundedTo() and expandedTo() */ if (Size(0, 0).alignedDownTo(16, 8) != Size(0, 0) || Size(1, 1).alignedDownTo(16, 8) != Size(0, 0) || Size(16, 8).alignedDownTo(16, 8) != Size(16, 8)) { cout << "Size::alignedDownTo() test failed" << endl; return TestFail; } if (Size(0, 0).alignedUpTo(16, 8) != Size(0, 0) || Size(1, 1).alignedUpTo(16, 8) != Size(16, 8) || Size(16, 8).alignedUpTo(16, 8) != Size(16, 8)) { cout << "Size::alignedUpTo() test failed" << endl; return TestFail; } if (Size(0, 0).boundedTo({ 100, 100 }) != Size(0, 0) || Size(200, 50).boundedTo({ 100, 100 }) != Size(100, 50) || Size(50, 200).boundedTo({ 100, 100 }) != Size(50, 100)) { cout << "Size::boundedTo() test failed" << endl; return TestFail; } if (Size(0, 0).expandedTo({ 100, 100 }) != Size(100, 100) || Size(200, 50).expandedTo({ 100, 100 }) != Size(200, 100) || Size(50, 200).expandedTo({ 100, 100 }) != Size(100, 200)) { cout << "Size::expandedTo() test failed" << endl; return TestFail; } /* Aspect ratio tests */ if (Size(0, 0).boundedToAspectRatio(Size(4, 3)) != Size(0, 0) || Size(1920, 1440).boundedToAspectRatio(Size(16, 9)) != Size(1920, 1080) || Size(1920, 1440).boundedToAspectRatio(Size(65536, 36864)) != Size(1920, 1080) || Size(1440, 1920).boundedToAspectRatio(Size(9, 16)) != Size(1080, 1920) || Size(1920, 1080).boundedToAspectRatio(Size(4, 3)) != Size(1440, 1080) || Size(1920, 1080).boundedToAspectRatio(Size(65536, 49152)) != Size(1440, 1080) || Size(1024, 1024).boundedToAspectRatio(Size(1, 1)) != Size(1024, 1024) || Size(1920, 1080).boundedToAspectRatio(Size(16, 9)) != Size(1920, 1080) || Size(200, 100).boundedToAspectRatio(Size(16, 9)) != Size(177, 100) || Size(300, 200).boundedToAspectRatio(Size(16, 9)) != Size(300, 168)) { cout << "Size::boundedToAspectRatio() test failed" << endl; return TestFail; } if (Size(0, 0).expandedToAspectRatio(Size(4, 3)) != Size(0, 0) || Size(1920, 1440).expandedToAspectRatio(Size(16, 9)) != Size(2560, 1440) || Size(1920, 1440).expandedToAspectRatio(Size(65536, 36864)) != Size(2560, 1440) || Size(1440, 1920).expandedToAspectRatio(Size(9, 16)) != Size(1440, 2560) || Size(1920, 1080).expandedToAspectRatio(Size(4, 3)) != Size(1920, 1440) || Size(1920, 1080).expandedToAspectRatio(Size(65536, 49152)) != Size(1920, 1440) || Size(1024, 1024).expandedToAspectRatio(Size(1, 1)) != Size(1024, 1024) || Size(1920, 1080).expandedToAspectRatio(Size(16, 9)) != Size(1920, 1080) || Size(200, 100).expandedToAspectRatio(Size(16, 9)) != Size(200, 112) || Size(300, 200).expandedToAspectRatio(Size(16, 9)) != Size(355, 200)) { cout << "Size::expandedToAspectRatio() test failed" << endl; return TestFail; } /* Size::centeredTo() tests */ if (Size(0, 0).centeredTo(Point(50, 100)) != Rectangle(50, 100, 0, 0) || Size(0, 0).centeredTo(Point(-50, -100)) != Rectangle(-50, -100, 0, 0) || Size(100, 200).centeredTo(Point(50, 100)) != Rectangle(0, 0, 100, 200) || Size(100, 200).centeredTo(Point(-50, -100)) != Rectangle(-100, -200, 100, 200) || Size(101, 201).centeredTo(Point(-50, -100)) != Rectangle(-100, -200, 101, 201) || Size(101, 201).centeredTo(Point(-51, -101)) != Rectangle(-101, -201, 101, 201)) { cout << "Size::centeredTo() test failed" << endl; return TestFail; } /* Scale a size by a float */ if (Size(1000, 2000) * 2.0 != Size(2000, 4000) || Size(300, 100) * 0.5 != Size(150, 50) || Size(1, 2) * 1.6 != Size(1, 3)) { cout << "Size::operator*() failed" << endl; return TestFail; } if (Size(1000, 2000) / 2.0 != Size(500, 1000) || Size(300, 100) / 0.5 != Size(600, 200) || Size(1000, 2000) / 3.0 != Size(333, 666)) { cout << "Size::operator*() failed" << endl; return TestFail; } s = Size(300, 100); s *= 0.3333; if (s != Size(99, 33)) { cout << "Size::operator*() test failed" << endl; return TestFail; } s = Size(300, 100); s /= 3; if (s != Size(100, 33)) { cout << "Size::operator*() test failed" << endl; return TestFail; } /* Test Size equality and inequality. */ if (!compare(Size(100, 100), Size(100, 100), &operator==, "==", true)) return TestFail; if (!compare(Size(100, 100), Size(100, 100), &operator!=, "!=", false)) return TestFail;