Esempio n. 1
0
    def __getattr__(self, attribute):
        """
        Reimplements the :meth:`MutableSequence.__getattr__` method.

        Parameters
        ----------
        attribute : unicode
            Attribute to retrieve the value.

        Returns
        -------
        object
            Attribute value.
        """

        try:
            return self.__dict__[attribute]
        except KeyError:
            if hasattr(Image, attribute):
                value = [getattr(image, attribute) for image in self]
                if attribute == 'data':
                    return tstack(value)
                else:
                    return tuple(value)
            elif hasattr(Metadata, attribute):
                value = [getattr(image.metadata, attribute) for image in self]
                return np.asarray(value)
            else:
                raise AttributeError(
                    "'{0}' object has no attribute '{1}'".format(
                        self.__class__.__name__, attribute))
Esempio n. 2
0
def camera_response_functions_Debevec1997(image_stack,
                                          s=samples_Grossberg2003,
                                          samples=1000,
                                          l=30,
                                          w=weighting_function_Debevec1997,
                                          n=256,
                                          normalise=True):
    """
    Returns the camera response functions for given image stack using Debevec
    (1997) method.

    Image channels are sampled with :math:`s` sampling function and the output
    samples are passed to :func:`g_solve`.

    Parameters
    ----------
    image_stack : ImageStack
        Stack of single channel or multi-channel floating point images.
    s : callable, optional
        Sampling function :math:`s`.
    samples : int, optional
        Samples count per images.
    l : numeric, optional
        :math:`\lambda` smoothing term.
    w : callable, optional
        Weighting function :math:`w`.
    n : int, optional
        :math:`n` constant.
    normalise : bool, optional
        Enables the camera response functions normalisation. Uncertain camera
        response functions values resulting from :math:`w` function are
        set to zero.

    Returns
    -------
    ndarray
        Camera response functions :math:`g(z)`.
    """

    samples = s(image_stack.data, samples, n)

    L_l = np.log(average_luminance(image_stack.f_number,
                                   image_stack.exposure_time,
                                   image_stack.iso))

    crfs = np.exp(tstack(np.array([g_solve(samples[..., x], L_l, l, w, n)[0]
                                   for x in range(samples.shape[-1])])))

    if normalise:
        # TODO: Investigate if the normalisation value should account for the
        # percentage of uncertain camera response functions values or be
        # correlated to it and scaled accordingly. As an alternative of setting
        # the uncertain camera response functions values to zero, it would be
        # interesting to explore extrapolation as the camera response functions
        # are essentially smooth. It is important to note that camera sensors
        # are usually acting non linearly when reaching saturation level.
        crfs[w(np.linspace(0, 1, crfs.shape[0])) == 0] = 0
        crfs /= np.max(crfs, axis=0)

    return crfs
Esempio n. 3
0
def chromaticity_diagram_visual(
        samples=256,
        cmfs='CIE 1931 2 Degree Standard Observer',
        transformation='CIE 1931',
        parent=None):
    """
    Creates a chromaticity diagram visual based on
    :class:`colour_analysis.visuals.Primitive` class.

    Parameters
    ----------
    samples : int, optional
        Inner samples count used to construct the chromaticity diagram
        triangulation.
    cmfs : unicode, optional
        Standard observer colour matching functions used for the chromaticity
        diagram boundaries.
    transformation : unicode, optional
        {'CIE 1931', 'CIE 1960 UCS', 'CIE 1976 UCS'}

        Chromaticity diagram transformation.
    parent : Node, optional
        Parent of the chromaticity diagram in the `SceneGraph`.

    Returns
    -------
    Primitive
        Chromaticity diagram visual.
    """

    cmfs = get_cmfs(cmfs)

    illuminant = DEFAULT_PLOTTING_ILLUMINANT

    XYZ_to_ij = (
        CHROMATICITY_DIAGRAM_TRANSFORMATIONS[transformation]['XYZ_to_ij'])
    ij_to_XYZ = (
        CHROMATICITY_DIAGRAM_TRANSFORMATIONS[transformation]['ij_to_XYZ'])

    ij_c = XYZ_to_ij(cmfs.values, illuminant)

    triangulation = Delaunay(ij_c, qhull_options='QJ')
    samples = np.linspace(0, 1, samples)
    ii, jj = np.meshgrid(samples, samples)
    ij = tstack((ii, jj))
    ij = np.vstack((ij_c, ij[triangulation.find_simplex(ij) > 0]))

    ij_p = np.hstack((ij, np.full((ij.shape[0], 1), 0)))
    triangulation = Delaunay(ij, qhull_options='QJ')
    RGB = normalise(XYZ_to_sRGB(ij_to_XYZ(ij, illuminant), illuminant),
                    axis=-1)

    diagram = Primitive(vertices=ij_p,
                        faces=triangulation.simplices,
                        vertex_colours=RGB,
                        parent=parent)

    return diagram
def test_multi_signal_copy_operations():
    domain = np.arange(0, 1000, 100)
    range_1 = np.linspace(1, 10, domain.size)
    range_2 = np.linspace(1, 10, domain.size) + 1
    range_3 = np.linspace(1, 10, domain.size) + 2

    cms1 = MultiSignal(tstack((domain, range_1, range_2, range_3)))
    cms2 = cms1.copy()
    assert id(cms1) != id(cms2)
Esempio n. 5
0
def chromaticity_diagram_visual(samples=256,
                                cmfs='CIE 1931 2 Degree Standard Observer',
                                transformation='CIE 1931',
                                parent=None):
    """
    Creates a chromaticity diagram visual based on
    :class:`colour_analysis.visuals.Primitive` class.

    Parameters
    ----------
    samples : int, optional
        Inner samples count used to construct the chromaticity diagram
        triangulation.
    cmfs : unicode, optional
        Standard observer colour matching functions used for the chromaticity
        diagram boundaries.
    transformation : unicode, optional
        **{'CIE 1931', 'CIE 1960 UCS', 'CIE 1976 UCS'}**,
        Chromaticity diagram transformation.
    parent : Node, optional
        Parent of the chromaticity diagram in the `SceneGraph`.

    Returns
    -------
    Primitive
        Chromaticity diagram visual.
    """

    cmfs = get_cmfs(cmfs)

    illuminant = DEFAULT_PLOTTING_ILLUMINANT

    XYZ_to_ij = (
        CHROMATICITY_DIAGRAM_TRANSFORMATIONS[transformation]['XYZ_to_ij'])
    ij_to_XYZ = (
        CHROMATICITY_DIAGRAM_TRANSFORMATIONS[transformation]['ij_to_XYZ'])

    ij_c = XYZ_to_ij(cmfs.values, illuminant)

    triangulation = Delaunay(ij_c, qhull_options='QJ')
    samples = np.linspace(0, 1, samples)
    ii, jj = np.meshgrid(samples, samples)
    ij = tstack((ii, jj))
    ij = np.vstack((ij_c, ij[triangulation.find_simplex(ij) > 0]))

    ij_p = np.hstack((ij, np.full((ij.shape[0], 1), 0, DEFAULT_FLOAT_DTYPE)))
    triangulation = Delaunay(ij, qhull_options='QJ')
    RGB = normalise_maximum(
        XYZ_to_sRGB(ij_to_XYZ(ij, illuminant), illuminant), axis=-1)

    diagram = Primitive(
        vertices=ij_p,
        faces=triangulation.simplices,
        vertex_colours=RGB,
        parent=parent)

    return diagram
