def createImageParams(): def finished(): def addParams(): def getJsonImages(): vmap = {} for l in self.paramProcess['layerImages']: vmap[ l.name() ] = l.source() return json.dumps( vmap ) e = self.paramProcess['canvas'].extent() imgWidth, imgHeight = image.width(), image.height() resX, resY = e.width() / imgWidth, e.height() / imgHeight self.paramProcess['json_images'] = getJsonImages() self.paramProcess['crs_map'] = self.paramProcess['canvas'].mapSettings().destinationCrs().authid() self.paramProcess['extent_map'] = e.asWktCoordinates() # xMin, yMin, xMax, yMax self.paramProcess['res'] = { 'X': resX, 'Y': resY } image = job.renderedImage() if bool( self.paramProcess['canvas'].property('retro') ): image = image.scaled( image.width() / 3, image.height() / 3 ) image = image.convertToFormat( QImage.Format_Indexed8, Qt.OrderedDither | Qt.OrderedAlphaDither ) image.save( self.paramProcess['pathfileImage'], "TIFF", 100 ) # 100: Uncompressed addParams() settings = QgsMapSettings( self.paramProcess['canvas'].mapSettings() ) settings.setBackgroundColor( QColor( Qt.transparent ) ) layers = self.paramProcess['layerImages'] if 'layerPolygon' in self.paramProcess: layers = [ self.paramProcess['layerPolygon'] ] + layers settings.setLayers( layers ) job = QgsMapRendererParallelJob( settings ) job.start() job.finished.connect( finished) job.waitForFinished()
def render_layer(): projectpath = Path('./data/france_parts.qgs') prj = QgsProject() prj.read(str(projectpath.absolute())) layers = layers = prj.mapLayersByName('france_parts') xt = layers[0].extent() width = 1200 height = int(width * xt.height() / xt.width()) options = QgsMapSettings() options.setLayers(layers) options.setBackgroundColor(QColor(255, 255, 255)) options.setOutputSize(QSize(width, height)) options.setExtent(xt) render = QgsMapRendererParallelJob(options) render.start() render.waitForFinished() image = render.renderedImage() return image
def test_render_via_job(self): """ Test rendering an annotation layer via a map render job """ layer = QgsAnnotationLayer('test', QgsAnnotationLayer.LayerOptions(QgsProject.instance().transformContext())) self.assertTrue(layer.isValid()) item = QgsAnnotationPolygonItem( QgsPolygon(QgsLineString([QgsPoint(11.5, 13), QgsPoint(12, 13), QgsPoint(12, 13.5), QgsPoint(11.5, 13)]))) item.setSymbol( QgsFillSymbol.createSimple({'color': '200,100,100', 'outline_color': 'black', 'outline_width': '2'})) item.setZIndex(1) i1_id = layer.addItem(item) item = QgsAnnotationLineItem(QgsLineString([QgsPoint(11, 13), QgsPoint(12, 13), QgsPoint(12, 15)])) item.setSymbol(QgsLineSymbol.createSimple({'color': '#ffff00', 'line_width': '3'})) item.setZIndex(2) i2_id = layer.addItem(item) item = QgsAnnotationMarkerItem(QgsPoint(12, 13)) item.setSymbol(QgsMarkerSymbol.createSimple({'color': '100,200,200', 'size': '6', 'outline_color': 'black'})) item.setZIndex(3) i3_id = layer.addItem(item) layer.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) settings = QgsMapSettings() settings.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326')) settings.setExtent(QgsRectangle(10, 10, 18, 18)) settings.setOutputSize(QSize(200, 200)) settings.setLayers([layer]) job = QgsMapRendererParallelJob(settings) job.start() job.waitForFinished() # check rendered item results item_results = job.takeRenderedItemResults() item_details = item_results.renderedItems() self.assertEqual(len(item_details), 3) self.assertEqual([i.layerId() for i in item_details], [layer.id()] * 3) self.assertCountEqual([i.itemId() for i in item_details], [i1_id, i2_id, i3_id]) self.assertCountEqual( [i.itemId() for i in item_results.renderedAnnotationItemsInBounds(QgsRectangle(0, 0, 1, 1))], []) self.assertCountEqual( [i.itemId() for i in item_results.renderedAnnotationItemsInBounds(QgsRectangle(10, 10, 11, 18))], [i2_id]) self.assertCountEqual( [i.itemId() for i in item_results.renderedAnnotationItemsInBounds(QgsRectangle(10, 10, 12, 18))], [i1_id, i2_id, i3_id]) # bounds should be in map crs self.assertEqual([i.boundingBox() for i in item_details if i.itemId() == i1_id][0], QgsRectangle(11.5, 13, 12, 13.5)) self.assertEqual([i.boundingBox() for i in item_details if i.itemId() == i2_id][0], QgsRectangle(11, 13, 12, 15)) self.assertEqual([i.boundingBox().toString(1) for i in item_details if i.itemId() == i3_id][0], '11.5,12.5 : 12.5,13.5')
def render_layer(settings, layer, width, height): settings.setLayers([layer.id()]) settings.setFlags(settings.flags() ^ QgsMapSettings.Antialiasing) settings.setOutputSize(QSize(width, height)) job = QgsMapRendererParallelJob(settings) job.start() job.waitForFinished() image = job.renderedImage() # image.save(r"/media/nathan/Data/dev/qgis-term/{}.jpg".format(layer.name())) return image
def render(name, settings): settings.setOutputSize(IMAGE_SIZE) job = QgsMapRendererParallelJob(settings) #job = QgsMapRendererSequentialJob(settings) job.start() job.waitForFinished() image = job.renderedImage() if not os.path.exists(image_path): os.mkdir(image_path) image.save(os.path.join(image_path, name + '.png')) return job.renderingTime()
def setMap(self): def finished(): super(SwipeMap, self).setContent( job.renderedImage(), self.canvas.extent() ) settings = QgsMapSettings( self.canvas.mapSettings() ) settings.setLayers( self.layers ) job = QgsMapRendererParallelJob( settings) job.start() job.finished.connect( finished) job.waitForFinished()
def render(settings): """ Render the given settings to a image and save to disk. name: The name of the final result file. settings: QgsMapSettings containing the settings to render exportpath: The folder for the images to be exported to. """ job = QgsMapRendererParallelJob(settings) #job = QgsMapRendererSequentialJob(settings) job.start() job.waitForFinished() image = job.renderedImage() return image, job.renderingTime()
def render_wms_to_image(xyz=True, extent=EXTENT, width=64, height=60): """ :type xyz: bool :type extent: tuple :type width: int :type height: int :rtype: QImage """ # p = QgsProject.instance() # p = QgsProject() uri = QgsDataSourceUri() if xyz: uri.setParam('type', 'xyz') uri.setParam('crs', 'EPSG:3857') uri.setParam('format', '') # uri.setParam('zmin', '0') # uri.setParam('zmax', '18') uri.setParam('url', XYZ_URL) else: uri.setParam('tileMatrixSet', 'GoogleMapsCompatible23') uri.setParam('crs', 'EPSG:3857') uri.setParam('format', 'image/png') uri.setParam('styles', '') uri.setParam('layers', 'Combined scene layer') uri.setParam('url', WMS_URL) # Important to do this conversion, else WMS provider will double encode; # instead of just `str(uri.encodedUri())`, which outputs "b'uri'" # This coerces QByteArray -> str ... assuming UTF-8 is valid. final_uri = bytes(uri.encodedUri()).decode("utf-8") layer = QgsRasterLayer(final_uri, "scene_layer", "wms") if not layer.isValid(): print('Layer is not valid') return QImage() # p.addMapLayer(layer) settings = QgsMapSettings() settings.setExtent(QgsRectangle(*extent)) settings.setOutputSize(QSize(width, height)) settings.setLayers([layer]) job = QgsMapRendererParallelJob(settings) job.start() # This blocks... # It should really be a QEventLoop or QTimer that checks for finished() # Any intermediate image can safely be pulled from renderedImage() job.waitForFinished() return job.renderedImage()
def renderMapToImage(mapsettings, parallel=False): """ Render current map to an image, via multi-threaded renderer :param QgsMapSettings mapsettings: :param bool parallel: Do parallel or sequential render job :rtype: QImage """ if parallel: job = QgsMapRendererParallelJob(mapsettings) else: job = QgsMapRendererSequentialJob(mapsettings) job.start() job.waitForFinished() return job.renderedImage()
def setMap(self): def finished(): super(SwipeMap, self).setContent(job.renderedImage(), self.canvas.extent()) if len(self.layers) == 0: return settings = QgsMapSettings(self.canvas.mapSettings()) settings.setLayers(self.layers) job = QgsMapRendererParallelJob(settings) job.start() job.finished.connect(finished) job.waitForFinished()
def _process(self): def finished(): image = job.renderedImage() if bool(self.data['canvas'].property('retro')): image = image.scaled(image.width() / 3, image.height() / 3) image = image.convertToFormat( QImage.Format_Indexed8, Qt.OrderedDither | Qt.OrderedAlphaDither) image.save(self.data['filepath'], "TIFF", 100) # 100: Uncompressed self._setParamsSendData(image) settings = QgsMapSettings(self.data['canvas'].mapSettings()) settings.setBackgroundColor(QColor(Qt.transparent)) settings.setLayers(self.data['layers']) job = QgsMapRendererParallelJob(settings) job.start() job.finished.connect(finished) job.waitForFinished()
def render_qgis_map(self): logging.info("Rendering QGIS map") # Gross. Fix me if not self.settings and project: self.settings = project.map_settings # TODO We should only get visible layers here but this will do for now self.settings.setLayers(QgsMapLayerRegistry.instance().mapLayers().keys()) self.settings.setFlags(self.settings.flags() ^ QgsMapSettings.Antialiasing) logging.info(self.settings.flags()) logging.info(self.settings.testFlag(QgsMapSettings.Antialiasing)) height, width = self.mapwin.getmaxyx() logging.info("Setting output size to {}, {}".format(width, height)) self.settings.setOutputSize(QSize(width, height)) job = QgsMapRendererParallelJob(self.settings) job.start() job.waitForFinished() image = job.renderedImage() logging.info("Saving rendered image for checks...") image.save(r"F:\dev\qgis-term\render.jpg") return image
def create_image(self, extent, width, height, canvas_name, output_dir): ''' This method create an image :param extent: Extent :param width: Output image width :param height: Output image height :param canvas_name: Map name :param output_dir: Output directory for image ''' if not extent: raise_exception('extent is empty') if not width: raise_exception('width is empty') if not height: raise_exception('height is empty') if not canvas_name: raise_exception('canvas name is empty') if not output_dir: raise_exception('output_dir is empty') file_name = '{0}/{1}.png'.format(output_dir, canvas_name) settings = QgsMapSettings() settings.setLayers(iface.mapCanvas().layers()) settings.setBackgroundColor(QColor(255, 255, 255)) settings.setOutputSize(QSize(width, height)) settings.setExtent(extent) render = QgsMapRendererParallelJob(settings) render.start() render.waitForFinished() image = render.renderedImage() image.save(file_name, "png") return file_name
def write_image(destination_crs, extent, filepath, imagetype): """ Save current QGIS canvas to image file. """ settings = QgsMapSettings() # build settings settings.setDestinationCrs(destination_crs) # set output crs settings.setExtent(extent) # in destination_crs layers = iface.mapCanvas().layers() # get visible layers settings.setLayers(layers) w = 1920 h = int((extent.yMaximum() - extent.yMinimum()) / (extent.xMaximum() - extent.xMinimum()) * w) settings.setOutputSize(QSize(w, h)) settings.setOutputDpi(200) render = QgsMapRendererParallelJob(settings) render.start() render.waitForFinished() image = render.renderedImage() try: image.save(filepath, imagetype) except IOError: raise QgsProcessingException(f"Image not writable at <{filepath}>")
def update_summary_sheet(self,lyr=None, force=None): ''' Creates a summary sheet with thumbnail, layer metadata and online view link ''' #create a layer snapshot and upload it to google drive if not lyr: lyr = self.lyr mapbox_style = self.service_sheet.sheet_cell('settings!A5') if not mapbox_style: logger("migrating mapbox style") self.service_sheet.set_style_mapbox(self.layer_style_to_json(self.lyr)) if not force and not self.dirty and not self.restyled: return if self.restyled: self.service_sheet.set_style_qgis(self.layer_style_to_xml(self.lyr)) self.service_sheet.set_style_sld(self.SLD_to_xml(self.lyr)) self.service_sheet.set_style_mapbox(self.layer_style_to_json(self.lyr)) self.saveMetadataState() canvas = QgsMapCanvas() canvas.resize(QSize(600,600)) canvas.setCanvasColor(Qt.white) canvas.setExtent(lyr.extent()) canvas.setLayers([lyr]) canvas.refresh() canvas.update() settings = canvas.mapSettings() settings.setLayers([lyr]) job = QgsMapRendererParallelJob(settings) job.start() job.waitForFinished() image = job.renderedImage() transparent_image = QImage(image.width(), image.height(), QImage.Format_ARGB32) transparent_image.fill(Qt.transparent) p = QPainter(transparent_image) mask = image.createMaskFromColor(QColor(255, 255, 255).rgb(), Qt.MaskInColor) p.setClipRegion(QRegion(QBitmap(QPixmap.fromImage(mask)))) p.drawPixmap(0, 0, QPixmap.fromImage(image)) p.end() tmp_path = os.path.join(self.parent.plugin_dir,self.service_sheet.name+".png") transparent_image.save(tmp_path,"PNG") image_istances = self.service_drive.list_files(mimeTypeFilter='image/png',filename=self.service_sheet.name+".png") for imagename, image_props in image_istances.items(): self.service_drive.delete_file(image_props['id']) result = self.service_drive.upload_image(tmp_path) self.service_drive.add_permission(result['id'],'anyone','reader') webLink = result['webContentLink'] #'https://drive.google.com/uc?export=view&id='+result['id'] logger("webLink:" + webLink) canvas.setDestinationCrs(QgsCoordinateReferenceSystem(4326)) worldfile = QgsMapSettingsUtils.worldFileContent(settings) lonlat_min = self.transformToWGS84(QgsPointXY(canvas.extent().xMinimum(), canvas.extent().yMinimum())) lonlat_max = self.transformToWGS84(QgsPointXY(canvas.extent().xMaximum(), canvas.extent().yMaximum())) keymap_extent = [lonlat_min.x(),lonlat_min.y(),lonlat_max.x(),lonlat_max.y()] os.remove(tmp_path) #update layer metadata summary_id = self.service_sheet.add_sheet('summary', no_grid=True) appPropsUpdate = [ ["keymap",webLink], ["worldfile",pack(worldfile)], ["keymap_extent", json.dumps(keymap_extent)] ] res = self.service_sheet.update_appProperties(self.spreadsheet_id,appPropsUpdate) self.saveMetadataState(metadata=self.get_layer_metadata()) self.parent.public_db.setKey(self.spreadsheet_id, dict(self.get_layer_metadata()+appPropsUpdate),only_update=True) #merge cells to visualize snapshot and aaply image snapshot request_body = { 'requests': [{ 'mergeCells': { "range": { "sheetId": summary_id, "startRowIndex": 9, "endRowIndex": 32, "startColumnIndex": 0, "endColumnIndex": 9, }, "mergeType": 'MERGE_ALL' } }] } self.service_sheet.service.spreadsheets().batchUpdate(spreadsheetId=self.spreadsheet_id, body=request_body).execute() self.service_sheet.set_sheet_cell('summary!A10','=IMAGE("%s",3)' % webLink) permissions = self.service_drive.file_property(self.spreadsheet_id,'permissions') for permission in permissions: if permission['type'] == 'anyone': public = True break else: public = False if public: update_range = 'summary!A9:B9' update_body = { "range": update_range, "values": [['public link', "https://enricofer.github.io/gdrive_provider/weblink/converter.html?spreadsheet_id="+self.spreadsheet_id]] } self.service_sheet.service.spreadsheets().values().update(spreadsheetId=self.spreadsheet_id,range=update_range, body=update_body, valueInputOption='USER_ENTERED').execute() #hide worksheets except summary sheets = self.service_sheet.get_sheets() #self.service_sheet.toggle_sheet('summary', sheets['summary'], hidden=None) for sheet_name,sheet_id in sheets.items(): if not sheet_name == 'summary': self.service_sheet.toggle_sheet(sheet_name, sheet_id, hidden=True)
def update_summary_sheet(self): ''' Creates a summary sheet with thumbnail, layer metadata and online view link ''' #create a layer snapshot and upload it to google drive mapbox_style = self.service_sheet.sheet_cell('settings!A5') if not mapbox_style: print "migrating mapbox style" self.service_sheet.set_style_mapbox(self.layer_style_to_json(self.lyr)) if not self.dirty: return canvas = QgsMapCanvas() canvas.resize(QSize(300,300)) canvas.setCanvasColor(Qt.white) canvas.setExtent(self.lyr.extent()) canvas.setLayerSet([QgsMapCanvasLayer(self.lyr)]) canvas.refresh() canvas.update() settings = canvas.mapSettings() settings.setLayers([self.lyr.id()]) job = QgsMapRendererParallelJob(settings) job.start() job.waitForFinished() image = job.renderedImage() tmp_path = os.path.join(self.parent.plugin_dir,self.service_sheet.name+".png") image.save(tmp_path,"PNG") image_istances = self.service_drive.list_files(mimeTypeFilter='image/png',filename=self.service_sheet.name+".png") for imagename, image_props in image_istances.iteritems(): print imagename, image_props['id'] self.service_drive.delete_file(image_props['id']) result = self.service_drive.upload_image(tmp_path) print "UPLOADED", result self.service_drive.add_permission(result['id'],'anyone','reader') webLink = 'https://drive.google.com/uc?export=view&id='+result['id'] os.remove(tmp_path) print 'result',result,webLink #update layer metadata summary_id = self.service_sheet.add_sheet('summary', no_grid=True) self.service_sheet.erase_cells('summary') metadata = self.get_layer_metadata() range = 'summary!A1:B8' update_body = { "range": range, "values": metadata, } print "update", self.service_sheet.service.spreadsheets().values().update(spreadsheetId=self.spreadsheet_id,range=range, body=update_body, valueInputOption='USER_ENTERED').execute() #merge cells to visualize snapshot and aaply image snapshot request_body = { 'requests': [{ 'mergeCells': { "range": { "sheetId": summary_id, "startRowIndex": 9, "endRowIndex": 32, "startColumnIndex": 0, "endColumnIndex": 9, }, "mergeType": 'MERGE_ALL' } }] } print "merge", self.service_sheet.service.spreadsheets().batchUpdate(spreadsheetId=self.spreadsheet_id, body=request_body).execute() print "image", self.service_sheet.set_sheet_cell('summary!A10','=IMAGE("%s",3)' % webLink) permissions = self.service_drive.file_property(self.spreadsheet_id,'permissions') for permission in permissions: if permission['type'] == 'anyone': public = True break else: public = False if public: range = 'summary!A9:B9' update_body = { "range": range, "values": [['public link', "https://enricofer.github.io/GooGIS2CSV/converter.html?spreadsheet_id="+self.spreadsheet_id]] } print "update_public_link", self.service_sheet.service.spreadsheets().values().update(spreadsheetId=self.spreadsheet_id,range=range, body=update_body, valueInputOption='USER_ENTERED').execute() #hide worksheets except summary sheets = self.service_sheet.get_sheets() #self.service_sheet.toggle_sheet('summary', sheets['summary'], hidden=None) for sheet_name,sheet_id in sheets.iteritems(): if not sheet_name == 'summary': print sheet_name, sheet_id self.service_sheet.toggle_sheet(sheet_name, sheet_id, hidden=True)
def render_scene_to_image(item_keys: List[str], extent_json: Union[str, dict], api_key: str, node: Optional[PlanetNode] = None, width: int = 512, height: int = 512) -> QImage: img = QImage() if not item_keys: log.debug('No item type_id keys list object passed') return img if not extent_json: log.debug('Extent is invalid') return img if node and node.node_type() != NodeT.DAILY_SCENE: log.debug('Item type is not a Daily Scene') return img if not api_key: log.debug('No API in passed') return img # p = QgsProject.instance() ext: QgsRectangle = \ qgsgeometry_from_geojson(extent_json).boundingBox() if ext.width() > ext.height(): height = int(ext.height() / ext.width() * height) elif ext.height() > ext.width(): width = int(ext.width() / ext.height() * width) # noinspection PyArgumentList transform = QgsCoordinateTransform( QgsCoordinateReferenceSystem("EPSG:4326"), QgsCoordinateReferenceSystem("EPSG:3857"), QgsProject.instance()) transform_extent = transform.transformBoundingBox(ext) data_src_uri = tile_service_data_src_uri(item_keys, api_key) log.debug(f'data_src_uri:\n' f'{data_src_uri}') rlayer = QgsRasterLayer(data_src_uri, "scene_layer", "wms") if not rlayer.isValid(): log.debug('Layer is not valid') return img # p.addMapLayer(rlayer) settings = QgsMapSettings() settings.setExtent(transform_extent) settings.setOutputSize(QSize(width, height)) settings.setLayers([rlayer]) job = QgsMapRendererParallelJob(settings) job.start() # This blocks... # It should really be a QEventLoop or QTimer that checks for finished() # Any intermediate image can safely be pulled from renderedImage() job.waitForFinished() return job.renderedImage()
def make_coco_dataset(self): layers = QgsProject.instance().mapLayers().values() vectorlayers = [layer for layer in layers if layer.type() == VectorLayer] rasterLayers = [layer for layer in layers if layer.type() == RasterLayer] vectorlayer = vectorlayers[self.dlg.vectorlayerselector.currentIndex()] rasterlayer = rasterLayers[self.dlg.rasterlayerselector.currentIndex()] img_size = int(self.dlg.imagesizeselector.currentText()) scale_realworld = int(self.dlg.zoomlevel.currentText()) buffer_size = int(self.dlg.buffersize.text()) / 100 target_dir = self.dlg.dirselectline.text() dataset_description = str(self.dlg.datasetdescription.text()) contributor = str(self.dlg.creatorname.text()) url = str(self.dlg.url.text()) version = str(self.dlg.datasetversion.text()) license = str(self.dlg.licenseselector.currentText()) # to implement scale_to_fit = self.dlg.scaletofit.isChecked() use_fieldcategory = bool(self.dlg.usecategoryfields.isChecked()) categoryfield = self.dlg.categoryfields.currentText() QgsMessageLog.logMessage(str(scale_to_fit), "cocotrainer", level=Qgis.Info) QgsMessageLog.logMessage(str(use_fieldcategory), "cocotrainer", level=Qgis.Info) # prepare directories os.makedirs(os.path.join(target_dir, "train"), exist_ok=True) os.makedirs(os.path.join(target_dir, "val"), exist_ok=True) QgsMessageLog.logMessage("====================================", "cocotrainer", level=Qgis.Info) # TODO: # - use field categories features_iterator = vectorlayer.getFeatures(QgsFeatureRequest().setFilterExpression('$area > 1')) features = [feature for feature in features_iterator] QgsMessageLog.logMessage("vector layer: " + vectorlayer.name(), "cocotrainer", level=Qgis.Info) QgsMessageLog.logMessage("Filtered polygons smaller than 1m2 from data", "cocotrainer", level=Qgis.Info) QgsMessageLog.logMessage("features: " + str(len(list(features))), "cocotrainer", level=Qgis.Info) options = QgsMapSettings() options.setLayers([rasterlayer]) options.setOutputSize(QSize(int(img_size), int(img_size))) QgsMessageLog.logMessage(str(scale_realworld), "cocotrainer", level=Qgis.Info) QgsMessageLog.logMessage(str(img_size), "cocotrainer", level=Qgis.Info) date = datetime.now() cat_dict = {} if use_fieldcategory: categories = [] # uniqueprovider = rasterlayer.dataProvider() fields = vectorlayer.fields() id = fields.indexFromName(categoryfield) uniquevalues = vectorlayer.uniqueValues(id) for i, val in enumerate(uniquevalues): categories.append({"supercategory": "object", "id": i, "name": str(val)}) cat_dict[str(val)] = i else: categories = [{"supercategory": "object", "id": 0, "name": "CATEGORYNAME"}] cat_dict["CATEGORYNAME"] = 0 coco_annotation = { "info": { "description": dataset_description, "url": url, "version": version, "year": int(date.strftime("%Y")), "contributor": contributor, "date_created": date.strftime("%d/%m/%y") }, "licenses": [self.license_dict[license]], "images": [], "annotations": [], "categories": categories, # < -- Not in Captionsannotations "segment_info": [] # < -- Only in Panoptic annotations } bboxes, polygons = {}, {} for i, feature in enumerate(features): polygons[i] = feature.geometry() bboxes[i] = feature.geometry().boundingBox() if use_fieldcategory: cats = {} for i, feature in enumerate(features): cats[i] = str(feature[categoryfield]) image_id = 0 annotation_id = 0 for i, feature in enumerate(features): self.dlg.progressBar.setValue((i / len(polygons) * 100)) QgsMessageLog.logMessage("something is happening", "cocotrainer", level=Qgis.Info) geoms = feature.geometry() bbox = geoms.boundingBox() if scale_to_fit: xmax = bbox.xMaximum() ymax = bbox.yMaximum() ymin = bbox.yMinimum() xmin = bbox.xMinimum() diffx = xmax - xmin diffy = ymax - ymin xmax = xmax + (buffer_size * diffx) xmin = xmin - (buffer_size * diffx) ymax = ymax + (buffer_size * diffy) ymin = ymin - (buffer_size * diffy) else: midpoint = bbox.center() QgsMessageLog.logMessage("trying to log centerpoint", "cocotrainer", level=Qgis.Info) QgsMessageLog.logMessage(str(midpoint.x()), "cocotrainer", level=Qgis.Info) QgsMessageLog.logMessage(str(midpoint.y()), "cocotrainer", level=Qgis.Info) xmin = midpoint.x() - scale_realworld / 2 xmax = midpoint.x() + scale_realworld / 2 ymin = midpoint.y() - scale_realworld / 2 ymax = midpoint.y() + scale_realworld / 2 extent = QgsRectangle(xmin, ymin, xmax, ymax) fileid = "{}_{}_{}".format(xmin, ymin, scale_realworld) image = { "license": 0, "file_name": fileid + ".png", "coco_url": None, "height": img_size, "width": img_size, "date_captured": date.strftime("%d/%m/%y"), "flickr_url": None, "id": image_id } coco_annotation["images"].append(image) for j, geo in bboxes.items(): if extent.contains(geo) or extent.intersects(geo): points = polygons[j].asMultiPolygon() xs = np.array([p.x() - xmin for p in points[0][0]]) ys = np.array([(ymax - ymin) - (p.y() - ymin) for p in points[0][0]]) xs *= (img_size / scale_realworld) xs = np.round(xs) xs = xs.astype(np.int32) ys *= (img_size / scale_realworld) ys = np.round(ys) ys = ys.astype(np.int32) ys[ys < 0] = 0 xs[xs < 0] = 0 polygon = [[int(p[0]), int(p[1])] for p in zip(xs, ys)] flat_list = [item for sublist in polygon for item in sublist] QgsMessageLog.logMessage(str(flat_list), "cocotrainer", level=Qgis.Info) pixelposbbox = [int(np.min(xs)), (int(np.min(ys))), geo.width() * (img_size / scale_realworld), geo.height() * (img_size / scale_realworld)] pixelposbbox = [number if number > 0 else 0 for number in pixelposbbox] QgsMessageLog.logMessage(str([geo.xMinimum(), geo.yMaximum(), geo.width(), geo.height()]), "cocotrainer", level=Qgis.Info) QgsMessageLog.logMessage(str(pixelposbbox), "cocotrainer", level=Qgis.Info) annotation = { "segmentation": [flat_list], # format is [x1,y1,x2,y2] "area": polygons[j].area(), "iscrowd": 0, "image_id": image_id, "bbox": pixelposbbox, # format is [top left x position, top left y position, width, height] "category_id": cat_dict[cats[j]], "id": annotation_id } annotation_id += 1 coco_annotation["annotations"].append(annotation) options.setExtent(extent) render = QgsMapRendererParallelJob(options) def finished(): QgsMessageLog.logMessage("saving image to disk", "cocotrainer", level=Qgis.Info) fname = os.path.join(target_dir, 'train', "{}.png".format(fileid)) img = render.renderedImage() if not img.save(fname, "png"): print("Error saving image") render.finished.connect(finished) render.start() render.waitForFinished() image_id += 1 QgsMessageLog.logMessage(str(coco_annotation), "cocotrainer", level=Qgis.Info) with open(os.path.join(target_dir, "annotation.json"), "w") as outfile: json.dump(coco_annotation, outfile) self.dlg.progressBar.setValue(100) self.dlg.finished_label.setText("parsed {} features".format(len(list(features))))