def night_fog(self, fill_value=(0, 0, 0)): """Make a Night Fog RGB image composite. +--------------------+--------------------+--------------------+ | Channels | Temp | Gamma | +====================+====================+====================+ | IR12.0 - IR10.8 | -4 to 2 K | gamma 1 | +--------------------+--------------------+--------------------+ | IR10.8 - IR3.9 | 0 to 6 K | gamma 2.0 | +--------------------+--------------------+--------------------+ | IR10.8 | 243 to 293 K | gamma 1 | +--------------------+--------------------+--------------------+ """ self.check_channels(3.75, 10.8, 12.0) ch1 = self[12.0].data - self[10.8].data ch2 = self[10.8].data - self[3.75].data ch3 = self[10.8].data img = geo_image.GeoImage((ch1, ch2, ch3), self.area, self.time_slot, fill_value=fill_value, mode="RGB", crange=((-4, 2), (0, 6), (243, 293))) img.enhance(gamma=(1.0, 2.0, 1.0)) return img
def overview_sun(self, stretch='linear', gamma=1.6, fill_value=(0, 0, 0)): """Make an overview RGB image composite normalising with cosine to the sun zenith angle. """ self.check_channels('M05', 'M07', 'M15') lonlats = self['M15'].area.get_lonlats() red = self['M05'].sunzen_corr(self.time_slot, lonlats, limit=88., sunmask=95).data green = self['M07'].sunzen_corr(self.time_slot, lonlats, limit=88., sunmask=95).data blue = -self['M15'].data img = geo_image.GeoImage((red, green, blue), self.area, self.time_slot, fill_value=fill_value, mode="RGB") if stretch: img.enhance(stretch=stretch) if gamma: img.enhance(gamma=gamma) return img
def dust(self, fill_value=(0, 0, 0)): """Make a Dust RGB image composite. +--------------------+--------------------+--------------------+ | Channels | Temp | Gamma | +====================+====================+====================+ | IR12.0 - IR10.8 | -4 to 2 K | gamma 1 | +--------------------+--------------------+--------------------+ | IR10.8 - IR8.7 | 0 to 15 K | gamma 2.5 | +--------------------+--------------------+--------------------+ | IR10.8 | 261 to 289 K | gamma 1 | +--------------------+--------------------+--------------------+ """ self.check_channels(8.7, 10.8, 12.0) ch1 = self[12.0].data - self[10.8].data ch2 = self[10.8].data - self[8.7].data ch3 = self[10.8].data img = geo_image.GeoImage((ch1, ch2, ch3), self.area, self.time_slot, fill_value=fill_value, mode="RGB", crange=((-4, 2), (0, 15), (261, 289))) img.enhance(gamma=(1.0, 2.5, 1.0)) return img
def natural(self): """Make a Natural Colors RGB image composite from M-bands only. """ self.check_channels('M05', 'M06', 'M07', 'M10') ch1 = self['M10'].check_range() ch2 = self['M07'].check_range() ch3 = self['M05'].check_range() ch2b = self['M06'].check_range() ch2 = np.ma.where(ch2.mask, ch2b, ch2) common_mask = np.logical_or(ch1.mask, ch2.mask) common_mask = np.logical_or(common_mask, ch3.mask) ch1.mask = common_mask ch2.mask = common_mask ch3.mask = common_mask img = geo_image.GeoImage((ch1, ch2, ch3), self.area, self.time_slot, fill_value=(0, 0, 0), mode="RGB", crange=((0, 90), (0, 90), (0, 90))) img.enhance(gamma=1.8) return img
def overview(self, stretch='crude', gamma=1.6, fill_value=(0, 0, 0)): """Make an overview RGB image composite. +--------------------+--------------------+ | Channels | Gamma (default) | +====================+====================+ | VIS0.6 | gamma 1.6 | +--------------------+--------------------+ | VIS0.8 | gamma 1.6 | +--------------------+--------------------+ | IR10.8 (inverted) | gamma 1.6 | +--------------------+--------------------+ Linear stretch without clipping is applied. """ self.check_channels(0.635, 0.85, 10.8) ch1 = self[0.635].check_range() ch2 = self[0.85].check_range() ch3 = -self[10.8].data img = geo_image.GeoImage((ch1, ch2, ch3), self.area, self.time_slot, fill_value=fill_value, mode="RGB") if stretch: img.enhance(stretch=stretch) if gamma: img.enhance(gamma=gamma) return img
def snow(self): """Make a 'Snow' RGB as suggested in the MSG interpretation guide (rgbpart04.ppt). It is kind of special as it requires the derivation of the daytime component of the mixed Terrestrial/Solar 3.9 micron channel. Furthermore the sun zenith angle is used. """ self.refl39_chan() self.check_channels("_IR39Refl", 0.8, 1.63, 3.75) # We calculate the sun zenith angle again. Should be reused if already # calculated/available... # FIXME! lonlats = self[3.9].area.get_lonlats() sunz = sza(self.time_slot, lonlats[0], lonlats[1]) sunz = np.ma.masked_outside(sunz, 0.0, 88.0) sunzmask = sunz.mask sunz = sunz.filled(88.) costheta = np.cos(np.deg2rad(sunz)) red = np.ma.masked_where(sunzmask, self[0.8].data / costheta) green = np.ma.masked_where(sunzmask, self[1.6].data / costheta) img = geo_image.GeoImage((red, green, self['_IR39Refl'].data), self.area, self.time_slot, crange=((0, 100), (0, 70), (0, 30)), fill_value=None, mode="RGB") img.gamma((1.7, 1.7, 1.7)) return img
def oca(self, fieldname): """Make an OCA cloud parameter image""" palette = oca_palette_func[fieldname]() data = getattr(getattr(self['OCA'], fieldname), 'data') if fieldname in ['scenetype']: data = data.astype('uint8') elif fieldname in ['ul_ctp', 'll_ctp']: data = (22. - data / 5000.).astype('Int16') elif fieldname in ['reff']: data = (data * 1000000. + 0.5).astype('uint8') data.fill_value = 255 elif fieldname in ['ul_cot', 'll_cot']: data = np.ma.exp(data * np.ma.log(10)) max_value = palettes.CPP_COLORS['cot'].breaks[-1][0] data.fill_value = 255 no_data = 255 # FIXME! data = _arrange_log_data(data.filled(), max_value, no_data) else: raise NotImplementedError( "No imagery for parameter %s implemented yet...", fieldname) img = geo_image.GeoImage(data, self.area, self.time_slot, fill_value=(0), mode="P", palette=palette) return img
def test_save_geotiff_fill_value(self, mock_write_channels, gtbn, gui32, gui16, gby, gf, gad, spaceref): """Save to geotiff format. """ # source image data, masked data but only zeros self.data = np.ma.zeros((512, 512), dtype=np.uint8) self.data.mask = np.zeros(self.data.shape, dtype=bool) self.data.mask[0, 0] = True self.img = geo_image.GeoImage(self.data, area="euro", time_slot=self.time_slot) self.img.fill_value = [0] raster = gtbn.return_value self.img.geotiff_save("test.tif", 0, None, {"BLA": "09"}, 256) gtbn.assert_called_once_with("GTiff") raster.Create.assert_called_once_with( "test.tif", self.data.shape[0], self.data.shape[1], 1, gby, ["BLA=09", 'TILED=YES', 'BLOCKXSIZE=256', 'BLOCKYSIZE=256']) dst_ds = raster.Create.return_value self.assertEquals(mock_write_channels.call_count, 1) self.assertEquals(mock_write_channels.call_args[0][0], dst_ds) self.assertEquals(mock_write_channels.call_args[0][2], 255) self.assertTrue(mock_write_channels.call_args[0][3], self.img.fill_value) self.assertTrue( np.all(mock_write_channels.call_args[0][1] == self.data))
def dnb_overview(self, stretch='linear'): """Make a nighttime overview RGB image composite from VIIRS DNB and M bands. """ self.check_channels('DNB', 'M15') lonlats = self['M15'].area.get_lonlats() if sza: sunz = sza(self.time_slot, lonlats[0], lonlats[1]) sunz = np.ma.masked_outside(sunz, 103, 180) sunzmask = sunz.mask red = np.ma.masked_where(sunzmask, self['DNB'].data) green = np.ma.masked_where(sunzmask, self['DNB'].data) blue = np.ma.masked_where(sunzmask, -self['M15'].data) else: LOG.warning("No masking of solar contaminated pixels performed!") red = self['DNB'].data green = self['DNB'].data blue = -self['M15'].data img = geo_image.GeoImage((red, green, blue), self.area, self.time_slot, fill_value=None, mode="RGB") img.enhance(stretch=stretch) return img
def cloudtop(self, stretch=(0.005, 0.005), gamma=None): """Make a Cloudtop RGB image composite. +--------------------+--------------------+ | Channels | Gamma | +====================+====================+ | IR3.9 (inverted) | gamma 1 | +--------------------+--------------------+ | IR10.8 (inverted) | gamma 1 | +--------------------+--------------------+ | IR12.0 (inverted) | gamma 1 | +--------------------+--------------------+ Linear stretch with 0.5 % clipping at both ends. """ self.check_channels(3.75, 10.8, 12.0) ch1 = -self[3.75].data ch2 = -self[10.8].data ch3 = -self[12.0].data img = geo_image.GeoImage((ch1, ch2, ch3), self.area, self.time_slot, fill_value=(0, 0, 0), mode="RGB") if stretch: img.enhance(stretch=stretch) if gamma: img.enhance(gamma=gamma) return img
def red_snow(self, fill_value=(0, 0, 0)): """Make a Red Snow RGB image composite. +--------------------+--------------------+ | Channels | Gamma | +====================+====================+ | VIS0.6 | gamma 1.6 | +--------------------+--------------------+ | IR1.6 | gamma 1.6 | +--------------------+--------------------+ | IR10.8 (inverted) | gamma 1.6 | +--------------------+--------------------+ Linear stretch without clipping. """ self.check_channels(0.635, 1.63, 10.8) ch1 = self[0.635].check_range() ch2 = self[1.63].check_range() ch3 = -self[10.8].data img = geo_image.GeoImage((ch1, ch2, ch3), self.area, self.time_slot, fill_value=fill_value, mode="RGB") img.enhance(stretch="crude") return img
def convection(self, fill_value=(0, 0, 0)): """Make a Severe Convection RGB image composite. +--------------------+--------------------+--------------------+ | Channels | Span | Gamma | +====================+====================+====================+ | WV6.2 - WV7.3 | -30 to 0 K | gamma 1 | +--------------------+--------------------+--------------------+ | IR3.9 - IR10.8 | 0 to 55 K | gamma 1 | +--------------------+--------------------+--------------------+ | IR1.6 - VIS0.6 | -70 to 20 % | gamma 1 | +--------------------+--------------------+--------------------+ """ self.check_channels(0.635, 1.63, 3.75, 6.7, 7.3, 10.8) ch1 = self[6.7].data - self[7.3].data ch2 = self[3.75].data - self[10.8].data ch3 = self[1.63].check_range() - self[0.635].check_range() img = geo_image.GeoImage((ch1, ch2, ch3), self.area, self.time_slot, fill_value=fill_value, mode="RGB", crange=((-30, 0), (0, 55), (-70, 20))) return img
def chlorophyll(self, stretch=None): """ From http://oceancolor.gsfc.nasa.gov/REPROCESSING/R2009/ocv6/ * Rrs1 = blue wavelength Rrs (e.g., 443, 490, or 510-nm) * Rrs2 = green wavelength Rrs (e.g., 547, 555, or 565-nm) * X = log10(Rrs1 / Rrs2) * chlor_a = 10^(a0 + a1*X + a2*X^2 + a3*X^3 + a4*X^4) sensor default * blue green a0 a1 a2 a3 a4 OC3V VIIRS Y 443>486 550 0.2228 -2.4683 1.5867 -0.4275 -0.7768 blue: M02(445)>M03(488) green: M04(555) * X = log10(max(M2, M3)/M4) """ self.check_channels("M02", "M03", "M04") a0, a1, a2, a3, a4 = (0.2228, -2.4683, 1.5867, -0.4275, -0.7768) # X = np.maximum(self["M02"].data, self["M03"].data)/self["M04"].data X = self["M02"].data / self["M04"].data X = np.log10(X) chlor_a = 10**(a0 + a1 * X + a2 * (X**2) + a3 * (X**3) + a4 * (X**4)) print 'chlor_a:', chlor_a.min(), chlor_a.mean(), chlor_a.max() img = geo_image.GeoImage(chlor_a, self.area, self.time_slot, fill_value=0, mode="L") if stretch: img.enhance(stretch=stretch) return img
def airmass(self, fill_value=(0, 0, 0)): """Make an airmass RGB image composite. +--------------------+--------------------+--------------------+ | Channels | Temp | Gamma | +====================+====================+====================+ | WV6.2 - WV7.3 | -25 to 0 K | gamma 1 | +--------------------+--------------------+--------------------+ | IR9.7 - IR10.8 | -40 to 5 K | gamma 1 | +--------------------+--------------------+--------------------+ | WV6.2 | 243 to 208 K | gamma 1 | +--------------------+--------------------+--------------------+ """ self.check_channels(6.7, 7.3, 9.7, 10.8) ch1 = self[6.7].data - self[7.3].data ch2 = self[9.7].data - self[10.8].data ch3 = self[6.7].data img = geo_image.GeoImage((ch1, ch2, ch3), self.area, self.time_slot, fill_value=fill_value, mode="RGB", crange=((-25, 0), (-40, 5), (243, 208))) return img
def natural(self, stretch=None, gamma=1.8, fill_value=(0, 0, 0)): """Make a Natural Colors RGB image composite. +--------------------+--------------------+--------------------+ | Channels | Range (reflectance)| Gamma (default) | +====================+====================+====================+ | IR1.6 | 0 - 90 | gamma 1.8 | +--------------------+--------------------+--------------------+ | VIS0.8 | 0 - 90 | gamma 1.8 | +--------------------+--------------------+--------------------+ | VIS0.6 | 0 - 90 | gamma 1.8 | +--------------------+--------------------+--------------------+ """ self.check_channels(0.635, 0.85, 1.63) ch1 = self[1.63].check_range() ch2 = self[0.85].check_range() ch3 = self[0.635].check_range() img = geo_image.GeoImage((ch1, ch2, ch3), self.area, self.time_slot, fill_value=fill_value, mode="RGB", crange=((0, 90), (0, 90), (0, 90))) if stretch: img.enhance(stretch=stretch) if gamma: img.enhance(gamma=gamma) return img
def ash(self, fill_value=(0, 0, 0)): """Make a Ash RGB image composite. +--------------------+--------------------+--------------------+ | Channels | Temp | Gamma | +====================+====================+====================+ | IR12.0 - IR10.8 | -4 to 2 K | gamma 1 | +--------------------+--------------------+--------------------+ | IR10.8 - IR8.7 | -4 to 5 K | gamma 1 | +--------------------+--------------------+--------------------+ | IR10.8 | 243 to 303 K | gamma 1 | +--------------------+--------------------+--------------------+ """ self.check_channels(8.7, 10.8, 12.0) ch1 = self[12.0].data - self[10.8].data ch2 = self[10.8].data - self[8.7].data ch3 = self[10.8].data img = geo_image.GeoImage((ch1, ch2, ch3), self.area, self.time_slot, fill_value=fill_value, mode="RGB", crange=((-4, 2), (-4, 5), (243, 303))) return img
def setUp(self): """Setup the test. """ self.time_slot = datetime.datetime(2009, 10, 8, 14, 30) self.data = np.zeros((512, 512), dtype=np.uint8) self.img = geo_image.GeoImage(self.data, area="euro", time_slot=self.time_slot)
def dnb(self, stretch="histogram"): """Make a black and white image of the Day-Night band.""" self.check_channels('DNB') img = geo_image.GeoImage(self['DNB'].data, self.area, self.time_slot, fill_value=0, mode="L") if stretch: img.enhance(stretch=stretch) return img
def hr_ir108(self): """Make a black and white image of the IR 10.8um channel (320m). """ self.check_channels("I05") img = geo_image.GeoImage(self["I05"].data, self.area, self.time_slot, fill_value=0, mode="L", crange=(-70 + 273.15, 57.5 + 273.15)) img.enhance(inverse=True) return img
def channel_image(self, channel, fill_value=0): """Make a black and white image of the *channel*. Linear stretch without clipping is applied by default. """ self.check_channels(channel) img = geo_image.GeoImage(self[channel].data, self[channel].area, self.time_slot, fill_value=fill_value, mode="L") img.enhance(stretch="crude") return img
def _dwd_create_single_channel_image(self, chn, sun_zenith_angle_correction=True, backup_orig_data=False): """Creates a calibrated and corrected single channel black/white image. Data calibration: HRV, VIS channels: albedo 0 - 125 % IR channels: temperature -87.5 - +40 C Data correction: HRV, VIS channels: sun zenith angle correction IR channels: atmospheric correction (not implemented yet) """ if not isinstance(chn, basestring): return None self.check_channels(chn) # apply calibrations and corrections on channels if not self._dwd_channel_preparation(chn, sun_zenith_angle_correction, backup_orig_data=backup_orig_data): return None if self._is_solar_channel(chn): return geo_image.GeoImage(self[chn].data, self.area, get_first(self.time_slot), fill_value=0, mode="L", crange=(0, 125)) return geo_image.GeoImage(self[chn].data, self.area, get_first(self.time_slot), fill_value=0, mode="L", crange=(40, -87.5))
def test_save_geotiff_fill_value_subst(self, mock_write_channels, gtbn, gui32, gui16, gby, gf, gad, spaceref): """Save to geotiff format. """ # source image data, masked data but only zeros self.data = np.ma.zeros((512, 512), dtype=np.uint8) self.data.mask = np.zeros(self.data.shape, dtype=bool) self.data.mask[0, 0] = True self.img = geo_image.GeoImage(self.data, area="euro", time_slot=self.time_slot) self.img.fill_value = [0] # not masked zeros should be replaced by ones fill_value_substitution = 1 data_with_subst = np.ma.copy(self.data) np.place(data_with_subst, self.data == self.img.fill_value[0], 1) raster = gtbn.return_value self.img.geotiff_save("test.tif", 0, None, {"BLA": "09"}, 256, writer_options={ writer_opts.WR_OPT_FILL_VALUE_SUBST: fill_value_substitution }) gtbn.assert_called_once_with("GTiff") raster.Create.assert_called_once_with( "test.tif", self.data.shape[0], self.data.shape[1], 1, gby, ["BLA=09", 'TILED=YES', 'BLOCKXSIZE=256', 'BLOCKYSIZE=256']) dst_ds = raster.Create.return_value self.assertEquals(mock_write_channels.call_count, 1) self.assertEquals(mock_write_channels.call_args[0][0], dst_ds) self.assertEquals(mock_write_channels.call_args[0][2], 255) self.assertTrue(mock_write_channels.call_args[0][3], self.img.fill_value) # all zeros should be replaced by ones self.assertTrue( np.all(mock_write_channels.call_args[0][1] == data_with_subst))
def __call__(self, *channels, **keys): """Build a geoimage. e.g.: img = l.image(0.6, 0.8, -10.8, mode="RGB") """ data = [] area = None inv = [] new_channels = [] for channel in channels: if isinstance(channel, str): if channel.startswith("-"): inv.append(True) channel = channel[1:] else: inv.append(False) else: if channel < 0: inv.append(True) channel = -channel else: inv.append(False) new_channels.append(channel) data.append(self[channel].data) new_area = self[channel].area if area and (new_area != area): raise ValueError("Channels should have the same area") else: area = new_area self.check_channels(*new_channels) img = geo_image.GeoImage(data, area=area, time_slot=self.time_slot, fill_value=keys.get("fill_value", None), crange=keys.get("crange", None), mode=keys.get("mode", None)) img.enhance(inverse=inv, gamma=keys.get("gamma", 1.0), stretch=keys.get("stretch", "no")) return img
def wv_low(self): """Make a black and white image of the IR 7.3um channel. Channel data inverted and a linear stretch is applied with 0.5 % clipping at both ends. """ self.check_channels(7.3) img = geo_image.GeoImage(self[7.3].data, self.area, self.time_slot, fill_value=0, mode="L") img.enhance(inverse=True, stretch="linear") return img
def generate_rgb(image, r, g, b): image.check_channels(r, g, b) ch1 = image[r].data ch2 = image[g].data ch3 = image[b].data img = geo_image.GeoImage((ch1, ch2, ch3), image.area, image.time_slot, mode="RGB") #img.enhance(stretch = "crude") return img
def _dwd_create_RGB_image(self, channels, cranges): """Returns an RGB image of the given channel data and color ranges. """ if not isinstance(channels, (list, tuple, set)) and \ not isinstance(cranges, (tuple, list, set)) and \ not len(channels) == len(cranges) and \ not (len(channels) == 3 or len(channels == 4)): raise ValueError("Channels and color ranges must be list/tuple/set \ and they must have the same length of 3 or 4 elements") if len(channels) == 3: return geo_image.GeoImage(channels, self.area, get_first(self.time_slot), fill_value=(0, 0, 0), mode="RGB", crange=cranges) if len(channels) == 4: return geo_image.GeoImage(channels, self.area, get_first(self.time_slot), fill_value=(0, 0, 0, 0), mode="RGBA", crange=cranges)
def dnb_rgb(self, stretch="linear"): """Make a RGB Day-Night band using M15 as blue.""" self.check_channels('DNB', 'M15') ch1 = self['DNB'].data ch2 = self['DNB'].data ch3 = -self['M15'].data img = geo_image.GeoImage((ch1, ch2, ch3), self.area, self.time_slot, fill_value=(0, 0, 0), mode="RGB") if stretch: img.enhance(stretch=stretch) return img
def truecolorTest(image): image.check_channels('I01', 'M02', 'M04') ch1 = image['I01'].data ch2 = image['M04'].data ch3 = image['M02'].data img = geo_image.GeoImage((ch1, ch2, ch3), image.area, image.time_slot, fill_value=(0, 0, 0), mode="RGB") img.enhance(stretch="crude") return img
def ir108(self): """Make a black and white image of the IR 10.8um channel. Channel is inverted. Temperature range from -70 °C (white) to +57.5 °C (black) is shown. """ self.check_channels(10.8) img = geo_image.GeoImage(self[10.8].data, self.area, self.time_slot, fill_value=0, mode="L", crange=(-70 + 273.15, 57.5 + 273.15)) img.enhance(inverse=True) return img
def ash(self): """Make a Ash RGB image composite. """ self.check_channels('M14', 'M15', 'M16') ch1 = self['M16'].data - self['M15'].data ch2 = self['M15'].data - self['M14'].data ch3 = self['M15'].data img = geo_image.GeoImage((ch1, ch2, ch3), self.area, self.time_slot, fill_value=(0, 0, 0), mode="RGB", crange=((-4, 2), (-4, 5), (243, 303))) return img