def test_multi_signal_copy_operations():
    domain = np.arange(0, 1000, 100)
    range_1 = np.linspace(1, 10, domain.size)
    range_2 = np.linspace(1, 10, domain.size) + 1
    range_3 = np.linspace(1, 10, domain.size) + 2

    cms1 = MultiSignal(tstack((domain, range_1, range_2, range_3)))
    cms2 = cms1.copy()
    assert id(cms1) != id(cms2)
    def __repr__(self):
        try:
            representation = repr(tstack((self.domain, self.range)))
            representation = representation.replace('array',
                                                    self.__class__.__name__)
            representation = representation.replace('       [', '{0}['.format(
                ' ' * (len(self.__class__.__name__) + 2)))

            return representation
        except TypeError:
            return super(Signal, self).__repr__()
    def __repr__(self):
        try:
            representation = repr(tstack((self.domain, self.range)))
            representation = representation.replace('array',
                                                    self.__class__.__name__)
            representation = representation.replace(
                '       [',
                '{0}['.format(' ' * (len(self.__class__.__name__) + 2)))

            return representation
        except TypeError:
            return super(Signal, self).__repr__()
    def __create_image(self):
        """
        Creates the image used by the *Image View* according to
        :attr:`GamutView.__display_input_colourspace_out_of_gamut`,
        :attr:`GamutView.__display_correlate_colourspace_out_of_gamut`,
        :attr:`GamutView.__display_out_of_pointer_gamut` and
        :attr:`GamutView.__display_hdr_colours` attributes values.

        Returns
        -------
        ndarray
            Image
        """

        image = np.copy(self.__image)

        has_overlay = False
        if (self.__display_input_colourspace_out_of_gamut or
                self.__display_correlate_colourspace_out_of_gamut):
            image[image >= 0] = 0
            image[image < 0] = 1
            has_overlay = True

        if self.__display_correlate_colourspace_out_of_gamut:
            image = RGB_to_RGB(image,
                               RGB_COLOURSPACES[self.__input_colourspace],
                               RGB_COLOURSPACES[self.__correlate_colourspace])
            has_overlay = True

        if self.__display_out_of_pointer_gamut:
            colourspace = RGB_COLOURSPACES[self.__input_colourspace]
            image = is_within_pointer_gamut(
                RGB_to_XYZ(image,
                           colourspace.whitepoint,
                           colourspace.whitepoint,
                           colourspace.RGB_to_XYZ_matrix)).astype(int)

            # TODO: Investigate why stacking implies that image needs to be
            # inverted.
            image = 1 - tstack((image, image, image))
            has_overlay = True

        if self.__display_hdr_colours:
            image[image <= 1] = 0
            # has_overlay = True

        if self.__image_overlay and has_overlay:
            image = self.__image + image

        oecf = RGB_COLOURSPACES[DEFAULT_OECF].transfer_function

        return oecf(image)
Esempio n. 10
0
    def test_masks_CFA_Bayer(self):
        """
        Tests :func:`colour_demosaicing.bayer.masks.masks_CFA_Bayer`
        definition.
        """

        for pattern in ('RGGB', 'BGGR', 'GRBG', 'GBRG'):
            np.testing.assert_almost_equal(
                colour.tstack(masks_CFA_Bayer((8, 8), pattern)),
                colour.read_image(
                    str(os.path.join(BAYER_DIRECTORY,
                                     '{0}_Masks.exr'.format(pattern)))),
                decimal=7)
Esempio n. 11
0
    def _create_image(self):
        """
        Creates the image used by the *Image View* according to
        :attr:`GamutView._display_input_colourspace_out_of_gamut`,
        :attr:`GamutView._display_correlate_colourspace_out_of_gamut`,
        :attr:`GamutView._display_out_of_pointer_gamut` and
        :attr:`GamutView._display_hdr_colours` attributes values.

        Returns
        -------
        ndarray
            Image
        """

        image = np.copy(self._image)

        has_overlay = False
        if (self._display_input_colourspace_out_of_gamut
                or self._display_correlate_colourspace_out_of_gamut):
            image[image >= 0] = 0
            image[image < 0] = 1
            has_overlay = True

        if self._display_correlate_colourspace_out_of_gamut:
            image = RGB_to_RGB(image,
                               RGB_COLOURSPACES[self._input_colourspace],
                               RGB_COLOURSPACES[self._correlate_colourspace])
            has_overlay = True

        if self._display_out_of_pointer_gamut:
            colourspace = RGB_COLOURSPACES[self._input_colourspace]
            image = is_within_pointer_gamut(
                RGB_to_XYZ(image, colourspace.whitepoint,
                           colourspace.whitepoint,
                           colourspace.RGB_to_XYZ_matrix)).astype(int)

            # TODO: Investigate why stacking implies that image needs to be
            # inverted.
            image = 1 - tstack((image, image, image))
            has_overlay = True

        if self._display_hdr_colours:
            image[image <= 1] = 0
            # has_overlay = True

        if self._image_overlay and has_overlay:
            image = self._image + image

        oecf = RGB_COLOURSPACES[DEFAULT_ENCODING_CCTF].encoding_cctf

        return oecf(image)
def test_multi_signal_oject_initialisation():
    domain = np.arange(0, 1000, 100)
    range_1 = np.linspace(1, 10, domain.size)
    range_2 = np.linspace(1, 10, domain.size) + 1
    range_3 = np.linspace(1, 10, domain.size) + 2

    cms1 = MultiSignal(tstack((domain, range_1, range_2, range_3)))
    np.testing.assert_array_equal(cms1.range,
                                  tstack((range_1, range_2, range_3)))
    np.testing.assert_array_equal(cms1.domain, domain)

    cms2 = MultiSignal(range_1)
    np.testing.assert_array_equal(cms2.range, range_1[:, np.newaxis])
    np.testing.assert_array_equal(cms2.domain, np.linspace(0, 1, domain.size))

    cms3 = MultiSignal(range_1, labels=['My Label'])
    assert list(cms3.signals.keys()) == ['My Label']

    cms4 = MultiSignal(
        tstack((range_1, range_2, range_3)), domain / 1000, ('a', 'b', 'c'))
    np.testing.assert_array_equal(cms4.range,
                                  tstack((range_1, range_2, range_3)))
    np.testing.assert_array_equal(cms4.domain, domain / 1000)
    assert cms4.labels == ['a', 'b', 'c']

    cms5 = MultiSignal(Series(range_1, domain))
    np.testing.assert_array_equal(cms5.range, range_1[:, np.newaxis])
    np.testing.assert_array_equal(cms5.domain, domain)

    dataframe = DataFrame(
        OrderedDict([('aa', range_1), ('bb', range_2), ('cc', range_3)]))
    cms6 = MultiSignal(dataframe)
    np.testing.assert_array_equal(cms6.range,
                                  tstack((range_1, range_2, range_3)))

    assert cms6.labels == ['aa', 'bb', 'cc']
    np.testing.assert_array_equal(cms6.domain, np.arange(0, np.size(domain)))
