omero-integration について
顕微鏡研究者や Python 分析担当者が、omero-py で OMERO に接続して画像データを扱うためのスキルです。ピクセルデータや ROI の取得に加え、分析結果を注釈としてサーバーへ書き戻せます。
主な機能
- 01プロジェクト、データセット、画像の階層表示
- 02画像プレーンやタイルを NumPy 配列で取得
- 03タグとキー・バリュー注釈の管理
- 04画像 ROI 形状の読み取り
- 05メタデータによる画像検索
活用シーン
- 01OMERO から画像を取得して Python 分析
- 02画像へ QC タグや結果を一括付与
- 03下流の定量分析向けに ROI を読み取り
- 04分析パラメーターを注釈として記録
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ jaechang-hits/ sciagent-skills --skill omero-integrationインストール後、Claude Code で/omero-integrationを入力して読み込まれたか確認します。
詳細
omero-integration
概要
OMERO は、顕微鏡施設やコアラボで広く使用されているオープンソースの画像データ管理システムです。omero-py ライブラリは、OMERO サーバーに接続する Python クライアント(BlitzGateway)を提供し、画像、データセット、プロジェクト、タグ、アノテーション、ROI にプログラムからアクセスできるようにします。これを使用して、OMERO から画像を取得し、Python で処理して、結果をアノテーションとして書き戻す自動解析ワークフローを構築できます。
使用する場面
- OMERO からのプログラムによる画像取得:OMERO Insight GUI を使わずに、後続の解析用に顕微鏡画像を numpy 配列としてダウンロードします。
- 一括アノテーションとタグ付け:解析結果に基づいて、多数の画像やデータセットにタグ、キーと値のペアのアノテーション、またはコメントを適用します。
- 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 のデータ階層(プロジェクト → データセット → 画像)をたどります。
# 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 はデータをプロジェクト → データセット → 画像として整理します。画像にはピクセルデータとメタデータ(チャネル、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 を numpy 配列としてダウンロードして、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")
主要なパラメーター
| パラメーター | モジュール | デフォルト | 範囲/オプション | 効果 |
|---|---|---|---|---|
host | BlitzGateway | 必須 | ホスト名または IP | OMERO サーバーのアドレス |
port | BlitzGateway | 4064 | 1024–65535 | OMERO サーバーのポート(4064 は標準) |
secure | BlitzGateway | False | True、False | SSL/TLS で暗号化された接続を使用します |
z, c, t | getPlane | 0, 0, 0 | 0 – size-1 | Z スライス、チャネル、時間点のインデックス |
tile_coords | getTiles | — | (z,c,t,(x,y,w,h)) のリスト | 空間部分領域のダウンロード座標 |
Ns | annotations | None | 任意の URI 文字列 | アノテーションのフィルタリングに使用する名前空間 |
ベストプラクティス
-
接続は必ず閉じてください:すべての操作の後に
conn.close()を呼び出すか、コンテキストマネージャーを使用します。接続を閉じないとサーバーリソースを消費し、セッションタイムアウトの原因になることがあります。 -
アノテーションには名前空間を使用してください:作成するすべてのアノテーションに一意の
Ns(名前空間 URI)を設定すると、プログラムで作成したアノテーションを手動で作成したものや他のツールのものと区別できます。 -
必要なプレーンだけをダウンロードしてください:大きなタイムラプス画像や Z スタック画像では、すべてのプレーンをダウンロードするのではなく、特定のインデックスを指定して
getPlane(z, c, t)を使用します。空間部分領域にはgetTilesを使用します。 -
アノテーションの書き込みをまとめて、サーバーとの往復を減らしてください:画像ごとに個別の RPC 呼び出しを行うのではなく、複数の画像にわたるキーと値のペアを収集し、ループ内で書き込みます。
-
処理前に画像の寸法を確認してください:予期しない形状のデータセットでインデックスが範囲外になるエラーを避けるため、ピクセルデータにアクセスする前に必ず
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)、取得データに応じた dtype(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() を呼び出します |
参考資料
- OMERO Python API ドキュメント — omero-py の公式ドキュメント
- OMERO 開発者向けドキュメント — Python クライアントガイド
- OMERO GitHub(ome/omero-py) — ソースコードと課題トラッカー
- Linkert et al.(2010)、J Cell Biol — OMERO 論文 — OMERO の原著論文