# -*- coding: utf-8 -*-
"""
Malvar (2004) Bayer CFA Demosaicing
===================================
*Bayer* CFA (Colour Filter Array) *Malvar (2004)* demosaicing.
References
----------
- :cite:`Malvar2004a` : Malvar, H. S., He, L.-W., Cutler, R., & Way, O. M.
(2004). High-Quality Linear Interpolation for Demosaicing of
Bayer-Patterned Color Images. In International Conference of Acoustic,
Speech and Signal Processing (pp. 5-8). Institute of Electrical and
Electronics Engineers, Inc. Retrieved from
http://research.microsoft.com/apps/pubs/default.aspx?id=102068
"""
from __future__ import division, unicode_literals
import numpy as np
from scipy.ndimage.filters import convolve
from colour.utilities import tstack
from colour_demosaicing.bayer import masks_CFA_Bayer
__author__ = 'Colour Developers'
__copyright__ = 'Copyright (C) 2015-2018 - Colour Developers'
__license__ = 'New BSD License - http://opensource.org/licenses/BSD-3-Clause'
__maintainer__ = 'Colour Developers'
__email__ = 'colour-science@googlegroups.com'
__status__ = 'Production'
__all__ = ['demosaicing_CFA_Bayer_Malvar2004']
[docs]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.
Notes
-----
- The definition output is not clipped in range [0, 1] : this allows for
direct HDRI / radiance image generation on *Bayer* CFA data and post
demosaicing of the high dynamic range data as showcased in this
`Jupyter Notebook <https://github.com/colour-science/colour-hdri/\
blob/develop/colour_hdri/examples/\
examples_merge_from_raw_files_with_post_demosaicing.ipynb>`_.
References
----------
- :cite:`Malvar2004a`
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 # yapf: disable
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 # yapf: disable
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 # yapf: disable
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))