forked from sectra-medical/dpat_imageanalysisapi_sdk
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
0f60a06
commit 1c1bd79
Showing
14 changed files
with
710 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,14 @@ | ||
# Sectra Digital Pathology (DPAT) ImageAnalysis (IA) API - Software Development Kit (SDK) | ||
|
||
## About | ||
This is a work in progress repository providing examples on how to integrate with the Sectra IA-API. | ||
|
||
Currently only a basic application exist that returns (random) results given user input. | ||
|
||
See the `examples` folder for more info. A roadmap will be provided soon. | ||
|
||
## Changelog | ||
|
||
### 2024-01-05 | ||
|
||
- Added basic example `examples/python/ia_app_basic/` showing how an app can accept user input and return results for a specific sub-area of a WSI. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
# Temporary Python files | ||
*.pyc | ||
*.egg-info | ||
__pycache__ | ||
.ipynb_checkpoints | ||
|
||
# Temporary OS files | ||
Icon* | ||
|
||
# Temporary virtual environment files | ||
/.cache/ | ||
/.venv/ | ||
|
||
# Temporary server files | ||
.env | ||
*.pid | ||
|
||
# Build and release directories | ||
/build/ | ||
/dist/ | ||
/debug/ | ||
*.spec | ||
|
||
# Sublime Text | ||
*.sublime-workspace | ||
|
||
# Eclipse | ||
.settings | ||
|
||
# Don't include | ||
scripts | ||
.python-version |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
pcaddemo | ||
======== | ||
|
||
## About | ||
This is a demo repository for a simple Sectra Image Analysis API (IA-API) implementation. | ||
|
||
Author: Martin Lindvall, [email protected] | ||
|
||
## Application function | ||
|
||
- Input: User draws a polygon around a region of interest ( taggedPolygon, see `webserver.py:app_return_registerinfo` ) | ||
- Output: a graphical primitive, or a "patch gallery" (see `webserver.py:DEMO_TYPE` and `webserver.py:app_on_userinput` ) | ||
|
||
## Development notes | ||
Uses a simple flask server for responding to IA-API requests and a requests-based client for outgoing communications with the IA-API.. | ||
|
||
For simplicity, uses no async libraries. For load-scaling, simply run with number of workers processes corresponding to expected max number of simultaneous users. Tools such as gunicorn or a similar pre-forking worker server is recommended to spawn the workers. | ||
|
||
Should have no trouble scaling as long as number of max simultaneous users are below 1000 or so. | ||
|
||
### Install and run | ||
|
||
You can run this example in a virtualenv using poetry, or directly in the current python environment. | ||
|
||
Using poetry: | ||
``` | ||
poetry run python pcaddemo/__main__.py | ||
``` | ||
|
||
As plain-old python: | ||
|
||
``` | ||
python setup.py develop | ||
python pcaddemo/__main__.py | ||
``` | ||
|
||
## Sectra Server configuration | ||
|
||
Running this demo starts a web server on 0.0.0.0 (all local ips) listening on port 5001. | ||
|
||
You need to configure the Sectra Pathology Server (SPS) to call this server. This involves: | ||
|
||
1. Ensuring that the SPS can reach this host over the network (ensure there is a route and that firewall rules allow it) | ||
2. Registering the IA-API app in the configuration interface (see chapter 7 in the System Administrator Manual) | ||
- in brief: goto https://<pathologyserver>/sectrapathologyimport/config | ||
- log in, click Image Analysis Applications | ||
- Under Server Side Applications, click 'register new' | ||
- Enter the URL where your started web server (this repository) is running, as reachable from the pathology server. Example: `http://my-ia-app-server:5001/iademo` | ||
- Press 'Retrieve registration Info' | ||
- The fields should be populated, press *Save* | ||
- Per default, the app is disabled. Click the 'disabled' button to toggle it to enabled. | ||
|
||
If succesful, you should now be able to right-click in any Pathology Image and select your new IA-APP (you might need to refresh any running sessions). | ||
|
||
|
||
## Tested with | ||
|
||
- DPAT 3.4 on 2024-01-05 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
set FLASK_APP=pcaddemo\webserver | ||
set FLASK_RUN_PORT=5005 | ||
set FLASK_DEBUG=1 | ||
flask run |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
#!/bin/bash | ||
export FLASK_APP=pcaddemo/webserver | ||
export FLASK_RUN_PORT=5005 | ||
export FLASK_RUN_HOST=0.0.0.0 | ||
export FLASK_DEBUG=1 | ||
flask run |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
""" pcad demo """ | ||
|
||
from .version import __version__ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
#!/usr/bin/env python | ||
|
||
if __name__ == "__main__": | ||
from pcaddemo.webserver import app, BIND_PORT | ||
|
||
app.run(host="0.0.0.0", port=BIND_PORT, debug=False) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
# -*- coding: utf-8 -*- | ||
|
||
""" | ||
analysisapi -- python client for the Sectra Pathology Image Analysis API | ||
This is a requests-style, non-async implementation. | ||
""" | ||
|
||
import logging as log | ||
from io import BytesIO | ||
import time | ||
import requests | ||
|
||
DEFAULT_TIMEOUT = ( | ||
3.0 * 2 + 0.05, | ||
30.0 * 2, | ||
) # ( connect_timeout, read_timeout ) in seconds | ||
|
||
|
||
class AnalysisApi: | ||
def __init__(self, url, hookname, token=None, api_version="1.5"): | ||
""" | ||
@param url -- typically https://localhost/SectraPathologyServer/external/imageanalysis/v1 | ||
""" | ||
self.url = url | ||
self.name = hookname | ||
self.token = token | ||
self._session = requests.Session() | ||
self.api_version = api_version | ||
|
||
def _auth_get(self, url, ok_codes=[200]): | ||
"""make GET request adding the bearer token""" | ||
r = self._session.get(url, headers=self._headers(), timeout=DEFAULT_TIMEOUT) | ||
if not r.status_code in ok_codes: | ||
r.raise_for_status() | ||
return r | ||
|
||
def slideinfo(self, slide_id): | ||
"""GET slide metadata for slide""" | ||
r = self._auth_get("{}/slides/{}/info".format(self.url, slide_id)) | ||
slide_info = r.json()["blocks"][0]["slides"][0] # yeah, weird | ||
return slide_info | ||
|
||
def tile(self, slide_id, dzilvl, col, row, zstack=0, format="jpg"): | ||
"""retrieve an image tile""" | ||
tile_url = "{}/images/{}_files/{}/{}_{}_{}.{}".format( | ||
self.url, slide_id, dzilvl, col, row, zstack, format | ||
) | ||
r = self._session.get( | ||
tile_url, headers=self._headers(), timeout=DEFAULT_TIMEOUT | ||
) | ||
if not r.status_code == 200: | ||
r.raise_for_status() | ||
return BytesIO(r.content) | ||
|
||
def store_result(self, result_data): | ||
"""store result into sectra pathology db""" | ||
url = f"{self.url}/hooks/{self.name}/results/" | ||
r = self._session.post( | ||
url, headers=self._headers(), timeout=DEFAULT_TIMEOUT, json=result_data | ||
) | ||
if not r.status_code == 200: | ||
r.raise_for_status() | ||
parsed = r.json() | ||
return parsed | ||
|
||
def update_result(self, result_data): | ||
"""update existing result""" | ||
result_id = result_data["id"] | ||
url = f"{self.url}/hooks/{self.name}/results/{result_id}" | ||
r = self._session.put( | ||
url, headers=self._headers(), timeout=DEFAULT_TIMEOUT, json=result_data | ||
) | ||
if not r.status_code == 200: | ||
r.raise_for_status() | ||
parsed = r.json() | ||
return parsed | ||
|
||
def _headers(self): | ||
return { | ||
"Authorization": "Bearer {}".format(self.token), | ||
"X-Sectra-ApiVersion": f"{self.api_version}", | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import json | ||
import random | ||
|
||
from shapely.geometry import Polygon, Point | ||
|
||
|
||
def sectra_polygon_to_shapely(data_polygon): | ||
return Polygon([(pt["x"], pt["y"]) for pt in data_polygon["points"]]) | ||
|
||
|
||
def random_point_in_polygon(poly): | ||
minx, miny, maxx, maxy = poly.bounds | ||
while True: | ||
p = Point(random.uniform(minx, maxx), random.uniform(miny, maxy)) | ||
if poly.contains(p): | ||
return p |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
""" | ||
version info | ||
""" | ||
__version__ = "0.1.0" | ||
|
||
# this is the minimum version we require, we do not support | ||
# servers that run earlier versions. | ||
# | ||
# Bump this number when you add expectations on API datastructures or endpoints only | ||
# present from version X.Y onward. | ||
# | ||
# 1.5 here corresponds to DPAT 3.0 and we make use of /slides/<id>/info endpoint | ||
# only available from this version and onward | ||
SECTRA_IA_API_MIN_VERSION = "1.5" | ||
|
||
# this is the highest version we've explicitly tested with | ||
# higher-capable servers should fallback to this api version to ensure compatability | ||
# | ||
# Bump this to the highest number you've tested with. | ||
# If you are lazy, set: | ||
# SECTRA_IA_API_MAX_VERSION = SECTRA_IA_API_MIN_VERSION | ||
# (you might lose some enhancements that you do not rely on anyway) | ||
SECTRA_IA_API_MAX_VERSION = "1.8" |
Oops, something went wrong.