mcpField
O
omero-integration

omero-integration

github.com/jaechang-hits数据与数据库38469 次安装1 周前更新
代码仓库

关于 omero-integration

这是面向显微成像研究者和 Python 分析人员的 OMERO 集成技能,通过 omero-py 连接 OMERO 并操作图像数据。它支持像素与 ROI 获取,以及将分析结果作为标注写回服务器。

主要功能

  1. 01浏览项目、数据集和图像层级
  2. 02将图像平面或图块下载为 NumPy 数组
  3. 03管理标签与键值标注
  4. 04读取图像 ROI 形状
  5. 05按元数据查询图像

适用场景

  1. 01从 OMERO 获取图像用于 Python 分析
  2. 02批量为图像添加质控标签或结果
  3. 03读取 ROI 以进行下游定量
  4. 04将分析参数作为标注记录

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/jaechang-hits/sciagent-skills --skill omero-integration

安装后在 Claude Code 中输入/omero-integration确认已加载。

详细介绍

omero-integration

概述

OMERO 是一款开源图像数据管理系统,广泛应用于显微镜设施和核心实验室。omero-py 库提供了一个 Python 客户端(BlitzGateway),可连接到 OMERO 服务,以编程方式访问图像、数据集、项目、标签、注释和 ROI。可使用它构建自动化分析工作流,从 OMERO 获取图像,在 Python 中处理,并将结果作为注释写回。

适用场景

  • 以编程方式从 OMERO 获取图像:将显微图像下载为 numpy 数组,以供后续分析,而无需使用 OMERO Insight GUI。
  • 批量添加注释和标签:根据分析结果,为大量图像/数据集添加标签、键值对注释或评论。
  • 访问和管理 ROI:读取存储在 OMERO 中的分割 ROI(形状),以供后续定量分析或导出。
  • 将 OMERO 集成到 Python 分析流水线中:将 OMERO 图像数据接入 scikit-image、OpenCV、CellPose 或其他图像分析工具。
  • 自动化 QC 工作流:按元数据(通道、采集日期、实验人员)查询图像,并标记不符合质量标准的图像。
  • 数据溯源跟踪:将分析溯源信息(参数、工具版本)作为结构化键值注释附加到图像。
  • 如需在没有 OMERO 服务的情况下进行本地图像分析,请直接使用 tifffile、aicsimageio 或 imageio。

先决条件

  • Python 包:omero-py、numpy、Pillow
  • 系统:Java 8+(omero-py 内部依赖),Ice 3.6(通过 conda 自动安装)
  • 数据要求:具备运行中的 OMERO 服务的访问凭据(主机、端口、用户名、密码)
  • 环境:强烈建议使用 Conda;omero-py 的依赖关系较复杂
conda create -n omero python=3.9
conda activate omero
conda install -c ome -c conda-forge omero-py
pip install numpy Pillow

快速开始

import omero
from omero.gateway import BlitzGateway

# Connect to OMERO server
conn = BlitzGateway("username", "password", host="omero.example.org", port=4064)
conn.connect()
print(f"Connected: {conn.isConnected()}, user: {conn.getUser().getName()}")

# Get an image by ID and download as numpy array
image = conn.getObject("Image", 12345)
pixels = image.getPrimaryPixels()
plane = pixels.getPlane(0, 0, 0)   # z=0, c=0, t=0
print(f"Image shape: {plane.shape}, dtype: {plane.dtype}")

conn.close()

核心 API

模块 1:BlitzGateway — 连接管理

BlitzGateway 是与服务交互的主要入口。

from omero.gateway import BlitzGateway

# Establish connection
conn = BlitzGateway(
    username="user",
    passwd="password",
    host="omero.example.org",
    port=4064,
    secure=True,
)
success = conn.connect()
print(f"Connected: {success}")
print(f"Server version: {conn.getServerVersion()}")
print(f"Current group: {conn.getGroupFromContext().getName()}")

# Always close when done
conn.close()
# Context manager pattern for automatic cleanup
class OmeroConnection:
    def __init__(self, **kwargs):
        self.conn = BlitzGateway(**kwargs)
    def __enter__(self):
        self.conn.connect()
        return self.conn
    def __exit__(self, *args):
        self.conn.close()

