Skip to content

Instantly share code, notes, and snippets.

@alexlib
Last active September 13, 2024 12:08
Show Gist options
  • Save alexlib/5091b33947e4f8bde7a0d7445e054228 to your computer and use it in GitHub Desktop.
Save alexlib/5091b33947e4f8bde7a0d7445e054228 to your computer and use it in GitHub Desktop.
Remove background for shadow 3D-PTV and detecting overlapping spheres
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "code",
"execution_count": 124,
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"from skimage import io, measure, morphology, feature\n",
"from scipy import ndimage\n",
"import matplotlib.pyplot as plt\n",
"\n",
"# Load the image\n",
"image = io.imread('./spheres_isolated.png') # Replace with your image path\n"
]
},
{
"cell_type": "code",
"execution_count": 125,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAA7cAAAPdCAYAAABRC58/AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8fJSN1AAAACXBIWXMAAA9hAAAPYQGoP6dpAAAt7klEQVR4nO3de5TXdZ348deXgZlhALkMMiQKUqZAXtA1rBC5aahctkwtyyX1bLlUv9K81Z5WZb2Ft83DaurPVXNzs0hdUTdKxEslW7pu7jG1IycvuakQiMSACDPv3x/+mBqZgUEuMy97PM7hnObzfX8+7/fnO1/jPPl8v59vpZRSAgAAABLr1tkLAAAAgG0lbgEAAEhP3AIAAJCeuAUAACA9cQsAAEB64hYAAID0xC0AAADpiVsAAADSE7cAAACkJ24Bkrj55pujUqm0/KmtrY3BgwfHxIkT45JLLomlS5e+42M/9dRTcf7558fzzz+//Ra8k+c5//zzo1KpbHFcKSVuu+22GDduXAwaNChqa2tj9913jylTpsQNN9ywTXP/4Q9/eEf7d4a77747pk+fHg0NDVFdXR0DBgyIyZMnx6233hrr16/fYfPu6NdapVKJ888/f4vjNv73tKNf8wDsPOIWIJmbbropFi9eHPfdd19cffXVMXr06JgzZ06MHDkyFi5c+I6O+dRTT8Xs2bN3StzujHk25+tf/3qccMIJMXLkyLjhhhviRz/6UVx44YXR0NAQd911V6eta2cppcTJJ58cM2bMiObm5rjyyitj4cKF8Z3vfCcOOOCA+MIXvhDXXHPNDpt/R78GFi9eHH/7t3+7Q44NQNfWvbMXAMDW2XfffePggw9u+fkTn/hEnH766XHooYfGMcccE88++2w0NDR04gq7rrVr18a3vvWtmDlzZlx//fWtHjvppJOiubm5k1bWMWvWrIm6urptOsZll10WN998c8yePTvOPffcVo9Nnz49zj777FiyZMk2zbE9be05f+hDH9qBqwGgK3PlFuBdYOjQoXHFFVfEH//4x7juuutaPfbYY4/FjBkzYsCAAVFbWxsHHnhg/OAHP2h5/Oabb47jjjsuIiImTpzY8rbnm2++uWXMwoULY/LkybHLLrtEXV1djB07Nu6///5N1vHMM8/ECSecEA0NDVFTUxNDhw6NmTNnxrp167brPPfee2+MHj06ampqYvjw4XH55Zd36HlqbGyMdevWxXve8542H+/W7U9/LT7//PNRqVTi0ksvjYsuuiiGDh0atbW1cfDBB7e5poiIV199NU444YTo27dvNDQ0xCmnnBKvv/56qzGllLjmmmti9OjR0bNnz+jfv38ce+yx8dvf/rbVuAkTJsS+++4bDz/8cHzkIx+Jurq6OOWUUyIiYtWqVXHmmWfG8OHDo7q6OoYMGRKnnXZaNDY2bvb8169fH3PmzIkRI0bEP/zDP7Q5ZvDgwXHooYe2/Pzmm2/GhRdeGCNGjIiamprYdddd4+STT45ly5a12m/PPfeMadOmxYIFC+Kggw6Knj17xogRI+LGG29sGbOl18DmzvnFF1+ME088MQYNGhQ1NTUxcuTIuOKKKzb5B4m23pb8n//5nzF27Niora2N3XbbLb7+9a+3+dbrRYsWxYQJE6K+vj569uwZQ4cOjU984hOxZs2azT6vAHQRBYAUbrrpphIR5dFHH23z8dWrV5eqqqoyefLklm2LFi0q1dXVZdy4ceX73/9+WbBgQTnppJNKRJSbbrqplFLK0qVLy8UXX1wiolx99dVl8eLFZfHixWXp0qWllFL+9V//tVQqlfKxj32s3HHHHeXuu+8u06ZNK1VVVWXhwoUtc/3qV78qvXv3LnvuuWe59tpry/3331+++93vluOPP76sWrVqu82zcOHCUlVVVQ499NByxx13lHnz5pUPfvCDZejQoaUjf63ttddepU+fPuWKK64oTz/9dGlubm5z3HPPPVciouyxxx7l0EMPLbfffnvLXD169CiPPPJIy9jzzjuvRETZZ599yrnnnlvuu+++cuWVV5aamppy8skntzru5z73udKjR49yxhlnlAULFpR/+7d/KyNGjCgNDQ3llVdeaRk3fvz4MmDAgLLHHnuUuXPnlgceeKA89NBDpbGxsYwePboMHDiwXHnllWXhwoXlqquuKn379i2TJk1q93xKKeWRRx4pEVHOOeecLT5PpZTS1NRUjjzyyNKrV68ye/bsct9995UbbrihDBkypIwaNaqsWbOmZeywYcPK7rvvXkaNGlVuueWW8uMf/7gcd9xxJSLKQw89VErZ8mutvXNeunRpGTJkSNl1113LtddeWxYsWFC+9KUvlYgos2bNarXmiCjnnXdey8+//vWvS11dXRk1alT53ve+V+66664yZcqUltfLc8891/L7rq2tLUcccUT593//9/Lggw+WW2+9tfzN3/xNee211zr0fAHQucQtQBJbittSSmloaCgjR45s+XnEiBHlwAMPLOvXr281btq0aeU973lPaWpqKqWUMm/evBIR5YEHHmg1rrGxsQwYMKBMnz691fampqZywAEHlDFjxrRsmzRpUunXr19LqLRle8xzyCGHlN12262sXbu2ZduqVavKgAEDOhS3v/zlL1vCJiJKnz59yrRp08ott9zSKgw3xm17cx1++OEt2zbG7aWXXtpqri984Qultra25biLFy8uEVGuuOKKVuN+97vflZ49e5azzz67Zdv48eNLRJT777+/1dhLLrmkdOvWbZPXwQ9/+MMSEeU//uM/2j332267rUREufbaa7f0NJVSSvne975XIqLcfvvtrbY/+uijJSLKNddc07Jt2LBhpba2trzwwgst29auXVsGDBhQTj311JZt7b0GNnfOX/va10pElF/84hetts+aNatUKpXym9/8pmXb2+P2k5/8ZOnZs2erfzjYsGFDGTFiRKu43fj8/epXv9ryEwNAl+RtyQDvIqWUlv+9ZMmSeOaZZ+Izn/lMRERs2LCh5c/RRx8dL7/8cvzmN7/Z7PEeeeSRWLFiRXz2s59ttX9zc3MceeSR8eijj0ZjY2OsWbMmHnrooTj++ONj11133ep1d3SexsbGePTRR+OYY46J2tralv379OkT06dP79BcH/zgB2PJkiWxYMGC+Pu///v48Ic/HPfff3/MnDkzZsyY0eo5jIh253r44Yejqamp1dgZM2a0+nn//fePN954o+VO1vfcc09UKpU48cQTW53n4MGD44ADDogHH3yw1f79+/ePSZMmtdp2zz33xL777hujR49udYwpU6ZEpVLZ5Bjb4p577ol+/frF9OnTW801evToGDx48CZzjR49OoYOHdryc21tbey9997xwgsvdHjOts550aJFMWrUqBgzZkyr7SeddFKUUmLRokXtHu+BBx6IyZMnt/ocelVVVXzyk5/cZO3V1dXx+c9/Pr7zne9s8jZxALo+N5QCeJdobGyM5cuXx3777RcRb33+MyLizDPPjDPPPLPNfbb01TUbj3Hssce2O2bFihXRrVu3aGpqit133/2dLL3D81QqlWhubo7Bgwdv8nhb29rTo0ePmDJlSkyZMiUiIpYvXx7HHnts3HPPPfGjH/0ojj766M0ed/DgwfHmm2/G6tWro2/fvi3b6+vrW42rqamJiLduZBXx1nmWUtq94dd73/veVj+39dngV199NZYsWRI9evRo8xib+51uDM/nnnuu3TFvn2vlypVRXV3dobnefv4Rbz0HG8+/I9o65+XLl8eee+65yfbddtut5fH2LF++vEOvl/e9732xcOHCuPTSS+OLX/xiNDY2xnvf+9748pe/HF/5ylc6vH4AOo+4BXiXuPfee6OpqSkmTJgQEREDBw6MiLe++uaYY45pc5999tlns8fceIy5c+e2exfahoaGaGpqiqqqqnjppZfe0do7Os/69eujUqnEK6+8ssnjbW3rqPr6+jjttNPiwQcfjCeffLJV3LY3V3V1dfTu3Xur5hk4cGBUKpX46U9/2hK+f+7t29r63t6BAwdGz549W92o6e2Pt+fggw+OAQMGxF133RWXXHLJFr8XeODAgVFfXx8LFixo8/E+ffpsdv93oq011dfXx8svv7zJ9t///vcRsflzrq+v7/DrZdy4cTFu3LhoamqKxx57LObOnRunnXZaNDQ0xKc+9amtOQ0AOoG4BXgXePHFF+PMM8+Mvn37xqmnnhoRb4Xr+9///njiiSfi4osv3uz+b7/CuNHYsWOjX79+8dRTT8WXvvSlzR5j/PjxMW/evLjooovajY1tnae6ujrGjBkTd9xxR1x22WUtbxf+4x//GHffffdm1xfx1t2CV61a1eYVxqeffjoi/nQ1cKP25ho3blxUVVVtcc4/N23atPjmN78Z//u//xvHH3/8Vu3758e4+OKLo76+PoYPH75V+/bo0SPOOeecOOecc+KCCy7Y5KuAIiKWLl0azz77bIwdOzamTZsWt912WzQ1NcUhhxzyjtb7du29BjZn8uTJcckll8Tjjz8eBx10UMv2W265JSqVSkycOLHdfSdOnBjz58+PV199teWKeVNTU3z/+99vd5+qqqo45JBDYsSIEXHrrbfG448/Lm4BEhC3AMk8+eSTLZ99XLp0afz0pz+Nm266KaqqquLOO+9s9ZnX6667Lo466qiYMmVKnHTSSTFkyJBYsWJFPP300/H444/HvHnzIuKt786NiLj++uujT58+UVtbG8OHD4/6+vqYO3dufPazn40VK1bEscceG4MGDYply5bFE088EcuWLYtvf/vbERFx5ZVXxqGHHhqHHHJIfO1rX4u99torXn311Zg/f35cd9110adPn+0yzwUXXBBHHnlkHHHEEXHGGWdEU1NTzJkzJ3r16hUrVqzY7HP3+uuvx5577hnHHXdcHH744bHHHnvE6tWr48EHH4yrrroqRo4cuclV7qqqqjjiiCPiq1/9ajQ3N8ecOXNi1apVMXv27K3+3Y0dOzY+//nPx8knnxyPPfZYHHbYYdGrV694+eWX42c/+1nst99+MWvWrM0e47TTTovbb789DjvssDj99NNj//33j+bm5njxxRfjJz/5SZxxxhmbDdGzzjornn766TjvvPPil7/8ZXz605+OPfbYI15//fV4+OGH4/rrr4/Zs2fH2LFj41Of+lTceuutcfTRR8dXvvKVGDNmTPTo0SNeeumleOCBB+Kv//qv4+Mf//hWPQebew205/TTT49bbrklpk6dGv/4j/8Yw4YNi3vvvTeuueaamDVrVuy9997t7vuNb3wj5s+fH5MmTYpzzz036urq4uqrr97ka5OuvfbaWLRoUUydOjWGDh0ab7zxRsvV8cMPP3yrzhGATtK597MCoKM23i1545/q6uoyaNCgMn78+HLxxRe3e5fiJ554ohx//PFl0KBBpUePHmXw4MFl0qRJm9wx91vf+lYZPnx4qaqqavVVQaWU8tBDD5WpU6eWAQMGlB49epQhQ4aUqVOnlnnz5rU6xlNPPVWOO+64Ul9fX6qrq8vQoUPLSSedVN54443tOs/8+fPL/vvv3zLHN7/5zZY7Fm/OunXryuWXX16OOuqoMnTo0FJTU1Nqa2vLyJEjy9lnn12WL1/eMnbj3ZLnzJlTZs+eXXbfffdSXV1dDjzwwPLjH/+41XE3zr1s2bJW2zf+zjbekXejG2+8sRxyyCGlV69epWfPnuV973tfmTlzZnnsscdaxowfP7584AMfaPM8Vq9eXb7xjW+UffbZp1RXV5e+ffuW/fbbr5x++umt7gq8OXfddVeZOnVq2XXXXUv37t1L//79y8SJE8u1115b1q1b1zJu/fr15fLLLy8HHHBAqa2tLb179y4jRowop556ann22Wdbxg0bNqxMnTp1k3nGjx9fxo8f32pbe6+BzZ3zCy+8UD796U+X+vr60qNHj7LPPvuUyy67rOWO3xvF2+6WXEopP//5z8uHPvShUlNTUwYPHlzOOuuscv3117f63SxevLh8/OMfL8OGDSs1NTWlvr6+jB8/vsyfP79DzycAna9SyttuCwkAxPPPPx/Dhw+Pyy67rN0bcgEAXYevAgIAACA9cQsAAEB63pYMAABAeq7cAgAAkJ64BQAAID1xCwAAQHrdOzqwUqm0+nmXXXaJ+fPnx0c+8pFtWkBVVVV069YtSimxYcOGthfZvfsm829OU1NTNDc3b3HcI488Eh/+8IfjwgsvjAsuuKDDxwc6z6xZs2KvvfaKiIgDDzwwDjvssKiqqtpk3IYNG+LPbynw+OOPx89//vN2j/v888/H3Llzt/+CAQDYZh25VVSHbyjVVlz269cv+vXrt9UL+3MTJkyII488Mp599tn4l3/5lzbHzJw5M0aNGtXhY955553xi1/8YovjXnvttejfv3+sXLkyVq5c2eHjA13DLrvsEhMnTowTTjghIiLGjBkTw4cPjyVLlsRnPvOZWLp0acvY119/PV577bXOWioAANtgh8ctQFdy1llnxeTJk+OMM86IX//61529HAAAthNxCwAAQHodyVY3lAIAACA9cQsAAEB64hYAAID0xC0AAADpiVsAAADSE7cAAACkJ24BAABIT9wCAACQnrgFAAAgPXELAABAeuIWAACA9MQtAAAA6YlbAAAA0hO3AAAApCduAQAASE/cAgAAkJ64BQAAID1xCwAAQHriFgAAgPTELQAAAOmJWwAAANITtwAAAKQnbgEAAEhP3AIAAJCeuAUAACA9cQsAAEB64hYAAID0xC0AAADpiVsAAADSE7cAAACkJ24BAABIT9wCAACQnrgFAAAgPXELAABAeuIWAACA9MQtAAAA6YlbAAAA0hO3AAAApCduAQAASE/cAgAAkJ64BQAAID1xCwAAQHriFgAAgPTELQAAAOmJWwAAANITtwAAAKQnbgEAAEhP3AIAAJCeuAUAACA9cQsAAEB64hYAAID0xC0AAADpiVsAAADSE7cAAACk172zFwDA5vXp0ycOPPDAiIh46aWX4re//W0nrwgAoOsRtwBdVL9+/WLixIlx1t/9XXx49eqIFSvilfXr47/r6+PCq66KRx55pLOXCADQZVRKKaVDAyuVHb0WAP6//v37x/duuCE++tBDUbnhhog1a/70YF1d/PGEE2LG//xPPPjoo523SACAnaQj2SpuAbqY3r17x+233BIfveSS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pCduAQAASE/cAgAAkJ64BQAAID1xCwAAQHriFgAAgPTELQAAAOmJWwAAANITtwAAAKQnbgEAAEhP3AIAAJCeuAUAACA9cQsAAEB64hYAAID0xC0AAADpiVsAAADSE7cAAACkJ24BAABIT9wCAACQnrgFAAAgPXELAABAeuIWAACA9MQtAAAA6YlbAAAA0hO3AAAApCduAQAASE/cAgAAkJ64BQAAID1xCwAAQHriFgAAgPTELQAAAOmJWwAAANITtwAAAKQnbgEAAEhP3AIAAJCeuAUAACA9cQsAAEB64hYAAID0xC0AAADpiVsAAADSE7cAAACkJ24BAABIT9wCAACQnrgFAAAgPXELAABAeuIWAACA9MQtAAAA6YlbAAAA0hO3AAAApCduAQAASE/cAgAAkJ64BQAAID1xCwAAQHriFgAAgPTELQAAAOmJWwAAANITtwAAAKQnbgEAAEhP3AIAAJCeuAUAACA9cQsAAEB64hYAAID0xC0AAADpiVsAAADSE7cAAACkJ24BAABIT9wCAACQnrgFAAAgPXELAABAeuIWAACA9MQtAAAA6YlbAAAA0hO3AAAApCduAQAASE/cAgAAkJ64BQAAID1xCwAAQHriFgAAgPTELQAAAOmJWwAAANITtwAAAKQnbgEAAEhP3AIAAJCeuAUAACA9cQsAAEB64hYAAID0xC0AAADpiVsAAADSE7cAAACkJ24BAABIT9wCAACQnrgFAAAgPXELAABAeuIWAACA9MQtAAAA6YlbAAAA0hO3AAAApCduAQAASE/cAgAAkJ64BQAAID1xCwAAQHriFgAAgPTELQAAAOmJWwAAANITtwAAAKQnbgEAAEhP3AIAAJCeuAUAACA9cQsAAEB64hYAAID0xC0AAADpiVsAAADSE7cAAACkJ24BAABIT9wCAACQnrgFAAAgPXELAABAeuIWAACA9MQtAAAA6YlbAAAA0hO3AAAApCduAQAASE/cAgAAkJ64BQAAID1xCwAAQHriFgAAgPTELQAAAOmJWwAAANITtwAAAKQnbgEAAEhP3AIAAJCeuAUAACA9cQsAAEB64hYAAID0xC0AAADpiVsAAADSE7cAAACkJ24BAABIT9wCAACQnrgFAAAgPXELAABAeuIWAACA9MQtAAAA6YlbAAAA0hO3AAAApCduAQAASE/cAgAAkJ64BQAAID1xCwAAQHriFgAAgPTELQAAAOmJWwAAANITtwAAAKQnbgEAAEhP3AIAAJCeuAUAACA9cQsAAEB64hYAAID0xC0AAADpiVsAAADSE7cAAACkJ24BAABIT9wCAACQnrgFAAAgPXELAABAeuIWAACA9MQtAAAA6YlbAAAA0hO3AAAApCduAQAASE/cAgAAkJ64BQAAID1xCwAAQHriFgAAgPTELQAAAOmJWwAAANITtwAAAKQnbgEAAEhP3AIAAJCeuAUAACA9cQsAAEB64hYAAID0xC0AAADpiVsAAADSE7cAAACkJ24BAABIT9wCAACQnrgFAAAgPXELAABAeuIWAACA9MQtAAAA6YlbAAAA0hO3AAAApCduAQAASE/cAgAAkJ64BQAAID1xCwAAQHriFgAAgPTELQAAAOmJWwAAANITtwAAAKQnbgEAAEhP3AIAAJCeuAUAACA9cQsAAEB64hYAAID0xC0AAADpiVsAAADSE7cAAACkJ24BAABIT9wCAACQnrgFAAAgPXELAABAeuIWAACA9MQtAAAA6YlbAAAA0hO3AAAApCduAQAASE/cAgAAkJ64BQAAID1xCwAAQHriFgAAgPTELQAAAOmJWwAAANITtwAAAKQnbgEAAEhP3AIAAJCeuAUAACA9cQsAAEB64hYAAID0xC0AAADpiVsAAADSE7cAAACkJ24BAABIT9wCAACQnrgFAAAgPXELAABAeuIWAACA9MQtAAAA6YlbAAAA0hO3AAAApCduAQAASE/cAgAAkJ64BQAAID1xCwAAQHriFgAAgPTELQAAAOmJWwAAANITtwAAAKQnbgEAAEhP3AIAAJCeuAUAACA9cQsAAEB64hYAAID0xC0AAADpiVsAAADSE7cAAACkJ24BAABIT9wCAACQnrgFAAAgPXELAABAeuIWAACA9MQtAAAA6YlbAAAA0hO3AAAApCduAQAASE/cAgAAkJ64BQAAID1xCwAAQHriFgAAgPTELQAAAOmJWwAAANITtwAAAKQnbgEAAEhP3AIAAJCeuAUAACA9cQsAAEB64hYAAID0xC0AAADpiVsAAADSE7cAAACkJ24BAABIT9wCAACQnrgFAAAgPXELAABAeuIWAACA9MQtAAAA6YlbAAAA0hO3AAAApCduAQAASE/cAgAAkJ64BQAAID1xCwAAQHriFgAAgPTELQAAAOmJWwAAANITtwAAAKQnbgEAAEhP3AIAAJCeuAUAACA9cQsAAEB64hYAAID0xC0AAADpiVsAAADSE7cAAACkJ24BAABIT9wCAACQnrgFAAAgPXELAABAeuIWAACA9MQtAAAA6YlbAAAA0hO3AAAApCduAQAASE/cAgAAkJ64BQAAID1xCwAAQHriFgAAgPTELQAAAOmJWwAAANITtwAAAKQnbgEAAEhP3AIAAJCeuAUAACA9cQsAAEB64hYAAID0xC0AAADpiVsAAADSE7cAAACkJ24BAABIT9wCAACQnrgFAAAgPXELAABAeuIWAACA9MQtAAAA6YlbAAAA0hO3AAAApCduAQAASE/cAgAAkJ64BQAAID1xCwAAQHriFgAAgPTELQAAAOmJWwAAANITtwAAAKQnbgEAAEhP3AIAAJCeuAUAACA9cQsAAEB64hYAAID0xC0AAADpiVsAAADSE7cAAACkJ24BAABIT9wCAACQnrgFAAAgPXELAABAeuIWAACA9MQtAAAA6YlbAAAA0hO3AAAApCduAQAASE/cAgAAkJ64BQAAID1xCwAAQHriFgAAgPTELQAAAOmJWwAAANITtwAAAKQnbgEAAEhP3AIAAJCeuAUAACA9cQsAAEB64hYAAID0xC0AAADpiVsAAADSE7cAAACkJ24BAABIT9wCAACQnrgFAAAgPXELAABAeuIWAACA9MQtAAAA6YlbAAAA0hO3AAAApCduAQAASE/cAgAAkJ64BQAAID1xCwAAQHriFgAAgPTELQAAAOmJWwAAANITtwAAAKQnbgEAAEhP3AIAAJCeuAUAACA9cQsAAEB64hYAAID0xC0AAADpiVsAAADSE7cAAACkJ24BAABIT9wCAACQnrgFAAAgPXELAABAeuIWAACA9MQtAAAA6YlbAAAA0hO3AAAApCduAQAASE/cAgAAkJ64BQAAID1xCwAAQHriFgAAgPTELQAAAOmJWwAAANITtwAAAKQnbgEAAEhP3AIAAJCeuAUAACA9cQsAAEB64hYAAID0xC0AAADpiVsAAADSE7cAAACkJ24BAABIT9wCAACQnrgFAAAgPXELAABAeuIWAACA9MQtAAAA6YlbAAAA0hO3AAAApCduAQAASE/cAgAAkJ64BQAAID1xCwAAQHriFgAAgPTELQAAAOmJWwAAANITtwAAAKQnbgEAAEhP3AIAAJCeuAUAACA9cQsAAEB64hYAAID0xC0AAADpiVsAAADSE7cAAACkJ24BAABIT9wCAACQnrgFAAAgPXELAABAeuIWAACA9MQtAAAA6YlbAAAA0hO3AAAApCduAQAASE/cAgAAkJ64BQAAID1xCwAAQHriFgAAgPTELQAAAOmJWwAAANITtwAAAKQnbgEAAEhP3AIAAJCeuAUAACA9cQsAAEB64hYAAID0xC0AAADpiVsAAADSE7cAAACkJ24BAABIT9wCAACQnrgFAAAgPXELAABAeuIWAACA9MQtAAAA6YlbAAAA0hO3AAAApCduAQAASE/cAgAAkJ64BQAAID1xCwAAQHriFgAAgPTELQAAAOmJWwAAANITtwAAAKQnbgEAAEhP3AIAAJCeuAUAACA9cQsAAEB64hYAAID0xC0AAADpiVsAAADSE7cAAACkJ24BAABIT9wCAACQnrgFAAAgPXELAABAeuIWAACA9MQtAAAA6YlbAAAA0hO3AAAApCduAQAASE/cAgAAkJ64BQAAID1xCwAAQHriFgAAgPTELQAAAOmJWwAAANITtwAAAKQnbgEAAEhP3AIAAJCeuAUAACA9cQsAAEB64hYAAID0xC0AAADpiVsAAADSE7cAAACkJ24BAABIT9wCAACQnrgFAAAgPXELAABAeuIWAACA9MQtAAAA6YlbAAAA0hO3AAAApCduAQAASE/cAgAAkJ64BQAAID1xCwAAQHriFgAAgPTELQAAAOmJWwAAANITtwAAAKQnbgEAAEhP3AIAAJCeuAUAACA9cQsAAEB64hYAAID0xC0AAADpiVsAAADSE7cAAACkJ24BAABIT9wCAACQnrgFAAAgPXELAABAeuIWAACA9MQtAAAA6YlbAAAA0hO3AAAApCduAQAASE/cAgAAkJ64BQAAID1xCwAAQHriFgAAgPTELQAAAOmJWwAAANITtwAAAKQnbgEAAEhP3AIAAJCeuAUAACA9cQsAAEB64hYAAID0xC0AAADpiVsAAADSE7cAAACkJ24BAABIT9wCAACQnrgFAAAgPXELAABAeuIWAACA9MQtAAAA6YlbAAAA0hO3AAAApCduAQAASE/cAgAAkJ64BQAAID1xCwAAQHriFgAAgPTELQAAAOmJWwAAANITtwAAAKQnbgEAAEhP3AIAAJCeuAUAACA9cQsAAEB64hYAAID0xC0AAADpiVsAAADSE7cAAACkJ24BAABIT9wCAACQnrgFAAAgPXELAABAeuIWAACA9MQtAAAA6YlbAAAA0hO3AAAApCduAQAASE/cAgAAkJ64BQAAID1xCwAAQHriFgAAgPTELQAAAOmJWwAAANITtwAAAKQnbgEAAEhP3AIAAJCeuAUAACA9cQsAAEB64hYAAID0xC0AAADpiVsAAADSE7cAAACkJ24BAABIT9wCAACQnrgFAAAgPXELAABAeuIWAACA9MQtAAAA6YlbAAAA0hO3AAAApCduAQAASE/cAgAAkJ64BQAAID1xCwAAQHriFgAAgPTELQAAAOmJWwAAANITtwAAAKQnbgEAAEhP3AIAAJCeuAUAACA9cQsAAEB64hYAAID0xC0AAADpiVsAAADSE7cAAACkJ24BAABIT9wCAACQnrgFAAAgPXELAABAeuIWAACA9MQtAAAA6YlbAAAA0hO3AAAApCduAQAASE/cAgAAkJ64BQAAID1xCwAAQHriFgAAgPTELQAAAOmJWwAAANITtwAAAKQnbgEAAEhP3AIAAJCeuAUAACA9cQsAAEB64hYAAID0xC0AAADpiVsAAADSE7cAAACkJ24BAABIT9wCAACQnrgFAAAgPXELAABAeuIWAACA9MQtAAAA6YlbAAAA0hO3AAAApCduAQAASE/cAgAAkJ64BQAAID1xCwAAQHriFgAAgPTELQAAAOmJWwAAANITtwAAAKQnbgEAAEhP3AIAAJCeuAUAACA9cQsAAEB64hYAAID0xC0AAADpiVsAAADSE7cAAACkJ24BAABIT9wCAACQnrgFAAAgPXELAABAeuIWAACA9MQtAAAA6YlbAAAA0hO3AAAApCduAQAASE/cAgAAkJ64BQAAID1xCwAAQHriFgAAgPTELQAAAOmJWwAAANITtwAAAKQnbgEAAEhP3AIAAJCeuAUAACA9cQsAAEB64hYAAID0xC0AAADpiVsAAADSE7cAAACkJ24BAABIT9wCAACQnrgFAAAgPXELAABAeuIWAACA9MQtAAAA6YlbAAAA0hO3AAAApCduAQAASE/cAgAAkJ64BQAAID1xCwAAQHriFgAAgPTELQAAAOmJWwAAANITtwAAAKQnbgEAAEhP3AIAAJCeuAUAACA9cQsAAEB64hYAAID0xC0AAADpiVsAAADSE7cAAACkJ24BAABIT9wCAACQnrgFAAAgPXELAABAeuIWAACA9MQtAAAA6YlbAAAA0hO3AAAApCduAQAASE/cAgAAkJ64BQAAID1xCwAAQHriFgAAgPTELQAAAOmJWwAAANITtwAAAKQnbgEAAEive0cHllJ25DoAAADgHXPlFgAAgPTELQAAAOmJWwAAANITtwAAAKQnbgEAAEhP3AIAAJCeuAUAACA9cQsAAEB64hYAAID0/h9i4p0SDVSpBAAAAABJRU5ErkJggg==",
"text/plain": [
"<Figure size 1000x1000 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"<Figure size 640x480 with 0 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"import numpy as np\n",
"from skimage import io, measure, morphology, feature\n",
"from scipy import ndimage\n",
"import matplotlib.pyplot as plt\n",
"\n",
"# Load the image\n",
"# image = io.imread('path_to_your_image.png') # Replace with your image path\n",
"\n",
"def detect_spheres(binary_image):\n",
" # Label connected components\n",
" labeled_image = measure.label(binary_image)\n",
" properties = measure.regionprops(labeled_image)\n",
" \n",
" # Filter out small objects and objects touching the border\n",
" min_area = 100 # Adjust this value based on your image\n",
" height, width = binary_image.shape\n",
" filtered_props = [prop for prop in properties \n",
" if prop.area >= min_area and \n",
" 0 < prop.centroid[0] < height-1 and \n",
" 0 < prop.centroid[1] < width-1]\n",
" \n",
" # Sort by area, largest first\n",
" filtered_props.sort(key=lambda x: x.area, reverse=True)\n",
" \n",
" # Take the four largest objects\n",
" largest_four = filtered_props[:4]\n",
" \n",
" # For the overlapping spheres, use distance transform to find peaks\n",
" mask = np.zeros_like(binary_image)\n",
" for prop in largest_four:\n",
" mask[prop.coords[:, 0], prop.coords[:, 1]] = 1\n",
" \n",
" distance = ndimage.distance_transform_edt(mask)\n",
" coordinates = feature.peak_local_max(distance, min_distance=10, num_peaks=4)\n",
" \n",
" return coordinates\n",
"\n",
"# Detect spheres\n",
"centroids = detect_spheres(image)\n",
"\n",
"# Plot the results\n",
"fig, ax = plt.subplots(figsize=(10, 10))\n",
"ax.imshow(image, cmap='gray')\n",
"\n",
"for centroid in centroids:\n",
" ax.plot(centroid[1], centroid[0], 'r.', markersize=15)\n",
"\n",
"ax.set_title('Detected Sphere Centroids')\n",
"ax.axis('off')\n",
"plt.tight_layout()\n",
"plt.show()\n",
"\n",
"# Optional: Save the result\n",
"plt.savefig('sphere_centroids_detected.png', dpi=300, bbox_inches='tight')"
]
},
{
"cell_type": "code",
"execution_count": 126,
"metadata": {},
"outputs": [],
"source": [
"# # Function to detect non-overlapping spheres\n",
"# def detect_non_overlapping(binary_image):\n",
"# labeled_image = measure.label(binary_image)\n",
"# properties = measure.regionprops(labeled_image)\n",
"# return [prop.centroid for prop in properties]\n",
"\n",
"# # Function to detect overlapping spheres\n",
"# def detect_overlapping(binary_image):\n",
"# # Apply distance transform\n",
"# distance = ndimage.distance_transform_edt(binary_image)\n",
" \n",
"# # Find local maxima\n",
"# coordinates = feature.peak_local_max(distance, min_distance=10, exclude_border=True)\n",
" \n",
"# # If we found more than 4 peaks, keep only the 4 strongest\n",
"# if len(coordinates) > 4:\n",
"# peak_intensities = [distance[tuple(coord)] for coord in coordinates]\n",
"# sorted_indices = np.argsort(peak_intensities)[-4:]\n",
"# coordinates = coordinates[sorted_indices]\n",
" \n",
"# return coordinates\n",
"\n",
"# # Detect non-overlapping spheres\n",
"# non_overlapping_centroids = detect_non_overlapping(image)\n",
"\n",
"# # If we found less than 4 spheres, use the overlapping detection method\n",
"# if len(non_overlapping_centroids) < 4:\n",
"# centroids = detect_overlapping(image)\n",
"# else:\n",
"# centroids = non_overlapping_centroids\n",
"\n",
"# # Plot the results\n",
"# fig, ax = plt.subplots(figsize=(10, 10))\n",
"# ax.imshow(image, cmap='gray')\n",
"\n",
"# for centroid in centroids:\n",
"# ax.plot(centroid[1], centroid[0], 'r.', markersize=15)\n",
"\n",
"# ax.set_title('Detected Sphere Centroids')\n",
"# ax.axis('off')\n",
"# plt.tight_layout()\n",
"# plt.show()\n",
"\n",
"# # Optional: Save the result\n",
"# plt.savefig('sphere_centroids_detected.png', dpi=300, bbox_inches='tight')"
]
},
{
"cell_type": "code",
"execution_count": 127,
"metadata": {},
"outputs": [],
"source": [
"# import numpy as np\n",
"# from skimage import io, measure, morphology, feature, segmentation\n",
"# from scipy import ndimage\n",
"# import matplotlib.pyplot as plt\n",
"\n",
"# # Load the image\n",
"# # image = io.imread('path_to_your_image.png') # Replace with your image path\n",
"\n",
"# def detect_spheres(binary_image):\n",
"# # Label connected components\n",
"# labeled_image = measure.label(binary_image)\n",
"# properties = measure.regionprops(labeled_image)\n",
" \n",
"# # Filter out small objects and objects touching the border\n",
"# min_area = 100 # Adjust this value based on your image\n",
"# height, width = binary_image.shape\n",
"# filtered_props = [prop for prop in properties \n",
"# if prop.area >= min_area and \n",
"# 0 < prop.centroid[0] < height-1 and \n",
"# 0 < prop.centroid[1] < width-1]\n",
" \n",
"# # Sort by area, largest first\n",
"# filtered_props.sort(key=lambda x: x.area, reverse=True)\n",
" \n",
"# # Take the four largest objects\n",
"# largest_four = filtered_props[:4]\n",
" \n",
"# # Create a mask of the four largest objects\n",
"# mask = np.zeros_like(binary_image)\n",
"# for prop in largest_four:\n",
"# mask[prop.coords[:, 0], prop.coords[:, 1]] = 1\n",
" \n",
"# # Apply distance transform\n",
"# distance = ndimage.distance_transform_edt(mask)\n",
" \n",
"# # Use watershed to separate overlapping circles\n",
"# markers = np.zeros_like(mask, dtype=int)\n",
"# markers[distance < 3] = 1 # Background\n",
"# markers[distance > 30] = 2 # Foreground (adjust this threshold if needed)\n",
" \n",
"# # Find peaks for seeds\n",
"# peak_idx = feature.peak_local_max(distance, min_distance=20, num_peaks=4)\n",
"# for i, peak in enumerate(peak_idx, start=3):\n",
"# markers[tuple(peak)] = i\n",
" \n",
"# segments = segmentation.watershed(-distance, markers, mask=mask)\n",
" \n",
"# # Find centroids of the segmented regions\n",
"# centroids = []\n",
"# for i in range(3, 7): # 3 to 6 are our four spheres\n",
"# coords = np.column_stack(np.where(segments == i))\n",
"# if len(coords) > 0:\n",
"# centroid = coords.mean(axis=0)\n",
"# centroids.append(centroid)\n",
" \n",
"# return np.array(centroids)\n",
"\n",
"# # Detect spheres\n",
"# centroids = detect_spheres(image)\n",
"\n",
"# # Plot the results\n",
"# fig, ax = plt.subplots(figsize=(10, 10))\n",
"# ax.imshow(image, cmap='gray')\n",
"\n",
"# for centroid in centroids:\n",
"# ax.plot(centroid[1], centroid[0], 'r.', markersize=15)\n",
"\n",
"# ax.set_title('Detected Sphere Centroids')\n",
"# ax.axis('off')\n",
"# plt.tight_layout()\n",
"# plt.show()\n",
"\n",
"# # Optional: Save the result\n",
"# plt.savefig('sphere_centroids_detected.png', dpi=300, bbox_inches='tight')"
]
},
{
"cell_type": "code",
"execution_count": 128,
"metadata": {},
"outputs": [],
"source": [
"# import numpy as np\n",
"# from skimage import io, feature, draw\n",
"# from scipy import ndimage\n",
"# from skimage.transform import hough_circle, hough_circle_peaks\n",
"# import matplotlib.pyplot as plt\n",
"\n",
"# # Load the image\n",
"# # image = io.imread('path_to_your_image.png') # Replace with your image path\n",
"\n",
"# def detect_spheres(binary_image):\n",
"# # Apply distance transform\n",
"# distance = ndimage.distance_transform_edt(binary_image)\n",
" \n",
"# # Use Hough circle transform to detect circles\n",
"# hough_radii = np.arange(20, 100, 2) # Adjust this range based on your image\n",
"# hough_res = hough_circle(binary_image, hough_radii)\n",
" \n",
"# # Select the 4 most prominent circles\n",
"# accums, cx, cy, radii = hough_circle_peaks(hough_res, hough_radii,\n",
"# total_num_peaks=4)\n",
" \n",
"# # Create a mask of the detected circles\n",
"# mask = np.zeros_like(binary_image, dtype=float)\n",
"# for center_y, center_x, radius in zip(cy, cx, radii):\n",
"# circy, circx = draw.circle_perimeter(int(center_y), int(center_x), int(radius))\n",
"# mask[circy, circx] = 1\n",
" \n",
"# # Combine the distance transform with the circle mask\n",
"# combined = distance * mask\n",
" \n",
"# # Find local maxima\n",
"# coordinates = feature.peak_local_max(combined, min_distance=20, num_peaks=4)\n",
" \n",
"# return coordinates\n",
"\n",
"# # Detect spheres\n",
"# centroids = detect_spheres(image)\n",
"\n",
"# # Plot the results\n",
"# fig, ax = plt.subplots(figsize=(10, 10))\n",
"# ax.imshow(image, cmap='gray')\n",
"\n",
"# for centroid in centroids:\n",
"# ax.plot(centroid[1], centroid[0], 'r.', markersize=15)\n",
"\n",
"# ax.set_title('Detected Sphere Centroids')\n",
"# ax.axis('off')\n",
"# plt.tight_layout()\n",
"# plt.show()\n",
"\n",
"# # Optional: Save the result\n",
"# plt.savefig('sphere_centroids_detected.png', dpi=300, bbox_inches='tight')"
]
},
{
"cell_type": "code",
"execution_count": 129,
"metadata": {},
"outputs": [],
"source": [
"# import numpy as np\n",
"# from skimage import io, feature\n",
"# from scipy import ndimage\n",
"# import matplotlib.pyplot as plt\n",
"\n",
"# # Load the image\n",
"# # image = io.imread('path_to_your_image.png') # Replace with your image path\n",
"\n",
"# def detect_spheres(binary_image):\n",
"# # Apply distance transform\n",
"# distance = ndimage.distance_transform_edt(binary_image)\n",
" \n",
"# # Find local maxima\n",
"# coordinates = feature.peak_local_max(distance, min_distance=20, num_peaks=4, exclude_border=False)\n",
" \n",
"# return coordinates\n",
"\n",
"# # Detect spheres\n",
"# centroids = detect_spheres(image)\n",
"\n",
"# # Plot the results\n",
"# fig, ax = plt.subplots(figsize=(10, 10))\n",
"# ax.imshow(image, cmap='gray')\n",
"\n",
"# for centroid in centroids:\n",
"# ax.plot(centroid[1], centroid[0], 'r.', markersize=15)\n",
"\n",
"# ax.set_title('Detected Sphere Centroids')\n",
"# ax.axis('off')\n",
"# plt.tight_layout()\n",
"# plt.show()\n",
"\n",
"# # Optional: Save the result\n",
"# plt.savefig('sphere_centroids_detected.png', dpi=300, bbox_inches='tight')"
]
},
{
"cell_type": "code",
"execution_count": 130,
"metadata": {},
"outputs": [],
"source": [
"# import numpy as np\n",
"# import matplotlib.pyplot as plt\n",
"# from scipy import ndimage as ndi\n",
"\n",
"# from skimage.segmentation import watershed\n",
"# from skimage.feature import peak_local_max\n",
"\n",
"\n",
"# plt.imshow(image[10:400,500:800])\n",
"# large_image = image.copy()\n",
"# image = image.copy()[10:400,500:800]\n",
"\n",
"# # # Generate an initial image with two overlapping circles\n",
"# # x, y = np.indices((80, 80))\n",
"# # x1, y1, x2, y2 = 28, 28, 44, 52\n",
"# # r1, r2 = 16, 20\n",
"# # mask_circle1 = (x - x1) ** 2 + (y - y1) ** 2 < r1**2\n",
"# # mask_circle2 = (x - x2) ** 2 + (y - y2) ** 2 < r2**2\n",
"# # image = np.logical_or(mask_circle1, mask_circle2)\n",
"\n",
"# # Now we want to separate the two objects in image\n",
"\n",
"# # Generate the markers as local maxima of the distance to the background\n",
"# distance = ndi.distance_transform_edt(image)\n",
"# coords = peak_local_max(distance, footprint=np.ones((3, 3)), labels=image, min_distance=10)\n",
"# mask = np.zeros(distance.shape, dtype=bool)\n",
"# mask[tuple(coords.T)] = True\n",
"# markers, _ = ndi.label(mask)\n",
"# labels = watershed(-distance, markers, mask=image)\n",
"\n",
"# fig, axes = plt.subplots(ncols=3, figsize=(20, 20), sharex=True, sharey=True)\n",
"# ax = axes.ravel()\n",
"\n",
"# ax[0].imshow(image, cmap=plt.cm.gray)\n",
"# ax[0].set_title('Overlapping objects')\n",
"# ax[1].imshow(-distance, cmap=plt.cm.gray)\n",
"# ax[1].set_title('Distances')\n",
"# ax[2].imshow(labels, cmap=plt.cm.nipy_spectral)\n",
"# ax[2].set_title('Separated objects')\n",
"\n",
"# for a in ax:\n",
"# a.set_axis_off()\n",
"\n",
"# fig.tight_layout()\n",
"# plt.show()"
]
},
{
"cell_type": "code",
"execution_count": 131,
"metadata": {},
"outputs": [],
"source": [
"# import numpy as np\n",
"# from skimage import io, measure, morphology, feature\n",
"# from skimage.draw import circle_perimeter\n",
"# from scipy import optimize\n",
"# import matplotlib.pyplot as plt\n",
"\n",
"# def fit_circle(x, y):\n",
"# def calc_R(xc, yc):\n",
"# return np.sqrt((x-xc)**2 + (y-yc)**2)\n",
" \n",
"# def f_2(c):\n",
"# Ri = calc_R(*c)\n",
"# return Ri - Ri.mean()\n",
" \n",
"# center_estimate = np.mean(x), np.mean(y)\n",
"# center, _ = optimize.leastsq(f_2, center_estimate)\n",
"# xc, yc = center\n",
"# Ri = calc_R(*center)\n",
"# R = Ri.mean()\n",
"# return xc, yc, R\n",
"\n",
"# def detect_spheres(binary_image):\n",
"# # Get contours\n",
"# contours = measure.find_contours(binary_image, 0.8)\n",
" \n",
"# centroids = []\n",
"# for contour in contours:\n",
"# # Get convex hull\n",
"# hull = morphology.convex_hull_image(np.zeros(binary_image.shape, dtype=bool) | measure.grid_points_in_poly(binary_image.shape, contour))\n",
"# hull_contour = measure.find_contours(hull, 0.8)[0]\n",
" \n",
"# # Calculate distances to hull\n",
"# distances = np.array([np.min(np.sum((contour - hp)**2, axis=1)) for hp in hull_contour])\n",
" \n",
"# # Find local maxima in distances\n",
"# peaks = feature.peak_local_max(distances, min_distance=20)\n",
" \n",
"# if len(peaks) > 1: # Overlapping circles\n",
"# # Split contour at peaks and fit circles\n",
"# for i in range(len(peaks)):\n",
"# start, end = peaks[i][0], peaks[(i+1)%len(peaks)][0]\n",
"# segment = contour[start:end] if start < end else np.vstack((contour[start:], contour[:end]))\n",
"# xc, yc, _ = fit_circle(segment[:, 1], segment[:, 0])\n",
"# centroids.append((yc, xc))\n",
"# else: # Single circle\n",
"# xc, yc, _ = fit_circle(contour[:, 1], contour[:, 0])\n",
"# centroids.append((yc, xc))\n",
" \n",
"# return np.array(centroids)\n",
"\n",
"# # Load the image\n",
"# # image = io.imread('path_to_your_image.png') # Replace with your image path\n",
"\n",
"\n",
"# # Detect spheres\n",
"# centroids = detect_spheres(image)\n",
"\n",
"# # Plot the results\n",
"# fig, ax = plt.subplots(figsize=(10, 10))\n",
"# ax.imshow(image, cmap='gray')\n",
"\n",
"# for centroid in centroids:\n",
"# ax.plot(centroid[1], centroid[0], 'r.', markersize=15)\n",
"\n",
"# ax.set_title('Detected Sphere Centroids')\n",
"# ax.axis('off')\n",
"# plt.tight_layout()\n",
"# plt.show()\n",
"\n",
"# # Optional: Save the result\n",
"# plt.savefig('sphere_centroids_detected.png', dpi=300, bbox_inches='tight')"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "pro_my_open_ptv_benchmark",
"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.10.14"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment