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 = 2000def 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.ImagePlaneint 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.ImagePlanedef 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 processprint "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()) {  #检测ROIpathClass = 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博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/593006.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

React16源码: Hooks源码实现

Hooks 1 )概述 Hooks 在 React16.7版本出现的新功能Hooks 改变了整体应用开发的模式,同时开发体验会和以前会变得不一样Hooks 让函数组件具有类组件的能力 在 function component 里面没有this无法保存 state通过 Hooks可以让 function component 代替…

PSoc62™开发板之串口通信

实验目的 1.使用串口和PC机通信:接收和发送信息 2.接收GNSS模块定位信息 实验准备 PSoc62™开发板CH340 USB转TTL模块ATGM332D GNSS模块公母头杜邦线x4 板载资源 板载有多少uart 创建工程例程,在libraries/HAL_Drivers/uart_config.h中查看BSP支持…

跨境电商如何通过API选品文章

跨境电商通过API选品是一个相对复杂的过程,涉及到多个环节和考虑因素。以下是一个简化的概述,介绍了如何通过API进行选品,由于字数限制,这里仅能展示部分内容,如需5000字的文章,可能需要根据这个提纲进一步…

凯越推出复古150踏板欧洲先上?DAE150/150亮相

今天临下班发现凯越在欧洲的官网上更新了一台复古踏板,外观别说还有点精致的意思,一共分为125和150两个配置,都是采用的水冷单缸发动机。 配置和参数等数据简单过一下,这种车型更多的是看外观了,仪表采用的LCD的显示屏…

MySQL之四大引擎、账号管理以及建库认识

目录 一、数据库存储引擎(发动机) 1.1、认识引擎 1.2、查看存储引擎 1.3、引擎常识 1.4、support字段说明 1.5、四大引擎 二、数据库管理 2.1、元数据库介绍: 2.2、分类: 2.3、增删改查以及使用操作 2.4、权限 三、数…

ArkTS语言应用开发入门指南与简单案例解析

文章目录 前言创建项目及其介绍简单案例学习本文总结问答回顾-学习前言 在前几节课中,我们已经了解了ArkTS语言的特点以及其基本语法。现在,我们将正式利用ArkTS来进行应用开发。本节课将通过一个快速入门案例,让大家熟悉开发工具的用法,并介绍UI的基础概念。 创建项目及…

Mnist手写体数字数据集介绍与在Pytorch中使用

1.介绍 MNIST(Modified National Institute of Standards and Technology)数据集是一个广泛用于机器学习和计算机视觉研究的常用数据集之一。它由手写数字图像组成,包括0到9的数字,每张图像都是28x28像素的灰度图像,图…

探索大模型语言(LLM)科技的革新

文章目录 一. 引言二. 了解大模型语言2.1 什么是LLM?2.2 大模型与大模型语言的区分 三. 机器学习3.1 AI开发3.2 机器学习服务 四. 大模型的应用场景五. 全篇总结 一. 引言 自然语言处理领域的发展取得了巨大的突破,其中广义语言模型(LLM&…

pytorch学习笔记

torchvision处理图像的 pytorch官网上看数据集的包,COCO数据集目标检测、语义分割,cifar物体识别 预训练好的模型 这个模块是图片的处理 root-位置,train-创建的true是个训练集,transform 前面是输出图片的数据类型,“…

ByteTrack算法流程的简单示例

ByteTrack ByteTrack算法是将t帧检测出来的检测框集合 D t {\mathcal{D}_{t}} Dt​ 和t-1帧预测轨迹集合 T ~ t − 1 {\tilde{T}_{t-1}} T~t−1​ 进行匹配关联得到t帧的轨迹集合 T t {T_{t}} Tt​。 首先使用检测器检测t帧的图像得到检测框集合 D t {\mathcal{D}_{t}} …

md文件图片上传方案:Github+PicGo 搭建图床

文章目录 1. PicGo 下载2. 配置Github3. 配置PicGo4. PicGo集成Typora4.1 picGo监听端口设置 5. 测试 1. PicGo 下载 下载地址:https://molunerfinn.com/PicGo/ 尽量下载稳定版本 2. 配置Github 1. 创建一个新仓库,用于存放图片 2. 生成一个token&a…

【安卓的签名和权限】

Android 编译使用哪个key签名? 一看Android.mk 在我们内置某个apk的时候都会带有Android.mk,这里面就写明了该APK使用的是什么签名,如: LOCAL_CERTIFICATE : platform表明使用的是platform签名 LOCAL_CERTIFICATE : PRESIGNED…

Redis 生产环境查找无过期时间的 key

在项目中,Redis 不应该被当作传统数据库来使用;储存大量没有过期时间的数据。如果储存大量无过期时间,而且无效的key的话;再加上 Redis 本身的过期策略没有被正确设置,就会大量占用内存。这样就会导致再多的内存资源也不够用。 情况大致是这样,项目中采用 Redis 二级存储…

SpringBoot整合ElasticSearch实现CRUD操作

本文来说下SpringBoot整合ES实现CRUD操作 文章目录 概述项目搭建ES简单的crud操作保存数据修改数据查看数据删除数据 本文小结 概述 SpringBoot支持两种技术和es交互。一种的jest,还有一种就是SpringData-ElasticSearch。根据引入的依赖不同而选择不同的技术。反正作…

leetcode2967. 使数组成为等数数组的最小代价

文章目录 题目思路复杂度Code 题目 给你一个长度为 n 下标从 0 开始的整数数组 nums 。 你可以对 nums 执行特殊操作 任意次 (也可以 0 次)。每一次特殊操作中,你需要 按顺序 执行以下步骤: 从范围 [0, n - 1] 里选择一个下标 …

代码随想录算法训练营Day16 | 654.最大二叉树、617.合并二叉树、700.二叉搜索树中的搜索、98.验证二叉搜索树

LeetCode 654 最大二叉树 本题思路:我们可以看到每次其实这个找最大值,然后创建节点的过程就是一个二叉树的前序遍历的过程。所以,我们可以递归来完成它。 先创找到数组中,最大的值的下标,然后创建根节点然后根据下标…

pytest装饰器:@pytest.mark.incremental

pytest.mark.incremental 是一个pytest中的装饰器,用于标记增量测试。增量测试是一种测试策略,它将测试分解成多个递增的步骤或阶段,并按顺序执行这些步骤。 pytest.mark.incremental 装饰器的作用是告诉pytest,该测试函数是一个…

c语言-整型在内存的存储

文章目录 前言一、整型数值在内存中的存储1.1 整型数值的表示形式1.2 二进制的表示形式1.3 整数在内存中存储 二、大端字节序存储和小端字节序存储2.1 大端字节序存储2.2 小端字节序存储2.3 练习 总结 前言 本篇文章叙述c语言中整型数据在内存中的存储方式。 一、整型数值在内…

Vue学习计划-Vue3--核心语法(一)OptionsAPI、CompositionAPI与setup

1. OptionsAPI与CompositionAPI Vue2的API设计是Options(配置)风格的Vue3的API设计是Composition(组合)风格的 Options API的弊端: Options类型的API,数据、方法、计算属性等,是分散在:data、methods、computed中的,若…

【操作系统xv6】学习记录2 -RISC-V Architecture

说明:看完这节,不会让你称为汇编程序员,知识操作系统的前置。 ref:https://binhack.readthedocs.io/zh/latest/assembly/mips.html https://www.bilibili.com/video/BV1w94y1a7i8/?p7 MIPS MIPS的意思是 “无内部互锁流水级的微…