Exporting rendered SVG images in batch mode

Hi! I would like to do the equivalent of manually selecting File > Export images > Rendered SVG in QuPath, but in a script, to export all images from a project. In other words, I would like to export only the vectors corresponding to the annotations on these images, with contours.

So far, I’ve tried 2 approaches by looking at different forums, but both were unsuccessful.

  1. If I export images using getCurrentImageData() and RenderedImageServer.Builder (see example code 1), I obtain images in which the annotations are represented, but I also see my background original image, which I don’t want.

  2. If I export images using LabeledImageServer.Builder (see example code 2), I obtain only the annotations (so the background original image is removed, as I wanted), but these masks are binary, and I cannot see the contour of the annotations anymore.

Sample code

Example code 1:
import qupath.imagej.tools.IJTools
import qupath.lib.gui.images.servers.RenderedImageServer
import qupath.lib.gui.viewer.overlays.HierarchyOverlay
import qupath.lib.regions.RegionRequest
import static qupath.lib.gui.scripting.QPEx.*
// It is important to define the downsample!
// This is required to determine annotation line thicknesses
double downsample = 1
// Add the output file path here
String path = buildFilePath(PROJECT_BASE_DIR, ‘rendered’, getProjectEntry().getImageName() + ‘.png’)
// Request the current viewer for settings, and current image (which may be used in batch processing)
def viewer = getCurrentViewer()
def imageData = getCurrentImageData()
// Create a rendered server that includes a hierarchy overlay using the current display settings
def server = new RenderedImageServer.Builder(imageData)
.downsamples(downsample)
.layers(new HierarchyOverlay(viewer.getImageRegionStore(), viewer.getOverlayOptions(), imageData))
.build()
// Write or display the rendered image
if (path != null) {
mkdirs(new File(path).getParent())
writeImage(server, path)
} else
IJTools.convertToImagePlus(server, RegionRequest.createInstance(server)).getImage().show()

Example code 2:
def imageData = getCurrentImageData()
// Define output path (relative to project)
def outputDir = buildFilePath(PROJECT_BASE_DIR, ‘export’)
mkdirs(outputDir)
def name = GeneralTools.getNameWithoutExtension(imageData.getServer().getMetadata().getName())
def path = buildFilePath(outputDir, name + “-labels.png”)
// Define how much to downsample during export (may be required for large images)
double downsample = 1
// Create an ImageServer where the pixels are derived from annotations
def labelServer = new LabeledImageServer.Builder(imageData)
.backgroundLabel(0, ColorTools.BLACK) // Specify background label (usually 0 or 255)
.downsample(downsample) // Choose server resolution; this should match the resolution at which tiles are exported
.addUnclassifiedLabel(1, ColorTools.WHITE)
.lineThickness(5.0)
.build()
// Write the image
writeImage(labelServer, path)

Analysis goals

Is there a way to mimic the manual action of clicking on File > Export images > Rendered SVG in a QuPath script? I really need to export images of the annotations only with a highlighted contour, but exporting these images manually is not an option for me (I have too many of them). Any input would be super appreciated!

1 Like

Hi @Helena-todd this should be close:

import qupath.lib.extension.svg.SvgTools.SvgBuilder

def imageData = getCurrentImageData()
def options = getCurrentViewer().getOverlayOptions()

def doc = new SvgBuilder()
    .imageData(imageData)
    .options(options)
    .downsample(1) // Increase if needed
    .createDocument()
    
def name = GeneralTools.getNameWithoutExtension(getProjectEntry().getImageName())
def path = buildFilePath(PROJECT_BASE_DIR, name + '.svg')

new File(path).text = doc

Other customizations are possible using the SvgBuilder – they are defined here.

1 Like

Thank you @petebankhead , the script works perfectly !

And thanks a lot for answering so quickly, I really appreciate it =)

1 Like