with OmeroConnection(username="user", passwd="pass",
                     host="omero.example.org", port=4064) as conn:
    print(f"Connected as: {conn.getUser().getFullName()}")
模块 2:项目、数据集和图像查询

遍历 OMERO 数据层级(Project → Dataset → Image)。

# List all projects for the current user
for project in conn.listProjects():
    print(f"Project {project.getId()}: {project.getName()}")
    for dataset in project.listChildren():
        print(f"  Dataset {dataset.getId()}: {dataset.getName()}")
        for image in dataset.listChildren():
            print(f"    Image {image.getId()}: {image.getName()}")
# Search for images by name
results = conn.searchObjects(["Image"], "GFP_control")
for img in results:
    print(f"  Found: {img.getId()} - {img.getName()}")

# Get a specific object by ID
image   = conn.getObject("Image",   12345)
dataset = conn.getObject("Dataset", 678)
project = conn.getObject("Project", 90)
print(f"Image: {image.getName()}, size: {image.getSizeX()}x{image.getSizeY()}")
print(f"Channels: {image.getSizeC()}, Z-slices: {image.getSizeZ()}, timepoints: {image.getSizeT()}")
模块 3:将图像下载为 NumPy 数组

获取像素数据作为 numpy 数组进行处理。

import numpy as np

image  = conn.getObject("Image", 12345)
pixels = image.getPrimaryPixels()

# Get a single 2D plane: getPlane(z_index, channel_index, time_index)
plane = pixels.getPlane(0, 0, 0)
print(f"Plane shape: {plane.shape}, dtype: {plane.dtype}")

# Get all channels at z=0, t=0
planes = [pixels.getPlane(0, c, 0) for c in range(image.getSizeC())]
stack  = np.stack(planes, axis=0)   # shape: (C, Y, X)
print(f"Multi-channel stack: {stack.shape}")
# Efficient bulk download using getTiles (for large images)
image  = conn.getObject("Image", 12345)
pixels = image.getPrimaryPixels()

tile_coords = [(0, 0, 0, (0, 0, 512, 512))]  # (z, c, t, (x, y, w, h))
for tile in pixels.getTiles(tile_coords):
    print(f"Tile shape: {tile.shape}")  # (512, 512) numpy array
模块 4:标签和注释管理

在 OMERO 对象上添加、获取和更新标签及键值对注释。

import omero

# Add a tag to an image
tag_ann = omero.gateway.TagAnnotationWrapper(conn)
tag_ann.setValue("passed_QC")
tag_ann.setNs("my.analysis.namespace")
tag_ann.save()

image = conn.getObject("Image", 12345)
image.linkAnnotation(tag_ann)
print(f"Tag '{tag_ann.getValue()}' linked to image {image.getId()}")
# Add key-value pairs (MapAnnotation) to an image
map_ann = omero.gateway.MapAnnotationWrapper(conn)
map_ann.setNs("openmicroscopy.org/omero/client/mapAnnotation")
kv_pairs = [
    ["analysis_tool",    "CellProfiler 4.2"],
    ["cell_count",       "342"],
    ["mean_intensity",   "1847.3"],
    ["analysis_date",    "2026-02-18"],
]
map_ann.setValue(kv_pairs)
map_ann.save()
image.linkAnnotation(map_ann)
print(f"Key-value annotation attached to image {image.getId()}")

# Read existing annotations
for ann in image.listAnnotations():
    print(f"  {ann.OMERO_TYPE}: {ann.getValue()}")
模块 5:ROI 访问

读取存储在 OMERO 中的分割 ROI(形状),以供后续定量分析。

from omero.model import RoiI

# Get all ROIs for an image
roi_service = conn.getRoiService()
result = roi_service.findByImage(12345, None)

for roi in result.rois:
    for shape in roi.copyShapes():
        shape_type = shape.__class__.__name__
        print(f"  ROI {roi.id.val}: {shape_type}")
        if shape_type == "RectangleI":
            print(f"    x={shape.x.val:.1f}, y={shape.y.val:.1f}, "
                  f"w={shape.width.val:.1f}, h={shape.height.val:.1f}")
        elif shape_type == "EllipseI":
            print(f"    cx={shape.x.val:.1f}, cy={shape.y.val:.1f}, "
                  f"rx={shape.radiusX.val:.1f}, ry={shape.radiusY.val:.1f}")
