Created
June 24, 2024 15:40
-
-
Save alexlib/71d2415eaad3768f997922822dae87c6 to your computer and use it in GitHub Desktop.
Customized image segmentation algorithm to find a sphere using cross-correlation and template matching
This file contains hidden or 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
{ | |
"cells": [ | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"cell_id": "bbe81409-b19e-42f4-8c96-65e028a8be58", | |
"deepnote_cell_type": "code" | |
}, | |
"source": "##### CHANGEABLE PARAMETERS ######", | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"cell_id": "00001-8f342c55-853f-4f08-8031-68dc7309bb7f", | |
"deepnote_cell_type": "code" | |
}, | |
"source": "import os # to know which computer it is\nimport yaml", | |
"execution_count": 2, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"cell_id": "00002-fd40fc37-77fb-42c3-b3c6-438dbfabd9ab", | |
"deepnote_cell_type": "code" | |
}, | |
"source": "# we do not need to change Jupyter notebook contents for every computer\n# better to ignore this file from git probably, or be ready to commit it\n# every time we switch the folder\n\nyaml_file = 'path_location.yaml'\nyaml_args = yaml.load(open(yaml_file,'r'),yaml.CLoader)\npath_args = yaml_args['path']\nframe_ranges = yaml_args['frame_ranges']\nxlim = yaml_args['xlim']\n\nfor key in yaml_args:\n print(key, yaml_args[key])", | |
"execution_count": 3, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": "path G:\\Shared drives\\Liron_Simon_Thesis\\Experimental_data\\Raw_data\\060222\\C001H001S0001\nframe_ranges [160, 560]\nxlim [90, 150]\nfps 250\npixel2meter 0.126/1024\n" | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"cell_id": "00003-09d42e0d-e3ad-4a23-8d5f-889a9ffddb3d", | |
"deepnote_cell_type": "code" | |
}, | |
"source": "# date_taken = '150222'\n# file = '0001'\ndate_taken = path_args.split(os.sep)[-2]\nfile = path_args.split(os.sep)[-1].split('S')[-1]\n\n\nsigma = 1 # gaussian\nN = 5 # moving average window for the background\n\n# data position and additional parameters\n\n# DATA_PATH = f\"/media/ron/Liron USB/06-02-22/C001H001S{file}/\"+\"*.tif\" #\"../../C001H001S0001/*.tif\"\n# if os.environ['COMPUTERNAME'] == 'DESKTOP-OV3L1FT':\n# DATA_PATH = r\"C:\\Users\\alex\\Downloads\\C001H001S0002\\*.tif\"\n# elif os.environ['COMPUTERNAME'] == 'DESKTOP-S68P8PR': # OFFICE PC\n# DATA_PATH = rf\"G:\\Shared drives\\Liron_Simon_Thesis\\Experimental data\\Raw data\\{date_taken}\\C001H001S{file}\\S{file}\"\n\n# see link to Google Drive https://docs.google.com/spreadsheets/d/1dkG03RMQC-XQx8klTu3SgG6a0SPWhHm2aTcwBeC51Zc/edit#gid=1532686687&range=B7\n\n\nDATA_PATH = os.path.join(path_args,'*.tif')\n\n", | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"cell_id": "00004-a700c8f7-1607-4008-949c-9a71a174485e", | |
"deepnote_cell_type": "code" | |
}, | |
"source": "import numpy as np\nimport pandas as pd\nimport trackpy as tp\nimport pims\n\nfrom glob import glob\nfrom skimage.io.collection import alphanumeric_key\n\nfrom skimage.feature import match_template\nfrom skimage.registration import phase_cross_correlation\nfrom skimage.feature import peak_local_max\nfrom skimage.filters import gaussian\n", | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"cell_id": "00005-b0965d32-693b-425f-8710-ca20147907b1", | |
"deepnote_cell_type": "code" | |
}, | |
"source": "import matplotlib.pyplot as plt\n#matplotlib notebook # if you need interactivity like zoom\n%matplotlib inline\n\nimport matplotlib\nmatplotlib.rcParams['figure.figsize'] = (12, 12)", | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"cell_id": "00006-55c237ea-8725-4b63-ab64-3b40add99ee2", | |
"deepnote_cell_type": "code" | |
}, | |
"source": "filenames = sorted( glob(DATA_PATH), key=alphanumeric_key )\nprint(f\"Found {len(filenames)} files in this path {DATA_PATH} \")", | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"cell_id": "00007-bfb32bb7-6442-4c34-a6b2-f2925f42983b", | |
"deepnote_cell_type": "code" | |
}, | |
"source": "if len(frame_ranges) < 1:\n frame_ranges = [0, len(filenames)]", | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"cell_id": "00008-ae2ba499-c12f-481d-8dff-a6fd9b7ee863", | |
"deepnote_cell_type": "code" | |
}, | |
"source": "# follow the example\n# http://soft-matter.github.io/trackpy/v0.5.0/tutorial/custom-feature-detection.html\[email protected]\ndef gray(fn):\n # img = imread(fn)\n return np.round(fn[:,slice(*xlim)]/4096*255).astype(np.uint8) # note the small ROI\n\n\n\nrawframes = gray(pims.open(os.path.join(DATA_PATH)))\nrawframes = rawframes[slice(*frame_ranges)]", | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"cell_id": "00009-edf70dca-591e-4921-9e37-cb241da1cb7e", | |
"deepnote_cell_type": "code" | |
}, | |
"source": "def moving_average(a, n=N) :\n ret = np.cumsum(a, dtype=float, axis=0)\n ret[n:,:,:] = ret[n:,:,:] - ret[:-n,:,:]\n return ret[n - 1:,:,:] / n", | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"cell_id": "00010-ac69f31e-3175-4434-8284-46a507d66933", | |
"deepnote_cell_type": "code" | |
}, | |
"source": "# moving average backgrounds (list of backgrounds)\nbkg = moving_average(rawframes,n=N);", | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"cell_id": "00011-e80d22da-1d11-459e-b6ba-612841628b22", | |
"deepnote_cell_type": "code" | |
}, | |
"source": "# note the clipping - bright spots change\n# along the image, so we have to clip it\n# we could possibly also do some \n# histogram equaliztion\n\nframes = []\nfor f, b in zip(rawframes[N-1:], bkg):\n frames.append(gaussian(np.clip(f - b, 0, 80),sigma=sigma))", | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"cell_id": "00012-ed91e57a-a65f-4fe8-8cb7-f65b7434b5ec", | |
"deepnote_cell_type": "code" | |
}, | |
"source": "template = frames[20][135:160,15:40]\nplt.imshow(template, cmap = 'gray')", | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"cell_id": "00013-c8ec9319-50bf-4029-9b76-e38ca04afff3", | |
"deepnote_cell_type": "code" | |
}, | |
"source": "img = frames[20]\n\nc = match_template(img, template)\n\nx, y = np.unravel_index(np.argmax(c), c.shape)\ntemplate_width, template_height = template.shape\nrect = plt.Rectangle((y, x), template_height, template_width, \n color='r', fc='none')\nplt.figure(num=None, figsize=(8, 6), dpi=80)\nplt.gca().add_patch(rect)\nplt.imshow(img);\n\n# plt.ylim(350,400)\n", | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"cell_id": "00014-0ab0eaa8-858a-407e-80e6-681eee437e04", | |
"deepnote_cell_type": "code" | |
}, | |
"source": "img = frames[100]\n\nc = match_template(img, template)\n\nplt.figure(num=None, figsize=(8, 6), dpi=80)\nfor x, y in peak_local_max(c, threshold_abs=0.85, \n exclude_border = 5):\n rect = plt.Rectangle((y, x), template_height, template_width,\n color='r', fc='none')\n plt.plot(y+template_height/2,x+template_width/2,'bo')\n plt.gca().add_patch(rect)\n\n small_img = img[x:x+template_width,y:y+template_height]\n shift, error, diffphase = phase_cross_correlation(small_img, template,\n upsample_factor=20)\n plt.plot(y+template_height/2+shift[1],x+template_width/2+shift[0],'r+',markersize=10)\n\nplt.imshow(img);\n\n# plt.ylim(240,260)\n# plt.ylim(300,400)\n# plt.gca().invert_yaxis()", | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"cell_id": "00015-6128e3db-f246-423a-b1d0-cd91a5f45645", | |
"deepnote_cell_type": "code" | |
}, | |
"source": "collect_features = []\nfor num, img in enumerate(frames):\n c = match_template(img, template)\n for x, y in peak_local_max(c, threshold_abs=0.85, \n exclude_border = 5):\n small_img = img[x:x+template_width,\\\n y:y+template_height]\n shift, error, diffphase = phase_cross_correlation(small_img, \\\n template, upsample_factor=20)\n\n # note the notation of features and images is different:\n collect_features.append(\n pd.DataFrame([{'x': y+template_height/2+shift[1],\n 'y': x+template_width/2+shift[0],\n 'frame': num\n },]))\n \nfeatures = pd.concat(collect_features)\n", | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"cell_id": "00016-c28b5dac-fc0b-4ad5-82c1-ee9235aa2868", | |
"deepnote_cell_type": "code" | |
}, | |
"source": "tp.annotate(features[features.frame == 175], frames[175]);", | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"cell_id": "00017-80bc2547-a9f8-4f32-bcd6-925d85834e76", | |
"deepnote_cell_type": "code" | |
}, | |
"source": "features.to_csv(f'features{date_taken}_{file}.csv')", | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"cell_id": "00018-f4d3c06f-48b5-490f-a743-cac7fcab93a2", | |
"deepnote_cell_type": "code" | |
}, | |
"source": "import trackpy.predict\n\[email protected]\ndef predict(t1, particle):\n velocity = np.array((0, -1)) # See fakeframe()\n return particle.pos + velocity * (t1 - particle.t)\n\n#tr = pandas.concat(trackpy.link_df_iter(f, 0.5, predictor=predict))\ntr = trackpy.link(features, 45, predictor=predict, memory=5)\n", | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"cell_id": "00019-3a725e6b-28de-4a0d-8b63-100b866838f8", | |
"deepnote_cell_type": "code" | |
}, | |
"source": "tp.plot_traj(tr,label=True)", | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"cell_id": "00020-883b19fb-3781-4e85-ae8c-ead15f8302e0", | |
"deepnote_cell_type": "code" | |
}, | |
"source": "# remove particles that do not move vertically\n\nlst_num = []\nfor p in set(tr.particle):\n t = tr[tr.particle == p]\n if t.y.max() - t.y.min() > 50:\n lst_num.append(p)\n \nprint(lst_num)", | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"cell_id": "00021-eb3e5985-bbe4-4fec-8de6-c15ed58ebb4b", | |
"deepnote_cell_type": "code" | |
}, | |
"source": "tr = tr[tr.particle.isin(lst_num)]\ntp.plot_traj(tr,label=True)", | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"cell_id": "00022-1c5afbb0-73a1-4690-8b72-304a660b066f", | |
"deepnote_cell_type": "code" | |
}, | |
"source": "tr.to_csv(f'tr_{date_taken}_{file}.csv')", | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"cell_id": "00023-049460ea-0275-4ec5-bcf1-cfef7cc6b1e2", | |
"deepnote_cell_type": "code" | |
}, | |
"source": "# lets sort data\n#tm = tr2.reset_index(drop=True)\ntm = tr.sort_values(['particle', 'frame'], ignore_index=True)", | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"cell_id": "00024-66457a57-4c4b-4100-8b51-3ebd3b29f5f0", | |
"deepnote_cell_type": "code" | |
}, | |
"source": "from scipy.signal import savgol_filter\ndef calc_V(V_col, fps=fps, pixel2meter=pixel2meter):\n # delta = np.gradient(V_col)*Pixel2meter\n delta = savgol_filter(V_col, window_length=11, polyorder=2, deriv=1)\n delta *= pixel2meter\n return delta * fps", | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"cell_id": "00025-48e14806-4573-4f48-911f-1972200cef62", | |
"deepnote_cell_type": "code" | |
}, | |
"source": "tm['sec'] = tm.loc[:,'frame'] /fps\ntm['Vx'] = calc_V(tm.loc[:,'x'])\ntm['Vy'] = calc_V(tm.loc[:,'y'])", | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"cell_id": "00026-fc1251d0-a079-49ad-9fbe-e3f235e9b9b2", | |
"deepnote_cell_type": "code" | |
}, | |
"source": "#tm.plot(x=\"sec\", y=[\"Vx\",\"Vy\"])\n\ntm_i = tm[tm['particle'] == 0]\ntm_i = tm_i[5:-5]\ntm_i.plot(x=\"sec\", y=[\"Vx\",\"Vy\"])", | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"metadata": { | |
"cell_id": "00027-c54cfd66-4f13-4ca1-8e07-159521860c75", | |
"deepnote_cell_type": "code" | |
}, | |
"source": "fig,ax = plt.subplots(2,1)\n\nfor p in set(tm.particle):\n t = tm[tm.particle == p]\n t1 = t.drop(t[(t.Vy < .1) | (t.Vy > 0.2) ].index)\n y = t1.y.values\n Vy = t1.Vy.values\n Vx = t1.x.values\n fr = t1.frame.values\n ax[0].plot(y,Vy/Vy[0]+p*.05,label=p)\n ind = np.argmin(np.abs(y-800))\n ax[0].text(y[ind],Vy[ind]/Vy[0]+p*.05,str(p),fontsize=14)\n # t1.plot(x='y',y='Vy',ax=ax)\n\n ax[1].plot(y,Vx,label=p)\n\n\nax[0].set_xlim([20,810])\nax[0].set_xlabel('$y$',fontsize=14)\nax[0].set_ylabel('$V_y/V_y(t=0)$ (shifted for clarity)',fontsize=14)\n\nax[1].set_xlim([20,810])\nax[1].set_xlabel('$y$',fontsize=14)\nax[1].set_ylabel('$V_x$',fontsize=14)\n\n# plt.legend()", | |
"execution_count": null, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "markdown", | |
"source": "<a style='text-decoration:none;line-height:16px;display:flex;color:#5B5B62;padding:10px;justify-content:end;' href='https://deepnote.com?utm_source=created-in-deepnote-cell&projectId=83d975df-8c0a-4829-9055-240c8ceb60e4' target=\"_blank\">\n<img alt='Created in deepnote.com' style='display:inline;max-height:16px;margin:0px;margin-right:7.5px;' src='data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iODBweCIgaGVpZ2h0PSI4MHB4IiB2aWV3Qm94PSIwIDAgODAgODAiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CiAgICA8IS0tIEdlbmVyYXRvcjogU2tldGNoIDU0LjEgKDc2NDkwKSAtIGh0dHBzOi8vc2tldGNoYXBwLmNvbSAtLT4KICAgIDx0aXRsZT5Hcm91cCAzPC90aXRsZT4KICAgIDxkZXNjPkNyZWF0ZWQgd2l0aCBTa2V0Y2guPC9kZXNjPgogICAgPGcgaWQ9IkxhbmRpbmciIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIxIiBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPgogICAgICAgIDxnIGlkPSJBcnRib2FyZCIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTEyMzUuMDAwMDAwLCAtNzkuMDAwMDAwKSI+CiAgICAgICAgICAgIDxnIGlkPSJHcm91cC0zIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxMjM1LjAwMDAwMCwgNzkuMDAwMDAwKSI+CiAgICAgICAgICAgICAgICA8cG9seWdvbiBpZD0iUGF0aC0yMCIgZmlsbD0iIzAyNjVCNCIgcG9pbnRzPSIyLjM3NjIzNzYyIDgwIDM4LjA0NzY2NjcgODAgNTcuODIxNzgyMiA3My44MDU3NTkyIDU3LjgyMTc4MjIgMzIuNzU5MjczOSAzOS4xNDAyMjc4IDMxLjY4MzE2ODMiPjwvcG9seWdvbj4KICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik0zNS4wMDc3MTgsODAgQzQyLjkwNjIwMDcsNzYuNDU0OTM1OCA0Ny41NjQ5MTY3LDcxLjU0MjI2NzEgNDguOTgzODY2LDY1LjI2MTk5MzkgQzUxLjExMjI4OTksNTUuODQxNTg0MiA0MS42NzcxNzk1LDQ5LjIxMjIyODQgMjUuNjIzOTg0Niw0OS4yMTIyMjg0IEMyNS40ODQ5Mjg5LDQ5LjEyNjg0NDggMjkuODI2MTI5Niw0My4yODM4MjQ4IDM4LjY0NzU4NjksMzEuNjgzMTY4MyBMNzIuODcxMjg3MSwzMi41NTQ0MjUgTDY1LjI4MDk3Myw2Ny42NzYzNDIxIEw1MS4xMTIyODk5LDc3LjM3NjE0NCBMMzUuMDA3NzE4LDgwIFoiIGlkPSJQYXRoLTIyIiBmaWxsPSIjMDAyODY4Ij48L3BhdGg+CiAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMCwzNy43MzA0NDA1IEwyNy4xMTQ1MzcsMC4yNTcxMTE0MzYgQzYyLjM3MTUxMjMsLTEuOTkwNzE3MDEgODAsMTAuNTAwMzkyNyA4MCwzNy43MzA0NDA1IEM4MCw2NC45NjA0ODgyIDY0Ljc3NjUwMzgsNzkuMDUwMzQxNCAzNC4zMjk1MTEzLDgwIEM0Ny4wNTUzNDg5LDc3LjU2NzA4MDggNTMuNDE4MjY3Nyw3MC4zMTM2MTAzIDUzLjQxODI2NzcsNTguMjM5NTg4NSBDNTMuNDE4MjY3Nyw0MC4xMjg1NTU3IDM2LjMwMzk1NDQsMzcuNzMwNDQwNSAyNS4yMjc0MTcsMzcuNzMwNDQwNSBDMTcuODQzMDU4NiwzNy43MzA0NDA1IDkuNDMzOTE5NjYsMzcuNzMwNDQwNSAwLDM3LjczMDQ0MDUgWiIgaWQ9IlBhdGgtMTkiIGZpbGw9IiMzNzkzRUYiPjwvcGF0aD4KICAgICAgICAgICAgPC9nPgogICAgICAgIDwvZz4KICAgIDwvZz4KPC9zdmc+' > </img>\nCreated in <span style='font-weight:600;margin-left:4px;'>Deepnote</span></a>", | |
"metadata": { | |
"tags": [], | |
"created_in_deepnote_cell": true, | |
"deepnote_cell_type": "markdown" | |
} | |
} | |
], | |
"nbformat": 4, | |
"nbformat_minor": 4, | |
"metadata": { | |
"kernelspec": { | |
"display_name": "Python 3.9.7 ('liron_danny')", | |
"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.9.7" | |
}, | |
"vscode": { | |
"interpreter": { | |
"hash": "fa416831bb8d2bce8670c6668d9a9f308649692bc2c0170a27935576e90f9346" | |
} | |
}, | |
"deepnote_notebook_id": "68e5a673-cc4c-4023-8305-fd22dc421700", | |
"deepnote": {}, | |
"deepnote_execution_queue": [] | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment