{
"cells": [
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"# Generate cutting XML from exported results from QUPath\n",
"\n",
"The stitched images were loaded into Qupath and specific regions annotaed by hand. calibration points were also selected and labelled with `calib1`, `calib2` and `calib3`.\n",
"\n",
"\n",
"\n",
"The annotated shapes were then exported to geojson file.\n",
"\n",
"\n",
"\n"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"## Import libraries and define helper functions"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import shapely\n",
"import geopandas\n",
"import pandas as pd\n",
"import numpy as np\n",
"\n",
"from lmd.lib import Collection"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"def separate_points_polygons(df: geopandas.GeoDataFrame, geometry_column: str = \"geometry\") -> tuple[geopandas.GeoDataFrame, geopandas.GeoDataFrame]:\n",
" \"\"\"Split QuPath geopandas dataframe by shape types\"\"\"\n",
" points = df[geometry_column].apply(lambda geom: isinstance(geom, shapely.Point))\n",
" polygons = df[geometry_column].apply(lambda geom: isinstance(geom, shapely.Polygon))\n",
"\n",
" return df.loc[points], df.loc[polygons]"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"def get_calib_points(list_of_calibpoint_names: str, df: geopandas.GeoDataFrame) -> np.ndarray:\n",
" \"\"\"Parse selected points into np.array\"\"\"\n",
"\n",
" #Create list of relevant shapes\n",
" pointlist = []\n",
" for point_name in list_of_calibpoint_names:\n",
" pointlist.append(df.loc[df['name'] == point_name, 'geometry'].values[0])\n",
" \n",
" return np.array([[point.x, point.y] for point in pointlist])"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"## Import GEOjson regions\n",
"\n",
"The geojson dataset is loaded into a dataframe with the following structure:\n",
"\n",
"id | objectType | classification | name | geometry |\n",
"--- | --- | --- | --- | --- \n",
"unique shape id | type of shape (e.g. annotation) | all annotation information from qupath | shape name if given | contains information relevant for shape\n",
"\n",
"The geojson should besides containing individual segemnted shapes contain 3 points annotated as calib1, calib2, calib3 that will be used as calibration points for generating the XML"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"Skipping field color: unsupported OGR type: 1\n"
]
},
{
"data": {
"text/html": [
"
\n",
"\n",
"
\n",
" \n",
" \n",
" \n",
" id \n",
" objectType \n",
" name \n",
" geometry \n",
" \n",
" \n",
" \n",
" \n",
" 0 \n",
" 9287277d-e46f-47e9-aa3f-c540b3318b5e \n",
" annotation \n",
" region2 \n",
" POLYGON ((507 1524, 506.6 1539.01, 505.39 1553... \n",
" \n",
" \n",
" 1 \n",
" ab63cfd3-17d0-4dd3-b8e6-95172dda64de \n",
" annotation \n",
" Region1 \n",
" POLYGON ((1789 990, 1730 1153, 1744 1467, 1944... \n",
" \n",
" \n",
" 2 \n",
" b60d2cf7-963e-42ae-8a2a-69ff289d29db \n",
" annotation \n",
" calib1 \n",
" POINT (343.24 368.53) \n",
" \n",
" \n",
" 3 \n",
" 56bdd076-ac9a-4950-97f3-b8c2268ee090 \n",
" annotation \n",
" calib3 \n",
" POINT (361.78 2301.51) \n",
" \n",
" \n",
" 4 \n",
" 03d9bb6e-16b1-4cd9-9181-86da90fb98bf \n",
" annotation \n",
" calib2 \n",
" POINT (1353.77 1165.83) \n",
" \n",
" \n",
"
\n",
"
"
],
"text/plain": [
" id objectType name \\\n",
"0 9287277d-e46f-47e9-aa3f-c540b3318b5e annotation region2 \n",
"1 ab63cfd3-17d0-4dd3-b8e6-95172dda64de annotation Region1 \n",
"2 b60d2cf7-963e-42ae-8a2a-69ff289d29db annotation calib1 \n",
"3 56bdd076-ac9a-4950-97f3-b8c2268ee090 annotation calib3 \n",
"4 03d9bb6e-16b1-4cd9-9181-86da90fb98bf annotation calib2 \n",
"\n",
" geometry \n",
"0 POLYGON ((507 1524, 506.6 1539.01, 505.39 1553... \n",
"1 POLYGON ((1789 990, 1730 1153, 1744 1467, 1944... \n",
"2 POINT (343.24 368.53) \n",
"3 POINT (361.78 2301.51) \n",
"4 POINT (1353.77 1165.83) "
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df = geopandas.read_file(\"test_data/cellculture_example/annotated_regions_Qupath.geojson\")\n",
"df"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Annotations and calibration points (`shapely.Point` objects) and annoatations (`shapely.Polygon` objects) should be processed separately. Therefore, we will use the previously defined helper function `separate_points_polygons` to split the dataframe by shape type."
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"# Separate calibration points (shapely.Points) from annotations (shapely.Polygons)\n",
"points, annotations = separate_points_polygons(df)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's inspect the separated geodataframes"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" \n",
" id \n",
" objectType \n",
" name \n",
" geometry \n",
" \n",
" \n",
" \n",
" \n",
" 2 \n",
" b60d2cf7-963e-42ae-8a2a-69ff289d29db \n",
" annotation \n",
" calib1 \n",
" POINT (343.24 368.53) \n",
" \n",
" \n",
" 3 \n",
" 56bdd076-ac9a-4950-97f3-b8c2268ee090 \n",
" annotation \n",
" calib3 \n",
" POINT (361.78 2301.51) \n",
" \n",
" \n",
" 4 \n",
" 03d9bb6e-16b1-4cd9-9181-86da90fb98bf \n",
" annotation \n",
" calib2 \n",
" POINT (1353.77 1165.83) \n",
" \n",
" \n",
"
\n",
"
"
],
"text/plain": [
" id objectType name \\\n",
"2 b60d2cf7-963e-42ae-8a2a-69ff289d29db annotation calib1 \n",
"3 56bdd076-ac9a-4950-97f3-b8c2268ee090 annotation calib3 \n",
"4 03d9bb6e-16b1-4cd9-9181-86da90fb98bf annotation calib2 \n",
"\n",
" geometry \n",
"2 POINT (343.24 368.53) \n",
"3 POINT (361.78 2301.51) \n",
"4 POINT (1353.77 1165.83) "
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"points"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" \n",
" id \n",
" objectType \n",
" name \n",
" geometry \n",
" \n",
" \n",
" \n",
" \n",
" 0 \n",
" 9287277d-e46f-47e9-aa3f-c540b3318b5e \n",
" annotation \n",
" region2 \n",
" POLYGON ((507 1524, 506.6 1539.01, 505.39 1553... \n",
" \n",
" \n",
" 1 \n",
" ab63cfd3-17d0-4dd3-b8e6-95172dda64de \n",
" annotation \n",
" Region1 \n",
" POLYGON ((1789 990, 1730 1153, 1744 1467, 1944... \n",
" \n",
" \n",
"
\n",
"
"
],
"text/plain": [
" id objectType name \\\n",
"0 9287277d-e46f-47e9-aa3f-c540b3318b5e annotation region2 \n",
"1 ab63cfd3-17d0-4dd3-b8e6-95172dda64de annotation Region1 \n",
"\n",
" geometry \n",
"0 POLYGON ((507 1524, 506.6 1539.01, 505.39 1553... \n",
"1 POLYGON ((1789 990, 1730 1153, 1744 1467, 1944... "
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"annotations"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"## Calibration points\n",
"\n",
"pyLMD expects calibration points as numpy array of the shape (N, 2). We therefore need to extract the coordinates of the calibration points from the `points` geodataframe. To do so, we will use the second helper function `get_calib_points` that converts the `geometry` column of the selected points to a numpy array. Each row in the numpy array represents the coordinates of the calibration points in (x, y) format. "
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[ 343.24, 368.53],\n",
" [1353.77, 1165.83],\n",
" [ 361.78, 2301.51]])"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"caliblist = get_calib_points(['calib1','calib2','calib3'], points)\n",
"caliblist"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"## Generate shape collection\n",
"\n",
"We are now able to convert the annotation dataframe to a collection of shapes. To do so, we initialize an empty pylmd `Collection` with the previously defined calibration points. We will further define the flip the axes of the points with an `orientation_transform` as the image coordinates are flipped compared to the microscope coordinates (for a detailed explanation see [this tutorial](https://mannlabs.github.io/py-lmd/html/pages/segmentation_loader.html#different-coordinate-systems))"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" \n",
" id \n",
" objectType \n",
" name \n",
" geometry \n",
" \n",
" \n",
" \n",
" \n",
" 0 \n",
" 9287277d-e46f-47e9-aa3f-c540b3318b5e \n",
" annotation \n",
" region2 \n",
" POLYGON ((507 1524, 506.6 1539.01, 505.39 1553... \n",
" \n",
" \n",
" 1 \n",
" ab63cfd3-17d0-4dd3-b8e6-95172dda64de \n",
" annotation \n",
" Region1 \n",
" POLYGON ((1789 990, 1730 1153, 1744 1467, 1944... \n",
" \n",
" \n",
"
\n",
"
"
],
"text/plain": [
" id objectType name \\\n",
"0 9287277d-e46f-47e9-aa3f-c540b3318b5e annotation region2 \n",
"1 ab63cfd3-17d0-4dd3-b8e6-95172dda64de annotation Region1 \n",
"\n",
" geometry \n",
"0 POLYGON ((507 1524, 506.6 1539.01, 505.39 1553... \n",
"1 POLYGON ((1789 990, 1730 1153, 1744 1467, 1944... "
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"annotations"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"===== Collection Stats =====\n",
"Number of shapes: 2\n",
"Number of vertices: 117\n",
"============================\n",
"Mean vertices: 58\n",
"Min vertices: 16\n",
"5% percentile vertices: 20\n",
"Median vertices: 58\n",
"95% percentile vertices: 97\n",
"Max vertices: 101\n"
]
}
],
"source": [
"orientation_transform = np.array(\n",
" [\n",
" [1, 0], \n",
" [0, -1]\n",
" ]\n",
")\n",
"\n",
"shape_collection = Collection(\n",
" calibration_points=caliblist,\n",
" orientation_transform=orientation_transform\n",
" )\n",
"\n",
"# Load geopandas into collection class \n",
"shape_collection.load_geopandas(annotations, name_column=\"name\")\n",
"\n",
"shape_collection.stats()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's inspect the loaded annotations and calibration points with the internal `plot` function:"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAeMAAAHACAYAAACRTwCgAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlHJYcgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAR4ZJREFUeJzt3Qd0FNXbBvAnvUFCAgESIIEA0nsNIKLSsWBBiiJFacInCIKgFMGCgDSVKoINBZGif0SkK0jvgoAgnZBQk0BC+n7nvcMuuylAMMnsbJ7fOXN2Z3eymb0sefbeucXJZDKZQERERLpx1u9XExERkWAYExER6YxhTEREpDOGMRERkc4YxkRERDpjGBMREemMYUxERKQzhjEREZHOXPU+AUeUlpaGiIgIFCxYEE5OTnqfDhER6UTm1bpx4waCg4Ph7Jx1/ZdhnAskiEuVKqX3aRARkZ04d+4cSpYsmeXzDONcIDVic+H7+voiOTkZa9asQcuWLeHm5ob8juVhi+Vhi+VxB8vC+OURGxurKmfmXMgKwzgXmJumJYjNYezt7a3uG+UDlJtYHrZYHrZYHnewLBynPO51yZIduIiIiHTGMCYiItIZw5iIiEhnDGMiIiKdMYyzMGPGDJQuXRqenp5o0KABdu7cqfcpERGRg2IYZ2Lx4sUYPHgwxowZg71796JGjRpo1aoVLl26pPepERGRA2IYZ2LKlCno1asXevTogcqVK2P27NmqO/38+fP1PjUiInJAHGecTlJSEvbs2YMRI0ZYHpMpzJo3b45t27Zl+jOJiYlqsx7kbR4TZ97M+3SnHFgeGpaHLZbHHSwL45fH/Z4rwzidK1euIDU1FcWKFbN5XPaPHj2a6c+MHz8eY8eOzfC4zBQjNWqztWvX5sIZGxfLwxbLwxbL4w6WhXHLIz4+/r6OYxjnAKlFyzXm9NOfyZRt5hm45MPTokULw80akxtYHrZYHrZYHnewLIxfHuaW0nthGKdTpEgRuLi4ICoqyuZx2S9evHimP+Ph4aG29OTDYv2BSb+f37E8bLE8bLE87mBZGLc87vc82YErHXd3d9SpUwfr16+3WRJR9sPDw3U9NyIickysGWdCmpy7deuGunXron79+pg2bRri4uJU72oiIqKcxjDORMeOHXH58mWMHj0akZGRqFmzJlavXp2hUxcREVFOYBhnYcCAAWojIiLKbbxmTEREpDOGMRERkc4YxkRERDpjGBMREemMYUxERKQzhjEREZHOGMZEREQ6YxgTERHpjGFMRESkM4YxERGRzhjGREREOmMYExER6YxhTEREpDOGMRERkc4YxkRERDpjGBMREemMYUxERKQzhjEREZHOGMZEREQ6YxgTERHpjGFMRESkM4YxERGRzhjGREREOmMYExER6YxhTEREpDOGMRERkc4YxkRERDpjGBMREemMYUxERKQzhjEREZHOGMZEREQ6YxgTERHpjGFMRESkM4YxERGRzhjGREREOmMYExER6YxhTEREpDOGMRERkc4YxpRBbEIyLsbcyvQ5eVyeJyKinMMwJhsStN3m70THOdsREW0byLIvj8vzDGQiopzDMCYbcYkpuHozCWevxaPT3DuBLLeyL4/L83IcERHlDIYx2Qjy88Ki3g0REuBtCeQ9Z65Zglgel+flOCIiyhkMY8oguJBtID83a5tNEMvzRESUcxjGlCkJ3Kkda9g8JvsMYiKinMcwpkzJNeI3Fh+weUz203fqIiKi/45hTBlYd9aSpuml/cJtriEzkImIchbDmDKMI07fWatOaECGTl1ZjUMmIqLsYxiTDR8PVxQu4J6hs5Z1py55Xo4jIqKcwb+oZMPX0w1f9ayvxhGnH74kgby4T0MVxHIcERHlDIYxZSBBm1XYcnwxEVHOYzM1ERGRzhjGREREOmMYExER6YxhTEREpDOGMRERkc4YxkRERDpjGBMREenMocK4dOnScHJystk++ugjm2MOHjyIhx9+GJ6enihVqhQmTpyY4XWWLFmCihUrqmOqVauGVatW5eG7ICKi/MahwliMGzcOFy9etGz/93//Z3kuNjYWLVu2RGhoKPbs2YNJkybh3Xffxdy5cy3HbN26FZ07d8Yrr7yCffv2oX379mo7dOiQTu+IiIgcncPNwFWwYEEUL1480+cWLlyIpKQkzJ8/H+7u7qhSpQr279+PKVOmoHfv3uqY6dOno3Xr1hg6dKjaf++997B27Vp89tlnmD17dp6+FyIiyh8cLoylWVoCNCQkBF26dMEbb7wBV1ftbW7btg1NmzZVQWzWqlUrTJgwAdevX4e/v786ZvDgwTavKcesWLEiy9+ZmJioNusauEhOTrZs5n26Uw4sDw3LwxbL4w6WhfHL437P1aHC+PXXX0ft2rUREBCg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tGkYOXIknn76aXXM119/jWLFimHFihXo1KlTrr5PIiLKnwwRxpmJiYlBQEBAhsefeuopVYt96KGHMGzYMLVvtm3bNgwePNjmeKn1StCKU6dOITIyUjVNm/n5+aFBgwbqZ7MK48TERLWZxcbGqtvk5GTLZt6nO+XA8tCwPGyxPO5gWRi/PO73XA0ZxidOnMCnn35qUysuUKAAJk+ejMaNG8PZ2RlLly5VTdAStOZAlqCVWq412ZfHzc+bH8vqmMyMHz8eY8eOzfD4mjVr4O3tbdmXWjjdwfKwxfKwxfK4g2Vh3PKIj4+3/zAePnw4JkyYcNdjjhw5ojpcmV24cEE1NXfo0AG9evWyPF6kSBGbWm+9evUQERGBSZMm2dSOc8OIESNsfrfUjEuVKoWWLVvC19dXfTOSD0+LFi3g5uaG/I7lYYvlYYvlcQfLwvjlYW4pteswHjJkCLp3737XY+T6sJmE66OPPopGjRph7ty593x9aV62/gYl15KjoqJsjpF98zVm8608Jr2prY+pWbNmlr/Hw8NDbenJh8X6A5N+P79jedhiedhiedzBsjBuedzveeoaxoGBgWq7H1IjliCW3tELFixQTdH3sn//fptQDQ8Px/r16zFo0CDLYxLW8riQoVMSyHKMOXzlW430qu7Xr98DvEMiIiIHuWYsQdysWTOEhoaq68SXL1+2PGeuzX711Vdwd3dHrVq11P6yZcswf/58zJs3z3LswIED8cgjj6hry+3atcOiRYuwe/duSy1bxiVLUL///vsoX768CudRo0YhODhYXX8mIiLKt2EstVfptCVbyZIlbZ6T4UhmMlTpzJkzcHV1VdeZFy9ejOeff97yvDRvf/fdd2rokoxRlsCVDl5Vq1a1HCM9sOPi4tC7d29ER0ejSZMmWL16tZokhIiIKN+GsVxXvte15W7duqntXqTjl2xZkdrxuHHj1EZERJQXDDEDFxERkSNjGBMREemMYUxERKQzhjEREZHOGMZEREQ6YxgTERHpjGFMRESkM4YxERGRzhjGREREOmMYExER6YxhTEREpDOGMRERkc4YxkRERDpjGBMREemMYUxERKQzhjEREZHOGMZEREQ6YxgTERHpjGFMRESkM4YxERGRzhjGREREOmMYExER6YxhTEREpDOGMRERkc4YxkRERDpjGBMREemMYUxERKQzV71PwBGZ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",
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"shape_collection.plot(calibration = True)"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"## Write to XML"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"You can now write the selection to a Leica-compatible xml file"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[ 34324. -36853.]\n",
"[ 135377. -116583.]\n",
"[ 36178. -230151.]\n"
]
}
],
"source": [
"shape_collection.save(\"./test_data/cellculture_example/shapes_2.xml\")"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "pylmd",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.11"
},
"orig_nbformat": 4
},
"nbformat": 4,
"nbformat_minor": 2
}