# Convert ROI masks to numpy boolean arrays
import numpy as np
from omero.gateway import BlitzGateway

def roi_to_mask(shape, height, width):
    """Convert a rectangle ROI to a boolean numpy mask."""
    mask = np.zeros((height, width), dtype=bool)
    x  = int(shape.x.val)
    y  = int(shape.y.val)
    w  = int(shape.width.val)
    h  = int(shape.height.val)
    mask[y:y+h, x:x+w] = True
    return mask

image  = conn.getObject("Image", 12345)
height = image.getSizeY()
width  = image.getSizeX()

result = conn.getRoiService().findByImage(12345, None)
for roi in result.rois:
    for shape in roi.copyShapes():
        if shape.__class__.__name__ == "RectangleI":
            mask = roi_to_mask(shape, height, width)
            print(f"ROI mask: {mask.sum()} pixels selected")

核心概念

OMERO 数据层级

OMERO 按 Project → Dataset → Image 的层级组织数据。图像包含像素数据和元数据(通道、Z 切片、时间点)。注释(标签、键值对、评论)可以附加到层级中的任意对象。

# Hierarchy navigation
project = conn.getObject("Project", 90)
for dataset in project.listChildren():
    imgs = list(dataset.listChildren())
    print(f"Dataset '{dataset.getName()}': {len(imgs)} images")
像素访问模式

OMERO 将像素存储为(Z、C、T)堆栈。getPlane(z, c, t) 返回一个 2D numpy 数组。对于大型图像,请使用 getTiles 下载空间子区域。像素类型(uint8、uint16、float32)与原始采集格式一致。

image  = conn.getObject("Image", 12345)
pixels = image.getPrimaryPixels()
ptype  = pixels.getPixelsType().getValue()
print(f"Pixel type: {ptype}")  # e.g., "uint16"
print(f"Dimensions: XY={image.getSizeX()}x{image.getSizeY()}, "
      f"Z={image.getSizeZ()}, C={image.getSizeC()}, T={image.getSizeT()}")

常见工作流

工作流 1:批量下载和分析

目标:下载数据集中的所有图像,进行处理,并将结果存储为键值注释。

import numpy as np
from omero.gateway import BlitzGateway, MapAnnotationWrapper

def mean_intensity(plane):
    return float(plane.mean())

conn = BlitzGateway("user", "pass", host="omero.example.org", port=4064)
conn.connect()

dataset = conn.getObject("Dataset", 678)
results = []

for image in dataset.listChildren():
    pixels = image.getPrimaryPixels()
    plane  = pixels.getPlane(0, 0, 0)         # first z, channel 0, t=0
    mi     = mean_intensity(plane)
    results.append((image, mi))

    # Attach mean intensity as key-value annotation
    ann = MapAnnotationWrapper(conn)
    ann.setNs("my.pipeline.v1")
    ann.setValue([["mean_intensity_ch0", f"{mi:.2f}"]])
    ann.save()
    image.linkAnnotation(ann)
    print(f"Image {image.getId()} '{image.getName()}': mean={mi:.2f}")

print(f"\nProcessed {len(results)} images in dataset '{dataset.getName()}'")
conn.close()
工作流 2:按标签获取图像并导出

目标:查找所有带有 "screen_hits" 标签的图像,下载通道 1 并保存为 TIFF 文件。

import numpy as np
import tifffile
from omero.gateway import BlitzGateway

conn = BlitzGateway("user", "pass", host="omero.example.org", port=4064)
conn.connect()

# Find images with a specific tag
tag_value = "screen_hits"
tagged_images = []
for ann in conn.getObjects("TagAnnotation", attributes={"textValue": tag_value}):
    for image in ann.listLinkedObjects(["Image"]):
        tagged_images.append(image)

print(f"Found {len(tagged_images)} images tagged '{tag_value}'")