def test_multi_signal_oject_initialisation():
    domain = np.arange(0, 1000, 100)
    range_1 = np.linspace(1, 10, domain.size)
    range_2 = np.linspace(1, 10, domain.size) + 1
    range_3 = np.linspace(1, 10, domain.size) + 2

    cms1 = MultiSignal(tstack((domain, range_1, range_2, range_3)))
    np.testing.assert_array_equal(cms1.range,
                                  tstack((range_1, range_2, range_3)))
    np.testing.assert_array_equal(cms1.domain, domain)

    cms2 = MultiSignal(range_1)
    np.testing.assert_array_equal(cms2.range, range_1[:, np.newaxis])
    np.testing.assert_array_equal(cms2.domain, np.linspace(0, 1, domain.size))

    cms3 = MultiSignal(range_1, labels=['My Label'])
    assert list(cms3.signals.keys()) == ['My Label']

    cms4 = MultiSignal(tstack((range_1, range_2, range_3)), domain / 1000,
                       ('a', 'b', 'c'))
    np.testing.assert_array_equal(cms4.range,
                                  tstack((range_1, range_2, range_3)))
    np.testing.assert_array_equal(cms4.domain, domain / 1000)
    assert cms4.labels == ['a', 'b', 'c']

    cms5 = MultiSignal(Series(range_1, domain))
    np.testing.assert_array_equal(cms5.range, range_1[:, np.newaxis])
    np.testing.assert_array_equal(cms5.domain, domain)

    dataframe = DataFrame(
        OrderedDict([('aa', range_1), ('bb', range_2), ('cc', range_3)]))
    cms6 = MultiSignal(dataframe)
    np.testing.assert_array_equal(cms6.range,
                                  tstack((range_1, range_2, range_3)))

    assert cms6.labels == ['aa', 'bb', 'cc']
    np.testing.assert_array_equal(cms6.domain, np.arange(0, np.size(domain)))
Esempio n. 14
0
def samples_Grossberg2003(image_stack, samples=1000, n=256):
    """
    Returns the samples for given image stack intensity histograms using
    Grossberg (2003) method.

    Parameters
    ----------
    image_stack : array_like
        Stack of single channel or multi-channel floating point images.
    samples : int, optional
        Samples count.
    n : int, optional
        Histograms bins count.

    Returns
    -------
    ndarray
        Intensity histograms samples.
    """

    image_stack = np.asarray(image_stack)

    if image_stack.ndim == 3:
        channels_c = 1
    else:
        channels_c = image_stack.shape[-2]

    cdf_i = []
    for image in tsplit(image_stack):
        histograms = tstack(
            [np.histogram(image[..., c], n, range=(0, 1))[0]
             for c in np.arange(channels_c)])
        cdf = np.cumsum(histograms, axis=0)
        cdf_i.append(cdf.astype(np.float_) / np.max(cdf, axis=0))

    samples_cdf_i = np.zeros((samples, len(cdf_i), channels_c))
    samples_u = np.linspace(0, 1, samples)
    for i in np.arange(samples):
        for j in np.arange(channels_c):
            for k, cdf in enumerate(cdf_i):
                samples_cdf_i[i, k, j] = np.argmin(np.abs(cdf[:, j] -
                                                          samples_u[i]))

    return samples_cdf_i
def test_multi_signal_getter():
    domain = np.arange(0, 1000, 100)
    range_1 = np.linspace(1, 10, domain.size)
    range_2 = np.linspace(1, 10, domain.size) + 1
    range_3 = np.linspace(1, 10, domain.size) + 2

    cms1 = MultiSignal(tstack((domain, range_1, range_2, range_3)))
    np.testing.assert_array_almost_equal(cms1[150.25],
                                         [2.5025, 3.5025, 4.5025])

    np.testing.assert_array_almost_equal(
        cms1[np.linspace(100, 400, 10)],
        np.array([[2.00000000, 3.00000000,
                   4.00000000], [2.33333333, 3.33333333, 4.33333333], [
                       2.66666667, 3.66666667, 4.66666667
                   ], [3.00000000, 4.00000000,
                       5.00000000], [3.33333333, 4.33333333, 5.33333333],
                  [3.66666667, 4.66666667,
                   5.66666667], [4.00000000, 5.00000000, 6.00000000], [
                       4.33333333, 5.33333333, 6.33333333
                   ], [4.66666667, 5.66666667, 6.66666667],
                  [5.00000000, 6.00000000, 7.00000000]]))
def test_multi_signal_getter():
    domain = np.arange(0, 1000, 100)
    range_1 = np.linspace(1, 10, domain.size)
    range_2 = np.linspace(1, 10, domain.size) + 1
    range_3 = np.linspace(1, 10, domain.size) + 2

    cms1 = MultiSignal(tstack((domain, range_1, range_2, range_3)))
    np.testing.assert_array_almost_equal(cms1[150.25],
                                         [2.5025, 3.5025, 4.5025])

    np.testing.assert_array_almost_equal(
        cms1[np.linspace(100, 400, 10)],
        np.array([[2.00000000, 3.00000000, 4.00000000],
                  [2.33333333, 3.33333333, 4.33333333],
                  [2.66666667, 3.66666667, 4.66666667],
                  [3.00000000, 4.00000000, 5.00000000],
                  [3.33333333, 4.33333333, 5.33333333],
                  [3.66666667, 4.66666667, 5.66666667],
                  [4.00000000, 5.00000000, 6.00000000],
                  [4.33333333, 5.33333333, 6.33333333],
                  [4.66666667, 5.66666667, 6.66666667],
                  [5.00000000, 6.00000000, 7.00000000]]))
 def __str__(self):
     try:
         return str(tstack((self.domain, self.range)))
     except TypeError:
         return super(Signal, self).__str__()
