├── 00-Index.ipynb ├── 01-Introduction.ipynb ├── 02-Numpy_images.ipynb ├── 03-Image_import.ipynb ├── 04-Basics.ipynb ├── 04b-Other_image_types.ipynb ├── 05-Binary_operations.ipynb ├── 06-Functions.ipynb ├── 07-Active_contours.ipynb ├── 08-Pattern_matching.ipynb ├── 09-Watershed.ipynb ├── 10-3D_case.ipynb ├── 11-Complete_analysis.ipynb ├── 12-Registration.ipynb ├── 13-Pixel_classification.ipynb ├── 14-DeepLearning.ipynb ├── 14-OCR.ipynb ├── 15-Image_classification.ipynb ├── 16-Semantic_segmentation.ipynb ├── Env_setup ├── Data_setup_SwitchEngine.ipynb ├── Data_setup_local.ipynb ├── Instructions_SwitchEngine.md ├── Instructions_local.md ├── Setting_up_colab.ipynb ├── local_install.bsh └── switch_engine_install.bsh ├── Exercises ├── Exercise1.ipynb ├── Exercise2.ipynb ├── Exercise3.ipynb ├── Exercise4.ipynb ├── Exercise5.ipynb ├── Exercise6.ipynb ├── Exercise7.ipynb └── Exercise8.ipynb ├── LICENSE ├── MyData ├── DL │ └── dl_info.txt └── your_data.txt ├── README.md ├── course_functions.py └── deeplearning.py /00-Index.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Image processing with Python\n", 8 | "#### **Guillaume Witz**, Science IT Support, Bern University" 9 | ] 10 | }, 11 | { 12 | "cell_type": "markdown", 13 | "metadata": {}, 14 | "source": [ 15 | "## Table of Contents\n", 16 | "\n", 17 | "### [1. Introduction](01-Introduction.ipynb)\n", 18 | "\n", 19 | "### [2. Numpy refresh with images](02-Numpy_images.ipynb)\n", 20 | "\n", 21 | "### [3. Importing images](03-Image_import.ipynb)\n", 22 | "\n", 23 | "### [4. Basics: scaling, thresholding, filtering](04-Basics.ipynb)\n", 24 | "\n", 25 | "### [4b. Basics with non-biology data](04b-Other_image_types.ipynb)\n", 26 | "\n", 27 | "### [5. Binary operations](05-Binary_operations.ipynb)\n", 28 | "\n", 29 | "### [6. Wrapping code into functions](06-Functions.ipynb)\n", 30 | "\n", 31 | "### [7. Segmentation: active contours](07-Active_contours.ipynb)\n", 32 | "\n", 33 | "### [8. Segmentation: pattern matching](08-Pattern_matching.ipynb)\n", 34 | "\n", 35 | "### [9. Segmentation: Watershed algorithm](09-Watershed.ipynb)\n", 36 | "\n", 37 | "### [10. Operations in 3D](10-3D_case.ipynb)\n", 38 | "\n", 39 | "### [11. A complete pipeline](11-Complete_analysis.ipynb)\n", 40 | "\n", 41 | "### [12. Image registration](12-Registration.ipynb)\n", 42 | "\n", 43 | "### [13. Machine learning: Pixel classification](13-Pixel_classification.ipynb)\n", 44 | "\n", 45 | "### [14.Machine learning: segmentation with deep learning](14-DeepLearning.ipynb)" 46 | ] 47 | }, 48 | { 49 | "cell_type": "code", 50 | "execution_count": null, 51 | "metadata": {}, 52 | "outputs": [], 53 | "source": [] 54 | } 55 | ], 56 | "metadata": { 57 | "anaconda-cloud": {}, 58 | "kernelspec": { 59 | "display_name": "Python 3", 60 | "language": "python", 61 | "name": "python3" 62 | }, 63 | "language_info": { 64 | "codemirror_mode": { 65 | "name": "ipython", 66 | "version": 3 67 | }, 68 | "file_extension": ".py", 69 | "mimetype": "text/x-python", 70 | "name": "python", 71 | "nbconvert_exporter": "python", 72 | "pygments_lexer": "ipython3", 73 | "version": "3.7.1" 74 | } 75 | }, 76 | "nbformat": 4, 77 | "nbformat_minor": 2 78 | } 79 | -------------------------------------------------------------------------------- /Env_setup/Data_setup_SwitchEngine.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import sys, os, zipfile\n", 10 | "import urllib.request" 11 | ] 12 | }, 13 | { 14 | "cell_type": "code", 15 | "execution_count": 3, 16 | "metadata": {}, 17 | "outputs": [ 18 | { 19 | "data": { 20 | "text/plain": [ 21 | "'/Users/gw18g940/Google Drive/BernMIC/ImageProcessingLecture/Python_image_processing/Env_setup'" 22 | ] 23 | }, 24 | "execution_count": 3, 25 | "metadata": {}, 26 | "output_type": "execute_result" 27 | } 28 | ], 29 | "source": [ 30 | "pwd" 31 | ] 32 | }, 33 | { 34 | "cell_type": "code", 35 | "execution_count": null, 36 | "metadata": {}, 37 | "outputs": [], 38 | "source": [ 39 | "#if you want to specify a particular location for file, give it here:\n", 40 | "#where_to_save = '/Users/gw18g940/Desktop/ImageProcessingLectureData/'\n", 41 | "\n", 42 | "#regular case\n", 43 | "where_to_save = '../../Data/'\n", 44 | "\n", 45 | "#create data directory\n", 46 | "if not os.path.exists(where_to_save):\n", 47 | " os.makedirs(where_to_save)" 48 | ] 49 | }, 50 | { 51 | "cell_type": "code", 52 | "execution_count": 6, 53 | "metadata": {}, 54 | "outputs": [ 55 | { 56 | "data": { 57 | "text/plain": [ 58 | "('../../Data/Klee.jpg', )" 59 | ] 60 | }, 61 | "execution_count": 6, 62 | "metadata": {}, 63 | "output_type": "execute_result" 64 | } 65 | ], 66 | "source": [ 67 | "#import Klee painting\n", 68 | "url = 'https://img.myswitzerland.com/671846/407' \n", 69 | "urllib.request.urlretrieve(url, where_to_save+'Klee.jpg')" 70 | ] 71 | }, 72 | { 73 | "cell_type": "code", 74 | "execution_count": null, 75 | "metadata": {}, 76 | "outputs": [], 77 | "source": [ 78 | "#import zebrafish embry\n", 79 | "os.makedirs(where_to_save+'30567')\n", 80 | "url = 'https://cildata.crbs.ucsd.edu/media/images/30567/30567.tif' \n", 81 | "urllib.request.urlretrieve(url, where_to_save+'30567/30567.tif')\n" 82 | ] 83 | }, 84 | { 85 | "cell_type": "code", 86 | "execution_count": null, 87 | "metadata": {}, 88 | "outputs": [], 89 | "source": [ 90 | "#import scifio wtembryo\n", 91 | "os.makedirs(where_to_save+'2chZT')\n", 92 | "url = 'https://samples.scif.io/2chZT.zip'\n", 93 | "urllib.request.urlretrieve(url, where_to_save+'2chZT.zip')\n", 94 | "#unzip\n", 95 | "with zipfile.ZipFile(where_to_save+'2chZT.zip', 'r') as zip_ref:\n", 96 | " zip_ref.extractall(where_to_save+'2chZT')\n", 97 | "os.remove(where_to_save+'2chZT.zip')" 98 | ] 99 | }, 100 | { 101 | "cell_type": "code", 102 | "execution_count": null, 103 | "metadata": {}, 104 | "outputs": [], 105 | "source": [ 106 | "#import landsat images\n", 107 | "os.makedirs(where_to_save+'geography')\n", 108 | "url = 'https://ndownloader.figshare.com/files/7677208'\n", 109 | "urllib.request.urlretrieve(url, where_to_save+'geography.zip')\n", 110 | "#unzip\n", 111 | "with zipfile.ZipFile(where_to_save+'geography.zip', 'r') as zip_ref:\n", 112 | " zip_ref.extractall(where_to_save+'geography')\n", 113 | "os.remove(where_to_save+'geography.zip')" 114 | ] 115 | }, 116 | { 117 | "cell_type": "code", 118 | "execution_count": 12, 119 | "metadata": {}, 120 | "outputs": [], 121 | "source": [ 122 | "#import BBBC007\n", 123 | "url = 'https://data.broadinstitute.org/bbbc/BBBC007/BBBC007_v1_images.zip'\n", 124 | "urllib.request.urlretrieve(url, where_to_save+'BBBC007_v1_images.zip')\n", 125 | "#unzip\n", 126 | "with zipfile.ZipFile(where_to_save+'BBBC007_v1_images.zip', 'r') as zip_ref:\n", 127 | " zip_ref.extractall(where_to_save)\n", 128 | "os.remove(where_to_save+'BBBC007_v1_images.zip')" 129 | ] 130 | }, 131 | { 132 | "cell_type": "code", 133 | "execution_count": null, 134 | "metadata": {}, 135 | "outputs": [], 136 | "source": [ 137 | "#import BBBC032\n", 138 | "os.makedirs(where_to_save+'BBBC032_v1_dataset')\n", 139 | "url = 'https://data.broadinstitute.org/bbbc/BBBC032/BBBC032_v1_dataset.zip'\n", 140 | "urllib.request.urlretrieve(url, where_to_save+'BBBC032_v1_dataset.zip')\n", 141 | "#unzip\n", 142 | "with zipfile.ZipFile(where_to_save+'BBBC032_v1_dataset.zip', 'r') as zip_ref:\n", 143 | " zip_ref.extractall(where_to_save+'BBBC032_v1_dataset')\n", 144 | "os.remove(where_to_save+'BBBC032_v1_dataset.zip')" 145 | ] 146 | }, 147 | { 148 | "cell_type": "code", 149 | "execution_count": 13, 150 | "metadata": {}, 151 | "outputs": [], 152 | "source": [ 153 | "#import BBBC034\n", 154 | "os.makedirs(where_to_save+'BBBC034_v1_dataset')\n", 155 | "url = 'https://data.broadinstitute.org/bbbc/BBBC034/BBBC034_v1_dataset.zip'\n", 156 | "urllib.request.urlretrieve(url, where_to_save+'BBBC034_v1_dataset.zip')\n", 157 | "#unzip\n", 158 | "with zipfile.ZipFile(where_to_save+'BBBC034_v1_dataset.zip', 'r') as zip_ref:\n", 159 | " zip_ref.extractall(where_to_save+'BBBC034_v1_dataset')\n", 160 | "os.remove(where_to_save+'BBBC034_v1_dataset.zip')" 161 | ] 162 | }, 163 | { 164 | "cell_type": "code", 165 | "execution_count": null, 166 | "metadata": {}, 167 | "outputs": [], 168 | "source": [ 169 | "#import channels\n", 170 | "os.makedirs(where_to_save+'channels')\n", 171 | "url = 'https://drive.google.com/uc?id=1kNzXN_FkRflU4uNOpNfmpK8hUcJ1Dz6R'\n", 172 | "urllib.request.urlretrieve(url, where_to_save+'channels/channels1.tif')\n", 173 | "url = 'https://drive.google.com/uc?id=1OMBGdO3t_RvCIcmTLPX6zBfRiWt5KP3Z'\n", 174 | "urllib.request.urlretrieve(url, where_to_save+'channels/channels2.tif')" 175 | ] 176 | }, 177 | { 178 | "cell_type": "code", 179 | "execution_count": 8, 180 | "metadata": {}, 181 | "outputs": [], 182 | "source": [ 183 | "#create a share folder and move data there" 184 | ] 185 | }, 186 | { 187 | "cell_type": "code", 188 | "execution_count": null, 189 | "metadata": {}, 190 | "outputs": [], 191 | "source": [ 192 | "!sudo mkdir -p /srv/data/" 193 | ] 194 | }, 195 | { 196 | "cell_type": "code", 197 | "execution_count": null, 198 | "metadata": {}, 199 | "outputs": [], 200 | "source": [ 201 | "!sudo mv '../../Data' '/srv/data/'" 202 | ] 203 | }, 204 | { 205 | "cell_type": "code", 206 | "execution_count": null, 207 | "metadata": {}, 208 | "outputs": [], 209 | "source": [ 210 | "!sudo ln -s /srv/data/Data /etc/skel/Data" 211 | ] 212 | } 213 | ], 214 | "metadata": { 215 | "kernelspec": { 216 | "display_name": "Python 3", 217 | "language": "python", 218 | "name": "python3" 219 | }, 220 | "language_info": { 221 | "codemirror_mode": { 222 | "name": "ipython", 223 | "version": 3 224 | }, 225 | "file_extension": ".py", 226 | "mimetype": "text/x-python", 227 | "name": "python", 228 | "nbconvert_exporter": "python", 229 | "pygments_lexer": "ipython3", 230 | "version": "3.6.7" 231 | }, 232 | "toc": { 233 | "base_numbering": 1, 234 | "nav_menu": {}, 235 | "number_sections": true, 236 | "sideBar": true, 237 | "skip_h1_title": false, 238 | "title_cell": "Table of Contents", 239 | "title_sidebar": "Contents", 240 | "toc_cell": false, 241 | "toc_position": {}, 242 | "toc_section_display": true, 243 | "toc_window_display": false 244 | } 245 | }, 246 | "nbformat": 4, 247 | "nbformat_minor": 2 248 | } 249 | -------------------------------------------------------------------------------- /Env_setup/Data_setup_local.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import sys, os, zipfile\n", 10 | "import urllib.request" 11 | ] 12 | }, 13 | { 14 | "cell_type": "code", 15 | "execution_count": 1, 16 | "metadata": {}, 17 | "outputs": [ 18 | { 19 | "data": { 20 | "text/plain": [ 21 | "'/Users/gw18g940/Google Drive/BernMIC/ImageProcessingLecture/Python_image_processing/Env_setup'" 22 | ] 23 | }, 24 | "execution_count": 1, 25 | "metadata": {}, 26 | "output_type": "execute_result" 27 | } 28 | ], 29 | "source": [ 30 | "pwd" 31 | ] 32 | }, 33 | { 34 | "cell_type": "code", 35 | "execution_count": 3, 36 | "metadata": {}, 37 | "outputs": [], 38 | "source": [ 39 | "#if you want to specify a particular location for file, give it here:\n", 40 | "#where_to_save = '/Users/gw18g940/Desktop/ImageProcessingLectureData/'\n", 41 | "\n", 42 | "#regular case\n", 43 | "where_to_save = '../../Data/'\n", 44 | "\n", 45 | "#create data directory\n", 46 | "if not os.path.exists(where_to_save):\n", 47 | " os.makedirs(where_to_save)" 48 | ] 49 | }, 50 | { 51 | "cell_type": "code", 52 | "execution_count": 6, 53 | "metadata": {}, 54 | "outputs": [ 55 | { 56 | "data": { 57 | "text/plain": [ 58 | "('../../Data/Klee.jpg', )" 59 | ] 60 | }, 61 | "execution_count": 6, 62 | "metadata": {}, 63 | "output_type": "execute_result" 64 | } 65 | ], 66 | "source": [ 67 | "#import Klee painting\n", 68 | "url = 'https://img.myswitzerland.com/671846/407' \n", 69 | "urllib.request.urlretrieve(url, where_to_save+'Klee.jpg')" 70 | ] 71 | }, 72 | { 73 | "cell_type": "code", 74 | "execution_count": null, 75 | "metadata": {}, 76 | "outputs": [], 77 | "source": [ 78 | "#import zebrafish embry\n", 79 | "os.makedirs(where_to_save+'30567')\n", 80 | "url = 'https://cildata.crbs.ucsd.edu/media/images/30567/30567.tif' \n", 81 | "urllib.request.urlretrieve(url, where_to_save+'30567/30567.tif')\n" 82 | ] 83 | }, 84 | { 85 | "cell_type": "code", 86 | "execution_count": 7, 87 | "metadata": {}, 88 | "outputs": [], 89 | "source": [ 90 | "#import scifio wtembryo\n", 91 | "os.makedirs(where_to_save+'2chZT')\n", 92 | "url = 'https://samples.scif.io/2chZT.zip'\n", 93 | "urllib.request.urlretrieve(url, where_to_save+'2chZT.zip')\n", 94 | "#unzip\n", 95 | "with zipfile.ZipFile(where_to_save+'2chZT.zip', 'r') as zip_ref:\n", 96 | " zip_ref.extractall(where_to_save+'2chZT')\n", 97 | "os.remove(where_to_save+'2chZT.zip')" 98 | ] 99 | }, 100 | { 101 | "cell_type": "code", 102 | "execution_count": 8, 103 | "metadata": {}, 104 | "outputs": [], 105 | "source": [ 106 | "#import landsat images\n", 107 | "os.makedirs(where_to_save+'geography')\n", 108 | "url = 'https://ndownloader.figshare.com/files/7677208'\n", 109 | "urllib.request.urlretrieve(url, where_to_save+'geography.zip')\n", 110 | "#unzip\n", 111 | "with zipfile.ZipFile(where_to_save+'geography.zip', 'r') as zip_ref:\n", 112 | " zip_ref.extractall(where_to_save+'geography')\n", 113 | "os.remove(where_to_save+'geography.zip')" 114 | ] 115 | }, 116 | { 117 | "cell_type": "code", 118 | "execution_count": 12, 119 | "metadata": {}, 120 | "outputs": [], 121 | "source": [ 122 | "#import BBBC007\n", 123 | "url = 'https://data.broadinstitute.org/bbbc/BBBC007/BBBC007_v1_images.zip'\n", 124 | "urllib.request.urlretrieve(url, where_to_save+'BBBC007_v1_images.zip')\n", 125 | "#unzip\n", 126 | "with zipfile.ZipFile(where_to_save+'BBBC007_v1_images.zip', 'r') as zip_ref:\n", 127 | " zip_ref.extractall(where_to_save)\n", 128 | "os.remove(where_to_save+'BBBC007_v1_images.zip')" 129 | ] 130 | }, 131 | { 132 | "cell_type": "code", 133 | "execution_count": null, 134 | "metadata": {}, 135 | "outputs": [], 136 | "source": [ 137 | "#import BBBC032\n", 138 | "os.makedirs(where_to_save+'BBBC032_v1_dataset')\n", 139 | "url = 'https://data.broadinstitute.org/bbbc/BBBC032/BBBC032_v1_dataset.zip'\n", 140 | "urllib.request.urlretrieve(url, where_to_save+'BBBC032_v1_dataset.zip')\n", 141 | "#unzip\n", 142 | "with zipfile.ZipFile(where_to_save+'BBBC032_v1_dataset.zip', 'r') as zip_ref:\n", 143 | " zip_ref.extractall(where_to_save+'BBBC032_v1_dataset')\n", 144 | "os.remove(where_to_save+'BBBC032_v1_dataset.zip')" 145 | ] 146 | }, 147 | { 148 | "cell_type": "code", 149 | "execution_count": 13, 150 | "metadata": {}, 151 | "outputs": [], 152 | "source": [ 153 | "#import BBBC034\n", 154 | "os.makedirs(where_to_save+'BBBC034_v1_dataset')\n", 155 | "url = 'https://data.broadinstitute.org/bbbc/BBBC034/BBBC034_v1_dataset.zip'\n", 156 | "urllib.request.urlretrieve(url, where_to_save+'BBBC034_v1_dataset.zip')\n", 157 | "#unzip\n", 158 | "with zipfile.ZipFile(where_to_save+'BBBC034_v1_dataset.zip', 'r') as zip_ref:\n", 159 | " zip_ref.extractall(where_to_save+'BBBC034_v1_dataset')\n", 160 | "os.remove(where_to_save+'BBBC034_v1_dataset.zip')" 161 | ] 162 | }, 163 | { 164 | "cell_type": "code", 165 | "execution_count": 14, 166 | "metadata": {}, 167 | "outputs": [ 168 | { 169 | "data": { 170 | "text/plain": [ 171 | "('../../Data/channels/channels2.tif', )" 172 | ] 173 | }, 174 | "execution_count": 14, 175 | "metadata": {}, 176 | "output_type": "execute_result" 177 | } 178 | ], 179 | "source": [ 180 | "#import channels\n", 181 | "os.makedirs(where_to_save+'channels')\n", 182 | "url = 'https://drive.google.com/uc?id=1kNzXN_FkRflU4uNOpNfmpK8hUcJ1Dz6R'\n", 183 | "urllib.request.urlretrieve(url, where_to_save+'channels/channels1.tif')\n", 184 | "url = 'https://drive.google.com/uc?id=1OMBGdO3t_RvCIcmTLPX6zBfRiWt5KP3Z'\n", 185 | "urllib.request.urlretrieve(url, where_to_save+'channels/channels2.tif')" 186 | ] 187 | }, 188 | { 189 | "cell_type": "code", 190 | "execution_count": null, 191 | "metadata": {}, 192 | "outputs": [], 193 | "source": [] 194 | } 195 | ], 196 | "metadata": { 197 | "kernelspec": { 198 | "display_name": "Python 3", 199 | "language": "python", 200 | "name": "python3" 201 | }, 202 | "language_info": { 203 | "codemirror_mode": { 204 | "name": "ipython", 205 | "version": 3 206 | }, 207 | "file_extension": ".py", 208 | "mimetype": "text/x-python", 209 | "name": "python", 210 | "nbconvert_exporter": "python", 211 | "pygments_lexer": "ipython3", 212 | "version": "3.6.7" 213 | }, 214 | "toc": { 215 | "base_numbering": 1, 216 | "nav_menu": {}, 217 | "number_sections": true, 218 | "sideBar": true, 219 | "skip_h1_title": false, 220 | "title_cell": "Table of Contents", 221 | "title_sidebar": "Contents", 222 | "toc_cell": false, 223 | "toc_position": {}, 224 | "toc_section_display": true, 225 | "toc_window_display": false 226 | } 227 | }, 228 | "nbformat": 4, 229 | "nbformat_minor": 2 230 | } 231 | -------------------------------------------------------------------------------- /Env_setup/Instructions_SwitchEngine.md: -------------------------------------------------------------------------------- 1 | 1. Create Ubuntu 18.04 machine on switch engine 2 | 3 | 2. login using 4 | 5 | ``` 6 | ubuntu@ipaddress 7 | ``` 8 | 9 | 10 | 3. Download the bash script from the github repository: 11 | 12 | ``` 13 | curl -O https://raw.githubusercontent.com/guiwitz/Python_image_processing/master/Env_setup/switch_engine_install.bsh 14 | ``` 15 | 16 | 17 | 4. Check address using code below and copy it: 18 | 19 | ``` 20 | host yourIPaddress 21 | ``` 22 | 23 | 24 | 5. Open the downloaded script (e.g. with vim): 25 | 26 | ``` 27 | vim switch_engine_install.bsh 28 | ``` 29 | 30 | 31 | 6. On line 18 replace the address yourhub.yourdomain.edu with the address copied in 4. 32 | On line 17 repliace your.email.address with your email address 33 | On line 14 replace choose_admin_name with your chosen admin name 34 | 35 | 7. Make script executable 36 | 37 | ``` 38 | chmod u+x switch_engine_install.bsh 39 | ``` 40 | 41 | 42 | 8. Execute the script: 43 | 44 | ``` 45 | ./switch_engine_install.bsh 46 | ``` 47 | 48 | 49 | 9. Answer yes to all questions 50 | 51 | 10. Create an nbgitpuller link on this model by replacing the jupyterhub address (https://hubaddress.cloud.switch.ch) with your hub address (see point 4) in : https://hubaddress.cloud.switch.ch/hub/user-redirect/git-pull?repo=https://github.com/guiwitz/Python_image_processing&app=lab 52 | 53 | 11. Go to Env_setup and open the Data_download notebook and execute it (this takes some time) 54 | 55 | 12. You should be all set ! 56 | 57 | -------------------------------------------------------------------------------- /Env_setup/Instructions_local.md: -------------------------------------------------------------------------------- 1 | 1. Install miniconda on your system following these instructions: https://conda.io/docs/user-guide/install/index.html 2 | 2. Clone or download this repository: https://github.com/guiwitz/Python_image_processing 3 | 3. cd (your location)/Python_image_processing/Env_setup 4 | 4. Make the install script executable: 5 | ``` 6 | chmod u+x local_install.bsh 7 | ``` 8 | 5. Execute the install script: 9 | ``` 10 | ./local_install.bsh 11 | ``` 12 | 13 | 6. Activate the conda environment: 14 | ``` 15 | source activate pyimageprocessing 16 | ``` 17 | 7. Start a jupyterlab session: 18 | ``` 19 | jupyter lab 20 | ``` 21 | 8. Open the Data_setup_local.ipynb notebook and execute all cells 22 | 9. Now you can close everything and stop Jupyterlab (Ctrl+C in the Terminal) 23 | 24 | Now, whenever you want to use the course material: 25 | 1. Open the Terminal 26 | 2. Activate the conda environment: 27 | ``` 28 | source activate pyimageprocessing 29 | ``` 30 | 3. Start Jupyter notebook or Jupyterlab: 31 | ``` 32 | jupyter notebook 33 | Jupyter lab 34 | ``` 35 | 4. Navigate to course material and execute notebooks -------------------------------------------------------------------------------- /Env_setup/Setting_up_colab.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 2, 6 | "metadata": { 7 | "colab": { 8 | "base_uri": "https://localhost:8080/", 9 | "height": 34 10 | }, 11 | "colab_type": "code", 12 | "executionInfo": { 13 | "elapsed": 559, 14 | "status": "ok", 15 | "timestamp": 1546968578426, 16 | "user": { 17 | "displayName": "Guillaume Witz", 18 | "photoUrl": "", 19 | "userId": "16411890613256560277" 20 | }, 21 | "user_tz": -60 22 | }, 23 | "id": "8y9R_jfKU8SQ", 24 | "outputId": "39eeac38-ce7a-4f20-c845-e88f1c635480" 25 | }, 26 | "outputs": [ 27 | { 28 | "name": "stdout", 29 | "output_type": "stream", 30 | "text": [ 31 | "Drive already mounted at /content/gdrive; to attempt to forcibly remount, call drive.mount(\"/content/gdrive\", force_remount=True).\n" 32 | ] 33 | } 34 | ], 35 | "source": [ 36 | "from google.colab import drive\n", 37 | "drive.mount('/content/gdrive')" 38 | ] 39 | }, 40 | { 41 | "cell_type": "code", 42 | "execution_count": 22, 43 | "metadata": { 44 | "colab": { 45 | "base_uri": "https://localhost:8080/", 46 | "height": 153 47 | }, 48 | "colab_type": "code", 49 | "executionInfo": { 50 | "elapsed": 5741, 51 | "status": "ok", 52 | "timestamp": 1546967665639, 53 | "user": { 54 | "displayName": "Guillaume Witz", 55 | "photoUrl": "", 56 | "userId": "16411890613256560277" 57 | }, 58 | "user_tz": -60 59 | }, 60 | "id": "VNLwAgrzcZrS", 61 | "outputId": "86085441-b10b-498e-d1a8-9f55ba247f34" 62 | }, 63 | "outputs": [ 64 | { 65 | "name": "stdout", 66 | "output_type": "stream", 67 | "text": [ 68 | "Requirement already satisfied: gdown in /usr/local/lib/python3.6/dist-packages (3.6.4)\n", 69 | "Requirement already satisfied: requests in /usr/local/lib/python3.6/dist-packages (from gdown) (2.18.4)\n", 70 | "Requirement already satisfied: six in /usr/local/lib/python3.6/dist-packages (from gdown) (1.11.0)\n", 71 | "Requirement already satisfied: tqdm in /usr/local/lib/python3.6/dist-packages (from gdown) (4.28.1)\n", 72 | "Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.6/dist-packages (from requests->gdown) (2018.11.29)\n", 73 | "Requirement already satisfied: chardet<3.1.0,>=3.0.2 in /usr/local/lib/python3.6/dist-packages (from requests->gdown) (3.0.4)\n", 74 | "Requirement already satisfied: idna<2.7,>=2.5 in /usr/local/lib/python3.6/dist-packages (from requests->gdown) (2.6)\n", 75 | "Requirement already satisfied: urllib3<1.23,>=1.21.1 in /usr/local/lib/python3.6/dist-packages (from requests->gdown) (1.22)\n" 76 | ] 77 | } 78 | ], 79 | "source": [ 80 | "!pip install gdown" 81 | ] 82 | }, 83 | { 84 | "cell_type": "code", 85 | "execution_count": null, 86 | "metadata": { 87 | "colab": {}, 88 | "colab_type": "code", 89 | "id": "UIxW6HDBU8yy" 90 | }, 91 | "outputs": [], 92 | "source": [ 93 | "import gdown" 94 | ] 95 | }, 96 | { 97 | "cell_type": "code", 98 | "execution_count": 31, 99 | "metadata": { 100 | "colab": { 101 | "base_uri": "https://localhost:8080/", 102 | "height": 102 103 | }, 104 | "colab_type": "code", 105 | "executionInfo": { 106 | "elapsed": 13492, 107 | "status": "ok", 108 | "timestamp": 1546968145472, 109 | "user": { 110 | "displayName": "Guillaume Witz", 111 | "photoUrl": "", 112 | "userId": "16411890613256560277" 113 | }, 114 | "user_tz": -60 115 | }, 116 | "id": "1mkJPG-AdX8d", 117 | "outputId": "8a003aa7-604e-4760-e332-e4bf536da19d" 118 | }, 119 | "outputs": [ 120 | { 121 | "name": "stderr", 122 | "output_type": "stream", 123 | "text": [ 124 | "Downloading...\n", 125 | "From: https://drive.google.com/uc?id=13UafeUl0hSmGO4JptzI-9F-PA39QJlX7\n", 126 | "To: /content/gdrive/My Drive/Data.zip\n", 127 | "699MB [00:06, 113MB/s]\n" 128 | ] 129 | }, 130 | { 131 | "data": { 132 | "text/plain": [ 133 | "'/content/gdrive/My Drive/Data.zip'" 134 | ] 135 | }, 136 | "execution_count": 31, 137 | "metadata": { 138 | "tags": [] 139 | }, 140 | "output_type": "execute_result" 141 | } 142 | ], 143 | "source": [ 144 | "gdown.download('https://drive.google.com/uc?id=13UafeUl0hSmGO4JptzI-9F-PA39QJlX7', '/content/gdrive/My Drive/Data.zip', quiet=False)" 145 | ] 146 | }, 147 | { 148 | "cell_type": "code", 149 | "execution_count": 32, 150 | "metadata": { 151 | "colab": { 152 | "base_uri": "https://localhost:8080/", 153 | "height": 1190 154 | }, 155 | "colab_type": "code", 156 | "executionInfo": { 157 | "elapsed": 32142, 158 | "status": "ok", 159 | "timestamp": 1546968200005, 160 | "user": { 161 | "displayName": "Guillaume Witz", 162 | "photoUrl": "", 163 | "userId": "16411890613256560277" 164 | }, 165 | "user_tz": -60 166 | }, 167 | "id": "NHhPzS8jVFbX", 168 | "outputId": "26d0388a-8099-47ff-e6b6-ff8e9fcc7e79" 169 | }, 170 | "outputs": [ 171 | { 172 | "name": "stdout", 173 | "output_type": "stream", 174 | "text": [ 175 | "Archive: /content/gdrive/My Drive/Data.zip\n", 176 | " creating: Data/\n", 177 | " inflating: Data/Klee.jpg \n", 178 | " creating: __MACOSX/\n", 179 | " creating: __MACOSX/Data/\n", 180 | " inflating: __MACOSX/Data/._Klee.jpg \n", 181 | " creating: Data/BBBC034_v1_dataset/\n", 182 | " inflating: Data/BBBC034_v1_dataset/edge_C=3_EGFP.tif \n", 183 | " creating: __MACOSX/Data/BBBC034_v1_dataset/\n", 184 | " inflating: __MACOSX/Data/BBBC034_v1_dataset/._edge_C=3_EGFP.tif \n", 185 | " extracting: Data/BBBC034_v1_dataset/Icon \n", 186 | " inflating: __MACOSX/Data/BBBC034_v1_dataset/._Icon \n", 187 | " inflating: Data/BBBC034_v1_dataset/AICS-12_134_C=3.tif \n", 188 | " inflating: __MACOSX/Data/BBBC034_v1_dataset/._AICS-12_134_C=3.tif \n", 189 | " inflating: Data/BBBC034_v1_dataset/colony_center_C=3_EGFP.tif \n", 190 | " inflating: __MACOSX/Data/BBBC034_v1_dataset/._colony_center_C=3_EGFP.tif \n", 191 | " inflating: Data/BBBC034_v1_dataset/edge_C=1_DeepRed.tif \n", 192 | " inflating: __MACOSX/Data/BBBC034_v1_dataset/._edge_C=1_DeepRed.tif \n", 193 | " inflating: Data/BBBC034_v1_dataset/colony_center_C=5_Hoechst.tif \n", 194 | " inflating: __MACOSX/Data/BBBC034_v1_dataset/._colony_center_C=5_Hoechst.tif \n", 195 | " inflating: Data/BBBC034_v1_dataset/AICS_12_134_C=2.tif \n", 196 | " inflating: __MACOSX/Data/BBBC034_v1_dataset/._AICS_12_134_C=2.tif \n", 197 | " inflating: Data/BBBC034_v1_dataset/AICS_12_134_C=1.tif \n", 198 | " inflating: __MACOSX/Data/BBBC034_v1_dataset/._AICS_12_134_C=1.tif \n", 199 | " inflating: Data/BBBC034_v1_dataset/AICS_12_134_C=0.tif \n", 200 | " inflating: __MACOSX/Data/BBBC034_v1_dataset/._AICS_12_134_C=0.tif \n", 201 | " inflating: Data/BBBC034_v1_dataset/edge_C=5_Hoechst.tif \n", 202 | " inflating: __MACOSX/Data/BBBC034_v1_dataset/._edge_C=5_Hoechst.tif \n", 203 | " inflating: Data/BBBC034_v1_dataset/colony_center_C=1_DeepRed.tif \n", 204 | " inflating: __MACOSX/Data/BBBC034_v1_dataset/._colony_center_C=1_DeepRed.tif \n", 205 | " inflating: __MACOSX/Data/._BBBC034_v1_dataset \n", 206 | " inflating: Data/.DS_Store \n", 207 | " inflating: __MACOSX/Data/._.DS_Store \n", 208 | " extracting: Data/Icon \n", 209 | " inflating: __MACOSX/Data/._Icon \n", 210 | " creating: Data/30567/\n", 211 | " extracting: Data/30567/Icon \n", 212 | " creating: __MACOSX/Data/30567/\n", 213 | " inflating: __MACOSX/Data/30567/._Icon \n", 214 | " inflating: Data/30567/30567_orig.tiff \n", 215 | " inflating: __MACOSX/Data/30567/._30567_orig.tiff \n", 216 | " inflating: __MACOSX/Data/._30567 \n", 217 | " creating: Data/A9/\n", 218 | " inflating: Data/A9/A9 p10d.tif \n", 219 | " creating: __MACOSX/Data/A9/\n", 220 | " inflating: __MACOSX/Data/A9/._A9 p10d.tif \n", 221 | " extracting: Data/A9/Icon \n", 222 | " inflating: __MACOSX/Data/A9/._Icon \n", 223 | " inflating: Data/A9/A9 p10f.tif \n", 224 | " inflating: __MACOSX/Data/A9/._A9 p10f.tif \n", 225 | " inflating: Data/A9/A9 p7d.tif \n", 226 | " inflating: __MACOSX/Data/A9/._A9 p7d.tif \n", 227 | " inflating: Data/A9/A9 p7f.tif \n", 228 | " inflating: __MACOSX/Data/A9/._A9 p7f.tif \n", 229 | " inflating: Data/A9/A9 p9f.tif \n", 230 | " inflating: __MACOSX/Data/A9/._A9 p9f.tif \n", 231 | " inflating: Data/A9/A9 p5d.tif \n", 232 | " inflating: __MACOSX/Data/A9/._A9 p5d.tif \n", 233 | " inflating: Data/A9/A9 p5f.tif \n", 234 | " inflating: __MACOSX/Data/A9/._A9 p5f.tif \n", 235 | " inflating: Data/A9/A9 p9d.tif \n", 236 | " inflating: __MACOSX/Data/A9/._A9 p9d.tif \n", 237 | " inflating: __MACOSX/Data/._A9 \n", 238 | " creating: Data/.ipynb_checkpoints/\n", 239 | " extracting: Data/.ipynb_checkpoints/Icon \n", 240 | " creating: __MACOSX/Data/.ipynb_checkpoints/\n", 241 | " inflating: __MACOSX/Data/.ipynb_checkpoints/._Icon \n", 242 | " inflating: __MACOSX/Data/._.ipynb_checkpoints \n", 243 | " inflating: __MACOSX/._Data \n" 244 | ] 245 | } 246 | ], 247 | "source": [ 248 | "!unzip '/content/gdrive/My Drive/Data.zip'" 249 | ] 250 | }, 251 | { 252 | "cell_type": "code", 253 | "execution_count": 9, 254 | "metadata": { 255 | "colab": { 256 | "base_uri": "https://localhost:8080/", 257 | "height": 119 258 | }, 259 | "colab_type": "code", 260 | "executionInfo": { 261 | "elapsed": 3323, 262 | "status": "ok", 263 | "timestamp": 1546969081871, 264 | "user": { 265 | "displayName": "Guillaume Witz", 266 | "photoUrl": "", 267 | "userId": "16411890613256560277" 268 | }, 269 | "user_tz": -60 270 | }, 271 | "id": "eJQrYJcnVQuZ", 272 | "outputId": "e04d1ae3-fd61-4ba7-ea3c-4e0d992bc4c1" 273 | }, 274 | "outputs": [ 275 | { 276 | "name": "stdout", 277 | "output_type": "stream", 278 | "text": [ 279 | "Cloning into '/content/gdrive/My Drive/Python_image_processing'...\n", 280 | "remote: Enumerating objects: 16, done.\u001b[K\n", 281 | "remote: Counting objects: 100% (16/16), done.\u001b[K\n", 282 | "remote: Compressing objects: 100% (15/15), done.\u001b[K\n", 283 | "remote: Total 16 (delta 0), reused 13 (delta 0), pack-reused 0\u001b[K\n", 284 | "Unpacking objects: 100% (16/16), done.\n" 285 | ] 286 | } 287 | ], 288 | "source": [ 289 | "!git clone https://github.com/guiwitz/Python_image_processing.git '/content/gdrive/My Drive/Python_image_processing'" 290 | ] 291 | } 292 | ], 293 | "metadata": { 294 | "colab": { 295 | "name": "Setting_up_colab.ipynb", 296 | "provenance": [], 297 | "version": "0.3.2" 298 | }, 299 | "kernelspec": { 300 | "display_name": "Python 3", 301 | "language": "python", 302 | "name": "python3" 303 | }, 304 | "language_info": { 305 | "codemirror_mode": { 306 | "name": "ipython", 307 | "version": 3 308 | }, 309 | "file_extension": ".py", 310 | "mimetype": "text/x-python", 311 | "name": "python", 312 | "nbconvert_exporter": "python", 313 | "pygments_lexer": "ipython3", 314 | "version": "3.6.7" 315 | } 316 | }, 317 | "nbformat": 4, 318 | "nbformat_minor": 2 319 | } 320 | -------------------------------------------------------------------------------- /Env_setup/local_install.bsh: -------------------------------------------------------------------------------- 1 | #bash script to setup the environment necessary for the lecture 2 | #please install miniconda for your system first 3 | 4 | conda create -y -n pyimageprocessing pip numpy pandas scikit-image matplotlib scipy jupyter jupyterlab 5 | source activate pyimageprocessing 6 | 7 | #to get jupyterlab extensions 8 | conda install -y -c conda-forge nodejs 9 | 10 | #to get TOC 11 | jupyter labextension install @jupyterlab/toc 12 | 13 | #install jupyter notebook extensions 14 | conda install -y -c conda-forge jupyter_contrib_nbextensions 15 | 16 | #install RISE 17 | conda install -y -c conda-forge rise 18 | 19 | #get trackpy package 20 | conda install -y -c conda-forge trackpy 21 | 22 | #get scikit-learn 23 | conda install -y scikit-learn 24 | 25 | #to get itk-widgets 26 | conda install -y -c conda-forge itkwidgets 27 | jupyter labextension install @jupyter-widgets/jupyterlab-manager itk-jupyter-widgets 28 | 29 | #install ipyvolume 30 | pip install ipyvolume 31 | jupyter labextension install ipyvolume 32 | jupyter labextension install jupyter-threejs 33 | 34 | #install tensorflow 35 | pip install tensorflow 36 | 37 | #install keras 38 | pip install keras 39 | 40 | #install tqdm 41 | sudo env "PATH=$PATH" pip install tqdm 42 | 43 | #update stuff for openCV 44 | sudo env "PATH=$PATH" apt update && apt install -y libsm6 libxext6 45 | 46 | #install openCV 47 | sudo env "PATH=$PATH" pip install opencv-python -------------------------------------------------------------------------------- /Env_setup/switch_engine_install.bsh: -------------------------------------------------------------------------------- 1 | #bash script to setup a JupyterHub for a Python Image processing lecture on a switch engine 2 | #using Ubuntu 18.04. 3 | #Follow the instructions in Instructions_SwitchEngine.md to use this installation script. 4 | #You will have to edit line 14, 17 and 18 5 | 6 | 7 | #update the machine state and install a missing python package 8 | sudo apt-get update 9 | sudo apt-get upgrade 10 | sudo apt-get install python3.6-dev 11 | sudo apt-get install unzip 12 | 13 | #install TLJH 14 | curl https://raw.githubusercontent.com/jupyterhub/the-littlest-jupyterhub/master/bootstrap/bootstrap.py | sudo python3 - --admin choose_admin_name 15 | 16 | sudo tljh-config set https.enabled true 17 | sudo tljh-config set https.letsencrypt.email your.email.address 18 | sudo tljh-config add-item https.letsencrypt.domains yourhub.yourdomain.edu 19 | sudo tljh-config reload proxy 20 | 21 | #install the necessary packages 22 | export PATH=/opt/tljh/user/bin:${PATH} 23 | 24 | #to get jupyterlab extensions 25 | sudo env "PATH=$PATH" conda install -y -c conda-forge nodejs 26 | 27 | #to get TOC 28 | sudo env "PATH=$PATH" jupyter labextension install @jupyterlab/toc 29 | 30 | #install jupyter notebook extensions 31 | sudo env "PATH=$PATH" conda install -y -c conda-forge jupyter_contrib_nbextensions 32 | 33 | #getting main libraries 34 | sudo env "PATH=$PATH" conda install -y numpy pandas scikit-image matplotlib scipy 35 | 36 | #get trackpy 37 | sudo env "PATH=$PATH" conda install -y -c conda-forge trackpy 38 | 39 | #get scikit-learn 40 | sudo env "PATH=$PATH" conda install -y scikit-learn 41 | 42 | #install RISE 43 | sudo env "PATH=$PATH" conda install -y -c conda-forge rise 44 | 45 | #to get itk-widgets 46 | sudo env "PATH=$PATH" conda install -y -c conda-forge itkwidgets 47 | sudo env "PATH=$PATH" jupyter labextension install @jupyter-widgets/jupyterlab-manager itk-jupyter-widgets 48 | 49 | #install ipyvolume 50 | sudo env "PATH=$PATH" pip install ipyvolume 51 | #sudo env "PATH=$PATH" jupyter labextension install @jupyter-widgets/jupyterlab-manager 52 | sudo env "PATH=$PATH" jupyter labextension install ipyvolume 53 | sudo env "PATH=$PATH" jupyter labextension install jupyter-threejs 54 | 55 | #install tensorflow 56 | sudo env "PATH=$PATH" pip install tensorflow 57 | 58 | #install keras 59 | sudo env "PATH=$PATH" pip install keras 60 | 61 | #install tqdm 62 | sudo env "PATH=$PATH" pip install tqdm 63 | 64 | #update stuff for openCV 65 | sudo env "PATH=$PATH" apt update && apt install -y libsm6 libxext6 66 | 67 | #install openCV 68 | sudo env "PATH=$PATH" pip install opencv-python 69 | 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /Exercises/Exercise1.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Exercises 1" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "- Create a list of the squares of numbers from 0 to 10.\n", 15 | "- Make a copy of the list\n", 16 | "- Find all the methods/functions that one can apply to that list\n", 17 | "- Find and apply a method that allows you to flip the order of elements\n", 18 | "- Verify what happened to the list and its copy\n", 19 | "- Can you find a way to make two truly independent copies ?\n" 20 | ] 21 | }, 22 | { 23 | "cell_type": "markdown", 24 | "metadata": {}, 25 | "source": [ 26 | "# Solutions 1" 27 | ] 28 | }, 29 | { 30 | "cell_type": "code", 31 | "execution_count": 10, 32 | "metadata": {}, 33 | "outputs": [], 34 | "source": [ 35 | "#create list\n", 36 | "square_list = [i**2 for i in range(10)]" 37 | ] 38 | }, 39 | { 40 | "cell_type": "code", 41 | "execution_count": 11, 42 | "metadata": {}, 43 | "outputs": [], 44 | "source": [ 45 | "#make a copy\n", 46 | "square_list2 = square_list" 47 | ] 48 | }, 49 | { 50 | "cell_type": "code", 51 | "execution_count": 12, 52 | "metadata": {}, 53 | "outputs": [ 54 | { 55 | "data": { 56 | "text/plain": [ 57 | "['__add__',\n", 58 | " '__class__',\n", 59 | " '__contains__',\n", 60 | " '__delattr__',\n", 61 | " '__delitem__',\n", 62 | " '__dir__',\n", 63 | " '__doc__',\n", 64 | " '__eq__',\n", 65 | " '__format__',\n", 66 | " '__ge__',\n", 67 | " '__getattribute__',\n", 68 | " '__getitem__',\n", 69 | " '__gt__',\n", 70 | " '__hash__',\n", 71 | " '__iadd__',\n", 72 | " '__imul__',\n", 73 | " '__init__',\n", 74 | " '__init_subclass__',\n", 75 | " '__iter__',\n", 76 | " '__le__',\n", 77 | " '__len__',\n", 78 | " '__lt__',\n", 79 | " '__mul__',\n", 80 | " '__ne__',\n", 81 | " '__new__',\n", 82 | " '__reduce__',\n", 83 | " '__reduce_ex__',\n", 84 | " '__repr__',\n", 85 | " '__reversed__',\n", 86 | " '__rmul__',\n", 87 | " '__setattr__',\n", 88 | " '__setitem__',\n", 89 | " '__sizeof__',\n", 90 | " '__str__',\n", 91 | " '__subclasshook__',\n", 92 | " 'append',\n", 93 | " 'clear',\n", 94 | " 'copy',\n", 95 | " 'count',\n", 96 | " 'extend',\n", 97 | " 'index',\n", 98 | " 'insert',\n", 99 | " 'pop',\n", 100 | " 'remove',\n", 101 | " 'reverse',\n", 102 | " 'sort']" 103 | ] 104 | }, 105 | "execution_count": 12, 106 | "metadata": {}, 107 | "output_type": "execute_result" 108 | } 109 | ], 110 | "source": [ 111 | "#find all methods\n", 112 | "dir(square_list)" 113 | ] 114 | }, 115 | { 116 | "cell_type": "code", 117 | "execution_count": 13, 118 | "metadata": {}, 119 | "outputs": [], 120 | "source": [ 121 | "#use the revere method\n", 122 | "square_list.reverse()" 123 | ] 124 | }, 125 | { 126 | "cell_type": "code", 127 | "execution_count": 16, 128 | "metadata": {}, 129 | "outputs": [ 130 | { 131 | "data": { 132 | "text/plain": [ 133 | "[81, 64, 49, 36, 25, 16, 9, 4, 1, 0]" 134 | ] 135 | }, 136 | "execution_count": 16, 137 | "metadata": {}, 138 | "output_type": "execute_result" 139 | } 140 | ], 141 | "source": [ 142 | "#check first list\n", 143 | "square_list" 144 | ] 145 | }, 146 | { 147 | "cell_type": "code", 148 | "execution_count": 15, 149 | "metadata": {}, 150 | "outputs": [ 151 | { 152 | "data": { 153 | "text/plain": [ 154 | "[81, 64, 49, 36, 25, 16, 9, 4, 1, 0]" 155 | ] 156 | }, 157 | "execution_count": 15, 158 | "metadata": {}, 159 | "output_type": "execute_result" 160 | } 161 | ], 162 | "source": [ 163 | "#check second list\n", 164 | "square_list2" 165 | ] 166 | }, 167 | { 168 | "cell_type": "markdown", 169 | "metadata": {}, 170 | "source": [ 171 | "Through the simple assignement list1 = list2, one creates a \"true\" copy a a list in the sense that if one is modified, the other too.\n", 172 | "\n", 173 | "To avoid that one can use the copy() method, that creates a new independent object" 174 | ] 175 | }, 176 | { 177 | "cell_type": "code", 178 | "execution_count": 19, 179 | "metadata": {}, 180 | "outputs": [], 181 | "source": [ 182 | "square_list3 = square_list.copy()" 183 | ] 184 | }, 185 | { 186 | "cell_type": "code", 187 | "execution_count": 20, 188 | "metadata": {}, 189 | "outputs": [ 190 | { 191 | "data": { 192 | "text/plain": [ 193 | "[81, 64, 49, 36, 25, 16, 9, 4, 1, 0]" 194 | ] 195 | }, 196 | "execution_count": 20, 197 | "metadata": {}, 198 | "output_type": "execute_result" 199 | } 200 | ], 201 | "source": [ 202 | "square_list3" 203 | ] 204 | }, 205 | { 206 | "cell_type": "code", 207 | "execution_count": 21, 208 | "metadata": {}, 209 | "outputs": [], 210 | "source": [ 211 | "square_list.reverse()" 212 | ] 213 | }, 214 | { 215 | "cell_type": "code", 216 | "execution_count": 22, 217 | "metadata": {}, 218 | "outputs": [ 219 | { 220 | "data": { 221 | "text/plain": [ 222 | "[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]" 223 | ] 224 | }, 225 | "execution_count": 22, 226 | "metadata": {}, 227 | "output_type": "execute_result" 228 | } 229 | ], 230 | "source": [ 231 | "square_list" 232 | ] 233 | }, 234 | { 235 | "cell_type": "code", 236 | "execution_count": 23, 237 | "metadata": {}, 238 | "outputs": [ 239 | { 240 | "data": { 241 | "text/plain": [ 242 | "[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]" 243 | ] 244 | }, 245 | "execution_count": 23, 246 | "metadata": {}, 247 | "output_type": "execute_result" 248 | } 249 | ], 250 | "source": [ 251 | "square_list2" 252 | ] 253 | }, 254 | { 255 | "cell_type": "code", 256 | "execution_count": 24, 257 | "metadata": {}, 258 | "outputs": [ 259 | { 260 | "data": { 261 | "text/plain": [ 262 | "[81, 64, 49, 36, 25, 16, 9, 4, 1, 0]" 263 | ] 264 | }, 265 | "execution_count": 24, 266 | "metadata": {}, 267 | "output_type": "execute_result" 268 | } 269 | ], 270 | "source": [ 271 | "square_list3" 272 | ] 273 | }, 274 | { 275 | "cell_type": "code", 276 | "execution_count": null, 277 | "metadata": {}, 278 | "outputs": [], 279 | "source": [] 280 | } 281 | ], 282 | "metadata": { 283 | "kernelspec": { 284 | "display_name": "Python 3", 285 | "language": "python", 286 | "name": "python3" 287 | }, 288 | "language_info": { 289 | "codemirror_mode": { 290 | "name": "ipython", 291 | "version": 3 292 | }, 293 | "file_extension": ".py", 294 | "mimetype": "text/x-python", 295 | "name": "python", 296 | "nbconvert_exporter": "python", 297 | "pygments_lexer": "ipython3", 298 | "version": "3.6.7" 299 | } 300 | }, 301 | "nbformat": 4, 302 | "nbformat_minor": 2 303 | } 304 | -------------------------------------------------------------------------------- /Exercises/Exercise6.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Exercises 6" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "- Transform the small processing pipeline from Exercise 5 into a function, which takes your noisy image as input and outputs the mask. In principle this requires only copying all relevant lines into a function\n", 15 | "- Create a new file called mymodule.py and copy your function in there\n", 16 | "- Try to use that function from your notebook\n", 17 | "- If you get errors messages, try to debug (make sure variables are defined, modules imported *etc.*)\n", 18 | "- Instead of hard-coding the threshold level, use it as a function parameter\n", 19 | "- In a for loop, use thresholds from 100 to 160 in steps of 10 in the function and plot the resulting mask" 20 | ] 21 | }, 22 | { 23 | "cell_type": "markdown", 24 | "metadata": {}, 25 | "source": [ 26 | "# Solutions 6" 27 | ] 28 | }, 29 | { 30 | "cell_type": "code", 31 | "execution_count": 2, 32 | "metadata": {}, 33 | "outputs": [], 34 | "source": [ 35 | "import numpy as np\n", 36 | "import matplotlib.pyplot as plt\n", 37 | "import skimage.data" 38 | ] 39 | }, 40 | { 41 | "cell_type": "code", 42 | "execution_count": 6, 43 | "metadata": {}, 44 | "outputs": [], 45 | "source": [ 46 | "#load moon image\n", 47 | "image = skimage.data.rocket()" 48 | ] 49 | }, 50 | { 51 | "cell_type": "code", 52 | "execution_count": 15, 53 | "metadata": {}, 54 | "outputs": [], 55 | "source": [ 56 | "import skimage.color\n", 57 | "from skimage.morphology import binary_opening, disk\n", 58 | "from skimage.measure import label, regionprops\n", 59 | "from skimage.filters import median\n", 60 | "\n", 61 | "\n", 62 | "def create_mask(image):\n", 63 | " image_gray = skimage.color.rgb2gray(image)\n", 64 | " \n", 65 | " #generate normal noise\n", 66 | " normal_matrix = np.random.randn(image_gray.shape[0], image_gray.shape[1])\n", 67 | "\n", 68 | " #add it to the image\n", 69 | " noisy_image = image_gray + 0.1*normal_matrix\n", 70 | " \n", 71 | " #rescale image to uint8\n", 72 | " noisy_image_int = noisy_image-noisy_image.min()\n", 73 | " noisy_image_int = 255*noisy_image_int/noisy_image_int.max()\n", 74 | " noisy_image_int = noisy_image_int.astype(np.uint8)\n", 75 | "\n", 76 | " #filter image to suppress noise\n", 77 | " image_median = median(noisy_image_int, selem=disk(3))\n", 78 | " \n", 79 | " #create mask\n", 80 | " mask = image_median>140\n", 81 | " \n", 82 | " #close the mask\n", 83 | " mask_closed = binary_opening(mask, selem=disk(2))\n", 84 | " \n", 85 | " #measure regions\n", 86 | " image_label = label(mask_closed)\n", 87 | " regions = regionprops(image_label, image_median)\n", 88 | " \n", 89 | " area = [x.area for x in regions]\n", 90 | " mean_intensity = [x.mean_intensity for x in regions]\n", 91 | "\n", 92 | " newmask = np.zeros(image_label.shape)\n", 93 | " for x in regions:\n", 94 | " if (x.area<500) and (x.mean_intensity>160):\n", 95 | " newmask[x.coords[:,0],x.coords[:,1]]=1\n", 96 | " \n", 97 | " return newmask" 98 | ] 99 | }, 100 | { 101 | "cell_type": "code", 102 | "execution_count": 16, 103 | "metadata": {}, 104 | "outputs": [], 105 | "source": [ 106 | "mask = create_mask(image)" 107 | ] 108 | }, 109 | { 110 | "cell_type": "code", 111 | "execution_count": 17, 112 | "metadata": {}, 113 | "outputs": [ 114 | { 115 | "data": { 116 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXEAAAD8CAYAAACB3pQWAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvOIA7rQAAEyBJREFUeJzt3X+s3Xd93/Hna3Z+MGA4IT/k2d4cireSVsVEXjBKNdFAWyet6lSCKagaFrLkTgpSUNHapJPWIm3SkFbM0LZobpNiJkZIAyxWxEozJ6jbHyTYYIIdk8aMDN/ai4fyAxhSNifv/XE+l5zYJ77Hvvf4nI/v8yEdne/38/2cez8f3+95+XM/5/u9n1QVkqQ+/Y1pN0CSdO4McUnqmCEuSR0zxCWpY4a4JHXMEJekjk0sxJNsSfJkkiNJ7pjU95Gk5SyTuE48yQrgr4BfBuaArwMfqKonlvybSdIyNqmR+PXAkar6H1X1f4F7ga0T+l6StGytnNDXXQMcHdqfA975WpWTeNuoJL3aD6rqyoUqTSrEM6LsVUGdZAewY0LfX5J69z/HqTSpEJ8D1g3trwWODVeoql3ALnAkLknnalJz4l8HNiS5JsnFwK3Angl9L0latiYyEq+qk0k+DHwFWAHcU1WHJvG9JGk5m8glhmfdCKdTJOlU+6tq00KVvGNTkjpmiEtSxwxxSeqYIS5JHTPEJaljhrgkdcwQl6SOGeKS1DFDXJI6ZohLUscMcUnqmCEuSR0zxCWpY4a4JHXMEJekjhniktQxQ1ySOrao5dmSPA38CHgJOFlVm5JcDnweWA88Dfyjqnpucc2UJI2yFCPxX6qqjUPLCN0B7K2qDcDeti9JmoBJTKdsBXa37d3ALRP4HpIkFh/iBfxFkv1JdrSyq6vqOEB7vmrUC5PsSLIvyb5FtkGSlq1FzYkDN1TVsSRXAQ8l+c64L6yqXcAucLV7STpXixqJV9Wx9nwC+BJwPfBMktUA7fnEYhspSRrtnEM8yeuTvHF+G/gV4CCwB9jWqm0DHlhsIyVJoy1mOuVq4EtJ5r/Of6qqP0/ydeC+JNuB7wPvX3wzJUmjpGr609HOiUvSafYPXbr9mrxjU5I6ZohLUscMcUnqmCEuSR0zxCWpY4a4JHXMEJekjhniktQxQ1ySOmaIS1LHDHFJ6pghLkkdM8QlqWOGuCR1zBCXpI4Z4pLUsQVDPMk9SU4kOThUdnmSh5I81Z4va+VJ8qkkR5I8nuS6STZekpa7cUbinwa2nFJ2B7C3qjYAe9s+wE3AhvbYAdy1NM2UJI2yYIhX1V8Cz55SvBXY3bZ3A7cMlX+mBr4GrGor3kuSJuBc58SvrqrjAO35qla+Bjg6VG+ulUmSJmAxq92PkhFlIxdBTrKDwZSLJOkcnetI/Jn5aZL2fKKVzwHrhuqtBY6N+gJVtauqNo2zmrMkabRzDfE9wLa2vQ14YKj8g+0qlc3AC/PTLpKkpbfgdEqSzwHvBq5IMgf8AfCvgPuSbAe+D7y/Vf8ycDNwBPgJ8KEJtFmS1KRq5JT1+W1EMv1GSNJs2T/OdLN3bEpSxwxxSeqYIS5JHTPEJaljhrgkdcwQl6SOGeKS1DFDXJI6ZohLUscMcUnqmCEuSR0zxCWpY4a4JHXMEJekjhniktQxQ1ySOmaIS1LHFgzxJPckOZHk4FDZHyb56yQH2uPmoWN3JjmS5MkkvzqphkuSxhuJfxrYMqJ8Z1VtbI8vAyS5FrgV+Ln2mn+fZMVSNVaS9GoLhnhV/SXw7Jhfbytwb1W9WFXfY7Bg8vWLaJ8k6QwWMyf+4SSPt+mWy1rZGuDoUJ25VnaaJDuS7EuybxFtkKRl7VxD/C7gZ4CNwHHgj1p5RtQduZJ9Ve2qqk3jrOYsSRrtnEK8qp6pqpeq6mXgj3llymQOWDdUdS1wbHFNlCS9lnMK8SSrh3Z/E5i/cmUPcGuSS5JcA2wAHltcEyVJr2XlQhWSfA54N3BFkjngD4B3J9nIYKrkaeC3AarqUJL7gCeAk8BtVfXSZJouSUrVyCnr89uIZPqNkKTZsn+czwy9Y1OSOmaIS1LHDHFJ6pghLkkdM8QlqWOGuCR1zBCXpI4Z4pLUMUNckjpmiEtSxwxxSeqYIS5JHTPEJaljhrgkdcwQl6SOGeKS1LEFQzzJuiSPJDmc5FCS21v55UkeSvJUe76slSfJp5IcSfJ4kusm3QlJWq7GGYmfBD5aVW8DNgO3JbkWuAPYW1UbgL1tH+AmBmtrbgB2AHcteaslScAYIV5Vx6vqG237R8BhYA2wFdjdqu0GbmnbW4HP1MDXgFWnLKwsSVoiZzUnnmQ98A7gUeDqqjoOg6AHrmrV1gBHh14218pO/Vo7kuxLsu/smy1JgjFWu5+X5A3AF4CPVNUPk7xm1RFlpy2EXFW7gF3ta7tQsiSdg7FG4kkuYhDgn62qL7biZ+anSdrziVY+B6wbevla4NjSNFeSNGycq1MC3A0crqpPDB3aA2xr29uAB4bKP9iuUtkMvDA/7SJJWlqpOvNMRpJfBP4b8G3g5Vb8+wzmxe8D/g7wfeD9VfVsC/1/C2wBfgJ8qKrOOO/tdIoknWZ/VW1aqNKCIX4+GOKSdJqxQtw7NiWpY4a4JHXMEJekjhniktQxQ1ySOmaIS1LHDHFJ6pghLkkdM8QlqWOGuCR1zBCXpI4Z4pLUMUNckjpmiEtSxwxxSeqYIS5JHTPEJalj46yxuS7JI0kOJzmU5PZW/odJ/jrJgfa4eeg1dyY5kuTJJL86yQ5I0nK2cow6J4GPVtU3krwR2J/koXZsZ1X96+HKSa4FbgV+DvjbwH9N8veq6qWlbLgkaYyReFUdr6pvtO0fAYeBNWd4yVbg3qp6saq+BxwBrl+KxkqSXu2s5sSTrAfewWCle4APJ3k8yT1JLmtla4CjQy+bY0ToJ9mRZF+SfWfdakkScBYhnuQNwBeAj1TVD4G7gJ8BNgLHgT+arzri5aetZl9Vu6pq0zirOUuSRhsrxJNcxCDAP1tVXwSoqmeq6qWqehn4Y16ZMpkD1g29fC1wbOmaLEmaN87VKQHuBg5X1SeGylcPVftN4GDb3gPcmuSSJNcAG4DHlq7JkqR541ydcgPwj4FvJznQyn4f+ECSjQymSp4Gfhugqg4luQ94gsGVLbd5ZYokTUaqTpuuPv+NSKbfCEmaLfvH+czQOzYlqWOGuCR1zBCXpI4Z4pLUMUNckjpmiEtSxwxxSeqYIS5JHTPEJaljhrgkdcwQl6SOGeKS1DFDXJI6ZohLUscMcUnqmCEuSR0bZ3m2S5M8luRbSQ4l+VgrvybJo0meSvL5JBe38kva/pF2fP1kuyBJy9c4I/EXgRur6u0MVrbfkmQz8HFgZ1VtAJ4Dtrf624HnquqtwM5WT5I0AQuGeA38uO1e1B4F3Ajc38p3A7e07a1tn3b8PW2xZUnSEhtrTjzJirZI8gngIeC7wPNVdbJVmQPWtO01wFGAdvwF4M0jvuaOJPuS7FtcFyRp+RorxKvqparaCKwFrgfeNqpaex416j5tIeSq2lVVm8ZZCFSSNNpZXZ1SVc8DXwU2A6uSrGyH1gLH2vYcsA6gHX8T8OxSNFaS9GrjXJ1yZZJVbft1wHuBw8AjwPtatW3AA217T9unHX+4qk4biUuSFm/lwlVYDexOsoJB6N9XVQ8meQK4N8m/AL4J3N3q3w38xyRHGIzAb51AuyVJQGZhkJxk+o2QpNmyf5zPDL1jU5I6ZohLUscMcUnqmCEuSR0zxCWpY4a4JHXMEJekjhniktQxQ1ySOmaIS1LHDHFJ6pghLkkdM8QlqWOGuCR1zBCXpI4Z4pLUsXGWZ7s0yWNJvpXkUJKPtfJPJ/lekgPtsbGVJ8mnkhxJ8niS6ybdifOlqpiFRTQkad44y7O9CNxYVT9OchHw35P8l3bsn1bV/afUvwnY0B7vBO5qz906NbiriiRTao0kvWLBkXgN/LjtXtQeZxqObgU+0173NWBVktWLb6ok6VRjzYknWZHkAHACeKiqHm2H/mWbMtmZ5JJWtgY4OvTyuVYmSVpiY4V4Vb1UVRuBtcD1SX4euBP4WeAfAJcDv9eqj5pnOG3knmRHkn1J9p1TyyVJZ3d1SlU9D3wV2FJVx9uUyYvAnwLXt2pzwLqhl60Fjo34WruqatM4qzlLkkYb5+qUK5OsatuvA94LfGd+njuDT/huAQ62l+wBPtiuUtkMvFBVxyfS+vPk1A8x/VBT0qwY5+qU1cDuJCsYhP59VfVgkoeTXMlg+uQA8E9a/S8DNwNHgJ8AH1r6Zp9/BrekWZRZuO45yfQbIUmzZf84083esSlJHTPEJaljhrgkdcwQ75R/x0USGOLdM8il5c0Q78yoEbhBLi1f41wnrhlgUEsaxZF4BxYKcG9EkpYvQ7wDC4W0o3Rp+TLEJaljhvgFwOkUafkyxDthUEsaxRDvnOEuLW+GeEfmAzvJTx9LYf6DUe8ClfpjiHdmqUfewwF+apkuTP58LyyG+DJ2pjezb/QLk791XXgM8WXKN7DA8+BCMHaIJ1mR5JtJHmz71yR5NMlTST6f5OJWfknbP9KOr59M07UYfiC6/BjYF6azGYnfDhwe2v84sLOqNgDPAdtb+Xbguap6K7Cz1VOHfNNLs2+sEE+yFvg14E/afoAbgftbld0MVrwH2Nr2acffE4d9XfLHdmEZ9fP0Z9y/cUfinwR+F3i57b8ZeL6qTrb9OWBN214DHAVox19o9V8lyY4k+5LsO8e2a5F8Ay8/w5em+vO/MCwY4kl+HThRVfuHi0dUrTGOvVJQtauqNo2zmrMmxzfy8uTP/cIxzt8TvwH4jSQ3A5cCf4vByHxVkpVttL0WONbqzwHrgLkkK4E3Ac8uecs1Ub7JpT4sOBKvqjuram1VrQduBR6uqt8CHgHe16ptAx5o23vaPu34w+UnZDN9Xe7wHaBLeSeopMlbzHXivwf8TpIjDOa8727ldwNvbuW/A9yxuCb2z7shJU1KZiFUkky/ERNwpn9bR7uaNaPOV8/Tqdo/zmeG3rE5IQv95zgL/3lKC/E8nX2G+ASMc+I7wtEsWejv6Bjms8sQnxLfFJoV456LnrOzyRCfIt8U6om/Pc4mQ1xapN6nGwznvo1zs4/OgvPhy8uoy0cv1J9vVV2wfeuZI/El5kmu3kblvbVXr2aIT8CZgtyQXx4uxGD03J1NszKd8mPgyWk3YolcAfzgAjnhrwB+MO1GLJGJ9GVKP+cl7cuUz1XPsdf2d8epNCsh/uSF8tcMk+yzL7PHvswm+7J4TqdIUscMcUnq2KyE+K5pN2AJ2ZfZZF9mk31ZpJn4K4aSpHMzKyNxSdI5mHqIJ9mS5MkkR5LM/AISSe5JciLJwaGyy5M8lOSp9nxZK0+ST7W+PZ7kuum1/HRJ1iV5JMnhJIeS3N7Ku+tPkkuTPJbkW60vH2vl1yR5tPXl80kubuWXtP0j7fj6abb/VElWJPlmkgfbfq/9eDrJt5McmF8UvcfzCyDJqiT3J/lOe8+8axb6MtUQT7IC+HfATcC1wAeSXDvNNo3h08CWU8ruAPZW1QZgL6+sZnQTsKE9dgB3nac2jusk8NGqehuwGbit/fv32J8XgRur6u3ARmBLks3Ax4GdrS/PAdtb/e3Ac1X1VmBnqzdLbgcOD+332g+AX6qqjUOX3/V4fgH8G+DPq+pngbcz+PlMvy/zf7xnGg/gXcBXhvbvBO6cZpvGbPd64ODQ/pPA6ra9msF17wD/AfjAqHqz+GCwTuov994f4G8C3wDeyeDmi5Wnnm/AV4B3te2VrV6m3fbWnrUMAuFG4EEgPfajtelp4IpTyro7vxgsEP+9U/9tZ6Ev055OWQMcHdqfa2W9ubqqjgO056taeTf9a7+GvwN4lE7706YgDgAngIeA7wLPV9XJVmW4vT/tSzv+AoO1YmfBJ4HfBV5u+2+mz34AFPAXSfYn2dHKejy/3gL8b+BP2zTXnyR5PTPQl2mH+Kj7fS+ky2W66F+SNwBfAD5SVT88U9URZTPTn6p6qao2MhjJXg+8bVS19jyTfUny68CJqto/XDyi6kz3Y8gNVXUdg+mF25L8wzPUneW+rASuA+6qqncA/4czLwJ/3voy7RCfA9YN7a8Fjk2pLYvxTJLVAO35RCuf+f4luYhBgH+2qr7YirvtD0BVPQ98lcE8/6ok839eYri9P+1LO/4m4Nnz29KRbgB+I8nTwL0MplQ+SX/9AKCqjrXnE8CXGPzn2uP5NQfMVdWjbf9+BqE+9b5MO8S/Dmxon7xfDNwK7Jlym87FHmBb297GYG55vvyD7ZPqzcAL8796zYIkAe4GDlfVJ4YOddefJFcmWdW2Xwe8l8EHT48A72vVTu3LfB/fBzxcbfJymqrqzqpaW1XrGbwfHq6q36KzfgAkeX2SN85vA78CHKTD86uq/hdwNMnfb0XvAZ5gFvoyAx8Y3Az8FYP5y3827faM0d7PAceB/8fgf9vtDOYg9wJPtefLW90wuPrmu8C3gU3Tbv8pfflFBr/iPQ4caI+be+wP8AvAN1tfDgL/vJW/BXgMOAL8GXBJK7+07R9px98y7T6M6NO7gQd77Udr87fa49D8+7vH86u1byOwr51j/xm4bBb64h2bktSxaU+nSJIWwRCXpI4Z4pLUMUNckjpmiEtSxwxxSeqYIS5JHTPEJalj/x+eqNZqXVcsiAAAAABJRU5ErkJggg==\n", 117 | "text/plain": [ 118 | "
" 119 | ] 120 | }, 121 | "metadata": { 122 | "needs_background": "light" 123 | }, 124 | "output_type": "display_data" 125 | } 126 | ], 127 | "source": [ 128 | "plt.imshow(mask, cmap = 'gray')\n", 129 | "plt.show()" 130 | ] 131 | }, 132 | { 133 | "cell_type": "markdown", 134 | "metadata": {}, 135 | "source": [ 136 | "Use threshold as a parameter" 137 | ] 138 | }, 139 | { 140 | "cell_type": "code", 141 | "execution_count": 19, 142 | "metadata": {}, 143 | "outputs": [], 144 | "source": [ 145 | "def create_mask_threshold(image, threshold):\n", 146 | " image_gray = skimage.color.rgb2gray(image)\n", 147 | " \n", 148 | " #generate normal noise\n", 149 | " normal_matrix = np.random.randn(image_gray.shape[0], image_gray.shape[1])\n", 150 | "\n", 151 | " #add it to the image\n", 152 | " noisy_image = image_gray + 0.1*normal_matrix\n", 153 | " \n", 154 | " #rescale image to uint8\n", 155 | " noisy_image_int = noisy_image-noisy_image.min()\n", 156 | " noisy_image_int = 255*noisy_image_int/noisy_image_int.max()\n", 157 | " noisy_image_int = noisy_image_int.astype(np.uint8)\n", 158 | "\n", 159 | " #filter image to suppress noise\n", 160 | " image_median = median(noisy_image_int, selem=disk(3))\n", 161 | " \n", 162 | " #create mask\n", 163 | " mask = image_median>threshold\n", 164 | " \n", 165 | " #close the mask\n", 166 | " mask_closed = binary_opening(mask, selem=disk(2))\n", 167 | " \n", 168 | " #measure regions\n", 169 | " image_label = label(mask_closed)\n", 170 | " regions = regionprops(image_label, image_median)\n", 171 | " \n", 172 | " area = [x.area for x in regions]\n", 173 | " mean_intensity = [x.mean_intensity for x in regions]\n", 174 | "\n", 175 | " newmask = np.zeros(image_label.shape)\n", 176 | " for x in regions:\n", 177 | " if (x.area<500) and (x.mean_intensity>160):\n", 178 | " newmask[x.coords[:,0],x.coords[:,1]]=1\n", 179 | " \n", 180 | " return newmask" 181 | ] 182 | }, 183 | { 184 | "cell_type": "code", 185 | "execution_count": 20, 186 | "metadata": {}, 187 | "outputs": [ 188 | { 189 | "data": { 190 | "image/png": "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\n", 191 | "text/plain": [ 192 | "
" 193 | ] 194 | }, 195 | "metadata": { 196 | "needs_background": "light" 197 | }, 198 | "output_type": "display_data" 199 | }, 200 | { 201 | "data": { 202 | "image/png": "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\n", 203 | "text/plain": [ 204 | "
" 205 | ] 206 | }, 207 | "metadata": { 208 | "needs_background": "light" 209 | }, 210 | "output_type": "display_data" 211 | }, 212 | { 213 | "data": { 214 | "image/png": "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\n", 215 | "text/plain": [ 216 | "
" 217 | ] 218 | }, 219 | "metadata": { 220 | "needs_background": "light" 221 | }, 222 | "output_type": "display_data" 223 | }, 224 | { 225 | "data": { 226 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXEAAAD8CAYAAACB3pQWAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvOIA7rQAAEyBJREFUeJzt3X+snFed3/H3p3Z+UKA4IT/k2m4dFrdLtiomcoNRVhUb2F0nXa2zElRBq2IhS95KQQpa1N1kK3UXqZWK1MUUtY3q3WQxFSWkATZWxC6bOkHb/kGCDSbYMdlcSorv2o27yg+gSGmdfPvHnAsTe+w7vj88c3zfL2k0z3OeM3PP8cx87rlnnscnVYUkqU9/bdINkCQtnCEuSR0zxCWpY4a4JHXMEJekjhniktSxZQvxJNuSPJ1kJsldy/VzJGkly3KcJ55kFfAXwC8Cs8DXgQ9U1VNL/sMkaQVbrpH4jcBMVf2Pqvq/wP3A9mX6WZK0Yq1epuddBxwb2p8F3nm2ykm8bFSSXuuvqurq+SotV4hnRNlrgjrJLmDXMv18Serd/xyn0nKF+CywYWh/PXB8uEJV7QH2gCNxSVqo5ZoT/zqwKcl1SS4Fbgf2LdPPkqQVa1lG4lV1KsmHga8Aq4D7qurIcvwsSVrJluUUw/NuhNMpknS6g1W1Zb5KXrEpSR0zxCWpY4a4JHXMEJekjhniktQxQ1ySOmaIS1LHDHFJ6pghLkkdM8QlqWOGuCR1zBCXpI4Z4pLUMUNckjpmiEtSxwxxSeqYIS5JHVvU8mxJngV+CLwCnKqqLUmuBD4PbASeBf5xVb2wuGZKkkZZipH4L1TV5qFlhO4C9lfVJmB/25ckLYPlmE7ZDuxt23uB25bhZ0iSWHyIF/BnSQ4m2dXKrq2qEwDt/ppRD0yyK8mBJAcW2QZJWrEWNScO3FRVx5NcAzyS5DvjPrCq9gB7wNXuJWmhFjUSr6rj7f4k8CXgRuC5JGsB2v3JxTZSkjTagkM8yeuTvHFuG/gl4DCwD9jRqu0AHlpsIyVJoy1mOuVa4EtJ5p7nP1fVnyb5OvBAkp3A94H3L76ZkqRRUjX56WjnxCXpDAeHTt0+K6/YlKSOGeKS1DFDXJI6ZohLUscMcUnqmCEuSR0zxCWpY4a4JHXMEJekjhniktQxQ1ySOmaIS1LHDHFJ6pghLkkdM8QlqWOGuCR1bN4QT3JfkpNJDg+VXZnkkSTPtPsrWnmSfCrJTJInk9ywnI2XpJVunJH4p4Ftp5XdBeyvqk3A/rYPcAuwqd12AfcsTTMlSaPMG+JV9efA86cVbwf2tu29wG1D5Z+pga8Ba9qK95KkZbDQOfFrq+oEQLu/ppWvA44N1ZttZZKkZbCY1e5HyYiykYsgJ9nFYMpFkrRACx2JPzc3TdLuT7byWWDDUL31wPFRT1BVe6pqyzirOUuSRltoiO8DdrTtHcBDQ+UfbGepbAVempt2kSQtvXmnU5J8Dng3cFWSWeB3gX8NPJBkJ/B94P2t+peBW4EZ4MfAh5ahzZKkJlUjp6wvbCOSyTdCkqbLwXGmm71iU5I6ZohLUscMcUnqmCEuSR0zxCWpY4a4JHXMEJekjhniktQxQ1ySOmaIS1LHDHFJ6pghLkkdM8QlqWOGuCR1zBCXpI4Z4pLUMUNckjo2b4gnuS/JySSHh8p+L8lfJjnUbrcOHbs7yUySp5P88nI1XJI03kj808C2EeW7q2pzu30ZIMn1wO3Az7XH/Ickq5aqsZKk15o3xKvqz4Hnx3y+7cD9VfVyVX2PwYLJNy6ifZKkc1jMnPiHkzzZpluuaGXrgGNDdWZb2RmS7EpyIMmBRbRBkla0hYb4PcDPAJuBE8Dvt/KMqDtyJfuq2lNVW8ZZzVmSNNqCQryqnquqV6rqVeAP+OmUySywYajqeuD44pooSTqbBYV4krVDu78GzJ25sg+4PcllSa4DNgFPLK6JkqSzWT1fhSSfA94NXJVkFvhd4N1JNjOYKnkW+A2AqjqS5AHgKeAUcEdVvbI8TZckpWrklPWFbUQy+UZI0nQ5OM53hl6xKUkdM8QlqWOGuCR1zBCXpI4Z4pLUMUNckjpmiEtSxwxxSeqYIS5JHTPEJaljhrgkdcwQl6SOGeKS1DFDXJI6ZohLUscMcUnq2LwhnmRDkseSHE1yJMmdrfzKJI8keabdX9HKk+RTSWaSPJnkhuXuhCStVOOMxE8BH62qtwFbgTuSXA/cBeyvqk3A/rYPcAuDtTU3AbuAe5a81ZIkYIwQr6oTVfWNtv1D4CiwDtgO7G3V9gK3te3twGdq4GvAmtMWVpYkLZHzmhNPshF4B/A4cG1VnYBB0APXtGrrgGNDD5ttZac/164kB5IcOP9mS5JgjNXu5yR5A/AF4CNV9YMkZ606ouyMhZCrag+wpz23CyVL0gKMNRJPcgmDAP9sVX2xFT83N03S7k+28llgw9DD1wPHl6a5kqRh45ydEuBe4GhVfWLo0D5gR9veATw0VP7BdpbKVuCluWkXSdLSStW5ZzKS/Dzw34BvA6+24t9hMC/+APC3gO8D76+q51vo/ztgG/Bj4ENVdc55b6dTJOkMB6tqy3yV5g3xC8EQl6QzjBXiXrEpSR0zxCWpY4a4JHXMEJekjhniktQxQ1ySOmaIS1LHDHFJ6pghLkkdM8QlqWOGuCR1zBCXpI4Z4pLUMUNckjpmiEtSxwxxSeqYIS5JHRtnjc0NSR5LcjTJkSR3tvLfS/KXSQ61261Dj7k7yUySp5P88nJ2QJJWstVj1DkFfLSqvpHkjcDBJI+0Y7ur6t8MV05yPXA78HPA3wT+a5K/U1WvLGXDJUljjMSr6kRVfaNt/xA4Cqw7x0O2A/dX1ctV9T1gBrhxKRorSXqt85oTT7IReAeDle4BPpzkyST3Jbmila0Djg09bJYRoZ9kV5IDSQ6cd6slScB5hHiSNwBfAD5SVT8A7gF+BtgMnAB+f67qiIefsZp9Ve2pqi3jrOYsSRptrBBPcgmDAP9sVX0RoKqeq6pXqupV4A/46ZTJLLBh6OHrgeNL12RJ0pxxzk4JcC9wtKo+MVS+dqjarwGH2/Y+4PYklyW5DtgEPLF0TZYkzRnn7JSbgH8CfDvJoVb2O8AHkmxmMFXyLPAbAFV1JMkDwFMMzmy5wzNTJGl5pOqM6eoL34hk8o2QpOlycJzvDL1iU5I6ZohLUscMcUnqmCEuSR0zxCWpY4a4JHXMEJekjhniktQxQ1ySOmaIS1LHDHFJ6pghLkkdM8QlqWOGuCR1zBCXpI4Z4pLUsXGWZ7s8yRNJvpXkSJKPtfLrkjye5Jkkn09yaSu/rO3PtOMbl7cLkrRyjTMSfxm4uarezmBl+21JtgIfB3ZX1SbgBWBnq78TeKGq3grsbvUkSctg3hCvgR+13UvarYCbgQdb+V7gtra9ve3Tjr+nLbYsSVpiY82JJ1nVFkk+CTwCfBd4sapOtSqzwLq2vQ44BtCOvwS8ecRz7kpyIMmBxXVBklausUK8ql6pqs3AeuBG4G2jqrX7UaPuMxZCrqo9VbVlnIVAJUmjndfZKVX1IvBVYCuwJsnqdmg9cLxtzwIbANrxNwHPL0VjJUmvNc7ZKVcnWdO2Xwe8FzgKPAa8r1XbATzUtve1fdrxR6vqjJG4JGnxVs9fhbXA3iSrGIT+A1X1cJKngPuT/Evgm8C9rf69wH9KMsNgBH77MrRbkgRkGgbJSSbfCEmaLgfH+c7QKzYlqWOGuCR1zBCXpI4Z4pLUMUNckjpmiEtSxwxxSeqYIS5JHTPEJaljhrgkdcwQl6SOGeKS1DFDXJI6ZohLUscMcUnqmCEuSR0bZ3m2y5M8keRbSY4k+Vgr/3SS7yU51G6bW3mSfCrJTJInk9yw3J2QpJVqnOXZXgZurqofJbkE+O9J/qQd+2dV9eBp9W8BNrXbO4F72r0kaYnNOxKvgR+13Uva7VzLqW0HPtMe9zVgTZK1i2+qJOl0Y82JJ1mV5BBwEnikqh5vh/5VmzLZneSyVrYOODb08NlWJklaYmOFeFW9UlWbgfXAjUn+HnA38LPAPwCuBH67Vc+opzi9IMmuJAeSHFhQyyVJ53d2SlW9CHwV2FZVJ9qUycvAHwE3tmqzwIahh60Hjo94rj1VtWWc1ZwlSaONc3bK1UnWtO3XAe8FvjM3z50kwG3A4faQfcAH21kqW4GXqurEsrRekla4cc5OWQvsTbKKQeg/UFUPJ3k0ydUMpk8OAf+01f8ycCswA/wY+NDSN1uSBJCqc51ocoEakUy+EZI0XQ6OM93sFZsdqyqm4ZewpMkxxDtleEsCQ1ySumaIS1LHxjk7RVPibFMoVcXgTE9JK40j8U7MNwful5zSyuRIvAPjhLMjcWllciR+ETDApZXLEL8IOI0irVyGeAccaUs6G0O8A460JZ2NId4BR+KSzsYQ78S5gtyQl1YuTzHsSJLXXNizFNMso57DXwoXPy8Qu3gY4p0Z/uAt14dwONj9oF9chl9bg/zi4HTKCuUVnivPqNfb90D/DHFJ6tjYIZ5kVZJvJnm47V+X5PEkzyT5fJJLW/llbX+mHd+4PE3XYvhntHRxOJ+R+J3A0aH9jwO7q2oT8AKws5XvBF6oqrcCu1s9dco/t6XpNlaIJ1kP/CPgD9t+gJuBB1uVvQxWvAfY3vZpx98Th31TZ9xw9qWTptu4I/FPAr8FvNr23wy8WFWn2v4ssK5trwOOAbTjL7X6r5FkV5IDSQ4ssO1aIEfXK9OoX8j+ku7fvCGe5FeAk1V1cLh4RNUa49hPC6r2VNWWcVZz1tIa94PrB/ziM/eaJvH1vUiMc574TcCvJrkVuBz4GwxG5muSrG6j7fXA8VZ/FtgAzCZZDbwJeH7JW96haTovd74LhqalnVp6vrYXl3lH4lV1d1Wtr6qNwO3Ao1X168BjwPtatR3AQ217X9unHX+0/Pv9J2E5bf8Up1885AhN6stizhP/beA3k8wwmPO+t5XfC7y5lf8mcNfimtinuYtpRl1UM41BbnALzryic9reqzpTpuFFSjL5Riwxl1RTb5xamzoHx/nO0Cs2l8G4vxin4ReoBOd+Lzoin27+B1hL7Hze7I5wNGnn836dq+v7dro4EpdWKEfXFwdDfIL8EGmSFjKidhQ+fQxxaQUzlPtniC+h850P9wOk3vjX4/QxxJeQl7NrJTDIp4shvsQMaPVkoYFskE+PaTnF8EfA05NuxBK5KslfTboRS+QqwL5MnyXryxQMOnxdzu5vj1NpWkL86YvlfzNMcsC+TB/7Mp3sy+I5nSJJHTPEJalj0xLieybdgCVkX6aTfZlO9mWRpuJ/MZQkLcy0jMQlSQsw8RBPsi3J00lmkkz9AhJJ7ktyMsnhobIrkzyS5Jl2f0UrT5JPtb49meSGybX8TEk2JHksydEkR5Lc2cq760+Sy5M8keRbrS8fa+XXJXm89eXzSS5t5Ze1/Zl2fOMk23+6JKuSfDPJw22/1348m+TbSQ7NLYre4/sLIMmaJA8m+U77zLxrGvoy0RBPsgr498AtwPXAB5JcP8k2jeHTwLbTyu4C9lfVJmA/P13N6BZgU7vtAu65QG0c1yngo1X1NmArcEf79++xPy8DN1fV24HNwLYkW4GPA7tbX14Adrb6O4EXquqtwO5Wb5rcCRwd2u+1HwC/UFWbh06/6/H9BfBvgT+tqp8F3s7g9Zl8X05fRuxC3oB3AV8Z2r8buHuSbRqz3RuBw0P7TwNr2/ZaBue9A/xH4AOj6k3jjcE6qb/Ye3+Avw58A3gng4svVp/+fgO+Aryrba9u9TLptrf2rGcQCDcDDwPpsR+tTc8CV51W1t37i8EC8d87/d92Gvoy6emUdcCxof3ZVtaba6vqBEC7v6aVd9O/9mf4O4DH6bQ/bQriEHASeAT4LvBiVZ1qVYbb+5O+tOMvMVgrdhp8Evgt4NW2/2b67AdAAX+W5GCSXa2sx/fXW4D/DfxRm+b6wySvZwr6MukQH3XN78V0ukwX/UvyBuALwEeq6gfnqjqibGr6U1WvVNVmBiPZG4G3jarW7qeyL0l+BThZVQeHi0dUnep+DLmpqm5gML1wR5J/eI6609yX1cANwD1V9Q7g/3DuReAvWF8mHeKzwIah/fXA8Qm1ZTGeS7IWoN2fbOVT378klzAI8M9W1Rdbcbf9AaiqF4GvMpjnX5Nk7r+XGG7vT/rSjr8JeP7CtnSkm4BfTfIscD+DKZVP0l8/AKiq4+3+JPAlBr9ce3x/zQKzVfV423+QQahPvC+TDvGvA5vaN++XArcD+ybcpoXYB+xo2zsYzC3PlX+wfVO9FXhp7k+vaZAkwL3A0ar6xNCh7vqT5Ooka9r264D3Mvji6THgfa3a6X2Z6+P7gEerTV5OUlXdXVXrq2ojg8/Do1X163TWD4Akr0/yxrlt4JeAw3T4/qqq/wUcS/J3W9F7gKeYhr5MwRcGtwJ/wWD+8p9Puj1jtPdzwAng/zH4bbuTwRzkfuCZdn9lqxsGZ998F/g2sGXS7T+tLz/P4E+8J4FD7XZrj/0B/j7wzdaXw8C/aOVvAZ4AZoD/AlzWyi9v+zPt+Fsm3YcRfXo38HCv/Wht/la7HZn7fPf4/mrt2wwcaO+xPwaumIa+eMWmJHVs0tMpkqRFMMQlqWOGuCR1zBCXpI4Z4pLUMUNckjpmiEtSxwxxSerY/wccQtN80bXsUQAAAABJRU5ErkJggg==\n", 227 | "text/plain": [ 228 | "
" 229 | ] 230 | }, 231 | "metadata": { 232 | "needs_background": "light" 233 | }, 234 | "output_type": "display_data" 235 | }, 236 | { 237 | "data": { 238 | "image/png": "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\n", 239 | "text/plain": [ 240 | "
" 241 | ] 242 | }, 243 | "metadata": { 244 | "needs_background": "light" 245 | }, 246 | "output_type": "display_data" 247 | }, 248 | { 249 | "data": { 250 | "image/png": "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\n", 251 | "text/plain": [ 252 | "
" 253 | ] 254 | }, 255 | "metadata": { 256 | "needs_background": "light" 257 | }, 258 | "output_type": "display_data" 259 | } 260 | ], 261 | "source": [ 262 | "for th in range(100,160,10):\n", 263 | " mask = create_mask_threshold(image, threshold= th)\n", 264 | " plt.imshow(mask, cmap = 'gray')\n", 265 | " plt.show()" 266 | ] 267 | }, 268 | { 269 | "cell_type": "code", 270 | "execution_count": null, 271 | "metadata": {}, 272 | "outputs": [], 273 | "source": [] 274 | } 275 | ], 276 | "metadata": { 277 | "kernelspec": { 278 | "display_name": "Python 3", 279 | "language": "python", 280 | "name": "python3" 281 | }, 282 | "language_info": { 283 | "codemirror_mode": { 284 | "name": "ipython", 285 | "version": 3 286 | }, 287 | "file_extension": ".py", 288 | "mimetype": "text/x-python", 289 | "name": "python", 290 | "nbconvert_exporter": "python", 291 | "pygments_lexer": "ipython3", 292 | "version": "3.6.7" 293 | } 294 | }, 295 | "nbformat": 4, 296 | "nbformat_minor": 2 297 | } 298 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Guillaume Witz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MyData/DL/dl_info.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guiwitz/Python_image_processing/70f67808eb54555688e5d8a4095c3ec0b96f4eeb/MyData/DL/dl_info.txt -------------------------------------------------------------------------------- /MyData/your_data.txt: -------------------------------------------------------------------------------- 1 | This is the place where you can save images and data. 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Image processing with Python 2 | This project accompanies the course given by the [Science IT Support](http://www.scits.unibe.ch/) unit at Bern University. 3 | 4 | It contains as series of Notebooks exposing how to do mostly basic and some advanced image processing using Python. It uses standard packages ([Numpy](http://www.numpy.org/), [Maplotlib](https://matplotlib.org/)) and for the image processing parts is heavily based on the [scikit-image](https://scikit-image.org/) package. 5 | 6 | Most of the examples datasets are biology microscopy images taken from open repositories and can be downloaded using the [Data_setup_local](https://github.com/guiwitz/Python_image_processing/blob/master/Env_setup/Data_setup_local.ipynb) notebook. 7 | 8 | ## Installation 9 | One can install all necessary packages manually. However we provide some information to facilitate the installation of all parts (for UNIX machines) in the [Instructions_local.md](https://github.com/guiwitz/Python_image_processing/blob/master/Env_setup/Instructions_local.md) guide. 10 | 11 | The course is originally run using a JupyterHub based on [The Littlest JupyterHub](https://tljh.jupyter.org/en/latest/) and installed on a [switchEngine](https://engines.switch.ch). We also give instructions to create such as JupyterHub in the [Instructions_SwitchEngine.md](https://github.com/guiwitz/Python_image_processing/blob/master/Env_setup/Instructions_SwitchEngine.md) guide. 12 | -------------------------------------------------------------------------------- /course_functions.py: -------------------------------------------------------------------------------- 1 | import os, sys 2 | import numpy as np 3 | import skimage.morphology as skm 4 | import skimage.filters as skf 5 | 6 | from skimage.measure import label, regionprops 7 | 8 | from skimage.feature import match_template, peak_local_max 9 | 10 | #Define the path of leading to Data folder 11 | def define_data_path(): 12 | if 'google.colab' in sys.modules: 13 | datapath = '/content/gdrive/My Drive/' 14 | else: 15 | datapath = '../' 16 | 17 | return datapath 18 | 19 | 20 | 21 | def detect_nuclei(image, size = 200, shape = 0.8): 22 | 23 | """Detect nuclei in image using binary operations 24 | 25 | Parameters 26 | ---------- 27 | image : 2D numpy array 28 | image to be segmented 29 | size: number 30 | maximal nucleus size 31 | shape: float 32 | minimal nucleus eccentricity 33 | 34 | Returns 35 | ------- 36 | newimage : 2D numpy array 37 | mask of nuclei 38 | """ 39 | 40 | 41 | #median filter 42 | image_med = skf.rank.median(image,selem=np.ones((2,2))) 43 | #otsu thresholding 44 | image_local_threshold = skf.threshold_local(image_med,block_size=51) 45 | image_local = image > image_local_threshold 46 | #remove tiny features 47 | image_local_eroded = skm.binary_erosion(image_local, selem= skm.disk(1)) 48 | #label image 49 | image_labeled = label(image_local_eroded) 50 | #analyze regions 51 | our_regions = regionprops(image_labeled) 52 | #create a new mask with constraints on the regions to keep 53 | newimage = np.zeros(image.shape) 54 | #fill in using region coordinates 55 | for x in our_regions: 56 | if (x.area>200):# and (x.eccentricity>shape): 57 | newimage[x.coords[:,0],x.coords[:,1]] = 1 58 | 59 | return newimage 60 | 61 | 62 | def create_disk_template(radius): 63 | 64 | """Create a disk image 65 | 66 | Parameters 67 | ---------- 68 | radius : int 69 | radius of disk 70 | 71 | Returns 72 | ------- 73 | template : 2D numpy array 74 | binary image of a disk 75 | """ 76 | 77 | template = np.zeros((2*radius+5,2*radius+5)) 78 | center = [(template.shape[0]-1)/2,(template.shape[1]-1)/2] 79 | Y, X = np.mgrid[0:template.shape[0],0:template.shape[1]] 80 | dist_from_center = np.sqrt((X - center[0])**2 + (Y-center[1])**2) 81 | template[dist_from_center<=radius] = 1 82 | 83 | return template 84 | 85 | 86 | 87 | def detect_nuclei_template(image, template): 88 | 89 | """Detect nuclei in image using template matching 90 | 91 | Parameters 92 | ---------- 93 | image : 2D numpy array 94 | image to be segmented 95 | template: 2D numpy array 96 | template for nucleus shape 97 | 98 | Returns 99 | ------- 100 | masked_peaks : 2D numpy array 101 | mask where each nucleus is represented by a single white pixel 102 | otsu_mask : maks obtained using the Otsu threshold 103 | """ 104 | 105 | matched = match_template(image=image, template=template, pad_input=True) 106 | 107 | local_max = peak_local_max(matched, min_distance=10,indices=False) 108 | 109 | otsu = skf.threshold_otsu(image) 110 | otsu_mask = image>otsu 111 | 112 | otsu_mask = skm.binary_dilation(otsu_mask, np.ones((5,5))) 113 | masked_peaks = local_max*otsu_mask 114 | 115 | return masked_peaks, otsu_mask 116 | -------------------------------------------------------------------------------- /deeplearning.py: -------------------------------------------------------------------------------- 1 | from keras.models import Model 2 | from keras.layers import Input, concatenate, Conv2D, MaxPooling2D, Conv2DTranspose, Reshape, Flatten 3 | from keras.optimizers import Adam 4 | from keras.callbacks import ModelCheckpoint 5 | from keras import backend as K 6 | 7 | import numpy as np 8 | import matplotlib.pyplot as plt 9 | import pandas as pd 10 | 11 | K.set_image_data_format('channels_last') # TF dimension ordering in this code 12 | smooth = 1. 13 | output = None 14 | 15 | 16 | #define the dice coefficient 17 | def dice_coef(y_true, y_pred): 18 | smooth = 1 19 | y_true_f = K.flatten(y_true) 20 | y_pred_f = K.flatten(y_pred) 21 | intersection = K.sum(y_true_f * y_pred_f) 22 | return (2. * intersection + smooth) / (K.sum(y_true_f) + K.sum(y_pred_f) + smooth) 23 | 24 | 25 | #define the deep learning network, here a U-net architecture 26 | def get_unet(dims,img_rows,img_cols): 27 | inputs = Input((img_rows, img_cols, dims)) 28 | conv1 = Conv2D(32, (3, 3), activation='relu', padding='same')(inputs) 29 | conv1 = Conv2D(32, (3, 3), activation='relu', padding='same')(conv1) 30 | pool1 = MaxPooling2D(pool_size=(2, 2))(conv1) 31 | 32 | conv2 = Conv2D(64, (3, 3), activation='relu', padding='same')(pool1) 33 | conv2 = Conv2D(64, (3, 3), activation='relu', padding='same')(conv2) 34 | pool2 = MaxPooling2D(pool_size=(2, 2))(conv2) 35 | 36 | conv3 = Conv2D(128, (3, 3), activation='relu', padding='same')(pool2) 37 | conv3 = Conv2D(128, (3, 3), activation='relu', padding='same')(conv3) 38 | pool3 = MaxPooling2D(pool_size=(2, 2))(conv3) 39 | 40 | conv4 = Conv2D(256, (3, 3), activation='relu', padding='same')(pool3) 41 | conv4 = Conv2D(256, (3, 3), activation='relu', padding='same')(conv4) 42 | pool4 = MaxPooling2D(pool_size=(2, 2))(conv4) 43 | 44 | conv5 = Conv2D(512, (3, 3), activation='relu', padding='same')(pool4) 45 | conv5 = Conv2D(512, (3, 3), activation='relu', padding='same')(conv5) 46 | 47 | up6 = concatenate([Conv2DTranspose(256, (2, 2), strides=(2, 2), padding='same')(conv5), conv4], axis=3) 48 | conv6 = Conv2D(256, (3, 3), activation='relu', padding='same')(up6) 49 | conv6 = Conv2D(256, (3, 3), activation='relu', padding='same')(conv6) 50 | 51 | up7 = concatenate([Conv2DTranspose(128, (2, 2), strides=(2, 2), padding='same')(conv6), conv3], axis=3) 52 | conv7 = Conv2D(128, (3, 3), activation='relu', padding='same')(up7) 53 | conv7 = Conv2D(128, (3, 3), activation='relu', padding='same')(conv7) 54 | 55 | up8 = concatenate([Conv2DTranspose(64, (2, 2), strides=(2, 2), padding='same')(conv7), conv2], axis=3) 56 | conv8 = Conv2D(64, (3, 3), activation='relu', padding='same')(up8) 57 | conv8 = Conv2D(64, (3, 3), activation='relu', padding='same')(conv8) 58 | 59 | up9 = concatenate([Conv2DTranspose(32, (2, 2), strides=(2, 2), padding='same')(conv8), conv1], axis=3) 60 | conv9 = Conv2D(32, (3, 3), activation='relu', padding='same')(up9) 61 | conv9 = Conv2D(32, (3, 3), activation='relu', padding='same')(conv9) 62 | 63 | conv10 = Conv2D(1, (1, 1), activation='sigmoid')(conv9) 64 | 65 | conv11 = Reshape((img_rows*img_cols,1),input_shape=(img_rows,img_cols,1))(conv10) 66 | 67 | model = Model(inputs=[inputs], outputs=[conv11]) 68 | 69 | model.compile(optimizer='adam', loss='binary_crossentropy', metrics=[dice_coef], sample_weight_mode='temporal') 70 | 71 | return model 72 | 73 | 74 | #routine to train the network 75 | def nuclei_train(folder, img_rows,img_cols, dims=1, batch_size = 32, epochs = 100, weights = None): 76 | 77 | imgs_train = np.load(folder+'imgs_train.npy') 78 | imgs_mask_train = np.load(folder+'imgs_mask_train.npy') 79 | imgs_weight_train = np.load(folder+'imgs_weight_train.npy') 80 | 81 | imgs_train = imgs_train.astype('float32') 82 | 83 | imgs_mask_train = imgs_mask_train[..., np.newaxis] 84 | imgs_mask_train = imgs_mask_train.astype('float32') 85 | 86 | imgs_weight_train = imgs_weight_train.astype('float32') 87 | 88 | nuclei_model = get_unet(dims,img_rows,img_cols) 89 | model_checkpoint = ModelCheckpoint(folder+'weights.h5', monitor='val_loss', save_best_only=True) 90 | 91 | if weights: 92 | nuclei_model.load_weights(weights) 93 | 94 | nuclei_model.fit(imgs_train, imgs_mask_train, batch_size=batch_size, epochs=epochs, verbose=1, shuffle=True, 95 | validation_split=0.2,sample_weight = imgs_weight_train, 96 | callbacks=[model_checkpoint]) --------------------------------------------------------------------------------