def fix_style(layer: QgsRasterLayer) -> None: ''' Sets a sensible default style for loaded raster layers and fix up other issues. By default QGIS uses MultiBandColor renderer if there are multiple bands. (See https://github.com/qgis/QGIS/blob/final-3_0_1/src/core/raster/qgsrasterlayer.cpp#L729). This function picks the right renderers, either a palette or gray-band renderer. Also, fake categories/classes that exist due to GDAL limitations are removed. Search for UNUSED_CATEGORY_LABEL to find details. ''' provider = layer.dataProvider() # type: QgsRasterDataProvider color_interp = provider.colorInterpretation(1) is_palette = color_interp == QgsRaster.PaletteIndex # See the link below on how to create default-type renderers. # https://github.com/qgis/QGIS/blob/final-3_0_1/src/core/raster/qgsrasterrendererregistry.cpp#L128-L137 renderer = layer.renderer() # type: QgsRasterRenderer new_renderer = None if is_palette: # For paletted layers we always re-create the renderer even if it is already a # paletted renderer. This is because we need to remove the UNUSED categories. color_table = provider.colorTable(1) classes = QgsPalettedRasterRenderer.colorTableToClassData(color_table) if not any(c.label == gis4wrf.core.UNUSED_CATEGORY_LABEL for c in classes): return new_classes = filter(lambda c: c.label != gis4wrf.core.UNUSED_CATEGORY_LABEL, classes) new_renderer = QgsPalettedRasterRenderer(renderer.input(), 1, new_classes) layer.setRenderer(new_renderer) else: if not isinstance(renderer, QgsSingleBandGrayRenderer): new_renderer = QgsSingleBandGrayRenderer(renderer.input(), 1) layer.setRenderer(new_renderer) layer.setDefaultContrastEnhancement() # must be *after* setting the renderer
def apply_symbology(rlayer, rband, symbology): """Apply symbology to raster layer using Paletted/Unique values""" paletted_classes = [] for name, value, color in symbology: paletted_classes.append( QgsPalettedRasterRenderer.Class( value, QColor(color[0], color[1], color[2], color[3]), name)) renderer = QgsPalettedRasterRenderer(rlayer.dataProvider(), rband, paletted_classes) # Set renderer for raster layer rlayer.setRenderer(renderer) # set the opacity to the layer based on the opacity set in active layer UI from ThRasE.gui.main_dialog import ThRasEDialog active_layer = next((active_layer for active_layer in [ al for als in [ view_widget.active_layers for view_widget in ThRasEDialog.view_widgets ] for al in als ] if active_layer.layer == rlayer), False) if active_layer: if rlayer.type() == QgsMapLayer.VectorLayer: rlayer.setOpacity(active_layer.opacity / 100.0) else: rlayer.renderer().setOpacity(active_layer.opacity / 100.0) # Repaint if hasattr(rlayer, 'setCacheImage'): rlayer.setCacheImage(None) rlayer.triggerRepaint()
def homogenize_colors(raster_layer) -> bool: """Loops through labels in order and assign the color of the first label occourrence to all other classes having the same label. :param raster_layer: raster layer :type raster_layer: QgsRasterLayer :return: TRUE if the renderer has been reset :rtype: bool """ require_changes = False if can_create_rat(raster_layer): if isinstance(raster_layer.renderer(), QgsPalettedRasterRenderer): color_map = {} classes = raster_layer.renderer().classes() for klass in classes: if klass.label not in color_map: color_map[klass.label] = klass.color elif klass.color != color_map[klass.label]: klass.color = color_map[klass.label] require_changes = True if require_changes: renderer = QgsPalettedRasterRenderer( raster_layer.dataProvider(), raster_layer.renderer().band(), classes) elif isinstance(raster_layer.renderer(), QgsSingleBandPseudoColorRenderer): shader = raster_layer.renderer().shader() if shader: colorRampShaderFcn = shader.rasterShaderFunction() if colorRampShaderFcn: color_map = {} items = colorRampShaderFcn.colorRampItemList() for item in items: if item.label not in color_map: color_map[item.label] = item.color elif item.color != color_map[item.label]: item.color = color_map[item.label] require_changes = True if require_changes: colorRampShaderFcn.setColorRampItemList(items) if require_changes: # raster_layer.setRenderer(renderer) raster_layer.triggerRepaint() return require_changes
def test_can_create_rat(self): raster_layer = QgsRasterLayer(os.path.join(os.path.dirname( __file__), 'data', 'NBS_US5PSMBE_20200923_0_generalized_p.tiff'), 'rat_test', 'gdal') self.assertFalse(can_create_rat(raster_layer)) renderer = QgsPalettedRasterRenderer(raster_layer.dataProvider(), 1, []) raster_layer.setRenderer(renderer) self.assertTrue(can_create_rat(raster_layer))
def testPalettedBand(self): """ test paletted raster render band""" path = os.path.join(unitTestDataPath(), 'landsat_4326.tif') info = QFileInfo(path) base_name = info.baseName() layer = QgsRasterLayer(path, base_name) self.assertTrue(layer.isValid(), 'Raster not loaded: {}'.format(path)) renderer = QgsPalettedRasterRenderer(layer.dataProvider(), 2, [ QgsPalettedRasterRenderer.Class(137, QColor(0, 255, 0), 'class 2'), QgsPalettedRasterRenderer.Class(138, QColor(255, 0, 0), 'class 1'), QgsPalettedRasterRenderer.Class(139, QColor(0, 0, 255), 'class 1') ]) layer.setRenderer(renderer) ms = QgsMapSettings() ms.setLayers([layer]) ms.setExtent(layer.extent()) checker = QgsRenderChecker() checker.setControlName("expected_paletted_renderer_band2") checker.setMapSettings(ms) self.assertTrue(checker.runTest("expected_paletted_renderer_band2"), "Paletted rendering test failed") renderer = QgsPalettedRasterRenderer(layer.dataProvider(), 3, [ QgsPalettedRasterRenderer.Class(120, QColor(0, 255, 0), 'class 2'), QgsPalettedRasterRenderer.Class(123, QColor(255, 0, 0), 'class 1'), QgsPalettedRasterRenderer.Class(124, QColor(0, 0, 255), 'class 1') ]) layer.setRenderer(renderer) ms = QgsMapSettings() ms.setLayers([layer]) ms.setExtent(layer.extent()) checker = QgsRenderChecker() checker.setControlName("expected_paletted_renderer_band3") checker.setMapSettings(ms) self.assertTrue(checker.runTest("expected_paletted_renderer_band3"), "Paletted rendering test failed")
def _test(is_sidecar): QgsProject.instance().removeAllMapLayers() tmp_dir = QTemporaryDir() shutil.copy(os.path.join(os.path.dirname( __file__), 'data', 'raster-palette.tif'), tmp_dir.path()) rat_path = os.path.join( tmp_dir.path(), 'raster-palette.tif' + ('.vat.dbf' if is_sidecar else '.aux.xml')) self.assertFalse(os.path.exists(rat_path)) raster_layer = QgsRasterLayer(os.path.join(tmp_dir.path(), 'raster-palette.tif'), 'rat_test', 'gdal') QgsProject.instance().addMapLayer(raster_layer) self.assertTrue(raster_layer.isValid()) self.assertFalse(can_create_rat(raster_layer)) self.assertFalse(has_rat(raster_layer)) band = 1 # Set renderer ramp = QgsRandomColorRamp() renderer = QgsPalettedRasterRenderer( raster_layer.dataProvider(), 1, QgsPalettedRasterRenderer.classDataFromRaster(raster_layer.dataProvider(), band, ramp)) raster_layer.setRenderer(renderer) self.assertTrue(can_create_rat(raster_layer)) rat = create_rat_from_raster(raster_layer, is_sidecar, rat_path) self.assertTrue(rat.isValid()) self.assertEqual(rat.data['Count'], [78, 176, 52]) self.assertEqual(rat.data['Value'], [ 2.257495271713565, 7.037407804695962, 270.4551067154352]) self.assertEqual(rat.data['A'], [255, 255, 255]) self.assertNotEqual(rat.data['R'], [0, 0, 0]) self.assertTrue(rat.save(band)) self.assertTrue(os.path.exists(rat_path)) QgsProject.instance().removeMapLayers([raster_layer.id()]) del (raster_layer) self.assertTrue(os.path.exists(rat_path)) QgsApplication.processEvents() # Reload and check raster_layer = QgsRasterLayer(os.path.join( tmp_dir.path(), 'raster-palette.tif'), 'rat_test', 'gdal') self.assertTrue(raster_layer.isValid()) self.assertFalse(can_create_rat(raster_layer)) self.assertTrue(has_rat(raster_layer), rat_path) os.unlink(rat_path)
def mkRendererPalettedGnYlRd(layer): pr = layer.dataProvider() # colorRamp = getColorBrewColorRampGnYlRd() # colorRamp = getPresetGnYlRd() # colorRamp = QgsGradientColorRamp(color1=redCol,color2=greenCol) # colorRamp = QgsCptCityColorRamp(schemeName='cb/div/GnYlRd_',variantName='11') colorRamp = getGradientColorRampRdYlGn() classData = QgsPalettedRasterRenderer.classDataFromRaster(pr, 1, ramp=colorRamp) renderer = QgsPalettedRasterRenderer(pr, 1, classes=classData) return renderer
def raster_apply_unique_value_renderer(raster_layer, band_num=1, n_decimals=0, color_ramp='', invert=False): """ Apply a random colour to each each unique value for a raster band. In some case the unique values are floating, n_decimals allows these to be rounded for display Args: raster_layer (QgsRasterLayer): input raster layer band_num (int): the band number used to determine unique values n_decimals (int): number of decimals to round values to invert (bool) : Invert the color ramp before applying - Not implemented """ qgsStyles = QgsStyle().defaultStyle() # check to see if the colour ramp is installed if color_ramp != '' and color_ramp not in qgsStyles.colorRampNames(): raise ValueError( 'PAT symbology does not exist. See user manual for install instructions' ) if color_ramp == '': ramp = QgsRandomColorRamp() else: # get an existing color ramp ramp = qgsStyles.colorRamp(color_ramp) # generate a list of unique values and their colours. uniq_classes = QgsPalettedRasterRenderer.classDataFromRaster( raster_layer.dataProvider(), band_num, ramp) # Create the renderer renderer = QgsPalettedRasterRenderer(raster_layer.dataProvider(), band_num, uniq_classes) # assign the renderer to the raster layer: raster_layer.setRenderer(renderer) # refresh raster_layer.triggerRepaint()
def test_homogenize_colors(self): """Test color homogenize""" tmp_dir = QTemporaryDir() shutil.copy( os.path.join(os.path.dirname(__file__), 'data', 'ExistingVegetationTypes_sample.img'), tmp_dir.path()) shutil.copy( os.path.join(os.path.dirname(__file__), 'data', 'ExistingVegetationTypes_sample.img.vat.dbf'), tmp_dir.path()) raster_layer = QgsRasterLayer( os.path.join(tmp_dir.path(), 'ExistingVegetationTypes_sample.img'), 'rat_test', 'gdal') rat = get_rat(raster_layer, 1) self.assertTrue(rat.isValid()) unique_labels = rat_classify(raster_layer, 1, rat, 'EVT_NAME') if Qgis.QGIS_VERSION_INT >= 31800: self.assertEqual(unique_labels, list(range(1, 60))) else: self.assertEqual(unique_labels, list(range(0, 59))) # Get color map color_map = {} for klass in raster_layer.renderer().classes(): color_map[klass.value] = klass.color.name() # Two different colors for EVT_NAME self.assertEqual(color_map[11.0], '#0000ff') self.assertEqual(color_map[12.0], '#9fa1f0') # Reclass unique_labels = rat_classify(raster_layer, 1, rat, 'NVCSCLASS') if Qgis.QGIS_VERSION_INT >= 31800: self.assertEqual(unique_labels, [1, 3, 5, 6, 7, 22, 31, 41, 44]) else: self.assertEqual(unique_labels, [0, 2, 4, 5, 6, 21, 30, 40, 43]) color_map = {} for klass in raster_layer.renderer().classes(): color_map[klass.value] = klass.color.name() # Same colors for NVCSCLASS self.assertEqual(color_map[11.0], '#0000ff') self.assertEqual(color_map[12.0], '#0000ff') # Manually change one color classes = raster_layer.renderer().classes() classes[0].color = QColor(10, 20, 30) renderer = QgsPalettedRasterRenderer(raster_layer.dataProvider(), 1, classes) raster_layer.setRenderer(renderer) color_map = {} for klass in raster_layer.renderer().classes(): color_map[klass.value] = klass.color.name() # Manually changed colors for NVCSCLASS self.assertEqual(color_map[11.0], '#0a141e') self.assertEqual(color_map[12.0], '#0000ff') self.assertTrue(homogenize_colors(raster_layer)) color_map = {} for klass in raster_layer.renderer().classes(): color_map[klass.value] = klass.color.name() # Same colors for NVCSCLASS self.assertEqual(color_map[11.0], '#0a141e') self.assertEqual(color_map[12.0], '#0a141e')
result_dataset = None fileInfo = QFileInfo(result_path) baseName = fileInfo.baseName() layer = QgsRasterLayer(result_path, baseName) pcolor = [] pcolor.append(QgsColorRampShader.ColorRampItem(1, QColor("#d2ca97"))) pcolor.append(QgsColorRampShader.ColorRampItem(2, QColor("#f7f7f7"))) pcolor.append(QgsColorRampShader.ColorRampItem(3, QColor("#a1d99b"))) pcolor.append(QgsColorRampShader.ColorRampItem(4, QColor("#41ab5d"))) pcolor.append(QgsColorRampShader.ColorRampItem(5, QColor("#006d2c"))) pcolor.append(QgsColorRampShader.ColorRampItem(6, QColor("#00441b"))) renderer = QgsPalettedRasterRenderer(layer.dataProvider(), 1, QgsPalettedRasterRenderer.colorTableToClassData(pcolor)) layer.setRenderer(renderer) extent = layer.extent() width, height = layer.width(), layer.height() renderer = layer.renderer() provider = layer.dataProvider() crs = layer.crs().toWkt() pipe = QgsRasterPipe() pipe.set(provider.clone()) pipe.set(renderer.clone()) file_writer = QgsRasterFileWriter("C:/temp/naip/classified_res.tif") file_writer.writeRaster(pipe, width, height, extent,
def rat_classify(raster_layer, band, rat, criteria, ramp=None, feedback=QgsRasterBlockFeedback()) -> list: """Classify a raster. Note: cannot use a custom shader function QgsColorRampShader subclass because it's lost in the clone stage of the renderer. :param raster_layer: the raster layer to classify :type raster_layer: QgsRasterLayer :param band: band number (1-based) :type band: int :param rat: the RAT data :type rat: dict :param criteria: key of the RAT to be used for labels :type criteria: str :param ramp: optional color ramp, defaults to QgsRandomColorRamp() :type ramp: QgsColorRamp, optional :param feedback: QGIS feedback object, defaults to QgsRasterBlockFeedback() :type feedback: QgsRasterBlockFeedback, optional :return: unique row indexes for legend items (1-based) :rtype: list """ has_color = rat.has_color labels = rat.data[criteria] label_colors = {} unique_indexes = [] # QGIS >= 3.18 for first element label if Qgis.QGIS_VERSION_INT >= 31800: base_legend_row_index = 1 else: base_legend_row_index = 0 if rat.thematic_type == gdal.GRTT_THEMATIC: # Use paletted rat_log('Using paletted renderer') value_column_name = rat.field_name(gdal.GFU_MinMax) values = rat.data[value_column_name] is_integer = isinstance(values[0], int) if ramp is None: ramp = QgsRandomColorRamp() classes = QgsPalettedRasterRenderer.classDataFromRaster( raster_layer.dataProvider(), band, ramp, feedback) row_index = base_legend_row_index for klass in classes: value = int(klass.value) if is_integer else klass.value try: index = values.index(value) except ValueError: # NODATA rat_log( f'Value {value} not found in RAT, assuming NODATA', Qgis.Warning) data_provider = raster_layer.dataProvider() if not data_provider.userNoDataValuesContains(band, value): nodata = data_provider.userNoDataValues(band) nodata_value = QgsRasterRange(value, value) nodata.append(nodata_value) data_provider.setUserNoDataValue(band, nodata) continue klass.label = str(labels[index]) if klass.label not in label_colors: unique_indexes.append(row_index) if has_color: label_colors[klass.label] = rat.data[RAT_COLOR_HEADER_NAME][index] else: label_colors[klass.label] = klass.color klass.color = label_colors[klass.label] row_index += 1 renderer = QgsPalettedRasterRenderer( raster_layer.dataProvider(), band, classes) else: # ranges rat_log('Using singleband pseudocolor renderer') min_value_column = rat.field_name(gdal.GFU_Min) max_value_column = rat.field_name(gdal.GFU_Max) # Collect unique values and colors from criteria row_index = base_legend_row_index unique_labels = [] for index in range(len(labels)): label = labels[index] if label not in unique_labels: unique_labels.append(label) unique_indexes.append(row_index) # Collect color if has_color: label_colors[label] = rat.data[RAT_COLOR_HEADER_NAME][index] row_index += 1 # Assign colors from random ramp if not has_color: ramp = QgsRandomColorRamp() ramp.setTotalColorCount(len(unique_labels)) i = 0 for index in unique_indexes: label_colors[labels[index]] = ramp.color(ramp.value(i)) i += 1 # Create values for the ramp # Collect colors for all classes colors = [] for label in labels: colors.append(label_colors[label]) ramp = QgsPresetSchemeColorRamp(colors) minValue = min(rat.data[min_value_column]) maxValue = max(rat.data[max_value_column]) assert minValue < maxValue, "Min Value must be lower than Max Value" shader = QgsRasterShader(minValue, maxValue) colorRampShaderFcn = QgsColorRampShader( minValue, maxValue, ramp) colorRampShaderFcn.setClip(True) colorRampShaderFcn.setColorRampType(QgsColorRampShader.Discrete) items = [] row = 0 for label in labels: items.append(QgsColorRampShader.ColorRampItem( rat.data[max_value_column][row], label_colors[label], label)) row += 1 colorRampShaderFcn.setColorRampItemList(items) try: # for older QGIS colorRampShaderFcn.legendSettings().setUseContinuousLegend(False) except AttributeError: rat_log( 'QgsColorRampShader.legendSettings().setUseContinuousLegend() is not supported on ths QGIS version.', Qgis.Warning) shader.setRasterShaderFunction(colorRampShaderFcn) renderer = QgsSingleBandPseudoColorRenderer( raster_layer.dataProvider(), band, shader) raster_layer.setRenderer(renderer) raster_layer.triggerRepaint() return unique_indexes
def on_cannyPushButton_clicked(self): raster_layer_name = self.rasterLayerComboBox.currentText() raster_layer = QgsProject.instance().mapLayersByName( raster_layer_name)[0] provider = raster_layer.dataProvider() extent = provider.extent() rows = raster_layer.height() cols = raster_layer.width() # 读取栅格值 block = provider.block(1, extent, cols, rows) img = np.zeros([rows, cols, 3], np.uint8) band_num = 3 for band_index in range(band_num): block = provider.block(band_index + 1, extent, cols, rows) # for row_index in range(rows): # for col_index in range(cols): # img[row_index][col_index][band_index] = block.value( # row_index, col_index) img[:, :, band_index] = np.array(block.data()).reshape([rows, cols]) print(img) print(img.shape) edges = cv2.Canny(img, 200, 400, 15) plt.subplot(121) plt.imshow(img) plt.title('Original Image') plt.xticks([]) plt.yticks([]) plt.subplot(122) plt.imshow(edges, cmap='gray') plt.title('Edge Image') plt.xticks([]) plt.yticks([]) plt.show() cv2.imwrite(r'edge_result.jpg', edges) # 写入Tiff driver = gdal.GetDriverByName('GTiff') # 创建图像 print(f'cols {cols}, rows {rows}') ds = driver.Create('edge_result.tif', xsize=cols, ysize=rows, bands=1, eType=gdal.GDT_Byte) # 设置参考坐标系 crs_wkt = raster_layer.crs().toWkt() ds.SetProjection(crs_wkt) print(crs_wkt) # srs = osr.SpatialReference() # srs.SetUTM(12, 1) # srs.SetWellKnownGeogCS('WGS84') # ds.SetProjection(srs.ExportToWkt()) # 设置Tiff的图像转换参数 transformParam = [ extent.xMinimum(), (extent.width() / cols), 0, extent.yMaximum(), 0, -(extent.height() / rows) ] ds.SetGeoTransform(transformParam) print(transformParam) # 写入数据 ds.GetRasterBand(1).WriteArray(edges[:, :]) # 关闭文件 ds = None # 添加至图层并设置样式 rlayer = QgsRasterLayer('edge_result.tif', "result tif layer") QgsProject.instance().addMapLayer(rlayer) palette_raster_render = QgsPalettedRasterRenderer( rlayer.dataProvider(), 1, [ QgsPalettedRasterRenderer.Class(0, QtGui.QColor(0, 0, 0, 0)), QgsPalettedRasterRenderer.Class(255, QtGui.QColor(255, 0, 0, 255)) ]) rlayer.setRenderer(palette_raster_render)