QuPath学习④ 脚本使用

目录

1,基础学习

脚本打印项目中所有图像

访问当前图像内容

访问图像元数据

访问像素

创建ROI 

创建对象(使 ROI 可见)

多个ROI

Working with BufferedImage

使用 ImageJ

命令示例

2 脚本导出数据(重点)

3,脚本使用(老版本)

①统计不同类型的对象

②计数肿瘤分类

③计算百分比(重点)

④ 计算分类像素面积(重点)

4,阅读qupath概述


QuPath可以手动+脚本的方式进行运行。可以用于个批量处理数据和批量导出数据。

QuPath脚本是基于Groovy创建的。选择Groovy是因为Groovy具有很多新特性,同时又与QuPath本身所使用的Java编程语言非常匹配。熟悉Java语言的程序员应该很快就可以轻松地学习Groovy。

除了Groovy之外,还可以编写其他脚本语言。要切换到Javascript,只需打开脚本编辑器,然后选择Language(语言)→ Javascript 另外,还可以使用python、matlab或ImageJ宏语言。

在Groovy中,"//“被用作单行注释符号,用于注释掉一行代码。(下面部分习惯了R语言的#,自行修改)

1,基础学习
脚本打印项目中所有图像
def project = getProject()
for (entry in project.getImageList()) {
    print entry.getImageName()
}

批量提取:依次打开每个图像;从层次结构中提取批注;打印每张图像的图像名称和注释计数

def project = getProject()
for (entry in project.getImageList()) {
    def imageData = entry.readImageData()  #打开项目
    def hierarchy = imageData.getHierarchy()  #提取层次
    def annotations = hierarchy.getAnnotationObjects()  #提取注释
    print entry.getImageName() + '\t' + annotations.size() #输出名称+注释计数
}

#这个代码打开项目比较慢,因为他会打开一些不需要实际访问的像素

快速版:

def project = getProject()
for (entry in project.getImageList()) {
    def hierarchy = entry.readHierarchy()
    def annotations = hierarchy.getAnnotationObjects()
    print entry.getImageName() + '\t' + annotations.size()
}

访问当前图像内容
def imageData = getCurrentImageData()
print imageData

#或者
def viewer = getCurrentViewer()
def imageData = viewer.getImageData()
print imageData
访问图像元数据
def server = getCurrentServer()
print server

#查询图像的属性
def server = getCurrentServer()
print server.getWidth() + ' x ' + server.getHeight()

#metadata 原数据储存在一个对象中
def server = getCurrentServer()
print server.getMetadata()

#像素大小 PixelCalibrationObject
def server = getCurrentServer()
def cal = server.getMetadata().getPixelCalibration()
print cal

计算像素大小(微米)

def server = getCurrentServer()
def cal = server.getPixelCalibration() #获取像素大小
print cal.getPixelWidthMicrons() #像素宽度微米
print cal.getPixelHeightMicrons() #像素高度微米
print cal.getAveragedPixelSizeMicrons() #平均像素尺寸微米


#如果尺寸信息不可用,使用Double.NaN来输出结果
double myNaN = Double.NaN

// Two Java/Groovy-friendly ways to check values are 'usable'
print Double.isNaN(myNaN)
print Double.isFinite(myNaN)

访问像素

包括服务器路径、缩减像素采样因子和边界框坐标(以全分辨率像素单位定义,原点位于图像的左上角) 

import qupath.lib.regions.*

def server = getCurrentServer()
def path = server.getPath()

double downsample = 4.0
int x = 100
int y = 200
int width = 1000
int height = 2000

def request = RegionRequest.createInstance(path, downsample, x, y, width, height)

def img = server.readRegion(request)
print img

设置像素大小:

// Set pixel width and height to 0.5 microns
setPixelSizeMicrons(0.5, 0.5) #设置宽长的大小
创建ROI 

有多种ROI: createEllipseROIcreatePolygonROIcreateLineROI

创建一个椭圆ROI

import qupath.lib.roi.ROIs
import qupath.lib.regions.ImagePlane

