1"""Functions for converting between color spaces. 2 3The "central" color space in this module is RGB, more specifically the linear 4sRGB color space using D65 as a white-point [1]_. This represents a 5standard monitor (w/o gamma correction). For a good FAQ on color spaces see 6[2]_. 7 8The API consists of functions to convert to and from RGB as defined above, as 9well as a generic function to convert to and from any supported color space 10(which is done through RGB in most cases). 11 12 13Supported color spaces 14---------------------- 15* RGB : Red Green Blue. 16 Here the sRGB standard [1]_. 17* HSV : Hue, Saturation, Value. 18 Uniquely defined when related to sRGB [3]_. 19* RGB CIE : Red Green Blue. 20 The original RGB CIE standard from 1931 [4]_. Primary colors are 700 nm 21 (red), 546.1 nm (blue) and 435.8 nm (green). 22* XYZ CIE : XYZ 23 Derived from the RGB CIE color space. Chosen such that 24 ``x == y == z == 1/3`` at the whitepoint, and all color matching 25 functions are greater than zero everywhere. 26* LAB CIE : Lightness, a, b 27 Colorspace derived from XYZ CIE that is intended to be more 28 perceptually uniform 29* LUV CIE : Lightness, u, v 30 Colorspace derived from XYZ CIE that is intended to be more 31 perceptually uniform 32* LCH CIE : Lightness, Chroma, Hue 33 Defined in terms of LAB CIE. C and H are the polar representation of 34 a and b. The polar angle C is defined to be on ``(0, 2*pi)`` 35 36:author: Nicolas Pinto (rgb2hsv) 37:author: Ralf Gommers (hsv2rgb) 38:author: Travis Oliphant (XYZ and RGB CIE functions) 39:author: Matt Terry (lab2lch) 40:author: Alex Izvorski (yuv2rgb, rgb2yuv and related) 41 42:license: modified BSD 43 44References 45---------- 46.. [1] Official specification of sRGB, IEC 61966-2-1:1999. 47.. [2] http://www.poynton.com/ColorFAQ.html 48.. [3] https://en.wikipedia.org/wiki/HSL_and_HSV 49.. [4] https://en.wikipedia.org/wiki/CIE_1931_color_space 50""" 51 52from warnings import warn 53 54import numpy as np 55from scipy import linalg 56 57 58from .._shared.utils import (_supported_float_type, channel_as_last_axis, 59 identity, reshape_nd, slice_at_axis) 60from ..util import dtype, dtype_limits 61 62 63def convert_colorspace(arr, fromspace, tospace, *, channel_axis=-1): 64 """Convert an image array to a new color space. 65 66 Valid color spaces are: 67 'RGB', 'HSV', 'RGB CIE', 'XYZ', 'YUV', 'YIQ', 'YPbPr', 'YCbCr', 'YDbDr' 68 69 Parameters 70 ---------- 71 arr : (..., 3, ...) array_like 72 The image to convert. By default, the final dimension denotes 73 channels. 74 fromspace : str 75 The color space to convert from. Can be specified in lower case. 76 tospace : str 77 The color space to convert to. Can be specified in lower case. 78 channel_axis : int, optional 79 This parameter indicates which axis of the array corresponds to 80 channels. 81 82 .. versionadded:: 0.19 83 ``channel_axis`` was added in 0.19. 84 85 Returns 86 ------- 87 out : (..., 3, ...) ndarray 88 The converted image. Same dimensions as input. 89 90 Raises 91 ------ 92 ValueError 93 If fromspace is not a valid color space 94 ValueError 95 If tospace is not a valid color space 96 97 Notes 98 ----- 99 Conversion is performed through the "central" RGB color space, 100 i.e. conversion from XYZ to HSV is implemented as ``XYZ -> RGB -> HSV`` 101 instead of directly. 102 103 Examples 104 -------- 105 >>> from skimage import data 106 >>> img = data.astronaut() 107 >>> img_hsv = convert_colorspace(img, 'RGB', 'HSV') 108 """ 109 fromdict = {'rgb': identity, 'hsv': hsv2rgb, 'rgb cie': rgbcie2rgb, 110 'xyz': xyz2rgb, 'yuv': yuv2rgb, 'yiq': yiq2rgb, 111 'ypbpr': ypbpr2rgb, 'ycbcr': ycbcr2rgb, 'ydbdr': ydbdr2rgb} 112 todict = {'rgb': identity, 'hsv': rgb2hsv, 'rgb cie': rgb2rgbcie, 113 'xyz': rgb2xyz, 'yuv': rgb2yuv, 'yiq': rgb2yiq, 114 'ypbpr': rgb2ypbpr, 'ycbcr': rgb2ycbcr, 'ydbdr': rgb2ydbdr} 115 116 fromspace = fromspace.lower() 117 tospace = tospace.lower() 118 if fromspace not in fromdict: 119 msg = f'`fromspace` has to be one of {fromdict.keys()}' 120 raise ValueError(msg) 121 if tospace not in todict: 122 msg = f'`tospace` has to be one of {todict.keys()}' 123 raise ValueError(msg) 124 125 return todict[tospace]( 126 fromdict[fromspace](arr, channel_axis=channel_axis), 127 channel_axis=channel_axis 128 ) 129 130 131def _prepare_colorarray(arr, force_copy=False, *, channel_axis=-1): 132 """Check the shape of the array and convert it to 133 floating point representation. 134 """ 135 arr = np.asanyarray(arr) 136 137 if arr.shape[channel_axis] != 3: 138 msg = (f'the input array must have size 3 along `channel_axis`, ' 139 f'got {arr.shape}') 140 raise ValueError(msg) 141 142 float_dtype = _supported_float_type(arr.dtype) 143 if float_dtype == np.float32: 144 _func = dtype.img_as_float32 145 else: 146 _func = dtype.img_as_float64 147 return _func(arr, force_copy=force_copy) 148 149 150def _validate_channel_axis(channel_axis, ndim): 151 if not isinstance(channel_axis, int): 152 raise TypeError("channel_axis must be an integer") 153 if channel_axis < -ndim or channel_axis >= ndim: 154 raise np.AxisError("channel_axis exceeds array dimensions") 155 156 157def rgba2rgb(rgba, background=(1, 1, 1), *, channel_axis=-1): 158 """RGBA to RGB conversion using alpha blending [1]_. 159 160 Parameters 161 ---------- 162 rgba : (..., 4, ...) array_like 163 The image in RGBA format. By default, the final dimension denotes 164 channels. 165 background : array_like 166 The color of the background to blend the image with (3 floats 167 between 0 to 1 - the RGB value of the background). 168 channel_axis : int, optional 169 This parameter indicates which axis of the array corresponds to 170 channels. 171 172 .. versionadded:: 0.19 173 ``channel_axis`` was added in 0.19. 174 175 Returns 176 ------- 177 out : (..., 3, ...) ndarray 178 The image in RGB format. Same dimensions as input. 179 180 Raises 181 ------ 182 ValueError 183 If `rgba` is not at least 2D with shape (..., 4, ...). 184 185 References 186 ---------- 187 .. [1] https://en.wikipedia.org/wiki/Alpha_compositing#Alpha_blending 188 189 Examples 190 -------- 191 >>> from skimage import color 192 >>> from skimage import data 193 >>> img_rgba = data.logo() 194 >>> img_rgb = color.rgba2rgb(img_rgba) 195 """ 196 arr = np.asanyarray(rgba) 197 _validate_channel_axis(channel_axis, arr.ndim) 198 channel_axis = channel_axis % arr.ndim 199 200 if arr.shape[channel_axis] != 4: 201 msg = (f'the input array must have size 4 along `channel_axis`, ' 202 f'got {arr.shape}') 203 raise ValueError(msg) 204 205 float_dtype = _supported_float_type(arr.dtype) 206 if float_dtype == np.float32: 207 arr = dtype.img_as_float32(arr) 208 else: 209 arr = dtype.img_as_float64(arr) 210 211 background = np.ravel(background).astype(arr.dtype) 212 if len(background) != 3: 213 raise ValueError('background must be an array-like containing 3 RGB ' 214 f'values. Got {len(background)} items') 215 if np.any(background < 0) or np.any(background > 1): 216 raise ValueError('background RGB values must be floats between ' 217 '0 and 1.') 218 # reshape background for broadcasting along non-channel axes 219 background = reshape_nd(background, arr.ndim, channel_axis) 220 221 alpha = arr[slice_at_axis(slice(3, 4), axis=channel_axis)] 222 channels = arr[slice_at_axis(slice(3), axis=channel_axis)] 223 out = np.clip((1 - alpha) * background + alpha * channels, 224 a_min=0, a_max=1) 225 return out 226 227 228@channel_as_last_axis() 229def rgb2hsv(rgb, *, channel_axis=-1): 230 """RGB to HSV color space conversion. 231 232 Parameters 233 ---------- 234 rgb : (..., 3, ...) array_like 235 The image in RGB format. By default, the final dimension denotes 236 channels. 237 channel_axis : int, optional 238 This parameter indicates which axis of the array corresponds to 239 channels. 240 241 .. versionadded:: 0.19 242 ``channel_axis`` was added in 0.19. 243 244 Returns 245 ------- 246 out : (..., 3, ...) ndarray 247 The image in HSV format. Same dimensions as input. 248 249 Raises 250 ------ 251 ValueError 252 If `rgb` is not at least 2-D with shape (..., 3, ...). 253 254 Notes 255 ----- 256 Conversion between RGB and HSV color spaces results in some loss of 257 precision, due to integer arithmetic and rounding [1]_. 258 259 References 260 ---------- 261 .. [1] https://en.wikipedia.org/wiki/HSL_and_HSV 262 263 Examples 264 -------- 265 >>> from skimage import color 266 >>> from skimage import data 267 >>> img = data.astronaut() 268 >>> img_hsv = color.rgb2hsv(img) 269 """ 270 input_is_one_pixel = rgb.ndim == 1 271 if input_is_one_pixel: 272 rgb = rgb[np.newaxis, ...] 273 274 arr = _prepare_colorarray(rgb, channel_axis=-1) 275 out = np.empty_like(arr) 276 277 # -- V channel 278 out_v = arr.max(-1) 279 280 # -- S channel 281 delta = arr.ptp(-1) 282 # Ignore warning for zero divided by zero 283 old_settings = np.seterr(invalid='ignore') 284 out_s = delta / out_v 285 out_s[delta == 0.] = 0. 286 287 # -- H channel 288 # red is max 289 idx = (arr[..., 0] == out_v) 290 out[idx, 0] = (arr[idx, 1] - arr[idx, 2]) / delta[idx] 291 292 # green is max 293 idx = (arr[..., 1] == out_v) 294 out[idx, 0] = 2. + (arr[idx, 2] - arr[idx, 0]) / delta[idx] 295 296 # blue is max 297 idx = (arr[..., 2] == out_v) 298 out[idx, 0] = 4. + (arr[idx, 0] - arr[idx, 1]) / delta[idx] 299 out_h = (out[..., 0] / 6.) % 1. 300 out_h[delta == 0.] = 0. 301 302 np.seterr(**old_settings) 303 304 # -- output 305 out[..., 0] = out_h 306 out[..., 1] = out_s 307 out[..., 2] = out_v 308 309 # # remove NaN 310 out[np.isnan(out)] = 0 311 312 if input_is_one_pixel: 313 out = np.squeeze(out, axis=0) 314 315 return out 316 317 318@channel_as_last_axis() 319def hsv2rgb(hsv, *, channel_axis=-1): 320 """HSV to RGB color space conversion. 321 322 Parameters 323 ---------- 324 hsv : (..., 3, ...) array_like 325 The image in HSV format. By default, the final dimension denotes 326 channels. 327 channel_axis : int, optional 328 This parameter indicates which axis of the array corresponds to 329 channels. 330 331 .. versionadded:: 0.19 332 ``channel_axis`` was added in 0.19. 333 334 Returns 335 ------- 336 out : (..., 3, ...) ndarray 337 The image in RGB format. Same dimensions as input. 338 339 Raises 340 ------ 341 ValueError 342 If `hsv` is not at least 2-D with shape (..., 3, ...). 343 344 Notes 345 ----- 346 Conversion between RGB and HSV color spaces results in some loss of 347 precision, due to integer arithmetic and rounding [1]_. 348 349 References 350 ---------- 351 .. [1] https://en.wikipedia.org/wiki/HSL_and_HSV 352 353 Examples 354 -------- 355 >>> from skimage import data 356 >>> img = data.astronaut() 357 >>> img_hsv = rgb2hsv(img) 358 >>> img_rgb = hsv2rgb(img_hsv) 359 """ 360 arr = _prepare_colorarray(hsv, channel_axis=-1) 361 362 hi = np.floor(arr[..., 0] * 6) 363 f = arr[..., 0] * 6 - hi 364 p = arr[..., 2] * (1 - arr[..., 1]) 365 q = arr[..., 2] * (1 - f * arr[..., 1]) 366 t = arr[..., 2] * (1 - (1 - f) * arr[..., 1]) 367 v = arr[..., 2] 368 369 hi = np.stack([hi, hi, hi], axis=-1).astype(np.uint8) % 6 370 out = np.choose( 371 hi, np.stack([np.stack((v, t, p), axis=-1), 372 np.stack((q, v, p), axis=-1), 373 np.stack((p, v, t), axis=-1), 374 np.stack((p, q, v), axis=-1), 375 np.stack((t, p, v), axis=-1), 376 np.stack((v, p, q), axis=-1)])) 377 378 return out 379 380 381# --------------------------------------------------------------- 382# Primaries for the coordinate systems 383# --------------------------------------------------------------- 384cie_primaries = np.array([700, 546.1, 435.8]) 385sb_primaries = np.array([1. / 155, 1. / 190, 1. / 225]) * 1e5 386 387# --------------------------------------------------------------- 388# Matrices that define conversion between different color spaces 389# --------------------------------------------------------------- 390 391# From sRGB specification 392xyz_from_rgb = np.array([[0.412453, 0.357580, 0.180423], 393 [0.212671, 0.715160, 0.072169], 394 [0.019334, 0.119193, 0.950227]]) 395 396rgb_from_xyz = linalg.inv(xyz_from_rgb) 397 398# From https://en.wikipedia.org/wiki/CIE_1931_color_space 399# Note: Travis's code did not have the divide by 0.17697 400xyz_from_rgbcie = np.array([[0.49, 0.31, 0.20], 401 [0.17697, 0.81240, 0.01063], 402 [0.00, 0.01, 0.99]]) / 0.17697 403 404rgbcie_from_xyz = linalg.inv(xyz_from_rgbcie) 405 406# construct matrices to and from rgb: 407rgbcie_from_rgb = rgbcie_from_xyz @ xyz_from_rgb 408rgb_from_rgbcie = rgb_from_xyz @ xyz_from_rgbcie 409 410 411gray_from_rgb = np.array([[0.2125, 0.7154, 0.0721], 412 [0, 0, 0], 413 [0, 0, 0]]) 414 415yuv_from_rgb = np.array([[ 0.299 , 0.587 , 0.114 ], 416 [-0.14714119, -0.28886916, 0.43601035 ], 417 [ 0.61497538, -0.51496512, -0.10001026 ]]) 418 419rgb_from_yuv = linalg.inv(yuv_from_rgb) 420 421yiq_from_rgb = np.array([[0.299 , 0.587 , 0.114 ], 422 [0.59590059, -0.27455667, -0.32134392], 423 [0.21153661, -0.52273617, 0.31119955]]) 424 425rgb_from_yiq = linalg.inv(yiq_from_rgb) 426 427ypbpr_from_rgb = np.array([[ 0.299 , 0.587 , 0.114 ], 428 [-0.168736,-0.331264, 0.5 ], 429 [ 0.5 ,-0.418688,-0.081312]]) 430 431rgb_from_ypbpr = linalg.inv(ypbpr_from_rgb) 432 433ycbcr_from_rgb = np.array([[ 65.481, 128.553, 24.966], 434 [ -37.797, -74.203, 112.0 ], 435 [ 112.0 , -93.786, -18.214]]) 436 437rgb_from_ycbcr = linalg.inv(ycbcr_from_rgb) 438 439ydbdr_from_rgb = np.array([[ 0.299, 0.587, 0.114], 440 [ -0.45 , -0.883, 1.333], 441 [ -1.333, 1.116, 0.217]]) 442 443rgb_from_ydbdr = linalg.inv(ydbdr_from_rgb) 444 445 446# CIE LAB constants for Observer=2A, Illuminant=D65 447# NOTE: this is actually the XYZ values for the illuminant above. 448lab_ref_white = np.array([0.95047, 1., 1.08883]) 449 450# XYZ coordinates of the illuminants, scaled to [0, 1]. For each illuminant I 451# we have: 452# 453# illuminant[I]['2'] corresponds to the XYZ coordinates for the 2 degree 454# field of view. 455# 456# illuminant[I]['10'] corresponds to the XYZ coordinates for the 10 degree 457# field of view. 458# 459# illuminant[I]['R'] corresponds to the XYZ coordinates for R illuminants 460# in grDevices::convertColor 461# 462# The XYZ coordinates are calculated from [1], using the formula: 463# 464# X = x * ( Y / y ) 465# Y = Y 466# Z = ( 1 - x - y ) * ( Y / y ) 467# 468# where Y = 1. The only exception is the illuminant "D65" with aperture angle 469# 2, whose coordinates are copied from 'lab_ref_white' for 470# backward-compatibility reasons. 471# 472# References 473# ---------- 474# .. [1] https://en.wikipedia.org/wiki/Standard_illuminant 475 476illuminants = \ 477 {"A": {'2': (1.098466069456375, 1, 0.3558228003436005), 478 '10': (1.111420406956693, 1, 0.3519978321919493), 479 'R': (1.098466069456375, 1, 0.3558228003436005)}, 480 "B": {'2': (0.9909274480248003, 1, 0.8531327322886154), 481 '10': (0.9917777147717607, 1, 0.8434930535866175), 482 'R': (0.9909274480248003, 1, 0.8531327322886154)}, 483 "C": {'2': (0.980705971659919, 1, 1.1822494939271255), 484 '10': (0.9728569189782166, 1, 1.1614480488951577), 485 'R': (0.980705971659919, 1, 1.1822494939271255)}, 486 "D50": {'2': (0.9642119944211994, 1, 0.8251882845188288), 487 '10': (0.9672062750333777, 1, 0.8142801513128616), 488 'R': (0.9639501491621826, 1, 0.8241280285499208)}, 489 "D55": {'2': (0.956797052643698, 1, 0.9214805860173273), 490 '10': (0.9579665682254781, 1, 0.9092525159847462), 491 'R': (0.9565317453467969, 1, 0.9202554587037198)}, 492 "D65": {'2': (0.95047, 1., 1.08883), # This was: `lab_ref_white` 493 '10': (0.94809667673716, 1, 1.0730513595166162), 494 'R': (0.9532057125493769, 1, 1.0853843816469158)}, 495 "D75": {'2': (0.9497220898840717, 1, 1.226393520724154), 496 '10': (0.9441713925645873, 1, 1.2064272211720228), 497 'R': (0.9497220898840717, 1, 1.226393520724154)}, 498 "E": {'2': (1.0, 1.0, 1.0), 499 '10': (1.0, 1.0, 1.0), 500 'R': (1.0, 1.0, 1.0)}} 501 502 503def get_xyz_coords(illuminant, observer, dtype=float): 504 """Get the XYZ coordinates of the given illuminant and observer [1]_. 505 506 Parameters 507 ---------- 508 illuminant : {"A", "B", "C", "D50", "D55", "D65", "D75", "E"}, optional 509 The name of the illuminant (the function is NOT case sensitive). 510 observer : {"2", "10", "R"}, optional 511 One of: 2-degree observer, 10-degree observer, or 'R' observer as in 512 R function grDevices::convertColor. 513 dtype: dtype, optional 514 Output data type. 515 516 Returns 517 ------- 518 out : array 519 Array with 3 elements containing the XYZ coordinates of the given 520 illuminant. 521 522 Raises 523 ------ 524 ValueError 525 If either the illuminant or the observer angle are not supported or 526 unknown. 527 528 References 529 ---------- 530 .. [1] https://en.wikipedia.org/wiki/Standard_illuminant 531 """ 532 illuminant = illuminant.upper() 533 observer = observer.upper() 534 try: 535 return np.asarray(illuminants[illuminant][observer], dtype=dtype) 536 except KeyError: 537 raise ValueError(f'Unknown illuminant/observer combination ' 538 f'(`{illuminant}`, `{observer}`)') 539 540 541# Haematoxylin-Eosin-DAB colorspace 542# From original Ruifrok's paper: A. C. Ruifrok and D. A. Johnston, 543# "Quantification of histochemical staining by color deconvolution," 544# Analytical and quantitative cytology and histology / the International 545# Academy of Cytology [and] American Society of Cytology, vol. 23, no. 4, 546# pp. 291-9, Aug. 2001. 547rgb_from_hed = np.array([[0.65, 0.70, 0.29], 548 [0.07, 0.99, 0.11], 549 [0.27, 0.57, 0.78]]) 550hed_from_rgb = linalg.inv(rgb_from_hed) 551 552# Following matrices are adapted form the Java code written by G.Landini. 553# The original code is available at: 554# https://web.archive.org/web/20160624145052/http://www.mecourse.com/landinig/software/cdeconv/cdeconv.html 555 556# Hematoxylin + DAB 557rgb_from_hdx = np.array([[0.650, 0.704, 0.286], 558 [0.268, 0.570, 0.776], 559 [0.0, 0.0, 0.0]]) 560rgb_from_hdx[2, :] = np.cross(rgb_from_hdx[0, :], rgb_from_hdx[1, :]) 561hdx_from_rgb = linalg.inv(rgb_from_hdx) 562 563# Feulgen + Light Green 564rgb_from_fgx = np.array([[0.46420921, 0.83008335, 0.30827187], 565 [0.94705542, 0.25373821, 0.19650764], 566 [0.0, 0.0, 0.0]]) 567rgb_from_fgx[2, :] = np.cross(rgb_from_fgx[0, :], rgb_from_fgx[1, :]) 568fgx_from_rgb = linalg.inv(rgb_from_fgx) 569 570# Giemsa: Methyl Blue + Eosin 571rgb_from_bex = np.array([[0.834750233, 0.513556283, 0.196330403], 572 [0.092789, 0.954111, 0.283111], 573 [0.0, 0.0, 0.0]]) 574rgb_from_bex[2, :] = np.cross(rgb_from_bex[0, :], rgb_from_bex[1, :]) 575bex_from_rgb = linalg.inv(rgb_from_bex) 576 577# FastRed + FastBlue + DAB 578rgb_from_rbd = np.array([[0.21393921, 0.85112669, 0.47794022], 579 [0.74890292, 0.60624161, 0.26731082], 580 [0.268, 0.570, 0.776]]) 581rbd_from_rgb = linalg.inv(rgb_from_rbd) 582 583# Methyl Green + DAB 584rgb_from_gdx = np.array([[0.98003, 0.144316, 0.133146], 585 [0.268, 0.570, 0.776], 586 [0.0, 0.0, 0.0]]) 587rgb_from_gdx[2, :] = np.cross(rgb_from_gdx[0, :], rgb_from_gdx[1, :]) 588gdx_from_rgb = linalg.inv(rgb_from_gdx) 589 590# Hematoxylin + AEC 591rgb_from_hax = np.array([[0.650, 0.704, 0.286], 592 [0.2743, 0.6796, 0.6803], 593 [0.0, 0.0, 0.0]]) 594rgb_from_hax[2, :] = np.cross(rgb_from_hax[0, :], rgb_from_hax[1, :]) 595hax_from_rgb = linalg.inv(rgb_from_hax) 596 597# Blue matrix Anilline Blue + Red matrix Azocarmine + Orange matrix Orange-G 598rgb_from_bro = np.array([[0.853033, 0.508733, 0.112656], 599 [0.09289875, 0.8662008, 0.49098468], 600 [0.10732849, 0.36765403, 0.9237484]]) 601bro_from_rgb = linalg.inv(rgb_from_bro) 602 603# Methyl Blue + Ponceau Fuchsin 604rgb_from_bpx = np.array([[0.7995107, 0.5913521, 0.10528667], 605 [0.09997159, 0.73738605, 0.6680326], 606 [0.0, 0.0, 0.0]]) 607rgb_from_bpx[2, :] = np.cross(rgb_from_bpx[0, :], rgb_from_bpx[1, :]) 608bpx_from_rgb = linalg.inv(rgb_from_bpx) 609 610# Alcian Blue + Hematoxylin 611rgb_from_ahx = np.array([[0.874622, 0.457711, 0.158256], 612 [0.552556, 0.7544, 0.353744], 613 [0.0, 0.0, 0.0]]) 614rgb_from_ahx[2, :] = np.cross(rgb_from_ahx[0, :], rgb_from_ahx[1, :]) 615ahx_from_rgb = linalg.inv(rgb_from_ahx) 616 617# Hematoxylin + PAS 618rgb_from_hpx = np.array([[0.644211, 0.716556, 0.266844], 619 [0.175411, 0.972178, 0.154589], 620 [0.0, 0.0, 0.0]]) 621rgb_from_hpx[2, :] = np.cross(rgb_from_hpx[0, :], rgb_from_hpx[1, :]) 622hpx_from_rgb = linalg.inv(rgb_from_hpx) 623 624# ------------------------------------------------------------- 625# The conversion functions that make use of the matrices above 626# ------------------------------------------------------------- 627 628 629def _convert(matrix, arr): 630 """Do the color space conversion. 631 632 Parameters 633 ---------- 634 matrix : array_like 635 The 3x3 matrix to use. 636 arr : (..., 3, ...) array_like 637 The input array. By default, the final dimension denotes 638 channels. 639 640 Returns 641 ------- 642 out : (..., 3, ...) ndarray 643 The converted array. Same dimensions as input. 644 """ 645 arr = _prepare_colorarray(arr) 646 647 return arr @ matrix.T.astype(arr.dtype) 648 649 650@channel_as_last_axis() 651def xyz2rgb(xyz, *, channel_axis=-1): 652 """XYZ to RGB color space conversion. 653 654 Parameters 655 ---------- 656 xyz : (..., 3, ...) array_like 657 The image in XYZ format. By default, the final dimension denotes 658 channels. 659 channel_axis : int, optional 660 This parameter indicates which axis of the array corresponds to 661 channels. 662 663 .. versionadded:: 0.19 664 ``channel_axis`` was added in 0.19. 665 666 Returns 667 ------- 668 out : (..., 3, ...) ndarray 669 The image in RGB format. Same dimensions as input. 670 671 Raises 672 ------ 673 ValueError 674 If `xyz` is not at least 2-D with shape (..., 3, ...). 675 676 Notes 677 ----- 678 The CIE XYZ color space is derived from the CIE RGB color space. Note 679 however that this function converts to sRGB. 680 681 References 682 ---------- 683 .. [1] https://en.wikipedia.org/wiki/CIE_1931_color_space 684 685 Examples 686 -------- 687 >>> from skimage import data 688 >>> from skimage.color import rgb2xyz, xyz2rgb 689 >>> img = data.astronaut() 690 >>> img_xyz = rgb2xyz(img) 691 >>> img_rgb = xyz2rgb(img_xyz) 692 """ 693 # Follow the algorithm from http://www.easyrgb.com/index.php 694 # except we don't multiply/divide by 100 in the conversion 695 arr = _convert(rgb_from_xyz, xyz) 696 mask = arr > 0.0031308 697 arr[mask] = 1.055 * np.power(arr[mask], 1 / 2.4) - 0.055 698 arr[~mask] *= 12.92 699 np.clip(arr, 0, 1, out=arr) 700 return arr 701 702 703@channel_as_last_axis() 704def rgb2xyz(rgb, *, channel_axis=-1): 705 """RGB to XYZ color space conversion. 706 707 Parameters 708 ---------- 709 rgb : (..., 3, ...) array_like 710 The image in RGB format. By default, the final dimension denotes 711 channels. 712 channel_axis : int, optional 713 This parameter indicates which axis of the array corresponds to 714 channels. 715 716 .. versionadded:: 0.19 717 ``channel_axis`` was added in 0.19. 718 719 Returns 720 ------- 721 out : (..., 3, ...) ndarray 722 The image in XYZ format. Same dimensions as input. 723 724 Raises 725 ------ 726 ValueError 727 If `rgb` is not at least 2-D with shape (..., 3, ...). 728 729 Notes 730 ----- 731 The CIE XYZ color space is derived from the CIE RGB color space. Note 732 however that this function converts from sRGB. 733 734 References 735 ---------- 736 .. [1] https://en.wikipedia.org/wiki/CIE_1931_color_space 737 738 Examples 739 -------- 740 >>> from skimage import data 741 >>> img = data.astronaut() 742 >>> img_xyz = rgb2xyz(img) 743 """ 744 # Follow the algorithm from http://www.easyrgb.com/index.php 745 # except we don't multiply/divide by 100 in the conversion 746 arr = _prepare_colorarray(rgb, channel_axis=-1).copy() 747 mask = arr > 0.04045 748 arr[mask] = np.power((arr[mask] + 0.055) / 1.055, 2.4) 749 arr[~mask] /= 12.92 750 return arr @ xyz_from_rgb.T.astype(arr.dtype) 751 752 753@channel_as_last_axis() 754def rgb2rgbcie(rgb, *, channel_axis=-1): 755 """RGB to RGB CIE color space conversion. 756 757 Parameters 758 ---------- 759 rgb : (..., 3, ...) array_like 760 The image in RGB format. By default, the final dimension denotes 761 channels. 762 channel_axis : int, optional 763 This parameter indicates which axis of the array corresponds to 764 channels. 765 766 .. versionadded:: 0.19 767 ``channel_axis`` was added in 0.19. 768 769 Returns 770 ------- 771 out : (..., 3, ...) ndarray 772 The image in RGB CIE format. Same dimensions as input. 773 774 Raises 775 ------ 776 ValueError 777 If `rgb` is not at least 2-D with shape (..., 3, ...). 778 779 References 780 ---------- 781 .. [1] https://en.wikipedia.org/wiki/CIE_1931_color_space 782 783 Examples 784 -------- 785 >>> from skimage import data 786 >>> from skimage.color import rgb2rgbcie 787 >>> img = data.astronaut() 788 >>> img_rgbcie = rgb2rgbcie(img) 789 """ 790 return _convert(rgbcie_from_rgb, rgb) 791 792 793@channel_as_last_axis() 794def rgbcie2rgb(rgbcie, *, channel_axis=-1): 795 """RGB CIE to RGB color space conversion. 796 797 Parameters 798 ---------- 799 rgbcie : (..., 3, ...) array_like 800 The image in RGB CIE format. By default, the final dimension denotes 801 channels. 802 channel_axis : int, optional 803 This parameter indicates which axis of the array corresponds to 804 channels. 805 806 .. versionadded:: 0.19 807 ``channel_axis`` was added in 0.19. 808 809 Returns 810 ------- 811 out : (..., 3, ...) ndarray 812 The image in RGB format. Same dimensions as input. 813 814 Raises 815 ------ 816 ValueError 817 If `rgbcie` is not at least 2-D with shape (..., 3, ...). 818 819 References 820 ---------- 821 .. [1] https://en.wikipedia.org/wiki/CIE_1931_color_space 822 823 Examples 824 -------- 825 >>> from skimage import data 826 >>> from skimage.color import rgb2rgbcie, rgbcie2rgb 827 >>> img = data.astronaut() 828 >>> img_rgbcie = rgb2rgbcie(img) 829 >>> img_rgb = rgbcie2rgb(img_rgbcie) 830 """ 831 return _convert(rgb_from_rgbcie, rgbcie) 832 833 834@channel_as_last_axis(multichannel_output=False) 835def rgb2gray(rgb, *, channel_axis=-1): 836 """Compute luminance of an RGB image. 837 838 Parameters 839 ---------- 840 rgb : (..., 3, ...) array_like 841 The image in RGB format. By default, the final dimension denotes 842 channels. 843 844 Returns 845 ------- 846 out : ndarray 847 The luminance image - an array which is the same size as the input 848 array, but with the channel dimension removed. 849 850 Raises 851 ------ 852 ValueError 853 If `rgb` is not at least 2-D with shape (..., 3, ...). 854 855 Notes 856 ----- 857 The weights used in this conversion are calibrated for contemporary 858 CRT phosphors:: 859 860 Y = 0.2125 R + 0.7154 G + 0.0721 B 861 862 If there is an alpha channel present, it is ignored. 863 864 References 865 ---------- 866 .. [1] http://poynton.ca/PDFs/ColorFAQ.pdf 867 868 Examples 869 -------- 870 >>> from skimage.color import rgb2gray 871 >>> from skimage import data 872 >>> img = data.astronaut() 873 >>> img_gray = rgb2gray(img) 874 """ 875 rgb = _prepare_colorarray(rgb) 876 coeffs = np.array([0.2125, 0.7154, 0.0721], dtype=rgb.dtype) 877 return rgb @ coeffs 878 879 880def gray2rgba(image, alpha=None, *, channel_axis=-1): 881 """Create a RGBA representation of a gray-level image. 882 883 Parameters 884 ---------- 885 image : array_like 886 Input image. 887 alpha : array_like, optional 888 Alpha channel of the output image. It may be a scalar or an 889 array that can be broadcast to ``image``. If not specified it is 890 set to the maximum limit corresponding to the ``image`` dtype. 891 channel_axis : int, optional 892 This parameter indicates which axis of the output array will correspond 893 to channels. 894 895 .. versionadded:: 0.19 896 ``channel_axis`` was added in 0.19. 897 898 Returns 899 ------- 900 rgba : ndarray 901 RGBA image. A new dimension of length 4 is added to input 902 image shape. 903 """ 904 905 arr = np.asarray(image) 906 907 alpha_min, alpha_max = dtype_limits(arr, clip_negative=False) 908 909 if alpha is None: 910 alpha = alpha_max 911 912 if not np.can_cast(alpha, arr.dtype): 913 warn(f'alpha cannot be safely cast to image dtype {arr.dtype.name}', 914 stacklevel=2) 915 if np.isscalar(alpha): 916 alpha = np.full(arr.shape, alpha, dtype=arr.dtype) 917 elif alpha.shape != arr.shape: 918 raise ValueError("alpha.shape must match image.shape") 919 rgba = np.stack((arr,) * 3 + (alpha,), axis=channel_axis) 920 return rgba 921 922 923def gray2rgb(image, *, channel_axis=-1): 924 """Create an RGB representation of a gray-level image. 925 926 Parameters 927 ---------- 928 image : array_like 929 Input image. 930 channel_axis : int, optional 931 This parameter indicates which axis of the output array will correspond 932 to channels. 933 934 Returns 935 ------- 936 rgb : (..., 3, ...) ndarray 937 RGB image. A new dimension of length 3 is added to input image. 938 939 Notes 940 ----- 941 If the input is a 1-dimensional image of shape ``(M, )``, the output 942 will be shape ``(M, 3)``. 943 """ 944 return np.stack(3 * (image,), axis=channel_axis) 945 946 947@channel_as_last_axis() 948def xyz2lab(xyz, illuminant="D65", observer="2", *, channel_axis=-1): 949 """XYZ to CIE-LAB color space conversion. 950 951 Parameters 952 ---------- 953 xyz : (..., 3, ...) array_like 954 The image in XYZ format. By default, the final dimension denotes 955 channels. 956 illuminant : {"A", "B", "C", "D50", "D55", "D65", "D75", "E"}, optional 957 The name of the illuminant (the function is NOT case sensitive). 958 observer : {"2", "10", "R"}, optional 959 One of: 2-degree observer, 10-degree observer, or 'R' observer as in 960 R function grDevices::convertColor. 961 channel_axis : int, optional 962 This parameter indicates which axis of the array corresponds to 963 channels. 964 965 .. versionadded:: 0.19 966 ``channel_axis`` was added in 0.19. 967 968 Returns 969 ------- 970 out : (..., 3, ...) ndarray 971 The image in CIE-LAB format. Same dimensions as input. 972 973 Raises 974 ------ 975 ValueError 976 If `xyz` is not at least 2-D with shape (..., 3, ...). 977 ValueError 978 If either the illuminant or the observer angle is unsupported or 979 unknown. 980 981 Notes 982 ----- 983 By default Observer="2", Illuminant="D65". CIE XYZ tristimulus values 984 x_ref=95.047, y_ref=100., z_ref=108.883. See function `get_xyz_coords` for 985 a list of supported illuminants. 986 987 References 988 ---------- 989 .. [1] http://www.easyrgb.com/index.php?X=MATH&H=07 990 .. [2] https://en.wikipedia.org/wiki/Lab_color_space 991 992 Examples 993 -------- 994 >>> from skimage import data 995 >>> from skimage.color import rgb2xyz, xyz2lab 996 >>> img = data.astronaut() 997 >>> img_xyz = rgb2xyz(img) 998 >>> img_lab = xyz2lab(img_xyz) 999 """ 1000 arr = _prepare_colorarray(xyz, channel_axis=-1) 1001 1002 xyz_ref_white = get_xyz_coords(illuminant, observer, arr.dtype) 1003 1004 # scale by CIE XYZ tristimulus values of the reference white point 1005 arr = arr / xyz_ref_white 1006 1007 # Nonlinear distortion and linear transformation 1008 mask = arr > 0.008856 1009 arr[mask] = np.cbrt(arr[mask]) 1010 arr[~mask] = 7.787 * arr[~mask] + 16. / 116. 1011 1012 x, y, z = arr[..., 0], arr[..., 1], arr[..., 2] 1013 1014 # Vector scaling 1015 L = (116. * y) - 16. 1016 a = 500.0 * (x - y) 1017 b = 200.0 * (y - z) 1018 1019 return np.concatenate([x[..., np.newaxis] for x in [L, a, b]], axis=-1) 1020 1021 1022@channel_as_last_axis() 1023def lab2xyz(lab, illuminant="D65", observer="2", *, channel_axis=-1): 1024 """CIE-LAB to XYZcolor space conversion. 1025 1026 Parameters 1027 ---------- 1028 lab : (..., 3, ...) array_like 1029 The image in Lab format. By default, the final dimension denotes 1030 channels. 1031 illuminant : {"A", "B", "C", "D50", "D55", "D65", "D75", "E"}, optional 1032 The name of the illuminant (the function is NOT case sensitive). 1033 observer : {"2", "10", "R"}, optional 1034 The aperture angle of the observer. 1035 channel_axis : int, optional 1036 This parameter indicates which axis of the array corresponds to 1037 channels. 1038 1039 .. versionadded:: 0.19 1040 ``channel_axis`` was added in 0.19. 1041 1042 Returns 1043 ------- 1044 out : (..., 3, ...) ndarray 1045 The image in XYZ format. Same dimensions as input. 1046 1047 Raises 1048 ------ 1049 ValueError 1050 If `lab` is not at least 2-D with shape (..., 3, ...). 1051 ValueError 1052 If either the illuminant or the observer angle are not supported or 1053 unknown. 1054 UserWarning 1055 If any of the pixels are invalid (Z < 0). 1056 1057 Notes 1058 ----- 1059 By default Observer="2", Illuminant="D65". CIE XYZ tristimulus values x_ref 1060 = 95.047, y_ref = 100., z_ref = 108.883. See function 'get_xyz_coords' for 1061 a list of supported illuminants. 1062 1063 References 1064 ---------- 1065 .. [1] http://www.easyrgb.com/index.php?X=MATH&H=07 1066 .. [2] https://en.wikipedia.org/wiki/Lab_color_space 1067 """ 1068 arr = _prepare_colorarray(lab, channel_axis=-1).copy() 1069 1070 L, a, b = arr[..., 0], arr[..., 1], arr[..., 2] 1071 y = (L + 16.) / 116. 1072 x = (a / 500.) + y 1073 z = y - (b / 200.) 1074 1075 if np.any(z < 0): 1076 invalid = np.nonzero(z < 0) 1077 warn('Color data out of range: Z < 0 in %s pixels' % invalid[0].size, 1078 stacklevel=2) 1079 z[invalid] = 0 1080 1081 out = np.stack([x, y, z], axis=-1) 1082 1083 mask = out > 0.2068966 1084 out[mask] = np.power(out[mask], 3.) 1085 out[~mask] = (out[~mask] - 16.0 / 116.) / 7.787 1086 1087 # rescale to the reference white (illuminant) 1088 xyz_ref_white = get_xyz_coords(illuminant, observer) 1089 out *= xyz_ref_white 1090 return out 1091 1092 1093@channel_as_last_axis() 1094def rgb2lab(rgb, illuminant="D65", observer="2", *, channel_axis=-1): 1095 """Conversion from the sRGB color space (IEC 61966-2-1:1999) 1096 to the CIE Lab colorspace under the given illuminant and observer. 1097 1098 Parameters 1099 ---------- 1100 rgb : (..., 3, ...) array_like 1101 The image in RGB format. By default, the final dimension denotes 1102 channels. 1103 illuminant : {"A", "B", "C", "D50", "D55", "D65", "D75", "E"}, optional 1104 The name of the illuminant (the function is NOT case sensitive). 1105 observer : {"2", "10", "R"}, optional 1106 The aperture angle of the observer. 1107 channel_axis : int, optional 1108 This parameter indicates which axis of the array corresponds to 1109 channels. 1110 1111 .. versionadded:: 0.19 1112 ``channel_axis`` was added in 0.19. 1113 1114 Returns 1115 ------- 1116 out : (..., 3, ...) ndarray 1117 The image in Lab format. Same dimensions as input. 1118 1119 Raises 1120 ------ 1121 ValueError 1122 If `rgb` is not at least 2-D with shape (..., 3, ...). 1123 1124 Notes 1125 ----- 1126 RGB is a device-dependent color space so, if you use this function, be 1127 sure that the image you are analyzing has been mapped to the sRGB color 1128 space. 1129 1130 This function uses rgb2xyz and xyz2lab. 1131 By default Observer="2", Illuminant="D65". CIE XYZ tristimulus values 1132 x_ref=95.047, y_ref=100., z_ref=108.883. See function `get_xyz_coords` for 1133 a list of supported illuminants. 1134 1135 References 1136 ---------- 1137 .. [1] https://en.wikipedia.org/wiki/Standard_illuminant 1138 """ 1139 return xyz2lab(rgb2xyz(rgb), illuminant, observer) 1140 1141 1142@channel_as_last_axis() 1143def lab2rgb(lab, illuminant="D65", observer="2", *, channel_axis=-1): 1144 """Lab to RGB color space conversion. 1145 1146 Parameters 1147 ---------- 1148 lab : (..., 3, ...) array_like 1149 The image in Lab format. By default, the final dimension denotes 1150 channels. 1151 illuminant : {"A", "B", "C", "D50", "D55", "D65", "D75", "E"}, optional 1152 The name of the illuminant (the function is NOT case sensitive). 1153 observer : {"2", "10", "R"}, optional 1154 The aperture angle of the observer. 1155 channel_axis : int, optional 1156 This parameter indicates which axis of the array corresponds to 1157 channels. 1158 1159 .. versionadded:: 0.19 1160 ``channel_axis`` was added in 0.19. 1161 1162 Returns 1163 ------- 1164 out : (..., 3, ...) ndarray 1165 The image in RGB format. Same dimensions as input. 1166 1167 Raises 1168 ------ 1169 ValueError 1170 If `lab` is not at least 2-D with shape (..., 3, ...). 1171 1172 Notes 1173 ----- 1174 This function uses lab2xyz and xyz2rgb. 1175 By default Observer="2", Illuminant="D65". CIE XYZ tristimulus values 1176 x_ref=95.047, y_ref=100., z_ref=108.883. See function `get_xyz_coords` for 1177 a list of supported illuminants. 1178 1179 References 1180 ---------- 1181 .. [1] https://en.wikipedia.org/wiki/Standard_illuminant 1182 """ 1183 return xyz2rgb(lab2xyz(lab, illuminant, observer)) 1184 1185 1186@channel_as_last_axis() 1187def xyz2luv(xyz, illuminant="D65", observer="2", *, channel_axis=-1): 1188 """XYZ to CIE-Luv color space conversion. 1189 1190 Parameters 1191 ---------- 1192 xyz : (..., 3, ...) array_like 1193 The image in XYZ format. By default, the final dimension denotes 1194 channels. 1195 illuminant : {"A", "B", "C", "D50", "D55", "D65", "D75", "E"}, optional 1196 The name of the illuminant (the function is NOT case sensitive). 1197 observer : {"2", "10", "R"}, optional 1198 The aperture angle of the observer. 1199 channel_axis : int, optional 1200 This parameter indicates which axis of the array corresponds to 1201 channels. 1202 1203 .. versionadded:: 0.19 1204 ``channel_axis`` was added in 0.19. 1205 1206 Returns 1207 ------- 1208 out : (..., 3, ...) ndarray 1209 The image in CIE-Luv format. Same dimensions as input. 1210 1211 Raises 1212 ------ 1213 ValueError 1214 If `xyz` is not at least 2-D with shape (..., 3, ...). 1215 ValueError 1216 If either the illuminant or the observer angle are not supported or 1217 unknown. 1218 1219 Notes 1220 ----- 1221 By default XYZ conversion weights use observer=2A. Reference whitepoint 1222 for D65 Illuminant, with XYZ tristimulus values of ``(95.047, 100., 1223 108.883)``. See function 'get_xyz_coords' for a list of supported 1224 illuminants. 1225 1226 References 1227 ---------- 1228 .. [1] http://www.easyrgb.com/index.php?X=MATH&H=16#text16 1229 .. [2] https://en.wikipedia.org/wiki/CIELUV 1230 1231 Examples 1232 -------- 1233 >>> from skimage import data 1234 >>> from skimage.color import rgb2xyz, xyz2luv 1235 >>> img = data.astronaut() 1236 >>> img_xyz = rgb2xyz(img) 1237 >>> img_luv = xyz2luv(img_xyz) 1238 """ 1239 input_is_one_pixel = xyz.ndim == 1 1240 if input_is_one_pixel: 1241 xyz = xyz[np.newaxis, ...] 1242 1243 arr = _prepare_colorarray(xyz, channel_axis=-1) 1244 1245 # extract channels 1246 x, y, z = arr[..., 0], arr[..., 1], arr[..., 2] 1247 1248 eps = np.finfo(float).eps 1249 1250 # compute y_r and L 1251 xyz_ref_white = np.array(get_xyz_coords(illuminant, observer)) 1252 L = y / xyz_ref_white[1] 1253 mask = L > 0.008856 1254 L[mask] = 116. * np.cbrt(L[mask]) - 16. 1255 L[~mask] = 903.3 * L[~mask] 1256 1257 u0 = 4 * xyz_ref_white[0] / ([1, 15, 3] @ xyz_ref_white) 1258 v0 = 9 * xyz_ref_white[1] / ([1, 15, 3] @ xyz_ref_white) 1259 1260 # u' and v' helper functions 1261 def fu(X, Y, Z): 1262 return (4. * X) / (X + 15. * Y + 3. * Z + eps) 1263 1264 def fv(X, Y, Z): 1265 return (9. * Y) / (X + 15. * Y + 3. * Z + eps) 1266 1267 # compute u and v using helper functions 1268 u = 13. * L * (fu(x, y, z) - u0) 1269 v = 13. * L * (fv(x, y, z) - v0) 1270 1271 out = np.stack([L, u, v], axis=-1) 1272 1273 if input_is_one_pixel: 1274 out = np.squeeze(out, axis=0) 1275 1276 return out 1277 1278 1279@channel_as_last_axis() 1280def luv2xyz(luv, illuminant="D65", observer="2", *, channel_axis=-1): 1281 """CIE-Luv to XYZ color space conversion. 1282 1283 Parameters 1284 ---------- 1285 luv : (..., 3, ...) array_like 1286 The image in CIE-Luv format. By default, the final dimension denotes 1287 channels. 1288 illuminant : {"A", "B", "C", "D50", "D55", "D65", "D75", "E"}, optional 1289 The name of the illuminant (the function is NOT case sensitive). 1290 observer : {"2", "10", "R"}, optional 1291 The aperture angle of the observer. 1292 channel_axis : int, optional 1293 This parameter indicates which axis of the array corresponds to 1294 channels. 1295 1296 .. versionadded:: 0.19 1297 ``channel_axis`` was added in 0.19. 1298 1299 Returns 1300 ------- 1301 out : (..., 3, ...) ndarray 1302 The image in XYZ format. Same dimensions as input. 1303 1304 Raises 1305 ------ 1306 ValueError 1307 If `luv` is not at least 2-D with shape (..., 3, ...). 1308 ValueError 1309 If either the illuminant or the observer angle are not supported or 1310 unknown. 1311 1312 Notes 1313 ----- 1314 XYZ conversion weights use observer=2A. Reference whitepoint for D65 1315 Illuminant, with XYZ tristimulus values of ``(95.047, 100., 108.883)``. See 1316 function 'get_xyz_coords' for a list of supported illuminants. 1317 1318 References 1319 ---------- 1320 .. [1] http://www.easyrgb.com/index.php?X=MATH&H=16#text16 1321 .. [2] https://en.wikipedia.org/wiki/CIELUV 1322 """ 1323 arr = _prepare_colorarray(luv, channel_axis=-1).copy() 1324 1325 L, u, v = arr[..., 0], arr[..., 1], arr[..., 2] 1326 1327 eps = np.finfo(float).eps 1328 1329 # compute y 1330 y = L.copy() 1331 mask = y > 7.999625 1332 y[mask] = np.power((y[mask] + 16.) / 116., 3.) 1333 y[~mask] = y[~mask] / 903.3 1334 xyz_ref_white = get_xyz_coords(illuminant, observer) 1335 y *= xyz_ref_white[1] 1336 1337 # reference white x,z 1338 uv_weights = np.array([1, 15, 3]) 1339 u0 = 4 * xyz_ref_white[0] / (uv_weights @ xyz_ref_white) 1340 v0 = 9 * xyz_ref_white[1] / (uv_weights @ xyz_ref_white) 1341 1342 # compute intermediate values 1343 a = u0 + u / (13. * L + eps) 1344 b = v0 + v / (13. * L + eps) 1345 c = 3 * y * (5 * b - 3) 1346 1347 # compute x and z 1348 z = ((a - 4) * c - 15 * a * b * y) / (12 * b) 1349 x = -(c / b + 3. * z) 1350 1351 return np.concatenate([q[..., np.newaxis] for q in [x, y, z]], axis=-1) 1352 1353 1354@channel_as_last_axis() 1355def rgb2luv(rgb, *, channel_axis=-1): 1356 """RGB to CIE-Luv color space conversion. 1357 1358 Parameters 1359 ---------- 1360 rgb : (..., 3, ...) array_like 1361 The image in RGB format. By default, the final dimension denotes 1362 channels. 1363 channel_axis : int, optional 1364 This parameter indicates which axis of the array corresponds to 1365 channels. 1366 1367 .. versionadded:: 0.19 1368 ``channel_axis`` was added in 0.19. 1369 1370 Returns 1371 ------- 1372 out : (..., 3, ...) ndarray 1373 The image in CIE Luv format. Same dimensions as input. 1374 1375 Raises 1376 ------ 1377 ValueError 1378 If `rgb` is not at least 2-D with shape (..., 3, ...). 1379 1380 Notes 1381 ----- 1382 This function uses rgb2xyz and xyz2luv. 1383 1384 References 1385 ---------- 1386 .. [1] http://www.easyrgb.com/index.php?X=MATH&H=16#text16 1387 .. [2] http://www.easyrgb.com/index.php?X=MATH&H=02#text2 1388 .. [3] https://en.wikipedia.org/wiki/CIELUV 1389 """ 1390 return xyz2luv(rgb2xyz(rgb)) 1391 1392 1393@channel_as_last_axis() 1394def luv2rgb(luv, *, channel_axis=-1): 1395 """Luv to RGB color space conversion. 1396 1397 Parameters 1398 ---------- 1399 luv : (..., 3, ...) array_like 1400 The image in CIE Luv format. By default, the final dimension denotes 1401 channels. 1402 1403 Returns 1404 ------- 1405 out : (..., 3, ...) ndarray 1406 The image in RGB format. Same dimensions as input. 1407 1408 Raises 1409 ------ 1410 ValueError 1411 If `luv` is not at least 2-D with shape (..., 3, ...). 1412 1413 Notes 1414 ----- 1415 This function uses luv2xyz and xyz2rgb. 1416 """ 1417 return xyz2rgb(luv2xyz(luv)) 1418 1419 1420@channel_as_last_axis() 1421def rgb2hed(rgb, *, channel_axis=-1): 1422 """RGB to Haematoxylin-Eosin-DAB (HED) color space conversion. 1423 1424 Parameters 1425 ---------- 1426 rgb : (..., 3, ...) array_like 1427 The image in RGB format. By default, the final dimension denotes 1428 channels. 1429 channel_axis : int, optional 1430 This parameter indicates which axis of the array corresponds to 1431 channels. 1432 1433 .. versionadded:: 0.19 1434 ``channel_axis`` was added in 0.19. 1435 1436 Returns 1437 ------- 1438 out : (..., 3, ...) ndarray 1439 The image in HED format. Same dimensions as input. 1440 1441 Raises 1442 ------ 1443 ValueError 1444 If `rgb` is not at least 2-D with shape (..., 3, ...). 1445 1446 References 1447 ---------- 1448 .. [1] A. C. Ruifrok and D. A. Johnston, "Quantification of histochemical 1449 staining by color deconvolution.," Analytical and quantitative 1450 cytology and histology / the International Academy of Cytology [and] 1451 American Society of Cytology, vol. 23, no. 4, pp. 291-9, Aug. 2001. 1452 1453 Examples 1454 -------- 1455 >>> from skimage import data 1456 >>> from skimage.color import rgb2hed 1457 >>> ihc = data.immunohistochemistry() 1458 >>> ihc_hed = rgb2hed(ihc) 1459 """ 1460 return separate_stains(rgb, hed_from_rgb) 1461 1462 1463@channel_as_last_axis() 1464def hed2rgb(hed, *, channel_axis=-1): 1465 """Haematoxylin-Eosin-DAB (HED) to RGB color space conversion. 1466 1467 Parameters 1468 ---------- 1469 hed : (..., 3, ...) array_like 1470 The image in the HED color space. By default, the final dimension 1471 denotes channels. 1472 channel_axis : int, optional 1473 This parameter indicates which axis of the array corresponds to 1474 channels. 1475 1476 .. versionadded:: 0.19 1477 ``channel_axis`` was added in 0.19. 1478 1479 Returns 1480 ------- 1481 out : (..., 3, ...) ndarray 1482 The image in RGB. Same dimensions as input. 1483 1484 Raises 1485 ------ 1486 ValueError 1487 If `hed` is not at least 2-D with shape (..., 3, ...). 1488 1489 References 1490 ---------- 1491 .. [1] A. C. Ruifrok and D. A. Johnston, "Quantification of histochemical 1492 staining by color deconvolution.," Analytical and quantitative 1493 cytology and histology / the International Academy of Cytology [and] 1494 American Society of Cytology, vol. 23, no. 4, pp. 291-9, Aug. 2001. 1495 1496 Examples 1497 -------- 1498 >>> from skimage import data 1499 >>> from skimage.color import rgb2hed, hed2rgb 1500 >>> ihc = data.immunohistochemistry() 1501 >>> ihc_hed = rgb2hed(ihc) 1502 >>> ihc_rgb = hed2rgb(ihc_hed) 1503 """ 1504 return combine_stains(hed, rgb_from_hed) 1505 1506 1507@channel_as_last_axis() 1508def separate_stains(rgb, conv_matrix, *, channel_axis=-1): 1509 """RGB to stain color space conversion. 1510 1511 Parameters 1512 ---------- 1513 rgb : (..., 3, ...) array_like 1514 The image in RGB format. By default, the final dimension denotes 1515 channels. 1516 conv_matrix: ndarray 1517 The stain separation matrix as described by G. Landini [1]_. 1518 channel_axis : int, optional 1519 This parameter indicates which axis of the array corresponds to 1520 channels. 1521 1522 .. versionadded:: 0.19 1523 ``channel_axis`` was added in 0.19. 1524 1525 Returns 1526 ------- 1527 out : (..., 3, ...) ndarray 1528 The image in stain color space. Same dimensions as input. 1529 1530 Raises 1531 ------ 1532 ValueError 1533 If `rgb` is not at least 2-D with shape (..., 3, ...). 1534 1535 Notes 1536 ----- 1537 Stain separation matrices available in the ``color`` module and their 1538 respective colorspace: 1539 1540 * ``hed_from_rgb``: Hematoxylin + Eosin + DAB 1541 * ``hdx_from_rgb``: Hematoxylin + DAB 1542 * ``fgx_from_rgb``: Feulgen + Light Green 1543 * ``bex_from_rgb``: Giemsa stain : Methyl Blue + Eosin 1544 * ``rbd_from_rgb``: FastRed + FastBlue + DAB 1545 * ``gdx_from_rgb``: Methyl Green + DAB 1546 * ``hax_from_rgb``: Hematoxylin + AEC 1547 * ``bro_from_rgb``: Blue matrix Anilline Blue + Red matrix Azocarmine\ 1548 + Orange matrix Orange-G 1549 * ``bpx_from_rgb``: Methyl Blue + Ponceau Fuchsin 1550 * ``ahx_from_rgb``: Alcian Blue + Hematoxylin 1551 * ``hpx_from_rgb``: Hematoxylin + PAS 1552 1553 This implementation borrows some ideas from DIPlib [2]_, e.g. the 1554 compensation using a small value to avoid log artifacts when 1555 calculating the Beer-Lambert law. 1556 1557 References 1558 ---------- 1559 .. [1] https://web.archive.org/web/20160624145052/http://www.mecourse.com/landinig/software/cdeconv/cdeconv.html 1560 .. [2] https://github.com/DIPlib/diplib/ 1561 .. [3] A. C. Ruifrok and D. A. Johnston, “Quantification of histochemical 1562 staining by color deconvolution,” Anal. Quant. Cytol. Histol., vol. 1563 23, no. 4, pp. 291–299, Aug. 2001. 1564 1565 Examples 1566 -------- 1567 >>> from skimage import data 1568 >>> from skimage.color import separate_stains, hdx_from_rgb 1569 >>> ihc = data.immunohistochemistry() 1570 >>> ihc_hdx = separate_stains(ihc, hdx_from_rgb) 1571 """ 1572 rgb = _prepare_colorarray(rgb, force_copy=True, channel_axis=-1) 1573 np.maximum(rgb, 1E-6, out=rgb) # avoiding log artifacts 1574 log_adjust = np.log(1E-6) # used to compensate the sum above 1575 1576 stains = (np.log(rgb) / log_adjust) @ conv_matrix 1577 1578 np.maximum(stains, 0, out=stains) 1579 1580 return stains 1581 1582 1583@channel_as_last_axis() 1584def combine_stains(stains, conv_matrix, *, channel_axis=-1): 1585 """Stain to RGB color space conversion. 1586 1587 Parameters 1588 ---------- 1589 stains : (..., 3, ...) array_like 1590 The image in stain color space. By default, the final dimension denotes 1591 channels. 1592 conv_matrix: ndarray 1593 The stain separation matrix as described by G. Landini [1]_. 1594 channel_axis : int, optional 1595 This parameter indicates which axis of the array corresponds to 1596 channels. 1597 1598 .. versionadded:: 0.19 1599 ``channel_axis`` was added in 0.19. 1600 1601 Returns 1602 ------- 1603 out : (..., 3, ...) ndarray 1604 The image in RGB format. Same dimensions as input. 1605 1606 Raises 1607 ------ 1608 ValueError 1609 If `stains` is not at least 2-D with shape (..., 3, ...). 1610 1611 Notes 1612 ----- 1613 Stain combination matrices available in the ``color`` module and their 1614 respective colorspace: 1615 1616 * ``rgb_from_hed``: Hematoxylin + Eosin + DAB 1617 * ``rgb_from_hdx``: Hematoxylin + DAB 1618 * ``rgb_from_fgx``: Feulgen + Light Green 1619 * ``rgb_from_bex``: Giemsa stain : Methyl Blue + Eosin 1620 * ``rgb_from_rbd``: FastRed + FastBlue + DAB 1621 * ``rgb_from_gdx``: Methyl Green + DAB 1622 * ``rgb_from_hax``: Hematoxylin + AEC 1623 * ``rgb_from_bro``: Blue matrix Anilline Blue + Red matrix Azocarmine\ 1624 + Orange matrix Orange-G 1625 * ``rgb_from_bpx``: Methyl Blue + Ponceau Fuchsin 1626 * ``rgb_from_ahx``: Alcian Blue + Hematoxylin 1627 * ``rgb_from_hpx``: Hematoxylin + PAS 1628 1629 References 1630 ---------- 1631 .. [1] https://web.archive.org/web/20160624145052/http://www.mecourse.com/landinig/software/cdeconv/cdeconv.html 1632 .. [2] A. C. Ruifrok and D. A. Johnston, “Quantification of histochemical 1633 staining by color deconvolution,” Anal. Quant. Cytol. Histol., vol. 1634 23, no. 4, pp. 291–299, Aug. 2001. 1635 1636 Examples 1637 -------- 1638 >>> from skimage import data 1639 >>> from skimage.color import (separate_stains, combine_stains, 1640 ... hdx_from_rgb, rgb_from_hdx) 1641 >>> ihc = data.immunohistochemistry() 1642 >>> ihc_hdx = separate_stains(ihc, hdx_from_rgb) 1643 >>> ihc_rgb = combine_stains(ihc_hdx, rgb_from_hdx) 1644 """ 1645 stains = _prepare_colorarray(stains, channel_axis=-1) 1646 1647 # log_adjust here is used to compensate the sum within separate_stains(). 1648 log_adjust = -np.log(1E-6) 1649 log_rgb = -(stains * log_adjust) @ conv_matrix 1650 rgb = np.exp(log_rgb) 1651 1652 return np.clip(rgb, a_min=0, a_max=1) 1653 1654 1655@channel_as_last_axis() 1656def lab2lch(lab, *, channel_axis=-1): 1657 """CIE-LAB to CIE-LCH color space conversion. 1658 1659 LCH is the cylindrical representation of the LAB (Cartesian) colorspace 1660 1661 Parameters 1662 ---------- 1663 lab : (..., 3, ...) array_like 1664 The N-D image in CIE-LAB format. The last (``N+1``-th) dimension must 1665 have at least 3 elements, corresponding to the ``L``, ``a``, and ``b`` 1666 color channels. Subsequent elements are copied. 1667 channel_axis : int, optional 1668 This parameter indicates which axis of the array corresponds to 1669 channels. 1670 1671 .. versionadded:: 0.19 1672 ``channel_axis`` was added in 0.19. 1673 1674 Returns 1675 ------- 1676 out : (..., 3, ...) ndarray 1677 The image in LCH format, in a N-D array with same shape as input `lab`. 1678 1679 Raises 1680 ------ 1681 ValueError 1682 If `lch` does not have at least 3 color channels (i.e. l, a, b). 1683 1684 Notes 1685 ----- 1686 The Hue is expressed as an angle between ``(0, 2*pi)`` 1687 1688 Examples 1689 -------- 1690 >>> from skimage import data 1691 >>> from skimage.color import rgb2lab, lab2lch 1692 >>> img = data.astronaut() 1693 >>> img_lab = rgb2lab(img) 1694 >>> img_lch = lab2lch(img_lab) 1695 """ 1696 lch = _prepare_lab_array(lab) 1697 1698 a, b = lch[..., 1], lch[..., 2] 1699 lch[..., 1], lch[..., 2] = _cart2polar_2pi(a, b) 1700 return lch 1701 1702 1703def _cart2polar_2pi(x, y): 1704 """convert cartesian coordinates to polar (uses non-standard theta range!) 1705 1706 NON-STANDARD RANGE! Maps to ``(0, 2*pi)`` rather than usual ``(-pi, +pi)`` 1707 """ 1708 r, t = np.hypot(x, y), np.arctan2(y, x) 1709 t += np.where(t < 0., 2 * np.pi, 0) 1710 return r, t 1711 1712 1713@channel_as_last_axis() 1714def lch2lab(lch, *, channel_axis=-1): 1715 """CIE-LCH to CIE-LAB color space conversion. 1716 1717 LCH is the cylindrical representation of the LAB (Cartesian) colorspace 1718 1719 Parameters 1720 ---------- 1721 lch : (..., 3, ...) array_like 1722 The N-D image in CIE-LCH format. The last (``N+1``-th) dimension must 1723 have at least 3 elements, corresponding to the ``L``, ``a``, and ``b`` 1724 color channels. Subsequent elements are copied. 1725 channel_axis : int, optional 1726 This parameter indicates which axis of the array corresponds to 1727 channels. 1728 1729 .. versionadded:: 0.19 1730 ``channel_axis`` was added in 0.19. 1731 1732 Returns 1733 ------- 1734 out : (..., 3, ...) ndarray 1735 The image in LAB format, with same shape as input `lch`. 1736 1737 Raises 1738 ------ 1739 ValueError 1740 If `lch` does not have at least 3 color channels (i.e. l, c, h). 1741 1742 Examples 1743 -------- 1744 >>> from skimage import data 1745 >>> from skimage.color import rgb2lab, lch2lab, lab2lch 1746 >>> img = data.astronaut() 1747 >>> img_lab = rgb2lab(img) 1748 >>> img_lch = lab2lch(img_lab) 1749 >>> img_lab2 = lch2lab(img_lch) 1750 """ 1751 lch = _prepare_lab_array(lch) 1752 1753 c, h = lch[..., 1], lch[..., 2] 1754 lch[..., 1], lch[..., 2] = c * np.cos(h), c * np.sin(h) 1755 return lch 1756 1757 1758def _prepare_lab_array(arr, force_copy=True): 1759 """Ensure input for lab2lch, lch2lab are well-posed. 1760 1761 Arrays must be in floating point and have at least 3 elements in 1762 last dimension. Return a new array. 1763 """ 1764 arr = np.asarray(arr) 1765 shape = arr.shape 1766 if shape[-1] < 3: 1767 raise ValueError('Input array has less than 3 color channels') 1768 float_dtype = _supported_float_type(arr.dtype) 1769 if float_dtype == np.float32: 1770 _func = dtype.img_as_float32 1771 else: 1772 _func = dtype.img_as_float64 1773 return _func(arr, force_copy=force_copy) 1774 1775 1776@channel_as_last_axis() 1777def rgb2yuv(rgb, *, channel_axis=-1): 1778 """RGB to YUV color space conversion. 1779 1780 Parameters 1781 ---------- 1782 rgb : (..., 3, ...) array_like 1783 The image in RGB format. By default, the final dimension denotes 1784 channels. 1785 channel_axis : int, optional 1786 This parameter indicates which axis of the array corresponds to 1787 channels. 1788 1789 .. versionadded:: 0.19 1790 ``channel_axis`` was added in 0.19. 1791 1792 Returns 1793 ------- 1794 out : (..., 3, ...) ndarray 1795 The image in YUV format. Same dimensions as input. 1796 1797 Raises 1798 ------ 1799 ValueError 1800 If `rgb` is not at least 2-D with shape (..., 3, ...). 1801 1802 Notes 1803 ----- 1804 Y is between 0 and 1. Use YCbCr instead of YUV for the color space 1805 commonly used by video codecs, where Y ranges from 16 to 235. 1806 1807 References 1808 ---------- 1809 .. [1] https://en.wikipedia.org/wiki/YUV 1810 """ 1811 return _convert(yuv_from_rgb, rgb) 1812 1813 1814@channel_as_last_axis() 1815def rgb2yiq(rgb, *, channel_axis=-1): 1816 """RGB to YIQ color space conversion. 1817 1818 Parameters 1819 ---------- 1820 rgb : (..., 3, ...) array_like 1821 The image in RGB format. By default, the final dimension denotes 1822 channels. 1823 channel_axis : int, optional 1824 This parameter indicates which axis of the array corresponds to 1825 channels. 1826 1827 .. versionadded:: 0.19 1828 ``channel_axis`` was added in 0.19. 1829 1830 Returns 1831 ------- 1832 out : (..., 3, ...) ndarray 1833 The image in YIQ format. Same dimensions as input. 1834 1835 Raises 1836 ------ 1837 ValueError 1838 If `rgb` is not at least 2-D with shape (..., 3, ...). 1839 """ 1840 return _convert(yiq_from_rgb, rgb) 1841 1842 1843@channel_as_last_axis() 1844def rgb2ypbpr(rgb, *, channel_axis=-1): 1845 """RGB to YPbPr color space conversion. 1846 1847 Parameters 1848 ---------- 1849 rgb : (..., 3, ...) array_like 1850 The image in RGB format. By default, the final dimension denotes 1851 channels. 1852 channel_axis : int, optional 1853 This parameter indicates which axis of the array corresponds to 1854 channels. 1855 1856 .. versionadded:: 0.19 1857 ``channel_axis`` was added in 0.19. 1858 1859 Returns 1860 ------- 1861 out : (..., 3, ...) ndarray 1862 The image in YPbPr format. Same dimensions as input. 1863 1864 Raises 1865 ------ 1866 ValueError 1867 If `rgb` is not at least 2-D with shape (..., 3, ...). 1868 1869 References 1870 ---------- 1871 .. [1] https://en.wikipedia.org/wiki/YPbPr 1872 """ 1873 return _convert(ypbpr_from_rgb, rgb) 1874 1875 1876@channel_as_last_axis() 1877def rgb2ycbcr(rgb, *, channel_axis=-1): 1878 """RGB to YCbCr color space conversion. 1879 1880 Parameters 1881 ---------- 1882 rgb : (..., 3, ...) array_like 1883 The image in RGB format. By default, the final dimension denotes 1884 channels. 1885 channel_axis : int, optional 1886 This parameter indicates which axis of the array corresponds to 1887 channels. 1888 1889 .. versionadded:: 0.19 1890 ``channel_axis`` was added in 0.19. 1891 1892 Returns 1893 ------- 1894 out : (..., 3, ...) ndarray 1895 The image in YCbCr format. Same dimensions as input. 1896 1897 Raises 1898 ------ 1899 ValueError 1900 If `rgb` is not at least 2-D with shape (..., 3, ...). 1901 1902 Notes 1903 ----- 1904 Y is between 16 and 235. This is the color space commonly used by video 1905 codecs; it is sometimes incorrectly called "YUV". 1906 1907 References 1908 ---------- 1909 .. [1] https://en.wikipedia.org/wiki/YCbCr 1910 """ 1911 arr = _convert(ycbcr_from_rgb, rgb) 1912 arr[..., 0] += 16 1913 arr[..., 1] += 128 1914 arr[..., 2] += 128 1915 return arr 1916 1917 1918@channel_as_last_axis() 1919def rgb2ydbdr(rgb, *, channel_axis=-1): 1920 """RGB to YDbDr color space conversion. 1921 1922 Parameters 1923 ---------- 1924 rgb : (..., 3, ...) array_like 1925 The image in RGB format. By default, the final dimension denotes 1926 channels. 1927 channel_axis : int, optional 1928 This parameter indicates which axis of the array corresponds to 1929 channels. 1930 1931 .. versionadded:: 0.19 1932 ``channel_axis`` was added in 0.19. 1933 1934 Returns 1935 ------- 1936 out : (..., 3, ...) ndarray 1937 The image in YDbDr format. Same dimensions as input. 1938 1939 Raises 1940 ------ 1941 ValueError 1942 If `rgb` is not at least 2-D with shape (..., 3, ...). 1943 1944 Notes 1945 ----- 1946 This is the color space commonly used by video codecs. It is also the 1947 reversible color transform in JPEG2000. 1948 1949 References 1950 ---------- 1951 .. [1] https://en.wikipedia.org/wiki/YDbDr 1952 """ 1953 arr = _convert(ydbdr_from_rgb, rgb) 1954 return arr 1955 1956 1957@channel_as_last_axis() 1958def yuv2rgb(yuv, *, channel_axis=-1): 1959 """YUV to RGB color space conversion. 1960 1961 Parameters 1962 ---------- 1963 yuv : (..., 3, ...) array_like 1964 The image in YUV format. By default, the final dimension denotes 1965 channels. 1966 1967 Returns 1968 ------- 1969 out : (..., 3, ...) ndarray 1970 The image in RGB format. Same dimensions as input. 1971 1972 Raises 1973 ------ 1974 ValueError 1975 If `yuv` is not at least 2-D with shape (..., 3, ...). 1976 1977 References 1978 ---------- 1979 .. [1] https://en.wikipedia.org/wiki/YUV 1980 """ 1981 return _convert(rgb_from_yuv, yuv) 1982 1983 1984@channel_as_last_axis() 1985def yiq2rgb(yiq, *, channel_axis=-1): 1986 """YIQ to RGB color space conversion. 1987 1988 Parameters 1989 ---------- 1990 yiq : (..., 3, ...) array_like 1991 The image in YIQ format. By default, the final dimension denotes 1992 channels. 1993 channel_axis : int, optional 1994 This parameter indicates which axis of the array corresponds to 1995 channels. 1996 1997 .. versionadded:: 0.19 1998 ``channel_axis`` was added in 0.19. 1999 2000 Returns 2001 ------- 2002 out : (..., 3, ...) ndarray 2003 The image in RGB format. Same dimensions as input. 2004 2005 Raises 2006 ------ 2007 ValueError 2008 If `yiq` is not at least 2-D with shape (..., 3, ...). 2009 """ 2010 return _convert(rgb_from_yiq, yiq) 2011 2012 2013@channel_as_last_axis() 2014def ypbpr2rgb(ypbpr, *, channel_axis=-1): 2015 """YPbPr to RGB color space conversion. 2016 2017 Parameters 2018 ---------- 2019 ypbpr : (..., 3, ...) array_like 2020 The image in YPbPr format. By default, the final dimension denotes 2021 channels. 2022 channel_axis : int, optional 2023 This parameter indicates which axis of the array corresponds to 2024 channels. 2025 2026 .. versionadded:: 0.19 2027 ``channel_axis`` was added in 0.19. 2028 2029 Returns 2030 ------- 2031 out : (..., 3, ...) ndarray 2032 The image in RGB format. Same dimensions as input. 2033 2034 Raises 2035 ------ 2036 ValueError 2037 If `ypbpr` is not at least 2-D with shape (..., 3, ...). 2038 2039 References 2040 ---------- 2041 .. [1] https://en.wikipedia.org/wiki/YPbPr 2042 """ 2043 return _convert(rgb_from_ypbpr, ypbpr) 2044 2045 2046@channel_as_last_axis() 2047def ycbcr2rgb(ycbcr, *, channel_axis=-1): 2048 """YCbCr to RGB color space conversion. 2049 2050 Parameters 2051 ---------- 2052 ycbcr : (..., 3, ...) array_like 2053 The image in YCbCr format. By default, the final dimension denotes 2054 channels. 2055 channel_axis : int, optional 2056 This parameter indicates which axis of the array corresponds to 2057 channels. 2058 2059 .. versionadded:: 0.19 2060 ``channel_axis`` was added in 0.19. 2061 2062 Returns 2063 ------- 2064 out : (..., 3, ...) ndarray 2065 The image in RGB format. Same dimensions as input. 2066 2067 Raises 2068 ------ 2069 ValueError 2070 If `ycbcr` is not at least 2-D with shape (..., 3, ...). 2071 2072 Notes 2073 ----- 2074 Y is between 16 and 235. This is the color space commonly used by video 2075 codecs; it is sometimes incorrectly called "YUV". 2076 2077 References 2078 ---------- 2079 .. [1] https://en.wikipedia.org/wiki/YCbCr 2080 """ 2081 arr = ycbcr.copy() 2082 arr[..., 0] -= 16 2083 arr[..., 1] -= 128 2084 arr[..., 2] -= 128 2085 return _convert(rgb_from_ycbcr, arr) 2086 2087 2088@channel_as_last_axis() 2089def ydbdr2rgb(ydbdr, *, channel_axis=-1): 2090 """YDbDr to RGB color space conversion. 2091 2092 Parameters 2093 ---------- 2094 ydbdr : (..., 3, ...) array_like 2095 The image in YDbDr format. By default, the final dimension denotes 2096 channels. 2097 channel_axis : int, optional 2098 This parameter indicates which axis of the array corresponds to 2099 channels. 2100 2101 .. versionadded:: 0.19 2102 ``channel_axis`` was added in 0.19. 2103 2104 Returns 2105 ------- 2106 out : (..., 3, ...) ndarray 2107 The image in RGB format. Same dimensions as input. 2108 2109 Raises 2110 ------ 2111 ValueError 2112 If `ydbdr` is not at least 2-D with shape (..., 3, ...). 2113 2114 Notes 2115 ----- 2116 This is the color space commonly used by video codecs, also called the 2117 reversible color transform in JPEG2000. 2118 2119 References 2120 ---------- 2121 .. [1] https://en.wikipedia.org/wiki/YDbDr 2122 """ 2123 return _convert(rgb_from_ydbdr, ydbdr) 2124