Api 使用說明

22 minutes

1. API 是什麼?可以拿來做什麼?

ATrISys 建立於 Cytomine 之上,提供一組 HTTP API,讓使用者可以透過程式自動化操作平台,包括:

  • 列出專案、影像、標註
  • 批次下載標註(做 AI 訓練用 dataset)
  • 批次建立/更新標註
  • 整合到自己的分析程式或 pipeline

以下提供 api 基本操作,詳細操作請至 Cytomine 官方文件

2. API 需要資訊

使用 API 前,至少需要下列四個資訊:

  1. Host(主機位址): https://www.asynapse.xyz
  2. Public key(公開金鑰)/ Private key(私密金鑰):可於 使用者帳號 / API 金鑰 頁面查看。
  3. Project ID(專案 ID): 專案網址中將有 project/1234 的數字,1234 即為專案 ID。

3. 使用方式一:用 curl 測試

3.1 測試連線
curl -X GET \
"{HOST}/api/currentuser.json" \
-H "X-Auth-Token: {PUBLIC_KEY}" \
-H "X-Auth-Secret: {PRIVATE_KEY}"

請替換成:

  • {HOST}:https://www.asynapse.xyz/
  • {PUBLIC_KEY}:你的公鑰 public key
  • {PRIVATE_KEY}:你的私鑰 private key

若成功,會回傳一個 JSON,內容包含:

  • 使用者 ID
  • 帳號名稱
  • email 等資訊
3.2 列出所有專案
curl -X GET \
"{HOST}/api/project.json" \
-H "X-Auth-Token: {PUBLIC_KEY}" \
-H "X-Auth-Secret: {PRIVATE_KEY}"

回傳會是一個 JSON 陣列,裡面每個物件代表一個專案:
{"id": 123, "name": "Breast Cancer Project", ...}
你可以從這裡找到 專案 ID。

4. 使用方式二:用 python 連線

4.1 安裝必要套件

程式使用 Cytomine 官方 Python client:

pip install cytomine
4.2 連線到 Cytomine
from cytomine import Cytomine

HOST = "https://www.asynapse.xyz"
PUBLIC_KEY = "YOUR_PUBLIC_KEY"
PRIVATE_KEY = "YOUR_PRIVATE_KEY"

with Cytomine(HOST, PUBLIC_KEY, PRIVATE_KEY) as cyto:
    print("Connected")
4.3 取得專案資訊(Project)
from cytomine.models import Project

project = Project().fetch(PROJECT_ID)

print(project.name, project.ontology)

內容包含:

  • 專案名稱
  • 術語集 ID
  • 建立日期
  • 影像數量等
4.4 取得術語集(Terms)
from cytomine.models import Ontology, TermCollection

ontology = Ontology().fetch(project.ontology)
terms = TermCollection().fetch_with_filter("ontology", ontology.id)

for t in terms:
    print(t.id, t.name)

每個 term 就是一個標註類別,例如:

  • Tumor
  • Stroma
  • Lymphocyte
4.5 列出專案影像
from cytomine.models import ImageInstanceCollection

images = ImageInstanceCollection().fetch_with_filter("project", PROJECT_ID)
print("Number of images:", len(images))

for img in images:
    print(img.id, img.filename, img.width, img.height)
4.6 取得影像所有標註
from cytomine.models import AnnotationCollection

image_id = 12345
W, H = img.width, img.height
MSK_DIR = ""                               # 輸出地址
GEO_DIR = ""                               # 輸出地址
SAVE_WHOLE_MASK = True        # 是否輸出整張 mask
SAVE_PER_IMAGE_GEOJSON = True # 是否輸出 GeoJSON

anns = AnnotationCollection(image=image_id, showWKT=True, showTerm=True)
anns.fetch()

mask_img = None

if SAVE_WHOLE_MASK:
    mask_img = Image.new("L", (W, H), 0)
    drawer = ImageDraw.Draw(mask_img, "L")

if SAVE_PER_IMAGE_GEOJSON:
    geo = {
        "type": "FeatureCollection",
        "features": []
    }

for a in anns:
    print(a.id, a.location, a.term)
    wkt_str = a.location
    try:
        poly = wkt.loads(wkt_str)
    except Exception:
        continue

    term_names = []
    if getattr(a, "term", None):
        term_id = a.term[0]
        tname = next((t.name for t in terms if t.id == term_id), "Unlabeled")
        term_names.append(tname)
    else:
        tname = "Unlabeled"

    class_id = class_name_to_id.get(tname, 255)

    if SAVE_PER_IMAGE_GEOJSON:
        feature = {
            "type": "Feature",
            "properties": {
                "image_id": image_id,
                "annotation_id": a.id,
                "class_id": class_id,
                "class_name": tname,
            },
            "geometry": mapping(poly)
        }
        geo["features"].append(feature)

    if SAVE_WHOLE_MASK:
        def draw_polygon(geom):
            if geom.geom_type == "Polygon":
                exterior = [(x, y) for x, y in np.array(geom.exterior.coords)]
                interiors = [
                    [(x, y) for x, y in np.array(ring.coords)]
                    for ring in geom.interiors
                ]
                drawer.polygon(exterior, fill=int(class_id))
                for hole in interiors:
                    drawer.polygon(hole, fill=0)
            elif geom.geom_type == "MultiPolygon":
                for g in geom.geoms:
                    draw_polygon(g)

        draw_polygon(poly)

# === 輸出區 ===
if SAVE_PER_IMAGE_GEOJSON:
    with open(os.path.join(GEO_DIR, f"{image_id}.geojson"), "w", encoding="utf-8") as jf:
        json.dump(geo, jf, ensure_ascii=False)

if SAVE_WHOLE_MASK:
    mask_img.save(os.path.join(MSK_DIR, f"{image_id}_mask.png"))
4.7 下載影像(原圖)
win_url = f"{HOST}/api/imageinstance/{image_id}/window-{W}-{H}-0-0.jpg?zoom=0"
r = cyto._session.get(win_url)
open("image.jpg","wb").write(r.content)

API 安全性說明

使用 ATrIn/Cytomine API 時,所有權限皆依使用者帳號在平台上的原有權限。
API 無法存取使用者在網頁介面無權瀏覽或操作之資料。
API key 與 Private key 僅能由個人帳號取得,請勿公開或分享。

Next Post