Esempio n. 18
0
def demosaicing_CFA_Bayer_Menon2007(CFA, pattern='RGGB', refining_step=True):
    """
    Returns the demosaiced *RGB* colourspace array from given *Bayer* CFA using
    DDFAPD - Menon (2007) demosaicing algorithm.

    Parameters
    ----------
    CFA : array_like
        *Bayer* CFA.
    pattern : unicode, optional
        **{'RGGB', 'BGGR', 'GRBG', 'GBRG'}**,
        Arrangement of the colour filters on the pixel array.
    refining_step : bool
        Perform refining step.

    Returns
    -------
    ndarray
        *RGB* colourspace array.

    Examples
    --------
    >>> CFA = np.array([[ 0.30980393,  0.36078432,  0.30588236,  0.3764706 ],
    ...                 [ 0.35686275,  0.39607844,  0.36078432,  0.40000001]])
    >>> demosaicing_CFA_Bayer_Menon2007(CFA)
    array([[[ 0.30980393,  0.35686275,  0.39215687],
            [ 0.30980393,  0.36078432,  0.39607844],
            [ 0.30588236,  0.36078432,  0.39019608],
            [ 0.32156864,  0.3764706 ,  0.40000001]],
    <BLANKLINE>
           [[ 0.30980393,  0.35686275,  0.39215687],
            [ 0.30980393,  0.36078432,  0.39607844],
            [ 0.30588236,  0.36078432,  0.39019609],
            [ 0.32156864,  0.3764706 ,  0.40000001]]])
    >>> CFA = np.array([[ 0.3764706 ,  0.36078432,  0.40784314,  0.3764706 ],
    ...                 [ 0.35686275,  0.30980393,  0.36078432,  0.29803923]])
    >>> demosaicing_CFA_Bayer_Menon2007(CFA, 'BGGR')
    array([[[ 0.30588236,  0.35686275,  0.3764706 ],
            [ 0.30980393,  0.36078432,  0.39411766],
            [ 0.29607844,  0.36078432,  0.40784314],
            [ 0.29803923,  0.3764706 ,  0.42352942]],
    <BLANKLINE>
           [[ 0.30588236,  0.35686275,  0.3764706 ],
            [ 0.30980393,  0.36078432,  0.39411766],
            [ 0.29607844,  0.36078432,  0.40784314],
            [ 0.29803923,  0.3764706 ,  0.42352942]]])
    """

    CFA = np.asarray(CFA)
    R_m, G_m, B_m = masks_CFA_Bayer(CFA.shape, pattern)

    h_0 = np.array([0, 0.5, 0, 0.5, 0])
    h_1 = np.array([-0.25, 0, 0.5, 0, -0.25])

    R = CFA * R_m
    G = CFA * G_m
    B = CFA * B_m

    G_H = np.where(G_m == 0, _cnv_h(CFA, h_0) + _cnv_h(CFA, h_1), G)
    G_V = np.where(G_m == 0, _cnv_v(CFA, h_0) + _cnv_v(CFA, h_1), G)

    C_H = np.where(R_m == 1, R - G_H, 0)
    C_H = np.where(B_m == 1, B - G_H, C_H)

    C_V = np.where(R_m == 1, R - G_V, 0)
    C_V = np.where(B_m == 1, B - G_V, C_V)

    D_H = np.abs(C_H - np.pad(C_H, ((0, 0),
                                    (0, 2)), mode=str('reflect'))[:, 2:])
    D_V = np.abs(C_V - np.pad(C_V, ((0, 2),
                                    (0, 0)), mode=str('reflect'))[2:, :])

    k = np.array([[0, 0, 1, 0, 1], [0, 0, 0, 1, 0], [0, 0, 3, 0, 3],
                  [0, 0, 0, 1, 0], [0, 0, 1, 0, 1]])

    d_H = convolve(D_H, k, mode='constant')
    d_V = convolve(D_V, np.transpose(k), mode='constant')

    mask = d_V >= d_H
    G = np.where(mask, G_H, G_V)
    M = np.where(mask, 1, 0)

    # Red rows.
    R_r = np.transpose(np.any(R_m == 1, axis=1)[np.newaxis]) * np.ones(R.shape)
    # Blue rows.
    B_r = np.transpose(np.any(B_m == 1, axis=1)[np.newaxis]) * np.ones(B.shape)

    k_b = np.array([0.5, 0, 0.5])

    R = np.where(np.logical_and(G_m == 1, R_r == 1),
                 G + _cnv_h(R, k_b) - _cnv_h(G, k_b), R)

    R = np.where(
        np.logical_and(G_m == 1, B_r == 1) == 1,
        G + _cnv_v(R, k_b) - _cnv_v(G, k_b), R)

    B = np.where(np.logical_and(G_m == 1, B_r == 1),
                 G + _cnv_h(B, k_b) - _cnv_h(G, k_b), B)

    B = np.where(
        np.logical_and(G_m == 1, R_r == 1) == 1,
        G + _cnv_v(B, k_b) - _cnv_v(G, k_b), B)

    R = np.where(
        np.logical_and(B_r == 1, B_m == 1),
        np.where(M == 1, B + _cnv_h(R, k_b) - _cnv_h(B, k_b),
                 B + _cnv_v(R, k_b) - _cnv_v(B, k_b)), R)

    B = np.where(
        np.logical_and(R_r == 1, R_m == 1),
        np.where(M == 1, R + _cnv_h(B, k_b) - _cnv_h(R, k_b),
                 R + _cnv_v(B, k_b) - _cnv_v(R, k_b)), B)

    RGB = tstack((R, G, B))

    if refining_step:
        RGB = refining_step_Menon2007(RGB, tstack((R_m, G_m, B_m)), M)

    return RGB
