@@ -1528,14 +1528,14 @@ def ebbi(red_agg: xr.DataArray,
15281528
15291529
15301530@ngjit
1531- def _normalize_data_cpu (data , min_val , max_val , pixel_max ):
1531+ def _normalize_data_cpu (data , min_val , max_val , pixel_max , contrast ):
15321532 out = np .zeros_like (data )
15331533 out [:] = np .nan
15341534
15351535 range_val = max_val - min_val
15361536 rows , cols = data .shape
15371537
1538- c = 10
1538+ c = contrast
15391539 th = .125
15401540
15411541 # check range_val to avoid dividing by zero
@@ -1550,35 +1550,37 @@ def _normalize_data_cpu(data, min_val, max_val, pixel_max):
15501550 return out
15511551
15521552
1553- def _normalize_data_numpy (data , pixel_max ):
1553+ def _normalize_data_numpy (data , pixel_max , contrast ):
15541554 min_val = np .nanmin (data )
15551555 max_val = np .nanmax (data )
1556- out = _normalize_data_cpu (data , min_val , max_val , pixel_max )
1556+ out = _normalize_data_cpu (data , min_val , max_val , pixel_max , contrast )
15571557 return out
15581558
15591559
1560- def _normalize_data_dask (data , pixel_max ):
1560+ def _normalize_data_dask (data , pixel_max , contrast ):
15611561 min_val = da .nanmin (data )
15621562 max_val = da .nanmax (data )
1563- out = da .map_blocks (_normalize_data_cpu , data , min_val , max_val , pixel_max ,
1564- meta = np .array (()))
1563+ out = da .map_blocks (
1564+ _normalize_data_cpu , data , min_val , max_val , pixel_max , contrast ,
1565+ meta = np .array (())
1566+ )
15651567 return out
15661568
15671569
1568- def _normalize_data_cupy (data , pixel_max ):
1570+ def _normalize_data_cupy (data , pixel_max , contrast ):
15691571 raise NotImplementedError ('Not Supported' )
15701572
15711573
1572- def _normalize_data_dask_cupy (data , pixel_max ):
1574+ def _normalize_data_dask_cupy (data , pixel_max , contrast ):
15731575 raise NotImplementedError ('Not Supported' )
15741576
15751577
1576- def _normalize_data (agg , pixel_max = 255.0 ):
1578+ def _normalize_data (agg , pixel_max = 255.0 , contrast = 10 ):
15771579 mapper = ArrayTypeFunctionMapping (numpy_func = _normalize_data_numpy ,
15781580 dask_func = _normalize_data_dask ,
15791581 cupy_func = _normalize_data_cupy ,
15801582 dask_cupy_func = _normalize_data_dask_cupy )
1581- out = mapper (agg )(agg .data , pixel_max )
1583+ out = mapper (agg )(agg .data , pixel_max , contrast )
15821584 return out
15831585
15841586
@@ -1609,56 +1611,107 @@ def _alpha(red, nodata=1):
16091611 return out
16101612
16111613
1612- def _true_color_numpy (r , g , b , nodata ):
1614+ def _true_color_numpy (r , g , b , nodata , contrast ):
16131615 a = np .where (np .logical_or (np .isnan (r ), r <= nodata ), 0 , 255 )
16141616
16151617 h , w = r .shape
16161618 out = np .zeros ((h , w , 4 ), dtype = np .uint8 )
16171619
16181620 pixel_max = 255
1619- out [:, :, 0 ] = (_normalize_data (r , pixel_max )).astype (np .uint8 )
1620- out [:, :, 1 ] = (_normalize_data (g , pixel_max )).astype (np .uint8 )
1621- out [:, :, 2 ] = (_normalize_data (b , pixel_max )).astype (np .uint8 )
1621+ out [:, :, 0 ] = (_normalize_data (r , pixel_max , contrast )).astype (np .uint8 )
1622+ out [:, :, 1 ] = (_normalize_data (g , pixel_max , contrast )).astype (np .uint8 )
1623+ out [:, :, 2 ] = (_normalize_data (b , pixel_max , contrast )).astype (np .uint8 )
16221624 out [:, :, 3 ] = a .astype (np .uint8 )
16231625 return out
16241626
16251627
1626- def _true_color_dask (r , g , b , nodata ):
1628+ def _true_color_dask (r , g , b , nodata , contrast ):
16271629 pixel_max = 255
1628- red = (_normalize_data (r , pixel_max )).astype (np .uint8 )
1629- green = (_normalize_data (g , pixel_max )).astype (np .uint8 )
1630- blue = (_normalize_data (b , pixel_max )).astype (np .uint8 )
1630+ red = (_normalize_data (r , pixel_max , contrast )).astype (np .uint8 )
1631+ green = (_normalize_data (g , pixel_max , contrast )).astype (np .uint8 )
1632+ blue = (_normalize_data (b , pixel_max , contrast )).astype (np .uint8 )
16311633
16321634 alpha = _alpha (r , nodata ).astype (np .uint8 )
16331635
16341636 out = da .stack ([red , green , blue , alpha ], axis = - 1 )
16351637 return out
16361638
16371639
1638- def _true_color_cupy (r , g , b , nodata ):
1640+ def _true_color_cupy (r , g , b , nodata , contrast ):
16391641 raise NotImplementedError ('Not Supported' )
16401642
16411643
1642- def _true_color_dask_cupy (r , g , b , nodata ):
1644+ def _true_color_dask_cupy (r , g , b , nodata , contrast ):
16431645 raise NotImplementedError ('Not Supported' )
16441646
16451647
1646- def true_color (r , g , b , nodata = 1 , name = 'true_color' ):
1648+ def true_color (r , g , b , nodata = 1 , contrast = 10.0 , name = 'true_color' ):
1649+ """
1650+ Create true color composite from a combination of red, green and
1651+ blue bands satellite images.
1652+
1653+ Parameters
1654+ ----------
1655+ r : xarray.DataArray
1656+ 2D array of red band data.
1657+ g : xarray.DataArray
1658+ 2D array of green band data.
1659+ b : xarray.DataArray
1660+ 2D array of blue band data.
1661+ nodata : int, float numeric value
1662+ Nodata value of input DataArrays.
1663+ contrast : int, float numeric value
1664+ Contrast controlling parameter for output image.
1665+ name : str, default='true_color'
1666+ Name of output DataArray.
1667+
1668+ Returns
1669+ -------
1670+ true_color_agg : xarray.DataArray of the same type as inputs
1671+ 3D array true color image with dims of [y, x, band].
1672+ All output attributes are copied from red band image.
1673+
1674+
1675+ Examples
1676+ --------
1677+ .. plot::
1678+ :include-source:
1679+
1680+ import matplotlib.pyplot as plt
1681+ from xrspatial.multispectral import true_color
1682+ from xrspatial.datasets import get_data
1683+
1684+ # Open Example Data
1685+ data = get_data('sentinel-2')
1686+
1687+ red = data['Red']
1688+ green = data['Green']
1689+ blue = data['Blue']
1690+
1691+ # Generate ARVI Aggregate Array
1692+ true_color_img = true_color(r=red, g=green, b=blue)
1693+ true_color_img.plot.imshow()
1694+ """
1695+
16471696 mapper = ArrayTypeFunctionMapping (numpy_func = _true_color_numpy ,
16481697 dask_func = _true_color_dask ,
16491698 cupy_func = _true_color_cupy ,
16501699 dask_cupy_func = _true_color_dask_cupy )
16511700 with warnings .catch_warnings ():
16521701 warnings .simplefilter ('ignore' )
1653- out = mapper (r )(r , g , b , nodata )
1702+ out = mapper (r )(r , g , b , nodata , contrast )
16541703
1655- # TODO: output metadata: coords, dims, atts
1704+ # TODO: output metadata: coords, dims, attrs
16561705 _dims = ['y' , 'x' , 'band' ]
1706+ _attrs = r .attrs
16571707 _coords = {'y' : r ['y' ],
16581708 'x' : r ['x' ],
16591709 'band' : [0 , 1 , 2 , 3 ]}
16601710
1661- return DataArray (out ,
1662- dims = _dims ,
1663- coords = _coords
1664- )
1711+ return DataArray (
1712+ out ,
1713+ name = name ,
1714+ dims = _dims ,
1715+ coords = _coords ,
1716+ attrs = _attrs ,
1717+ )
0 commit comments