int z = 0
int t = 0
def plane = ImagePlane.getPlane(z, t)
def roi = ROIs.createRectangleROI(0, 0, 100, 100, plane)
print roi
创建对象(使 ROI 可见
import qupath.lib.objects.PathObjects #创建一个ROI项目
import qupath.lib.roi.ROIs  #创建ROI
import qupath.lib.regions.ImagePlane  ##传递参数

int z = 0
int t = 0
def plane = ImagePlane.getPlane(z, t) # 指定z-slice and timepoint,
def roi = ROIs.createEllipseROI(0, 0, 100, 100, plane)  #创建矩形ROI
def annotation = PathObjects.createAnnotationObject(roi) ##创建的是一个注释项目
addObject(annotation)


##若要创建检测而不是注释(检测区域)
def detection = PathObjects.createDetectionObject(roi)
多个ROI

如何创建和合并两个 ROI

import qupath.lib.roi.ROIs
import qupath.lib.roi.RoiTools
import qupath.lib.objects.PathObjects
import qupath.lib.regions.ImagePlane

def plane = ImagePlane.getDefaultPlane()
def roi1 = ROIs.createRectangleROI(0, 0, 100, 100, plane)
def roi2 = ROIs.createEllipseROI(80, 0, 100, 100, plane)

def roi3 = RoiTools.combineROIs(roi1, roi2, RoiTools.CombineOp.ADD)
def annotation = PathObjects.createAnnotationObject(roi3)
addObject(annotation)

Working with BufferedImage

Once you have a BufferedImage, you are already in Java-land and don’t need QuPath-specific documentation for most things.Scripts like this one to create binary images can then help with one major change. Previously, you had to do some awkward gymnastics to convert a ROI into a java.awt.Shape object. That’s now easier:

用于从选定的 ROI 的 RGB 图像中提取一个区域,并在 ImageJ 中显示该区域以及新的二进制掩码。

import qupath.lib.regions.*
import ij.*
import java.awt.Color
import java.awt.image.BufferedImage

// Read RGB image & show in ImageJ (won't work for multichannel!)
def server = getCurrentServer() #当前工作
def roi = getSelectedROI() ##选择ROI区域
double downsample = 4.0
def request = RegionRequest.createInstance(server.getPath(), downsample, roi)
def img = server.readRegion(request)
new ImagePlus("Image", img).show()

// Create a binary mask & show in ImageJ #创建掩码
def shape = roi.getShape()
def imgMask = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_BYTE_GRAY)
def g2d = imgMask.createGraphics()
g2d.scale(1.0/request.getDownsample(), 1.0/request.getDownsample())
g2d.translate(-request.getX(), -request.getY())
g2d.setColor(Color.WHITE)
g2d.fill(shape)
g2d.dispose()
new ImagePlus("Mask", imgMask).show()
使用 ImageJ

如果要在 QuPath 中应用 ImageJ 脚本,最好让 QuPath 负责转换。以下脚本与上述脚本类似,但适用于多通道图像并设置 ImageJ 属性。 它也不会直接创建掩码,而是转换 QuPath ROI,以便可以在 ImageJ 中执行进一步的处理(例如生成掩码)。

import qupath.lib.regions.*
import qupath.imagej.tools.IJTools
import qupath.imagej.gui.IJExtension
import ij.*

// Request an ImageJ instance - this will open the GUI if necessary
// This isn't essential, but makes it it possible to interact with any image that is shown
IJExtension.getImageJInstance()

// Read image & show in ImageJ
def server = getCurrentServer()
def roi = getSelectedROI()
double downsample = 4.0
def request = RegionRequest.createInstance(server.getPath(), downsample, roi)
def pathImage = IJTools.convertToImagePlus(server, request)
def imp = pathImage.getImage()
imp.show()

// Convert QuPath ROI to ImageJ Roi & add to open image
def roiIJ = IJTools.convertToIJRoi(roi, pathImage)
imp.setRoi(roiIJ)
命令示例
import qupath.imagej.gui.IJExtension
import qupath.imagej.tools.IJTools
import qupath.lib.gui.scripting.QPEx
import qupath.lib.images.servers.ImageServer
import qupath.lib.io.GsonTools
import qupath.lib.objects.PathObjects
import qupath.lib.objects.classes.PathClassFactory
import qupath.lib.objects.classes.PathClassTools
import qupath.lib.regions.ImagePlane
import qupath.lib.regions.RegionRequest
import qupath.lib.roi.ROIs
import qupath.lib.roi.jts.ConverterJTS
import qupath.opencv.tools.OpenCVTools

2 脚本导出数据(重点)

用脚本进行结果输出Exporting measurements — QuPath 0.5.0 documentation

import qupath.lib.gui.tools.MeasurementExporter
import qupath.lib.objects.PathCellObject

// Get the list of all images in the current project
def project = getProject()
def imagesToExport = project.getImageList()