def refining_step_Menon2007(RGB, RGB_m, M):
    """
    Performs the refining step on given *RGB* colourspace array.

    Parameters
    ----------
    RGB : array_like
        *RGB* colourspace array.
    RGB_m : array_like
        *Bayer* CFA red, green and blue masks.
    M : array_like
        Estimation for the best directional reconstruction.

    Returns
    -------
    ndarray
        Refined *RGB* colourspace array.

    Examples
    --------
    >>> RGB = np.array([[[0.30588236, 0.35686275, 0.3764706],
    ...                  [0.30980393, 0.36078432, 0.39411766],
    ...                  [0.29607844, 0.36078432, 0.40784314],
    ...                  [0.29803923, 0.37647060, 0.42352942]],
    ...                 [[0.30588236, 0.35686275, 0.3764706],
    ...                  [0.30980393, 0.36078432, 0.39411766],
    ...                  [0.29607844, 0.36078432, 0.40784314],
    ...                  [0.29803923, 0.37647060, 0.42352942]]])
    >>> RGB_m = np.array([[[0, 0, 1],
    ...                    [0, 1, 0],
    ...                    [0, 0, 1],
    ...                    [0, 1, 0]],
    ...                   [[0, 1, 0],
    ...                    [1, 0, 0],
    ...                    [0, 1, 0],
    ...                    [1, 0, 0]]])
    >>> M = np.array([[0, 1, 0, 1],
    ...               [1, 0, 1, 0]])
    >>> refining_step_Menon2007(RGB, RGB_m, M)
    array([[[ 0.30588236,  0.35686275,  0.3764706 ],
            [ 0.30980393,  0.36078432,  0.39411765],
            [ 0.29607844,  0.36078432,  0.40784314],
            [ 0.29803923,  0.3764706 ,  0.42352942]],
    <BLANKLINE>
           [[ 0.30588236,  0.35686275,  0.3764706 ],
            [ 0.30980393,  0.36078432,  0.39411766],
            [ 0.29607844,  0.36078432,  0.40784314],
            [ 0.29803923,  0.3764706 ,  0.42352942]]])
    """

    R, G, B = tsplit(RGB)
    R_m, G_m, B_m = tsplit(RGB_m)
    M = np.asarray(M)

    # Updating of the green component.
    R_G = R - G
    B_G = B - G

    FIR = np.ones(3) / 3

    B_G_m = np.where(B_m == 1,
                     np.where(M == 1, _cnv_h(B_G, FIR), _cnv_v(B_G, FIR)), 0)
    R_G_m = np.where(R_m == 1,
                     np.where(M == 1, _cnv_h(R_G, FIR), _cnv_v(R_G, FIR)), 0)

    G = np.where(R_m == 1, R - R_G_m, G)
    G = np.where(B_m == 1, B - B_G_m, G)

    # Updating of the red and blue components in the green locations.
    # Red rows.
    R_r = np.transpose(np.any(R_m == 1, axis=1)[np.newaxis]) * np.ones(R.shape)
    # Red columns.
    R_c = np.any(R_m == 1, axis=0)[np.newaxis] * np.ones(R.shape)
    # Blue rows.
    B_r = np.transpose(np.any(B_m == 1, axis=1)[np.newaxis]) * np.ones(B.shape)
    # Blue columns
    B_c = np.any(B_m == 1, axis=0)[np.newaxis] * np.ones(B.shape)

    R_G = R - G
    B_G = B - G

    k_b = np.array([0.5, 0, 0.5])

    R_G_m = np.where(np.logical_and(G_m == 1, B_r == 1),
                     _cnv_v(R_G, k_b),
                     R_G_m)
    R = np.where(np.logical_and(G_m == 1, B_r == 1), G + R_G_m, R)
    R_G_m = np.where(np.logical_and(G_m == 1, B_c == 1),
                     _cnv_h(R_G, k_b),
                     R_G_m)
    R = np.where(np.logical_and(G_m == 1, B_c == 1), G + R_G_m, R)

    B_G_m = np.where(np.logical_and(G_m == 1, R_r == 1),
                     _cnv_v(B_G, k_b),
                     B_G_m)
    B = np.where(np.logical_and(G_m == 1, R_r == 1), G + B_G_m, B)
    B_G_m = np.where(np.logical_and(G_m == 1, R_c == 1),
                     _cnv_h(B_G, k_b),
                     B_G_m)
    B = np.where(np.logical_and(G_m == 1, R_c == 1), G + B_G_m, B)

    # Updating of the red (blue) component in the blue (red) locations.
    R_B = R - B
    R_B_m = np.where(B_m == 1,
                     np.where(M == 1, _cnv_h(R_B, FIR), _cnv_v(R_B, FIR)), 0)
    R = np.where(B_m == 1, B + R_B_m, R)

    R_B_m = np.where(R_m == 1,
                     np.where(M == 1, _cnv_h(R_B, FIR), _cnv_v(R_B, FIR)), 0)
    B = np.where(R_m == 1, R - R_B_m, B)

    return tstack((R, G, B))
 def __getitem__(self, x):
     return tstack([signal[x] for signal in self._signals.values()])
 def range(self):
     if len(self._signals) != 0:
         return tstack([signal.range for signal in self._signals.values()])
def demosaicing_CFA_Bayer_Menon2007(CFA, pattern='RGGB', refining_step=True):
    """
    Returns the demosaiced *RGB* colourspace array from given *Bayer* CFA using
    DDFAPD - Menon (2007) demosaicing algorithm.

    Parameters
    ----------
    CFA : array_like
        *Bayer* CFA.
    pattern : unicode, optional
        **{'RGGB', 'BGGR', 'GRBG', 'GBRG'}**,
        Arrangement of the colour filters on the pixel array.
    refining_step : bool
        Perform refining step.

    Returns
    -------
    ndarray
        *RGB* colourspace array.

    Examples
    --------
    >>> CFA = np.array([[ 0.30980393,  0.36078432,  0.30588236,  0.3764706 ],
    ...                 [ 0.35686275,  0.39607844,  0.36078432,  0.40000001]])
    >>> demosaicing_CFA_Bayer_Menon2007(CFA)
    array([[[ 0.30980393,  0.35686275,  0.39215687],
            [ 0.30980393,  0.36078432,  0.39607844],
            [ 0.30588236,  0.36078432,  0.39019608],
            [ 0.32156864,  0.3764706 ,  0.40000001]],
    <BLANKLINE>
           [[ 0.30980393,  0.35686275,  0.39215687],
            [ 0.30980393,  0.36078432,  0.39607844],
            [ 0.30588236,  0.36078432,  0.39019609],
            [ 0.32156864,  0.3764706 ,  0.40000001]]])
    >>> CFA = np.array([[ 0.3764706 ,  0.36078432,  0.40784314,  0.3764706 ],
    ...                 [ 0.35686275,  0.30980393,  0.36078432,  0.29803923]])
    >>> demosaicing_CFA_Bayer_Menon2007(CFA, 'BGGR')
    array([[[ 0.30588236,  0.35686275,  0.3764706 ],
            [ 0.30980393,  0.36078432,  0.39411766],
            [ 0.29607844,  0.36078432,  0.40784314],
            [ 0.29803923,  0.3764706 ,  0.42352942]],
    <BLANKLINE>
           [[ 0.30588236,  0.35686275,  0.3764706 ],
            [ 0.30980393,  0.36078432,  0.39411766],
            [ 0.29607844,  0.36078432,  0.40784314],
            [ 0.29803923,  0.3764706 ,  0.42352942]]])
    """

    CFA = np.asarray(CFA)
    R_m, G_m, B_m = masks_CFA_Bayer(CFA.shape, pattern)

    h_0 = np.array([0, 0.5, 0, 0.5, 0])
    h_1 = np.array([-0.25, 0, 0.5, 0, -0.25])

    R = CFA * R_m
    G = CFA * G_m
    B = CFA * B_m

    G_H = np.where(G_m == 0, _cnv_h(CFA, h_0) + _cnv_h(CFA, h_1), G)
    G_V = np.where(G_m == 0, _cnv_v(CFA, h_0) + _cnv_v(CFA, h_1), G)

    C_H = np.where(R_m == 1, R - G_H, 0)
    C_H = np.where(B_m == 1, B - G_H, C_H)

    C_V = np.where(R_m == 1, R - G_V, 0)
    C_V = np.where(B_m == 1, B - G_V, C_V)

    D_H = np.abs(C_H -
                 np.pad(C_H, ((0, 0), (0, 2)), mode=str('reflect'))[:, 2:])
    D_V = np.abs(C_V -
                 np.pad(C_V, ((0, 2), (0, 0)), mode=str('reflect'))[2:, :])

    k = np.array(
        [[0, 0, 1, 0, 1],
         [0, 0, 0, 1, 0],
         [0, 0, 3, 0, 3],
         [0, 0, 0, 1, 0],
         [0, 0, 1, 0, 1]])

    d_H = convolve(D_H, k, mode='constant')
    d_V = convolve(D_V, np.transpose(k), mode='constant')

    mask = d_V >= d_H
    G = np.where(mask, G_H, G_V)
    M = np.where(mask, 1, 0)

    # Red rows.
    R_r = np.transpose(np.any(R_m == 1, axis=1)[np.newaxis]) * np.ones(R.shape)
    # Blue rows.
    B_r = np.transpose(np.any(B_m == 1, axis=1)[np.newaxis]) * np.ones(B.shape)

    k_b = np.array([0.5, 0, 0.5])

    R = np.where(np.logical_and(G_m == 1, R_r == 1),
                 G + _cnv_h(R, k_b) - _cnv_h(G, k_b),
                 R)

    R = np.where(np.logical_and(G_m == 1, B_r == 1) == 1,
                 G + _cnv_v(R, k_b) - _cnv_v(G, k_b),
                 R)

    B = np.where(np.logical_and(G_m == 1, B_r == 1),
                 G + _cnv_h(B, k_b) - _cnv_h(G, k_b),
                 B)

    B = np.where(np.logical_and(G_m == 1, R_r == 1) == 1,
                 G + _cnv_v(B, k_b) - _cnv_v(G, k_b),
                 B)

    R = np.where(np.logical_and(B_r == 1, B_m == 1),
                 np.where(M == 1,
                          B + _cnv_h(R, k_b) - _cnv_h(B, k_b),
                          B + _cnv_v(R, k_b) - _cnv_v(B, k_b)),
                 R)

    B = np.where(np.logical_and(R_r == 1, R_m == 1),
                 np.where(M == 1,
                          R + _cnv_h(B, k_b) - _cnv_h(R, k_b),
                          R + _cnv_v(B, k_b) - _cnv_v(R, k_b)),
                 B)

    RGB = tstack((R, G, B))

    if refining_step:
        RGB = refining_step_Menon2007(RGB, tstack((R_m, G_m, B_m)), M)

    return RGB
 def range(self):
     if len(self._signals) != 0:
         return tstack([signal.range for signal in self._signals.values()])
 def __getitem__(self, x):
     return tstack([signal[x] for signal in self._signals.values()])