for image in tagged_images:
    pixels = image.getPrimaryPixels()
    # Download DAPI channel (index 0) at z=0, t=0
    plane  = pixels.getPlane(0, 0, 0)
    fname  = f"image_{image.getId()}_DAPI.tif"
    tifffile.imwrite(fname, plane)
    print(f"Saved {fname}: shape={plane.shape}, dtype={plane.dtype}")

conn.close()
print("Export complete")

关键参数

参数模块默认值范围 / 选项作用
hostBlitzGateway必填主机名或 IPOMERO 服务地址
portBlitzGateway40641024–65535OMERO 服务端口(4064 = 标准端口)
secureBlitzGatewayFalseTrue、False使用 SSL/TLS 加密连接
z, c, tgetPlane0, 0, 00 – size-1Z 切片、通道、时间点索引
tile_coordsgetTiles—(z,c,t,(x,y,w,h)) 列表空间子区域下载坐标
NsannotationsNone任意 URI 字符串用于筛选注释的命名空间

最佳实践

  1. 始终关闭连接:完成所有操作后调用 conn.close(),或使用上下文管理器。未关闭的连接会占用服务资源,并可能导致会话超时。

  2. 为注释使用命名空间:为创建的每条注释设置唯一的 Ns(命名空间 URI),以便区分程序生成的注释、手动添加的注释和其他工具生成的注释。

  3. 只下载所需图像平面:对于大型延时成像或 Z-stack 图像,使用带有具体索引的 getPlane(z, c, t),而不是下载所有图像平面。若需空间子集,请使用 getTiles。

  4. 批量写入注释以减少服务端往返:收集多张图像上的键值对,并通过循环写入,而不是针对每张图像的每个键分别发起 RPC 调用。

  5. 处理前检查图像尺寸:访问像素数据前,务必读取 getSizeX()、getSizeY()、getSizeC()、getSizeZ()、getSizeT(),以避免数据集尺寸异常时发生索引越界错误。

常用示例

示例:列出图像上的所有标签

适用场景:添加新标签前检查现有注释,避免重复。

image = conn.getObject("Image", 12345)
for ann in image.listAnnotations():
    if ann.OMERO_TYPE == "TagAnnotation":
        print(f"  Tag: '{ann.getValue()}' (ns={ann.getNs()})")
    elif ann.OMERO_TYPE == "MapAnnotation":
        for k, v in ann.getValue():
            print(f"  KV: {k} = {v}")
示例:多通道最大值投影

适用场景:为指定通道创建跨所有 Z 切片的最大强度投影。

import numpy as np

def max_projection(image, channel=0, timepoint=0):
    pixels = image.getPrimaryPixels()
    planes = [pixels.getPlane(z, channel, timepoint)
              for z in range(image.getSizeZ())]
    stack  = np.stack(planes, axis=0)
    return stack.max(axis=0)

image = conn.getObject("Image", 12345)
proj  = max_projection(image, channel=1)
print(f"Max projection shape: {proj.shape}, max value: {proj.max()}")

预期输出

  • getPlane() 返回的 NumPy 数组:形状为 (Y, X),数据类型与采集数据一致(uint8、uint16、float32)
  • 多通道堆栈:堆叠图像平面时,形状为 (C, Y, X)
  • 附加到图像的注释可在 OMERO.web 和 OMERO Insight GUI 中查看
  • ROI 形状以 omero.model 对象形式返回,并包含坐标属性

故障排查

问题原因解决方案
Ice.ConnectionRefusedException主机/端口错误或服务端已关闭验证 host 和 port=4064;确认服务端正在运行
omero.SecurityViolation对对象的权限不足检查组成员身份;请服务端管理员授予访问权限
ImportError: omero未通过 conda 安装 omero-py使用 conda install -c ome -c conda-forge omero-py;pip 安装不可靠
AttributeError: 'NoneType' object服务端上未找到对象 ID验证对象是否存在:conn.getObject(type, id) 是否返回非 None
Ice.MemoryLimitException一次性下载的图像过大使用 getTiles() 下载空间子集,或逐个切片使用 getPlane()
下载速度慢按顺序下载大量小图像平面使用 getTiles() 并传入所有坐标的列表进行批量下载
运行中会话超时长时间分析超过服务端空闲超时时间在较长的循环中定期调用 conn.keepAlive()

参考资料

评论

支持 Markdown