// Separate each measurement value in the output file with a tab ("\t")
def separator = "\t"

// Choose the columns that will be included in the export
// Note: if 'columnsToInclude' is empty, all columns will be included
def columnsToInclude = new String[]{"Name", "Class", "Nucleus: Area"}

// Choose the type of objects that the export will process
// Other possibilities include:
//    1. PathAnnotationObject
//    2. PathDetectionObject
//    3. PathRootObject
// Note: import statements should then be modified accordingly
def exportType = PathCellObject.class

// Choose your *full* output path
def outputPath = "M:/measurements.tsv"
def outputFile = new File(outputPath)

// Create the measurementExporter and start the export
def exporter  = new MeasurementExporter()
                  .imageList(imagesToExport)            // Images from which measurements will be exported
                  .separator(separator)                 // Character that separates values
                  .includeOnlyColumns(columnsToInclude) // Columns are case-sensitive
                  .exportType(exportType)               // Type of objects to export
                  .filter(obj -> obj.getPathClass() == getPathClass("Tumor"))    // Keep only objects with class 'Tumor'
                  .exportMeasurements(outputFile)        // Start the export process

print "Done!"

3,脚本使用(老版本)

编写自定义脚本 ·qupath/qupath 维基 (github.com)

Writing custom scripts · qupath/qupath Wiki (github.com)

①统计不同类型的对象
detections = getDetectionObjects()
print("I have " + detections.size() + " detections") #计算检测对象

annotations = getAnnotationObjects()
print("I have " + annotations.size() + " annotations")  #注释对象的数量
②计数肿瘤分类

构建的一个应用程序是计算具有特定分类的检测次数。为此,我们首先需要获取对分类的引用,然后检查这是否与检测的分类匹配。

肿瘤计数脚本1(局限)

#以下脚本显示了一种执行此操作的方法,用于“肿瘤”分类
tumorClass = getPathClass("Tumor") #细胞分类器中的细胞
nTumor = 0
for (detection in getDetectionObjects()) {  #检测ROI
    pathClass = detection.getPathClass()
    if (pathClass == tumorClass)  ##肿瘤分类
      nTumor++
}
print("Number of tumor detections: " + nTumor)  ##计算肿瘤细胞


以上仅会计数严格等于Tumor分类的细胞,而不会统计Tumor分类下子类别的对象。这是因为它将只对准确分类为“肿瘤”的检测进行计数,而不会对衍生分类“肿瘤:阳性”或“肿瘤:阴性”进行计数。

classification 'Tumor' - but not the derived classifications 'Tumor: Positive' or 'Tumor: Negative'(也就是说对肿瘤进行再分类的就不适合上述代码统计)

肿瘤计数脚本2(完整)

想要实现子类的计数,可以修改代码为:通过使用每个分类中内置的isAncestorOf 方法,将执行检查以查看对象的分类是否等于或源自Tumor分类。

tumorClass = getPathClass("Tumor")
nTumor = 0
for (detection in getDetectionObjects()) {
    pathClass = detection.getPathClass()
    if (tumorClass.isAncestorOf(pathClass)) #isAncestorOftrue  执行检查以查看对象的分类是否等于肿瘤分类或派生自肿瘤分类
      nTumor++
}
print("Number of tumor detections: " + nTumor)

通过使用每个分类中内置的方法,执行检查以查看对象的分类是否等于肿瘤分类或派生自肿瘤分类。如果其中任一情况,该方法将返回。isAncestorOftrue。如果不使用派生分类,那么两个脚本会给出相同的结果。


③计算百分比(重点)

通过对最后一个脚本的少量修改,还可以计算非肿瘤分类并确定比例或百分比

tumorClass = getPathClass("Tumor") #应该是训练的细胞分类器
nTumor = 0
nNonTumor = 0
for (detection in getDetectionObjects()) {
    pathClass = detection.getPathClass()
    if (tumorClass.isAncestorOf(pathClass)) #属于肿瘤分类(包括肿瘤大类)
      nTumor++     ##计算肿瘤
    else 
      nNonTumor++   #计算非肿瘤
}
print("Number of tumor detections: " + nTumor) 
print("Number of non-tumor detections: " + nNonTumor) 
percentageTumor = nTumor / (nTumor + nNonTumor) * 100  ##计算肿瘤分类比例
print("Percentage of tumor detections: " + percentageTumor)
④ 计算分类像素面积(重点)

统计每个类别的所有区域的面积,在计算TSR和TIL计算中很有作用

tumorClass = getPathClass("Tumor")
nTumor = 0
nNonTumor = 0
areaTumor = 0
areaNonTumor = 0
for (detection in getDetectionObjects()) {
    roi = detection.getROI()                     ##检测选定的ROI区域
    pathClass = detection.getPathClass()         
    if (tumorClass.isAncestorOf(pathClass)) {    ##计算肿瘤
      nTumor++
      areaTumor += roi.getArea()                 ##计算ROI中肿瘤面积
    } else {
      nNonTumor++                                ##计算非肿瘤
      areaNonTumor += roi.getArea()              ##计算ROI中非肿瘤面积
    }
}
print("Number of tumor detections: " + nTumor)
print("Number of non-tumor detections: " + nNonTumor)
percentageTumor = nTumor / (nTumor + nNonTumor) * 100
print("Percentage of tumor detections: " + percentageTumor)

percentageAreaTumor = areaTumor / (areaTumor + areaNonTumor) * 100  ##计算肿瘤上皮面积占比
print("Percentage of tumor area: " + percentageAreaTumor)

请注意,此脚本不会输出区域的绝对值。这是因为,默认情况下,面积值将以像素为单位给出。因此,百分比仍然有意义,但绝对值可能会产生误导,除非它们按像素大小缩放。(前面提到计算TSR时,像素面积对结果影响小)

TSR勾画学习-CSDN博客


4,阅读qupath概述

QuPathGUI (QuPath 0.5.0) 介绍qupath部分函数

以下是 QuPath 中一般概念的概述:

  • 您的图像可能(并且可能应该)组织在一个Project

    • 项目中的每个图像都由ProjectImageEntry

    • 当您打开一个 时,您会在查看器中显示一个ProjectImageEntryImageData

      • 商店有一些东西,包括:ImageData

        • (例如明场、荧光)ImageType

        • 任何必需的(如果是明场)ColorDeconvolutionStains

        • 一个 ,用于访问像素和元数据ImageServer

        • A ,包含树状结构PathObjectHierarchyPathObjects

          • 每个都包含一个和PathObjectROIMeasurementList

当您在 QuPath 中分析图像时,您需要从 中获取 ,访问像素,并尝试表示图像包含在 .ImageDataImageServerPathObjectHierarchy

然后,查询对象层次结构以提取某种汇总度量。


参考:

1:自定义脚本 — QuPath 0.5.0 文档

2:QuPath script_qupath groovy脚本-CSDN博客

3:QuPath学习 ② H&E scripts_qupath 计算肿瘤面积-CSDN博客

相关推荐

  1. QuPath学习脚本使用

    2024-01-05 18:46:01       59 阅读
  2. 深度学习-使用 Bash 脚本

    2024-01-05 18:46:01       23 阅读
  3. 学习使用shell脚本获取进程号并杀死进程

    2024-01-05 18:46:01       45 阅读
  4. Docker学习笔记 - 使用配置脚本来启动image

    2024-01-05 18:46:01       48 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-01-05 18:46:01       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-01-05 18:46:01       106 阅读
  3. 在Django里面运行非项目文件

    2024-01-05 18:46:01       87 阅读
  4. Python语言-面向对象

    2024-01-05 18:46:01       96 阅读

热门阅读

  1. 第四章:智慧变现:探索ChatGPT的赚钱奥秘

    2024-01-05 18:46:01       42 阅读
  2. 区块链技术

    2024-01-05 18:46:01       52 阅读
  3. MySQL中UNION和UNION ALL的区别有哪些?

    2024-01-05 18:46:01       63 阅读
  4. BIO、NIO

    2024-01-05 18:46:01       57 阅读
  5. Python入门-实战练习-基于函数

    2024-01-05 18:46:01       55 阅读
  6. 【MySQL】MySQL运维SQL(持续更新。。。)

    2024-01-05 18:46:01       57 阅读
  7. dom4j生成XML文件

    2024-01-05 18:46:01       62 阅读
  8. 上界通配符(? extends Type)

    2024-01-05 18:46:01       66 阅读
  9. 三、C#面向对象编程(类与对象)

    2024-01-05 18:46:01       59 阅读
  10. Moment.js 使用

    2024-01-05 18:46:01       51 阅读
  11. 个人开发常用的eslint规则,适用vue、react

    2024-01-05 18:46:01       68 阅读
  12. 4. 动态SQL

    2024-01-05 18:46:01       50 阅读