Esempio n. 25
0
def image_stack_to_radiance_image(
        image_stack,
        weighting_function=weighting_function_Debevec1997,
        weighting_average=False,
        camera_response_functions=None):
    """
    Generates a HDRI / radiance image from given image stack.

    Parameters
    ----------
    image_stack : ImageStack
        Stack of single channel or multi-channel floating point images. The
        stack is assumed to be representing linear values except if
        ``camera_response_functions`` argument is provided.
    weighting_function : callable, optional
        Weighting function :math:`w`.
    weighting_average : bool, optional
         Enables weighting function :math:`w` computation on channels average
         instead of on a per channel basis.
    camera_response_functions : array_like, optional
        Camera response functions :math:`g(z)` of the imaging system / camera
        if the stack is representing non linear values.

    Returns
    -------
    ndarray
        Radiance image.
    """

    image_c = None
    weight_c = None
    for image in image_stack:
        if image_c is None:
            image_c = np.zeros(image.data.shape)
            weight_c = np.zeros(image.data.shape)

        L = average_luminance(
            image.metadata.f_number,
            image.metadata.exposure_time,
            image.metadata.iso)

        if weighting_average and image.data.ndim == 3:
            weight = weighting_function(np.average(image.data, axis=-1))
            weight = np.rollaxis(weight[np.newaxis], 0, 3)
        else:
            weight = weighting_function(image.data)

        image_data = image.data
        if camera_response_functions is not None:
            samples = np.linspace(0, 1, camera_response_functions.shape[0])

            R, G, B = tsplit(image.data)
            R = np.interp(R, samples, camera_response_functions[..., 0])
            G = np.interp(G, samples, camera_response_functions[..., 1])
            B = np.interp(B, samples, camera_response_functions[..., 2])
            image_data = tstack((R, G, B))

        image_c += weight * image_data / L
        weight_c += weight

    if image_c is not None:
        image_c /= weight_c
        image_c[np.isnan(image_c)] = 0

    return image_c
def demosaicing_CFA_Bayer_Malvar2004(CFA, pattern='RGGB'):
    """
    Returns the demosaiced *RGB* colourspace array from given *Bayer* CFA using
    Malvar (2004) demosaicing algorithm.

    Parameters
    ----------
    CFA : array_like
        *Bayer* CFA.
    pattern : unicode, optional
        **{'RGGB', 'BGGR', 'GRBG', 'GBRG'}**,
        Arrangement of the colour filters on the pixel array.

    Returns
    -------
    ndarray
        *RGB* colourspace array.

    Examples
    --------
    >>> CFA = np.array([[0.30980393, 0.36078432, 0.30588236, 0.3764706],
    ...                 [0.35686275, 0.39607844, 0.36078432, 0.40000001]])
    >>> demosaicing_CFA_Bayer_Malvar2004(CFA)
    array([[[ 0.30980393,  0.31666668,  0.32941177],
            [ 0.33039216,  0.36078432,  0.38112746],
            [ 0.30588236,  0.32794118,  0.34877452],
            [ 0.36274511,  0.3764706 ,  0.38480393]],
    <BLANKLINE>
           [[ 0.34828432,  0.35686275,  0.36568628],
            [ 0.35318628,  0.38186275,  0.39607844],
            [ 0.3379902 ,  0.36078432,  0.3754902 ],
            [ 0.37769609,  0.39558825,  0.40000001]]])
    >>> CFA = np.array([[0.3764706, 0.360784320, 0.40784314, 0.3764706],
    ...                 [0.35686275, 0.30980393, 0.36078432, 0.29803923]])
    >>> demosaicing_CFA_Bayer_Malvar2004(CFA, 'BGGR')
    array([[[ 0.35539217,  0.37058825,  0.3764706 ],
            [ 0.34264707,  0.36078432,  0.37450981],
            [ 0.36568628,  0.39607844,  0.40784314],
            [ 0.36568629,  0.3764706 ,  0.3882353 ]],
    <BLANKLINE>
           [[ 0.34411765,  0.35686275,  0.36200981],
            [ 0.30980393,  0.32990197,  0.34975491],
            [ 0.33039216,  0.36078432,  0.38063726],
            [ 0.29803923,  0.30441178,  0.31740197]]])
    """

    CFA = np.asarray(CFA)
    R_m, G_m, B_m = masks_CFA_Bayer(CFA.shape, pattern)

    GR_GB = np.asarray(
        [[0, 0, -1, 0, 0],
         [0, 0, 2, 0, 0],
         [-1, 2, 4, 2, -1],
         [0, 0, 2, 0, 0],
         [0, 0, -1, 0, 0]]) / 8

    Rg_RB_Bg_BR = np.asarray(
        [[0, 0, 0.5, 0, 0],
         [0, -1, 0, -1, 0],
         [-1, 4, 5, 4, - 1],
         [0, -1, 0, -1, 0],
         [0, 0, 0.5, 0, 0]]) / 8

    Rg_BR_Bg_RB = np.transpose(Rg_RB_Bg_BR)

    Rb_BB_Br_RR = np.asarray(
        [[0, 0, -1.5, 0, 0],
         [0, 2, 0, 2, 0],
         [-1.5, 0, 6, 0, -1.5],
         [0, 2, 0, 2, 0],
         [0, 0, -1.5, 0, 0]]) / 8

    R = CFA * R_m
    G = CFA * G_m
    B = CFA * B_m

    G = np.where(np.logical_or(R_m == 1, B_m == 1), convolve(CFA, GR_GB), G)

    RBg_RBBR = convolve(CFA, Rg_RB_Bg_BR)
    RBg_BRRB = convolve(CFA, Rg_BR_Bg_RB)
    RBgr_BBRR = convolve(CFA, Rb_BB_Br_RR)

    # Red rows.
    R_r = np.transpose(np.any(R_m == 1, axis=1)[np.newaxis]) * np.ones(R.shape)
    # Red columns.
    R_c = np.any(R_m == 1, axis=0)[np.newaxis] * np.ones(R.shape)
    # Blue rows.
    B_r = np.transpose(np.any(B_m == 1, axis=1)[np.newaxis]) * np.ones(B.shape)
    # Blue columns
    B_c = np.any(B_m == 1, axis=0)[np.newaxis] * np.ones(B.shape)

    R = np.where(np.logical_and(R_r == 1, B_c == 1), RBg_RBBR, R)
    R = np.where(np.logical_and(B_r == 1, R_c == 1), RBg_BRRB, R)

    B = np.where(np.logical_and(B_r == 1, R_c == 1), RBg_RBBR, B)
    B = np.where(np.logical_and(R_r == 1, B_c == 1), RBg_BRRB, B)

    R = np.where(np.logical_and(B_r == 1, B_c == 1), RBgr_BBRR, R)
    B = np.where(np.logical_and(R_r == 1, R_c == 1), RBgr_BBRR, B)

    return tstack((R, G, B))
Esempio n. 27
0
def refining_step_Menon2007(RGB, RGB_m, M):
    """
    Performs the refining step on given *RGB* colourspace array.

    Parameters
    ----------
    RGB : array_like
        *RGB* colourspace array.
    RGB_m : array_like
        *Bayer* CFA red, green and blue masks.
    M : array_like
        Estimation for the best directional reconstruction.

    Returns
    -------
    ndarray
        Refined *RGB* colourspace array.

    Examples
    --------
    >>> RGB = np.array([[[0.30588236, 0.35686275, 0.3764706],
    ...                  [0.30980393, 0.36078432, 0.39411766],
    ...                  [0.29607844, 0.36078432, 0.40784314],
    ...                  [0.29803923, 0.37647060, 0.42352942]],
    ...                 [[0.30588236, 0.35686275, 0.3764706],
    ...                  [0.30980393, 0.36078432, 0.39411766],
    ...                  [0.29607844, 0.36078432, 0.40784314],
    ...                  [0.29803923, 0.37647060, 0.42352942]]])
    >>> RGB_m = np.array([[[0, 0, 1],
    ...                    [0, 1, 0],
    ...                    [0, 0, 1],
    ...                    [0, 1, 0]],
    ...                   [[0, 1, 0],
    ...                    [1, 0, 0],
    ...                    [0, 1, 0],
    ...                    [1, 0, 0]]])
    >>> M = np.array([[0, 1, 0, 1],
    ...               [1, 0, 1, 0]])
    >>> refining_step_Menon2007(RGB, RGB_m, M)
    array([[[ 0.30588236,  0.35686275,  0.3764706 ],
            [ 0.30980393,  0.36078432,  0.39411765],
            [ 0.29607844,  0.36078432,  0.40784314],
            [ 0.29803923,  0.3764706 ,  0.42352942]],
    <BLANKLINE>
           [[ 0.30588236,  0.35686275,  0.3764706 ],
            [ 0.30980393,  0.36078432,  0.39411766],
            [ 0.29607844,  0.36078432,  0.40784314],
            [ 0.29803923,  0.3764706 ,  0.42352942]]])
    """

    R, G, B = tsplit(RGB)
    R_m, G_m, B_m = tsplit(RGB_m)
    M = np.asarray(M)

    # Updating of the green component.
    R_G = R - G
    B_G = B - G

    FIR = np.ones(3) / 3

    B_G_m = np.where(B_m == 1,
                     np.where(M == 1, _cnv_h(B_G, FIR), _cnv_v(B_G, FIR)), 0)
    R_G_m = np.where(R_m == 1,
                     np.where(M == 1, _cnv_h(R_G, FIR), _cnv_v(R_G, FIR)), 0)

    G = np.where(R_m == 1, R - R_G_m, G)
    G = np.where(B_m == 1, B - B_G_m, G)

    # Updating of the red and blue components in the green locations.
    # Red rows.
    R_r = np.transpose(np.any(R_m == 1, axis=1)[np.newaxis]) * np.ones(R.shape)
    # Red columns.
    R_c = np.any(R_m == 1, axis=0)[np.newaxis] * np.ones(R.shape)
    # Blue rows.
    B_r = np.transpose(np.any(B_m == 1, axis=1)[np.newaxis]) * np.ones(B.shape)
    # Blue columns
    B_c = np.any(B_m == 1, axis=0)[np.newaxis] * np.ones(B.shape)

    R_G = R - G
    B_G = B - G

    k_b = np.array([0.5, 0, 0.5])

    R_G_m = np.where(np.logical_and(G_m == 1, B_r == 1), _cnv_v(R_G, k_b),
                     R_G_m)
    R = np.where(np.logical_and(G_m == 1, B_r == 1), G + R_G_m, R)
    R_G_m = np.where(np.logical_and(G_m == 1, B_c == 1), _cnv_h(R_G, k_b),
                     R_G_m)
    R = np.where(np.logical_and(G_m == 1, B_c == 1), G + R_G_m, R)

    B_G_m = np.where(np.logical_and(G_m == 1, R_r == 1), _cnv_v(B_G, k_b),
                     B_G_m)
    B = np.where(np.logical_and(G_m == 1, R_r == 1), G + B_G_m, B)
    B_G_m = np.where(np.logical_and(G_m == 1, R_c == 1), _cnv_h(B_G, k_b),
                     B_G_m)
    B = np.where(np.logical_and(G_m == 1, R_c == 1), G + B_G_m, B)

    # Updating of the red (blue) component in the blue (red) locations.
    R_B = R - B
    R_B_m = np.where(B_m == 1,
                     np.where(M == 1, _cnv_h(R_B, FIR), _cnv_v(R_B, FIR)), 0)
    R = np.where(B_m == 1, B + R_B_m, R)

    R_B_m = np.where(R_m == 1,
                     np.where(M == 1, _cnv_h(R_B, FIR), _cnv_v(R_B, FIR)), 0)
    B = np.where(R_m == 1, R - R_B_m, B)

    return tstack((R, G, B))
 def __str__(self):
     try:
         return str(tstack((self.domain, self.range)))
     except TypeError:
         return super(Signal, self).__str__()
Esempio n. 29
0
def demosaicing_CFA_Bayer_Malvar2004(CFA, pattern='RGGB'):
    """
    Returns the demosaiced *RGB* colourspace array from given *Bayer* CFA using
    Malvar (2004) demosaicing algorithm.

    Parameters
    ----------
    CFA : array_like
        *Bayer* CFA.
    pattern : unicode, optional
        **{'RGGB', 'BGGR', 'GRBG', 'GBRG'}**,
        Arrangement of the colour filters on the pixel array.

    Returns
    -------
    ndarray
        *RGB* colourspace array.

    Examples
    --------
    >>> CFA = np.array([[0.30980393, 0.36078432, 0.30588236, 0.3764706],
    ...                 [0.35686275, 0.39607844, 0.36078432, 0.40000001]])
    >>> demosaicing_CFA_Bayer_Malvar2004(CFA)
    array([[[ 0.30980393,  0.31666668,  0.32941177],
            [ 0.33039216,  0.36078432,  0.38112746],
            [ 0.30588236,  0.32794118,  0.34877452],
            [ 0.36274511,  0.3764706 ,  0.38480393]],
    <BLANKLINE>
           [[ 0.34828432,  0.35686275,  0.36568628],
            [ 0.35318628,  0.38186275,  0.39607844],
            [ 0.3379902 ,  0.36078432,  0.3754902 ],
            [ 0.37769609,  0.39558825,  0.40000001]]])
    >>> CFA = np.array([[0.3764706, 0.360784320, 0.40784314, 0.3764706],
    ...                 [0.35686275, 0.30980393, 0.36078432, 0.29803923]])
    >>> demosaicing_CFA_Bayer_Malvar2004(CFA, 'BGGR')
    array([[[ 0.35539217,  0.37058825,  0.3764706 ],
            [ 0.34264707,  0.36078432,  0.37450981],
            [ 0.36568628,  0.39607844,  0.40784314],
            [ 0.36568629,  0.3764706 ,  0.3882353 ]],
    <BLANKLINE>
           [[ 0.34411765,  0.35686275,  0.36200981],
            [ 0.30980393,  0.32990197,  0.34975491],
            [ 0.33039216,  0.36078432,  0.38063726],
            [ 0.29803923,  0.30441178,  0.31740197]]])
    """

    CFA = np.asarray(CFA)
    R_m, G_m, B_m = masks_CFA_Bayer(CFA.shape, pattern)

    GR_GB = np.asarray([[0, 0, -1, 0, 0], [0, 0, 2, 0, 0], [-1, 2, 4, 2, -1],
                        [0, 0, 2, 0, 0], [0, 0, -1, 0, 0]]) / 8

    Rg_RB_Bg_BR = np.asarray([[0, 0, 0.5, 0, 0], [0, -1, 0, -1, 0],
                              [-1, 4, 5, 4, -1], [0, -1, 0, -1, 0],
                              [0, 0, 0.5, 0, 0]]) / 8

    Rg_BR_Bg_RB = np.transpose(Rg_RB_Bg_BR)

    Rb_BB_Br_RR = np.asarray([[0, 0, -1.5, 0, 0], [0, 2, 0, 2, 0],
                              [-1.5, 0, 6, 0, -1.5], [0, 2, 0, 2, 0],
                              [0, 0, -1.5, 0, 0]]) / 8

    R = CFA * R_m
    G = CFA * G_m
    B = CFA * B_m

    G = np.where(np.logical_or(R_m == 1, B_m == 1), convolve(CFA, GR_GB), G)

    RBg_RBBR = convolve(CFA, Rg_RB_Bg_BR)
    RBg_BRRB = convolve(CFA, Rg_BR_Bg_RB)
    RBgr_BBRR = convolve(CFA, Rb_BB_Br_RR)

    # Red rows.
    R_r = np.transpose(np.any(R_m == 1, axis=1)[np.newaxis]) * np.ones(R.shape)
    # Red columns.
    R_c = np.any(R_m == 1, axis=0)[np.newaxis] * np.ones(R.shape)
    # Blue rows.
    B_r = np.transpose(np.any(B_m == 1, axis=1)[np.newaxis]) * np.ones(B.shape)
    # Blue columns
    B_c = np.any(B_m == 1, axis=0)[np.newaxis] * np.ones(B.shape)

    R = np.where(np.logical_and(R_r == 1, B_c == 1), RBg_RBBR, R)
    R = np.where(np.logical_and(B_r == 1, R_c == 1), RBg_BRRB, R)

    B = np.where(np.logical_and(B_r == 1, R_c == 1), RBg_RBBR, B)
    B = np.where(np.logical_and(R_r == 1, B_c == 1), RBg_BRRB, B)

    R = np.where(np.logical_and(B_r == 1, B_c == 1), RBgr_BBRR, R)
    B = np.where(np.logical_and(R_r == 1, R_c == 1), RBgr_BBRR, B)

    return tstack((R, G, B))
def demosaicing_CFA_Bayer_bilinear(CFA, pattern='RGGB'):
    """
    Returns the demosaiced *RGB* colourspace array from given *Bayer* CFA using
    bilinear interpolation.

    Parameters
    ----------
    CFA : array_like
        *Bayer* CFA.
    pattern : unicode, optional
        **{'RGGB', 'BGGR', 'GRBG', 'GBRG'}**,
        Arrangement of the colour filters on the pixel array.

    Returns
    -------
    ndarray
        *RGB* colourspace array.

    Examples
    --------
    >>> CFA = np.array([[0.30980393, 0.36078432, 0.30588236, 0.3764706],
    ...                 [0.35686275, 0.39607844, 0.36078432, 0.40000001]])
    >>> demosaicing_CFA_Bayer_bilinear(CFA)
    array([[[ 0.69705884,  0.17941177,  0.09901961],
            [ 0.46176472,  0.4509804 ,  0.19803922],
            [ 0.45882354,  0.27450981,  0.19901961],
            [ 0.22941177,  0.5647059 ,  0.30000001]],
    <BLANKLINE>
           [[ 0.23235295,  0.53529412,  0.29705883],
            [ 0.15392157,  0.26960785,  0.59411766],
            [ 0.15294118,  0.4509804 ,  0.59705884],
            [ 0.07647059,  0.18431373,  0.90000002]]])
    >>> CFA = np.array([[0.3764706, 0.360784320, 0.40784314, 0.3764706],
    ...                 [0.35686275, 0.30980393, 0.36078432, 0.29803923]])
    >>> demosaicing_CFA_Bayer_bilinear(CFA, 'BGGR')
    array([[[ 0.07745098,  0.17941177,  0.84705885],
            [ 0.15490197,  0.4509804 ,  0.5882353 ],
            [ 0.15196079,  0.27450981,  0.61176471],
            [ 0.22352942,  0.5647059 ,  0.30588235]],
    <BLANKLINE>
           [[ 0.23235295,  0.53529412,  0.28235295],
            [ 0.4647059 ,  0.26960785,  0.19607843],
            [ 0.45588237,  0.4509804 ,  0.20392157],
            [ 0.67058827,  0.18431373,  0.10196078]]])
    """

    CFA = np.asarray(CFA)
    R_m, G_m, B_m = masks_CFA_Bayer(CFA.shape, pattern)

    H_G = np.asarray(
        [[0, 1, 0],
         [1, 4, 1],
         [0, 1, 0]]) / 4

    H_RB = np.asarray(
        [[1, 2, 1],
         [2, 4, 2],
         [1, 2, 1]]) / 4

    R = convolve(CFA * R_m, H_RB)
    G = convolve(CFA * G_m, H_G)
    B = convolve(CFA * B_m, H_RB)

    return tstack((R, G, B))