├── .gitignore ├── LICENSE ├── README.md ├── checkpoints └── .gitignore ├── data └── .gitignore ├── dataset.py ├── evaluation ├── __init__.py ├── compare.ipynb ├── result │ ├── eer_irr.png │ ├── eer_irr_SD.png │ ├── eer_irr_TJ.png │ ├── eer_irr_hd_SD.png │ ├── eer_irr_hd_TJ.png │ ├── hd_SD.png │ ├── heatmap.png │ ├── network.png │ ├── result.pkl │ └── result_tj.pkl ├── test-cx1.ipynb └── test-cx2.ipynb ├── log └── .gitignore ├── model ├── __init__.py ├── loss.py ├── pretrained │ ├── 1203_202301_MobileNetV2_Lite_CX1.pth │ └── 1211_202056_MobileNetV2_Lite_CX2.pth └── quality_model.py ├── test.py ├── train.py └── util ├── IrisQualityEvaluation.cpp ├── IrisQualityEvaluation.h ├── eye_quality_fact.py └── fmeasure.py /.gitignore: -------------------------------------------------------------------------------- 1 | # File created using '.gitignore Generator' for Visual Studio Code: https://bit.ly/vscode-gig 2 | 3 | # Created by https://www.gitignore.io/api/visualstudiocode,linux,jupyternotebooks,python 4 | # Edit at https://www.gitignore.io/?templates=visualstudiocode,linux,jupyternotebooks,python 5 | 6 | ### JupyterNotebooks ### 7 | # gitignore template for Jupyter Notebooks 8 | # website: http://jupyter.org/ 9 | 10 | .ipynb_checkpoints 11 | */.ipynb_checkpoints/* 12 | 13 | # IPython 14 | profile_default/ 15 | ipython_config.py 16 | 17 | # Remove previous ipynb_checkpoints 18 | # git rm -r .ipynb_checkpoints/ 19 | 20 | ### Linux ### 21 | *~ 22 | 23 | # temporary files which can be created if a process still has a handle open of a deleted file 24 | .fuse_hidden* 25 | 26 | # KDE directory preferences 27 | .directory 28 | 29 | # Linux trash folder which might appear on any partition or disk 30 | .Trash-* 31 | 32 | # .nfs files are created when an open file is removed but is still being accessed 33 | .nfs* 34 | 35 | ### Python ### 36 | # Byte-compiled / optimized / DLL files 37 | __pycache__/ 38 | *.py[cod] 39 | *$py.class 40 | 41 | # C extensions 42 | *.so 43 | 44 | # Distribution / packaging 45 | .Python 46 | build/ 47 | develop-eggs/ 48 | dist/ 49 | downloads/ 50 | eggs/ 51 | .eggs/ 52 | lib/ 53 | lib64/ 54 | parts/ 55 | sdist/ 56 | var/ 57 | wheels/ 58 | pip-wheel-metadata/ 59 | share/python-wheels/ 60 | *.egg-info/ 61 | .installed.cfg 62 | *.egg 63 | MANIFEST 64 | 65 | # PyInstaller 66 | # Usually these files are written by a python script from a template 67 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 68 | *.manifest 69 | *.spec 70 | 71 | # Installer logs 72 | pip-log.txt 73 | pip-delete-this-directory.txt 74 | 75 | # Unit test / coverage reports 76 | htmlcov/ 77 | .tox/ 78 | .nox/ 79 | .coverage 80 | .coverage.* 81 | .cache 82 | nosetests.xml 83 | coverage.xml 84 | *.cover 85 | .hypothesis/ 86 | .pytest_cache/ 87 | 88 | # Translations 89 | *.mo 90 | *.pot 91 | 92 | # Scrapy stuff: 93 | .scrapy 94 | 95 | # Sphinx documentation 96 | docs/_build/ 97 | 98 | # PyBuilder 99 | target/ 100 | 101 | # pyenv 102 | .python-version 103 | 104 | # pipenv 105 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 106 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 107 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 108 | # install all needed dependencies. 109 | #Pipfile.lock 110 | 111 | # celery beat schedule file 112 | celerybeat-schedule 113 | 114 | # SageMath parsed files 115 | *.sage.py 116 | 117 | # Spyder project settings 118 | .spyderproject 119 | .spyproject 120 | 121 | # Rope project settings 122 | .ropeproject 123 | 124 | # Mr Developer 125 | .mr.developer.cfg 126 | .project 127 | .pydevproject 128 | 129 | # mkdocs documentation 130 | /site 131 | 132 | # mypy 133 | .mypy_cache/ 134 | .dmypy.json 135 | dmypy.json 136 | 137 | # Pyre type checker 138 | .pyre/ 139 | 140 | ### VisualStudioCode ### 141 | .vscode/* 142 | 143 | ### VisualStudioCode Patch ### 144 | # Ignore all local history of files 145 | .history 146 | 147 | # End of https://www.gitignore.io/api/visualstudiocode,linux,jupyternotebooks,python 148 | 149 | # Custom rules (everything added below won't be overriden by 'Generate .gitignore File' if you use 'Update' option) 150 | feature 151 | .idea/* -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Recognition Oriented Iris Image Quality Assessment in the Feature Space 2 | 3 | ![network](evaluation/result/network.png) 4 | 5 | [Paper](https://arxiv.org/abs/2009.00294) [Dataset](http://www.cripacsir.cn/dataset/casia-iris-degradation/) 6 | 7 | ## Prerequisites 8 | 9 | - pytorch 1.0 10 | - torchvision 0.2 11 | - opencv 3.4 12 | - scipy 13 | - thop 14 | 15 | ## Citing 16 | 17 | If DFSNet is useful for your research, please consider citing: 18 | 19 | ```bibtex 20 | @InProceedings{wang-ijcb2020, 21 | author = {Leyuan, Wang and Kunbo, Zhang and Min, Ren and Yunlong, Wang and Zhenan, Sun}, 22 | title = {Recognition Oriented Iris Image Quality Assessment in the Feature Space}, 23 | booktitle = {International Joint Conference on Biometrics 2020 (IJCB2020)}, 24 | year = {2020}} 25 | } 26 | ``` 27 | -------------------------------------------------------------------------------- /checkpoints/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore -------------------------------------------------------------------------------- /data/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore -------------------------------------------------------------------------------- /dataset.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | import cv2 4 | import numpy as np 5 | import scipy.io as sio 6 | import torch 7 | from PIL import Image 8 | from torch.utils import data 9 | from torchvision.transforms import transforms 10 | 11 | 12 | class BaseDataset(data.Dataset): 13 | def __init__(self, 14 | path, 15 | mode='train', 16 | debug_data=False, 17 | size=(640, 480), 18 | seed=3141): 19 | np.random.seed(seed) 20 | 21 | self.path = path 22 | self.mode = mode 23 | 24 | if self.mode == 'train' or self.mode == 'val': 25 | with open(os.path.join(path, 'train.txt'), 'r') as f: 26 | img_list = [ 27 | tuple(line.strip().split(' ')) for line in f.readlines() 28 | ] 29 | np.random.shuffle(img_list) 30 | if self.mode == 'train': 31 | self.img_list = img_list[:int( 32 | 0.1 * len(img_list) 33 | )] if debug_data else img_list[:int(0.8 * len(img_list))] 34 | else: 35 | self.img_list = img_list[int( 36 | 0.95 * len(img_list) 37 | ):] if debug_data else img_list[int(0.8 * len(img_list)):] 38 | else: 39 | with open(os.path.join(path, 'test.txt'), 'r') as f: 40 | img_list = [ 41 | tuple(line.strip().split(' ')) for line in f.readlines() 42 | ] 43 | self.img_list = img_list[:int(0.1 * len(img_list) 44 | )] if debug_data else img_list 45 | self.all_imglist = img_list 46 | 47 | self.transform = transforms.Compose([ 48 | transforms.Resize(size), 49 | transforms.ToTensor(), 50 | ]) 51 | self.Norm = transforms.Normalize(mean=[0.480], 52 | std=[0.200], 53 | inplace=False) 54 | 55 | def __len__(self): 56 | return len(self.img_list) 57 | 58 | def __getitem__(self, item): 59 | img_name, score = self.img_list[item] 60 | score = torch.tensor(float(score), dtype=torch.float).view((-1)) 61 | 62 | img = Image.open(os.path.join(self.path, 'Image', img_name)) 63 | img = self.transform(img) 64 | return img, score 65 | 66 | 67 | class monoSimDataset(BaseDataset): 68 | def __init__(self, 69 | path, 70 | mode='train', 71 | debug_data=False, 72 | size=(480, 640), 73 | seed=3141, 74 | upsample=False): 75 | super(monoSimDataset, self).__init__(path, mode, debug_data, size, 76 | seed) 77 | 78 | self.sim = sio.loadmat(os.path.join(path, 'sim.mat'))['sim'] 79 | self.sim = (self.sim + 1) / 2 80 | 81 | with open(os.path.join(path, 'gallery.txt'), 'r') as f: 82 | self.gallery_dict = { 83 | x.strip().split(' ')[1]: x.strip().split(' ')[0] 84 | for x in f.readlines() 85 | } 86 | self.index = {x[0]: x[2] for x in self.all_imglist} 87 | 88 | self.transmask = transforms.Compose([ 89 | transforms.Resize((size[0] // 4, size[1] // 4)), 90 | transforms.ToTensor(), 91 | ]) 92 | 93 | def __getitem__(self, item): 94 | img_name, img_label, x = self.img_list[item] 95 | y = self.index[self.gallery_dict[img_label]] 96 | score = self.sim[int(x), int(y)] 97 | score = torch.tensor(float(score), dtype=torch.float).view((-1)) 98 | 99 | img = Image.open(os.path.join(self.path, 'Image', img_name)) 100 | img = self.transform(img) 101 | img = self.Norm(img) 102 | if self.mode != 'test': 103 | mask = Image.open( 104 | os.path.join(self.path, 'Mask', 105 | img_name.split('.')[0] + '.png')) 106 | mask = self.transmask(mask) 107 | else: 108 | mask = torch.ones_like(img) 109 | img = torch.cat((img, img, img)) 110 | ret = (img, mask, score, 111 | img_name) if self.mode == 'test' else (img, mask, score) 112 | return ret 113 | 114 | 115 | if __name__ == '__main__': 116 | data = monoSimDataset(path='data/cx2', debug_data=False) 117 | print(len(data)) 118 | # print(data.label_list) 119 | for x, y, z in data: 120 | print(x.shape, y.shape, z) 121 | -------------------------------------------------------------------------------- /evaluation/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Debatrix/DFSNet/4e9d18ed8fe7f92dd89f3ea968389108d96638cb/evaluation/__init__.py -------------------------------------------------------------------------------- /evaluation/compare.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 44, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import os\n", 10 | "import time\n", 11 | "\n", 12 | "import numpy as np\n", 13 | "import pickle\n", 14 | "import scipy.io as scio\n", 15 | "import torch\n", 16 | "import torchvision.transforms.functional as transforms\n", 17 | "from scipy import stats\n", 18 | "from torch import nn\n", 19 | "from torch.utils.data import DataLoader\n", 20 | "from tqdm import tqdm\n", 21 | "from thop import clever_format\n", 22 | "from thop import profile\n", 23 | "from sklearn import metrics\n", 24 | "from sklearn.preprocessing import normalize\n", 25 | "import matplotlib.pyplot as plt\n", 26 | "import matplotlib.mlab as mlab \n", 27 | "\n", 28 | "from dataset import monoSimDataset\n", 29 | "from model.loss import FocalLoss, CrossEntropy2d\n", 30 | "from model.quality_model import MobileNetV2_Lite_shower, MobileNetV3_wA, MobileNetV3_Lite, MobileNetV2_Lite" 31 | ] 32 | }, 33 | { 34 | "cell_type": "code", 35 | "execution_count": 142, 36 | "metadata": {}, 37 | "outputs": [], 38 | "source": [ 39 | "def cal_DET(sim, labels):\n", 40 | " label_num = len(labels)\n", 41 | " sim = sim[~np.eye(label_num, dtype=np.bool)]\n", 42 | " if labels.max() == 1 and labels.min() == 0 and labels.shape[0] != labels.shape[1]:\n", 43 | " label = np.dot(labels, labels.T)\n", 44 | " else:\n", 45 | " label = np.zeros((label_num, label_num))\n", 46 | " for x in range(label_num):\n", 47 | " for y in range(label_num):\n", 48 | " label[x, y] = labels[x] == labels[y]\n", 49 | " label = label[~np.eye(label_num, dtype=np.bool)].astype(np.bool)\n", 50 | "\n", 51 | " fpr, tpr, thresholds = metrics.roc_curve(label, sim)\n", 52 | " fnr = 1 - tpr\n", 53 | "\n", 54 | " eer = fpr[np.argmin(np.abs(fpr - fnr))]\n", 55 | " roc_auc = metrics.auc(fpr, tpr)\n", 56 | " return eer, fnr, fpr, roc_auc, thresholds" 57 | ] 58 | }, 59 | { 60 | "cell_type": "code", 61 | "execution_count": 67, 62 | "metadata": {}, 63 | "outputs": [], 64 | "source": [ 65 | "tj_dataset_path = 'data/cx2'\n", 66 | "sd_dataset_path = 'data/cx1'\n", 67 | "\n", 68 | "cp_path = cp_path = \"checkpoints/1203_202301_MobileNetV2_Lite/421_1.3395e-03.pth\"\n", 69 | "model_name = 'MobileNetV2_Lite'\n", 70 | "seed = 2248\n", 71 | "device = 'cuda:0'" 72 | ] 73 | }, 74 | { 75 | "cell_type": "code", 76 | "execution_count": 8, 77 | "metadata": {}, 78 | "outputs": [], 79 | "source": [ 80 | "with open(tj_dataset_path + '/test.txt','r') as f:\n", 81 | " tj_p_list = [x.strip().split(' ') for x in f.readlines()]\n", 82 | "tj_index = {x[0]:(x[1],x[2]) for x in tj_p_list}\n", 83 | "tj_sim = (scio.loadmat(tj_dataset_path + '/sim.mat')['sim'] +1)/2\n", 84 | "\n", 85 | "with open(sd_dataset_path + '/test.txt','r') as f:\n", 86 | " sd_p_list = [x.strip().split(' ') for x in f.readlines()]\n", 87 | "sd_index = {x[0]:(x[1],x[2]) for x in sd_p_list}\n", 88 | "sd_sim = (scio.loadmat(sd_dataset_path + '/sim.mat')['sim'] +1)/2" 89 | ] 90 | }, 91 | { 92 | "cell_type": "code", 93 | "execution_count": 16, 94 | "metadata": {}, 95 | "outputs": [ 96 | { 97 | "name": "stdout", 98 | "output_type": "stream", 99 | "text": [ 100 | "TJ All Test EER:28.59% FNMR:100.00%\n", 101 | "SD All Test EER:12.41% FNMR:100.00%\n" 102 | ] 103 | } 104 | ], 105 | "source": [ 106 | "tj_test_sim = np.zeros((len(tj_index), len(tj_index)))\n", 107 | "for tx , d in enumerate(tj_p_list):\n", 108 | " sx = int(d[2])\n", 109 | " for ty, d in enumerate(tj_p_list):\n", 110 | " sy = int(d[2])\n", 111 | " tj_test_sim[tx, ty] = tj_sim[sx,sy]\n", 112 | "tj_test_labels = np.array([int(x[1]) for x in tj_p_list])\n", 113 | "eer, fnr, fpr, roc_auc, thresholds = cal_DET(tj_test_sim, tj_test_labels)\n", 114 | "fnmr = fnr[np.argmin(np.abs(fpr - 1e-5))]\n", 115 | "print('TJ All Test EER:{:.2f}% FNMR:{:.2f}%'.format(eer*100, fnmr*100))\n", 116 | "\n", 117 | "sd_test_sim = np.zeros((len(sd_index), len(sd_index)))\n", 118 | "for tx , d in enumerate(sd_p_list):\n", 119 | " sx = int(d[2])\n", 120 | " for ty, d in enumerate(sd_p_list):\n", 121 | " sy = int(d[2])\n", 122 | " sd_test_sim[tx, ty] = sd_sim[sx,sy]\n", 123 | "sd_test_labels = np.array([int(x[1]) for x in sd_p_list])\n", 124 | "eer, fnr, fpr, roc_auc, thresholds = cal_DET(sd_test_sim, sd_test_labels)\n", 125 | "fnmr = fnr[np.argmin(np.abs(fpr - 1e-5))]\n", 126 | "print('SD All Test EER:{:.2f}% FNMR:{:.2f}%'.format(eer*100, fnmr*100))" 127 | ] 128 | }, 129 | { 130 | "cell_type": "code", 131 | "execution_count": 15, 132 | "metadata": {}, 133 | "outputs": [ 134 | { 135 | "name": "stdout", 136 | "output_type": "stream", 137 | "text": [ 138 | "SD All Test EER:1.28% FNMR:100.00%\n" 139 | ] 140 | } 141 | ], 142 | "source": [ 143 | "with open(sd_dataset_path + '/hq.txt','r') as f:\n", 144 | " sd_hq_set = set([x.split(' ')[0] for x in f.readlines()])\n", 145 | "sd_hq_names = [x[0] for x in sd_p_list if x[0] in sd_hq_set]\n", 146 | "\n", 147 | "sd_test_sim = np.zeros((len(sd_hq_names), len(sd_hq_names)))\n", 148 | "for tx , d in enumerate(sd_hq_names):\n", 149 | " sx = int(sd_index[d][1])\n", 150 | " for ty, d in enumerate(sd_hq_names):\n", 151 | " sy = int(sd_index[d][1])\n", 152 | " sd_test_sim[tx, ty] = sd_sim[sx,sy]\n", 153 | "sd_test_labels = np.array([int(sd_index[x][0]) for x in sd_hq_names])\n", 154 | "eer, fnr, fpr, roc_auc, thresholds = cal_DET(sd_test_sim, sd_test_labels)\n", 155 | "fnmr = fnr[np.argmin(np.abs(fpr - 1e-5))]\n", 156 | "print('SD All Test EER:{:.2f}% FNMR:{:.2f}%'.format(eer*100, fnmr*100))" 157 | ] 158 | }, 159 | { 160 | "cell_type": "code", 161 | "execution_count": 18, 162 | "metadata": {}, 163 | "outputs": [ 164 | { 165 | "name": "stdout", 166 | "output_type": "stream", 167 | "text": [ 168 | "92\n", 169 | "TJ All Test EER:16.46% FNMR:100.00%\n" 170 | ] 171 | } 172 | ], 173 | "source": [ 174 | "tj_hq_names = [x[0] for x in tj_p_list if x[0][8] == '1']\n", 175 | "print(len(tj_hq_names))\n", 176 | "\n", 177 | "tj_test_sim = np.zeros((len(tj_hq_names), len(tj_hq_names)))\n", 178 | "for tx , d in enumerate(tj_hq_names):\n", 179 | " sx = int(tj_index[d][1])\n", 180 | " for ty, d in enumerate(tj_hq_names):\n", 181 | " sy = int(tj_index[d][1])\n", 182 | " tj_test_sim[tx, ty] = tj_sim[sx,sy]\n", 183 | "tj_test_labels = np.array([int(tj_index[x][0]) for x in tj_hq_names])\n", 184 | "eer, fnr, fpr, roc_auc, thresholds = cal_DET(tj_test_sim, tj_test_labels)\n", 185 | "fnmr = fnr[np.argmin(np.abs(fpr - 1e-5))]\n", 186 | "print('TJ All Test EER:{:.2f}% FNMR:{:.2f}%'.format(eer*100, fnmr*100))" 187 | ] 188 | }, 189 | { 190 | "cell_type": "code", 191 | "execution_count": 154, 192 | "metadata": {}, 193 | "outputs": [ 194 | { 195 | "name": "stdout", 196 | "output_type": "stream", 197 | "text": [ 198 | "92\n" 199 | ] 200 | }, 201 | { 202 | "data": { 203 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYIAAAEKCAYAAAAfGVI8AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjEsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy8QZhcZAAAgAElEQVR4nO3dd3hUVfrA8e9JoZtECDUIoYQSIIQqUZp0QQFhlaIgNvAnoq4NVnTXBRQVXRVRBMTFhg0QQXEFVIpIl1ACAhEIBEiAQKgJaef3x0nGSUjP3MxM5v08zzxk7tx7570Q5p1zzznvUVprhBBCeC4vZwcghBDCuSQRCCGEh5NEIIQQHk4SgRBCeDhJBEII4eEkEQghhIfzcXYARRUYGKiDg4OdHYYQQriV7du3n9FaV8/tNbdLBMHBwWzbts3ZYQghhFtRSsXk9ZrcGhJCCA8niUAIITycJAIhhPBwbtdHIERZkpqaSmxsLMnJyc4ORZQRFSpUoG7duvj6+hb6GMsSgVLqQ+A24JTWumUuryvgbaA/cAUYo7X+3ap4hHBFsbGxXHfddQQHB2P+SwhRfFprEhISiI2NpUGDBoU+zspbQwuAfvm8fisQkvkYC8y2MBYhXFJycjLVqlWTJCAcQilFtWrVitzCtCwRaK3XAWfz2WUQ8LE2NgEBSqnaVsUjhKuSJCAcqTi/T87sLA4Cjtk9j83cdg2l1Fil1Dal1LbTp0+XSnBCeAqlFE899ZTt+euvv86LL77okHO///77fPzxx9dsP3LkCC1bXnPHuNCqVKlSkrCKbdWqVbRr145WrVrRrl07fv75Z9trn3/+Oa1atSIsLIx+/fpx5syZa45fs2YN/v7+hIeHEx4ezpQpU2yvvf3227Rs2ZIWLVrw1ltv2bZPnDiRsLAwRo8ebdv2ySef8PbbbzvsupyZCHJLW7mukqO1nqu1bq+1bl+9eq4T44QQxVS+fHmWLFmS6wdXST388MPZPsBcWXp6eoH7BAYGsnz5cnbv3s1HH33EqFGjAEhLS+Pxxx/nl19+YdeuXYSFhTFr1qxcz9GlSxciIyOJjIzkn//8JwB79uxh3rx5bNmyhZ07d/Ldd99x8OBBzp8/z2+//cauXbtIT09n9+7dJCUlsWDBAh555BGHXbszE0EscIPd87rACSfFIoTH8vHxYezYsbz55pvXvBYTE0PPnj0JCwujZ8+eHD16FIAxY8bw2GOPcdNNN9GwYUMWLVqU67lffPFFXn/9dQC2b99O69atiYiI4N1337Xtk56ezjPPPEOHDh0ICwtjzpw5AFy6dImePXvStm1bWrVqxbffflvgtXz66ad07NiR8PBwxo0bZ/twX7lyJREREbRt25Y777yTS5cuAaZSwZQpU+jcuTNff/11gedv06YNderUAaBFixYkJydz9epVtNZorbl8+TJaay5cuGDbrzD27dtHp06dqFSpEj4+PnTr1o1vvvkGLy8vUlJSSE5O5sKFC3h5eTFjxgwee+yxIo0KKogzh48uAx5VSn0B3Aic11qfdGI8QjjXE09AZKRjzxkeDna3GfIyfvx4wsLCePbZZ7Ntf/TRRxk9ejT33nsvH374IY899hhLly4F4OTJk/z666/88ccfDBw4kL/97W/5vsd9993HO++8Q7du3XjmmWds2+fPn4+/vz9bt27l6tWr3HzzzfTp04cbbriBb775Bj8/P86cOUOnTp0YOHBgnvfA9+3bx5dffsmGDRvw9fXlkUce4bPPPqN///5MmzaN1atXU7lyZV599VX+85//2L6NV6hQgV9//RWAGTNm8Nlnn11z7q5duzJz5sxs2xYvXkybNm0oX748ALNnz6ZVq1ZUrlyZkJCQbMnO3saNG2ndujV16tTh9ddfp0WLFrRs2ZLJkyeTkJBAxYoVWbFiBe3bt+e6665j6NChdOzYkYiICAICAti6dastdkexcvjo50B3IFApFQv8C/AF0Fq/D6zADB2Nxgwfvc+qWIQQ+fPz82P06NHMnDmTihUr2rZv3LiRJUuWADBq1KhsiWLw4MF4eXkRGhpKfHx8vuc/f/48iYmJdOvWzXauH374ATDf1nft2mVrVZw/f56DBw9St25dnnvuOdatW4eXlxfHjx8nPj6eWrVq5foeP/30E9u3b6dDhw4AJCUlUaNGDTZt2sTevXu5+eabAUhJSSEiIsJ23LBhw2w/P/PMM9mSVF6ioqKYOHEiK1euBMx8kNmzZ7Njxw4aNmzIhAkTmD59Os8//3y249q2bUtMTAxVqlRhxYoVDB48mIMHD9K8eXMmTpxI7969qVKlCq1bt8bHx3w8P/vss4wbN44rV67wwgsvMGXKFD744ANWrlxJWFjYNe9RHJYlAq31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\n", 204 | "text/plain": [ 205 | "
" 206 | ] 207 | }, 208 | "metadata": { 209 | "needs_background": "light" 210 | }, 211 | "output_type": "display_data" 212 | } 213 | ], 214 | "source": [ 215 | "plt.figure()\n", 216 | "tj_test_sim = np.zeros((len(tj_index), len(tj_index)))\n", 217 | "for tx , d in enumerate(tj_p_list):\n", 218 | " sx = int(d[2])\n", 219 | " for ty, d in enumerate(tj_p_list):\n", 220 | " sy = int(d[2])\n", 221 | " tj_test_sim[tx, ty] = tj_sim[sx,sy]\n", 222 | "tj_test_labels = np.array([int(x[1]) for x in tj_p_list])\n", 223 | "eer1, fnr1, fpr1, roc_auc, thresholds = cal_DET(tj_test_sim, tj_test_labels)\n", 224 | "\n", 225 | "\n", 226 | "tj_hq_names = [x[0] for x in tj_p_list if x[0][8] == '1']\n", 227 | "print(len(tj_hq_names))\n", 228 | "\n", 229 | "tj_test_sim = np.zeros((len(tj_hq_names), len(tj_hq_names)))\n", 230 | "for tx , d in enumerate(tj_hq_names):\n", 231 | " sx = int(tj_index[d][1])\n", 232 | " for ty, d in enumerate(tj_hq_names):\n", 233 | " sy = int(tj_index[d][1])\n", 234 | " tj_test_sim[tx, ty] = tj_sim[sx,sy]\n", 235 | "tj_test_labels = np.array([int(tj_index[x][0]) for x in tj_hq_names])\n", 236 | "eer2, fnr2, fpr2, roc_auc, thresholds = cal_DET(tj_test_sim, tj_test_labels)\n", 237 | "\n", 238 | "plt.plot(fpr1,fnr1,c='r',label='Non-ideal eer={:.2f}%'.format(eer1*100))\n", 239 | "plt.plot(fpr2,fnr2,c='g',label='Ideal eer={:.2f}%'.format(eer2*100))\n", 240 | "# plt.yscale('log')\n", 241 | "plt.xscale('log')\n", 242 | "plt.xlabel('FPR')\n", 243 | "plt.ylabel('FNR')\n", 244 | "plt.legend(loc = 'upper right')\n", 245 | "plt.plot(np.arange(0,1,0.01),np.arange(0,1,0.01),linestyle='-.',c='gray',label='eer')\n", 246 | "plt.show()" 247 | ] 248 | }, 249 | { 250 | "cell_type": "code", 251 | "execution_count": 155, 252 | "metadata": {}, 253 | "outputs": [ 254 | { 255 | "data": { 256 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYIAAAEKCAYAAAAfGVI8AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjEsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy8QZhcZAAAgAElEQVR4nO3dd3xUVRbA8d9JI/QOAqFKkQChJRRpClLEBrKKuCtiw46IYkNXV0DXtvaOiLogKKsICoJgQZAWFJCqSI0EDIEkEAJpd/+4SUhCOjPzZjLnu5/5OPPmlTPZMCf33XvPFWMMSiml/FeA0wEopZRyliYCpZTyc5oIlFLKz2kiUEopP6eJQCml/JwmAqWU8nNBTgdQWnXq1DHNmjVzOgyllPIp69evP2yMqVvQez6XCJo1a0Z0dLTTYSillE8Rkb2Fvae3hpRSys9pIlBKKT+niUAppfycz/URKFWepKWlERMTw8mTJ50ORZUToaGhhIWFERwcXOJj3JYIRGQ6cCnwlzGmfQHvC/AyMBQ4AYwxxvzsrniU8kYxMTFUrVqVZs2aYf9JKFV2xhji4+OJiYmhefPmJT7OnbeGZgBDinj/YqBV1mMs8KYbY1HKK508eZLatWtrElAuISLUrl271C1MtyUCY8xy4EgRu1wBfGis1UANEWngrniU8laaBJQrleX3ycnO4kbA/lyvY7K2nUFExopItIhEx8XFeSQ4pfyFiHDfffflvH7++ed54oknXHLut956iw8//PCM7Xv27KF9+zPuGJdYlSpVziasMouPj+fCCy+kSpUq3HXXXTnbT5w4wSWXXMJ5551Hu3bteOihh4o8z759+6hSpQrPP/98zrYbb7yRevXqnfFzefDBB4mIiGD06NE52z766CNefvllF30qZxNBQWmrwFVyjDHvGGMijTGRdesWODFOKVVGFSpU4LPPPuPw4cMuP/dtt92W5wvMm2VkZBS7T2hoKJMnT87zBZ7t/vvvZ/v27fzyyy+sXLmSRYsWFXqee++9l4svvjjPtjFjxvD111/n2ZaYmMhPP/3Epk2byMjI4NdffyUlJYUZM2Zwxx13lPCTFc/JRBADNM71Ogw44FAsSvmtoKAgxo4dy4svvnjGe3v37mXAgAFEREQwYMAA9u3bB9gvrXHjxnH++efTokUL5s6dW+C5n3jiiZwvzfXr19OxY0d69uzJ66+/nrNPRkYGEydOJCoqioiICN5++20Ajh8/zoABA+jSpQsdOnTgiy++KPaz/Pe//6Vbt2506tSJW2+9NefLfcmSJfTs2ZMuXbpw1VVXcfz4ccBWKnjyySfp3bs3n376abHnr1y5Mr179yY0NDTP9kqVKnHhhRcCEBISQpcuXYiJiSnwHPPmzaNFixa0a9cuz/a+fftSq1atPNsCAgJITU0lLS2N48ePExgYyHPPPce4ceNKNSqoOE4OH50P3CUis4HuQKIxJtbBeJRy1vjxsGGDa8/ZqRO89FKxu915551ERETwwAMP5Nl+1113MXr0aK6//nqmT5/OuHHjmDdvHgCxsbGsWLGC7du3c/nll/O3v/2tyGvccMMNvPrqq/Tr14+JEyfmbH/vvfeoXr0669at49SpU/Tq1YtBgwbRuHFjPv/8c6pVq8bhw4fp0aMHl19+eaH3wLdt28acOXNYuXIlwcHB3HHHHcycOZOhQ4cyZcoUli5dSuXKlXnmmWf4z3/+wz//+U/A/pW/YsUKAJ577jlmzpx5xrn79u3LK6+8UuzPESAhIYEFCxZwzz33nPFecnIyzzzzDN98802BrYr8qlatyogRI+jatSs9e/akWrVqrFu3Lid2V3Hn8NGPgQuAOiISAzwOBAMYY94CFmKHju7EDh+9wV2xKKWKVq1aNUaPHs0rr7xCxYoVc7avWrWKzz77DIDrrrsuT6IYNmwYAQEBhIeHc+jQoSLPn5iYSEJCAv369cs5V/atkyVLlrBp06acVkViYiK///47YWFhPPLIIyxfvpyAgAD+/PNPDh06xDnnnFPgNZYtW8b69euJiooCICUlhXr16rF69Wq2bt1Kr169AEhNTaVnz545x40cOTLn+cSJE/MkqdJKT09n1KhRjBs3jhYtWpzx/uOPP869995bqj6OBx54gPvuu4+MjAxuv/12nnzySaZNm8aSJUuIiIjg0UcfLXO82dyWCIwxo4p53wB3uuv6SvmcEvzl7k7jx4+nS5cu3HBD4X+T5f5rvEKFCjnP7T9nmDRpEl999RUAG3K1bowxhf4lb4zh1VdfZfDgwXm2z5gxg7i4ONavX09wcDDNmjUrclikMYbrr7+ep59+Os/2BQsWMHDgQD7++OMCj6tcuXLO87NtEYwdO5ZWrVoxfvz4At9fs2YNc+fO5YEHHiAhIYGAgABCQ0PzdDwXJDAwkE2bNiEitG7dmnvuuYfly5dzzTXX8Pvvv9OqVatiYyuKlphQSgFQq1Ytrr76at57772cbeeffz6zZ88GYObMmfTu3bvIc0ydOpUNGzbkSQIANWrUoHr16jm3YHJ/2Q4ePJg333yTtLQ0AH777TeSk5NJTEykXr16BAcH891337F3b6HFMwEYMGAAc+fO5a+//gLgyJEj7N27lx49erBy5Up27twJ2BE+v/32W4HnmDhxYk78uR8lSQKPPvooiYmJvFREQv/xxx/Zs2cPe/bsYfz48TzyyCPFJgGwrZtJkybx5JNPkpaWltP3ERAQwIkTJ4o9vjiaCJRSOe677748o4deeeUV3n//fSIiIs56yOL777/PnXfeSc+ePfPcfrr55psJDw+nS5cutG/fnltvvZX09HT+/ve/Ex0dTWRkJDNnzuS8884r8vzh4eFMmTKFQYMGERERwcCBA4mNjaVu3brMmDGDUaNGERERQY8ePdi+fXuZP0ezZs2YMGECM2bMICwsjK1btxITE8PUqVPZunUrXbp0oVOnTkybNg2A+fPnl+ie/qhRo+jZsyc7duwgLCwsT0KeM2cOERERNGzYkBo1atCzZ086dOiAiNCxY8cyf5Zskt2k8xWRkZFG1yNQ5cW2bdto27at02EoLxcbG0ulSpWoXr16ifYv6PdKRNYbYyIL2l9bBEop5cUyMzMxxhAYGOi2a2giUEopL5a7P8BdNBEopZQXy04E2iJQSik/lZmZCWgiUEopv6UtAqWU8nMZGRkEBAS4tVy5JgKl/Fxh5Q7GjBlTaDG54uQuNudpr732Gi1btkRECq2oumHDBnr27Em7du2IiIhgzpw5Oe8tW7YsZy5A7969cyaivfrqq7Rv356hQ4eSmpoKwIoVK5gwYYJbP09GRoZbWwOgiUAp5SPS09NLtF+vXr1YunQpTZs2LXSfSpUq8eGHH7Jlyxa+/vprxo8fT0JCAgC33347M2fOZMOGDVx77bVMmTIFgGnTprFp0yY6d+7M4sWLMcYwefJkHnvssbP/cEWoUaMGNWvWdOs1NBEopQBbq+euu+4iPDycSy65JKdUA9gS0v369aNr164MHjyY2FhbKPjdd98lKiqKjh07MmLEiGLLHcTFxTFixAiioqKIiopi5cqVgK3KeeONNxIVFUXnzp1zSk7PmDGDq666issuu4xBgwaV6HN07tyZZs2aFblP69atc+rzNGzYkHr16pG96JWIkJSUBNgCeA0bNsw5Li0tjRMnThAcHMxHH33E0KFD3f4lHRgYSFCQewtFO1mGWimVy/ivx7PhoGvLUHc6pxMvDSlZMbvPP/+cHTt28Ouvv3Lo0CHCw8O58cYbSUtL4+677+aLL76gbt26zJkzh0mTJjF9+nSuvPJKbrnlFsDW2nnvvfe4++67C73GPffcw7333kvv3r3Zt28fgwcPZtu2bUydOpX+/fszffp0EhIS6NatGxdddBFgK6Bu2rSJWrVqcezYMfr06VPguWfNmkV4eHgpf0Kwdu1aUlNTOffccwH7l//QoUOpWLEi1apVY/Xq1YBdeKZHjx60a9eOXr16MWzYsDMWknG1zMxMjh8/TsWKFV26/kB+mgiUUgAsX76cUaNGERgYSMOGDenfvz8AO3bsYPPmzQwcOBCw96wbNLDLi2/evJlHH32UhIQEjh8/fkYF0fyWLl3K1q1bc14nJSVx7NgxlixZwvz583P6FU6ePJmzCM7AgQNzFmypWrXqGQXtzkZsbCzXXXcdH3zwQc6ErRdffJGFCxfSvXt3nnvuOSZMmMC0adO47rrruO666wD417/+xbhx41i0aBEffvghjRs35oUXXnD5pK+MjAyOHz9OcHCwJgKl/EFJ/3J3p4JGphhjaNeuHatWrTrjvTFjxjBv3jw6duzIjBkz+P7774s8f2ZmJqtWrcpTdC77Gv/73/9o06ZNnu1r1qzJUybalS2CpKQkLrnkEqZMmUKPHj0Ae+tq48aNdO/eHbBrFQwZMiTPcQcOHGDdunU8/vjjdOvWjVWrVjFp0iSWLVuWkyxdJTg4OCfpupP2ESilAFtzf/bs2WRkZBAbG8t3330HQJs2bYiLi8tJBGlpaWzZsgWwX8wNGjQgLS2twDr++Q0aNIjXXnst53X2X/eDBw/m1VdfzVnX4Jdffinw+OwWQUGP0iSB1NRUhg8fzujRo7nqqqtyttesWZPExMScMtXffPPNGcXbHnvsMSZPngzY8tAi4rJy0AUREbcOHQVNBEqpLMOHD6dVq1Z06NCB22+/PWc1sZCQEObOncuDDz5Ix44d6dSpEz/99BMAkydPpnv37gwcOLDYMtFgy1pHR0cTERFBeHg4b731FmC/XNPS0oiIiKB9+/ZnNRLnlVdeISwsjJiYGCIiIrj55psBiI6Oznn+ySefsHz5cmbMmEGnTp3o1KkTGzZsICgoiHfffZcRI0bQsWNHPvroI5577rmcc2cnqM6dOwNw00030aFDB37++eczWg6ucOLECRITE3F3lWgtQ62Ug7QMtSrK0aNHSU1NpX79+qU6TstQK6VUOeGJyWSgiUAppbyWJgKllPJjxhhNBEr5C1/rp1OeUdby02X5fdJEoJSDQkNDiY+P12SgzlCW8tPGGOLj4wkNDS3VtXRCmVIOyh7mmF3nRqlsqampnDhxgiNHjpQqGYSGhhIWFlaqa2kiUMpBwcHBNG/e3OkwlBdauXIlS5cu5aGHHqJChQpuvZbeGlJKKS+UlpZGlSpV3J4EQFsESinllS644IKc2d3upi0CpZTyUu6uMZRNE4FSSnkZYwyzZs1i8+bNHrmeJgKllPIyaWlppKSk5KyN7G7aR6CUUl4mJCSEm266yWPXc2uLQESGiMgOEdkpIg8V8H4TEflORH4RkU0iMtSd8SillDqT2xKBiAQCrwMXA+HAKBHJv3LEo8AnxpjOwDXAG+6KRymlfMXatWt5++23SU9P98j13Nki6AbsNMbsMsakArOBK/LtY4BqWc+rAwfcGI9SSvmEuLg4EhISCAryzN17dyaCRsD+XK9jsrbl9gTwDxGJARYCdxd0IhEZKyLRIhKtU/GVUuVdQkICNWvW9Nj13JkIChoAm7+y1ihghjEmDBgKfCQiZ8RkjHnHGBNpjImsW7euG0JVSinvcfToUWrUqOGx67kzEcQAjXO9DuPMWz83AZ8AGGNWAaFAHTfGpJRSXs0YQ0JCQrlJBOuAViLSXERCsJ3B8/Ptsw8YACAibbGJQO/9KKX81rFjx8jIyCgft4aMMenAXcBiYBt2dNAWEXlSRC7P2u0+4BYR2Qh8DIwxWphdKeXHjh49CuDRRODWLmljzEJsJ3Dubf/M9Xwr0MudMSillC9xIhFoiQmllPIiR48eRUTKTR+BUkqpUqpWrRpt27b1yKL12bTWkFJKeZGuXbvStWtXj15TWwRKKeVFnBgvo4lAKaW8xKlTp3jqqadYv369R6+riUAppbxEZmYmkZGR1KtXz6PX1T4CpZTyEhUrVmTw4MEev662CJRSykukpKSQlpbm8ev6Xotg2zaIjCzbsS1awOzZEKD5Tynlfb755ht+//137rvvPo9e1/cSQXAwnHNO6Y/74w/49FN4/32oXNn1cSml1Fk6cuSIR2cUZ/O9RNCyJXz5ZemPe+45eOABGDMGSrvYQ+3a8OKLNgkppZSbHDlyhBYtWnj8ur6XCMqqe3cID4dNm0p3XFISHDwIIlDYWgjp6XDppVAnXwXtSpXK1npRSvmd1NRUjh07Rq1atTx+bf9JBH37wpYtpT9uzRro1w9ee63o/SZPLnh78+bQvv3p11WqwNVX2+cBAXDBBVCtWoGHKqX8x5EjRwCoXbu2x6/tP4mgrLp3hxMnit5n2TKIjc27LT4eXn4ZqleHmBi77Zdf7H8//vj0fk88AY8/7rJwlVK+KT4+HtBE4L2KG2U0cGDB2++9N+/rkydh+/bTr3v2hClTbP9Faqrtgxgxwl5v4kRo3Ni2IHSUk1LlXnaLQG8NlXehodCp0+nXb74Jmzfb5//9r33/iy9sv8QHH9jtVavCG2+cPiYiwj6UUuVKfHw8VatWJSQkxOPX1kTgpDFjTj9//vnTz2fNsh3U998Px47Bddedfq9JE/jwQ+jSxSYJpVS5EB8fT538A048RO85eKNrr4UJE+DUKfj999OP66+HfftsB/P99zsdpVLKhbp3705UVJQj1xZfWyI4MjLSREdHOx2GM44dg+hoGD3athgCA+HCC6F+fejaFUJCoEIF+2jRwo5GatrUDmNVSvk1EVlvjCmwLIMmAl80axbMmQPz55f8mOHD4corISoK2rRxX2xKqVJLTk7m2LFj1K1b120rk2kiKM+MgeRkexvp1CmIi4OjR+2Q1U2bYOHCgudP9OhhO6Y9XO5WKXWmn3/+mQULFjBu3Di3lZjQRODvjLF9C2vWwDPPwM8/n36vcmU74/qSS+C22+xtJqWURyUlJbF//37atm1LgJuGi2siUHmlpcF//gMbNsD339v+hmy9e9tRSpdeCg0bOhaiUsq1NBGooh0+DE89ZQvr5daoEezZU/oifUqpUtm0aRMNGjSgbmH1zFygqESgw0eVLZb3n/+cvoX073/b7X/+aWc7V64Mc+faUUtKKZdKT09n3rx5bM6eXOoATQQqr8aN4cEH7Zf+Sy/ZbSdOwFVX2eGoTz1lO6SVUi4RHx+PMcatrYHiaCJQBatSBe65BzIzYceO06UxJk2yI41CQmxyWLbM2TiV8nFxWX9YOTWrGDQRqOKIQOvWtnJqairMmAEdOtgO57lz4aKLoFYtuOYaWL3a3l5SSpXY4cOHAWeqjmbTRKBKLjjYlrnYtMl+4X/3nV297ehRO8GtZ09bKbVuXbj4Yvjf/+y+iYmaIJQqRFxcHLVq1SLYwRUQNRGosrvgAjviKDPTlr644w47Ue3wYfj6a/jb36BjR6hRwyaITp3go480KSiVS1xcnKP9A+DmRCAiQ0Rkh4jsFJGHCtnnahHZKiJbRGSWO+NRbiJiax29/jqsWmUTw549dlbza6+drp66caOtkxQQALfcAsuX232V8lMZGRnEx8eX30QgIoHA68DFQDgwSkTC8+3TCngY6GWMaQeMd1c8yoNEbLG7iy+GO++0ZbONsWsvVK5s95k2zS4BGhgIkZF2cZ6TJ52NWykPi4+PJzMzs/wmAqAbsNMYs8sYkwrMBq7It88twOvGmKMAxpi/3BiPclq7dnD8uE0KGzfCP/5ht69fDw88ABUrwrnn2iSRnu5srEp5QPaIoXoO1/xyZyJoBOzP9Toma1turYHWIrJSRFaLyBA3xqO8SUTE6f6C5GTbv1ClCuzaZW8bBQfDsGHw6ac6kU2VW+eddx533HFHuW4RSAHb8vcSBgGtgAuAUcA0EalxxolExopItIhEx+lkpvKnUiXbv3DsmJ3N/OyzcMUV8NVXcPXVdiLb+efD00/b+khKlROBgYFuLT1dUu5MBDFA41yvw4ADBezzhTEmzRizG9iBTQx5GGPeMcZEGmMinc6cys0aNoSJE2HePDss9auvbFXU48fhkUegc2cIC4Obb4bZs+0+Svmo77//nl27djkdhlsTwTqglYg0F5EQ4Bog/0oq84ALAUSkDvZWkfM/FeUdqlSBoUPhzTftfIQ//oCXX7YjlD78EEaNspPZbr7ZltbWYanKh6Snp7N69Wr2799f/M5u5tbqoyIyFHgJCASmG2OmisiTQLQxZr6ICPACMATIAKYaY2YXdU6tPqoAO8v5889tsby1a+22unVt/8KoUdC+vbPxKVUCxhgyMjII8kCFXy1Drcq3gwdtx/OcOadbBkOH2lnQV1xh13BWys9pGWpVvp1zju1XiI62S3Q++CCsXAkjR0Lz5rZQXu7Fd5TyAqtWrWLRokVOhwFoIlDlTcOGdj2FuDhbFK9NG1s6u1UruP12O+NZKS+wY8cODhzIP37GGZoIVPkUHAwjRtjCeD//DH37wttvQ4sW9rbRokV2nQWlHGCM4dChQ45PJMumiUCVf50722Go27bBfffBihU2GdSrB2PH2hFJSnlQUlISJ0+e5JxzznE6FEATgfInbdrYmkZ//WVnLA8fboehduxok8Wzz0JKitNRKj9wMKvPShOBUk4JDbUlsj/6CPbvt8khI8N2MrdpA6+8AklJTkepyrHsRFC/fn2HI7E0ESj/Vrcu3H+/vT20bBk0amSX6AwLgylTdOaycouDBw9Su3ZtQkJCnA4FKGMiEJE2IvKuq4NRylH9+9v1FFavtp3Ljz1my2n/6192lTWlXCQ2NtZrbgtBMYlARCJEZImIbBaRKSJSX0T+BywDtnomRKU8rHt3+PJLmxD69YMnnoDGjW3LYccOp6NTPi4lJYXExETfSQTAu8AsYAQQB/yMrQXU0hjzoptjU8pZ3bvDggV2lNFFF9lyFuedZ9dR2LvX6eiUj0pOTqZRo0aEhYU5HUqOIktMiMgGY0ynXK/3A82MMRmeCK4gWmJCOebAAduR/OKLkJZmO5yfegpatnQ6MqWKdTYlJkJFpLOIdBGRLsBxICLXa6X8R/as5d9/h/Hj7dyE1q3hhhu0haBKzBvruxXXIvieMxeTyWaMMf3dEVRRtEWgvEZMjB16+vbbkJlp10146CGbMJQqxJtvvknr1q0ZMGCAR69b5haBMeYCY8yFhTw8ngSU8iphYXZ9hN9+g+uugzfesEXuRo+GzZudjk55IWMMLVq08JrSEtmKaxH0LeJYY4z50fUhFU1bBMpr7dwJL70E779v6xiNGWM7mGvWdDoypcq+HoGILChgswE6AmHGGI8vtKmJQHm9+Hi7vvILL9gV1B5/HG69VddFUCQnJxMaGurIGsVnc2vostwP4BkgGIgFhrk+VKXKgdq14fnn7foIERF2pnLLlnamsk5M82sLFizgnXfecTqMM5RoZrGIDMjqOJ4M/McY08MYU1BrQSmVrWtX+PZbWLwY2ra1M5WbN7fF7U6edDo65WHGGGJiYmjQoIHToZyhuJnFl4jIT8D9wKSsTuJvPBOaUuWACAwaBEuW2LWVIyNtcbumTe18hAzHpuQoD0tKSiI5OZmGXjiqrLgWwQIgDEgHHhSR+bkf7g9PqXIkKsomhKVLoX17mDABunSxay1nZjodnXKzmJgYAK+aUZwtqJj3L/RIFEr5kwEDbIG7jz+GJ5+Ea66xncvPPgsDB9pWhCp3YmJiCAoK8prS07kV1yLYbYz5obCHRyJUqjwSgWuvha1bYeZMOHwYBg+2i+XousrlUkxMDA0bNnRkxFBxiksE87KfZFUdVUq5UkCATQg7d9q6RV9/Da1a2SU1Dx1yOjrlIunp6cTGxtKoUSOnQylQcYkgdxu1hTsDUcqvhYbCww/bhPD3v9uJaW3a2GGounymz4uNjSUjI4MmTZo4HUqBiksEppDnSil3CAuDGTNsiYqoKJg40XYsL17sdGTqLOzbtw/wzo5iKD4RdBSRJBE5hq06mpT9WkR0UVel3KVtWzvCaMkS258wZAgMHWornyqfEx4ezrBhw6hSpYrToRSouJnFgcaYasaYqsaYoKzn2a+reSpIpfySiB1FtGULPPMM/PijXRjn5pvt2gjKZ9SsWZOOHTs6HUahdPF6pbxdhQrwwAO2yuldd8EHH9j+gzfe0AlpPiApKYmNGzdy0otnk2siUMpXNGhgy15v325nKN95p/3vypVOR6aKsHPnTubNm0dycrLToRRKE4FSvubcc20No9mz7fyD3r3teggJCU5HpgrQqVMnbrvtNmrVquV0KIXSRKCULxKBkSNh2zZ49FE7S7l9e1i2zOnIVD4BAQHUr18f8eIZ425NBCIyRER2iMhOEXmoiP3+JiJGRAqsla2UKkSVKjB5Mvz0E1SqBBddZFdIi493OjIFJCQk8OWXXxLv5f9/uC0RiEgg8DpwMRAOjBKR8AL2qwqMA9a4Kxalyr1u3WDjRnjkEZg1Czp0gC++cDoqv7dr1y7Wr19PppcXFXRni6AbsNMYs8sYkwrMBq4oYL/JwLOA93apK+ULKlaEqVNh3TqoVw+GDYOrroLYWKcj81t79uyhcuXK1KlTx+lQiuTORNAI2J/rdUzWthwi0hlobIz5sqgTichYEYkWkei4uDjXR6pUedK5s137YPJkmD8fwsNh+nQtde1hxhh2795N8+bNvbp/ANybCAr65DllKkQkAHgRuK+4Exlj3jHGRBpjIuvWrevCEJUqp0JCbCfy5s3Qrh3cdJPtP9i1y+nI/Mbhw4c5fvw4zZs3dzqUYrkzEcQAjXO9DgNyT4esCrQHvheRPUAPYL52GCvlQq1awfLl8PbbsH69HVn05ptgtHSYu+3KSrr+ngjWAa1EpLmIhADXADmrmhljEo0xdYwxzYwxzYDVwOXGmGg3xqSU/wkIgLFjbamKPn3gjjts7aK9e52OrFzbtWsXNWvWpGbNmk6HUiy3JQJjTDpwF7AY2AZ8YozZIiJPisjl7rquUqoQYWGwaBG89hqsWAEREfDJJ05HVS5lZGSwZ88eWrTwjer9bp1HYIxZaIxpbYw51xgzNWvbP40xZ6x3bIy5QFsDSrlZQIAtTbF5sy1gN3KkHVm0f3/xx6oSi4mJITU1lXPPPdfpUEpEZxYr5Y+aN7c1iiZPhq++gozNJrMAABYASURBVK5dYeFCp6MqN9LS0mjQoIFP9A8AiPGxTqPIyEgTHa0NB6VcZvt22yrYvBluvdWujhYa6nRUysVEZL0xpsDBONoiUMrfnXeenYR23312dFHfvjY5qDJJS0sjPT3d6TBKRROBUsq2AJ5/Hv73P/jjD+jUCV59VSehlcHmzZt59tlnSfCharCaCJRSp115Jfz6K/TvD+PGwaBBuhpaKdWvX5+oqCiqV6/udCglpolAKZVXw4a2A/mtt2xV006d7NrJqkQaNmzIwIEDvb6sRG6aCJRSZxKxHcfZBewGD7bLZfrYvW9PO3z4MH/++Se+NghHE4FSqnDt2sGaNTYpPPec1isqxurVq/nggw/I8LG1pDURKKWKVrmyvU30wQcQHQ0dO8I772i9onyMMezYsYNWrVoRFBTkdDiloolAKVUyo0fD1q0QFWVbCCNHQkqK01F5jZiYGI4fP855553ndCilpolAKVVyTZrAN9/AU0/B3Ll2zsGePU5H5RW2bdtGYGAgrVq1cjqUUtNEoJQqncBAePhh+Owz2LHD3iqaN8/pqBxljGHr1q20aNGCUB+cla2JQClVNsOGwYYNds2D4cNtcvDTfoMDBw6QmJhIePgZy7L7BE0ESqmya9HCFq8bOxb+/W/4xz8gNdXpqDxu8+bNBAQE+GT/AIBvdW0rpbxPhQp2VFGTJnZ5zP377ToH55zjdGQekZmZyZYtW2jZsqVP3hYCbREopVxBBCZNglmzYO1a22+weLHTUXlEYmIimZmZdOjQwelQykwTgVLKdUaNsnMN6tSBiy+Gxx8HH5tcVVo1a9ZkwoQJtG3b1ulQykwTgVLKtdq3t6UprrsOnnzSzkbevdvpqNwiMzOTzMxMAgICCAwMdDqcMtNEoJRyvUqVYMYMmD7dthAiIuxto3I2qmjr1q28/PLLPlVyuiCaCJRS7iECN9xgVz6LiIC//x2uvRaSk52OzGWqVq1K8+bNfarkdEE0ESil3KtpU/jhB7s+8pw50KMHbNvmdFQu0bRpU4YNG+ZTJacLoolAKeV+QUF2aOmiRXDwoK1X9OmnTkd1Vvbs2UNSUpLTYbiEJgKllOcMHmxnI3foAFdfDXfe6ZO3ijIzM/nss89YsGCB06G4hCYCpZRnNWpkbxVNmABvvGFvFW3e7HRUpfLbb79x7NgxunTp4nQoLqGJQCnleSEh8MIL8PXXcOgQdOvmU7eK1q1bR7Vq1WjTpo3TobiEJgKllHMGD4Zff7Wjiq6+Gm680etvFcXFxbFr1y66du1KQED5+AotH59CKeW76teH5cvhoYfs3IPu3eGPP5yOqlBr1qwhMDCQrl27Oh2Ky2giUEo5LyQEnn7a1if68097q2jpUqejOsOJEyfYuHEjHTp0oHLlyk6H4zKaCJRS3mPgQFue4pxz7G2jf/4T0tKcjirHunXrSE9P5/zzz3c6FJfSRKCU8i4tW8Lq1bZW0eTJ0KcP7NvndFSkpaWxdu1aWrVqRd26dZ0Ox6XcmghEZIiI7BCRnSLyUAHvTxCRrSKySUSWiUhTd8ajlPIRVava/oLZs+3Q0g4dwOEx+6dOnaJFixb07t3b0TjcwW2JQEQCgdeBi4FwYJSI5F/H7Rcg0hgTAcwFnnVXPEopHzRypB1V1LIlXH45TJniWOG6KlWqMGLECJo0aeLI9d3JnS2CbsBOY8wuY0wqMBu4IvcOxpjvjDEnsl6uBsLcGI9Syhc1bw4rVtiCdY89ZoeYnjzp0RB27tzJoUOHPHpNT3JnImgE7M/1OiZrW2FuAha5MR6llK+qWBH++1/beTxjBvTqBTt3euTSxhiWLFnCokXl9+vJnYmgoHJ8BbbpROQfQCTwXCHvjxWRaBGJjouLc2GISimfIQL/+hfMmwd79tj5BkuWeOCywg033MBll13m9ms5xZ2JIAZonOt1GHAg/04ichEwCbjcGHOqoBMZY94xxkQaYyLLW2+9UqqUrrjCrovcsCEMGQLPPOO2foO0tDSMMVSsWJHatWu75RrewJ2JYB3QSkSai0gIcA0wP/cOItIZeBubBP5yYyxKqfLk3HPtENOrrrIzkkeOBDesEvbtt98ybdo0Msr5ustuSwTGmHTgLmAxsA34xBizRUSeFJHLs3Z7DqgCfCoiG0RkfiGnU0qpvCpXtsNL//1v+Oyz02slu0h8fDxr166lfv36Pr0ecUkEufPkxpiFwMJ82/6Z6/lF7ry+UqqcE4EHH4T+/eFvf7OTz955B0aPPutTL168mODgYPr37++CQL2bzixWSvm+qCjbGjj/fLj+epsc0tPLfLrt27fz+++/07dvX6pUqeLCQL2TJgKlVPlQr55dCvPWW+HZZ+Hii+1aB6V06tQpFi1aRL169ejevbsbAvU+mgiUUuVHhQrw1lvw3nu2tHVEhF38phSWLVtGUlISl156abnvG8imiUApVf7ceCOsXw9169qWwaOPQglG/uzZs4d169bRvXt3GjduXOz+5YUmAqVU+ZQ9iuimm2DqVLjoIjh8uNDdU1NT+eKLL6hZs6ZfdBDnpolAKVV+VawI774L06fDqlX2VlEhC94EBwfTp08fhg8fTkhIiIcDdZYmAqVU+SYCN9xgJ6BVrQqDBsHzz+eZjZyWloaI0KVLF7+6JZRNE4FSyj906gQ//wwjRsDEiXD77ZCSwqFDh3jppZf4w4vXSXY3TQRKKf9RuTLMmWMTwdtvQ69eVI6Lo0mTJtSvX9/p6ByjiUAp5V8CAuDZZ8n44gsyd++mSs+ejExN9YuJY4XRRKCU8jvGGBZkZjLr2WfJ6NrVlqS45RaPL3jjLTQRKKX8zrfffsvGjRtp3Lo1gd98YyuYTptmaxbt2uV0eB6niUAp5Vd+/PFHVqxYQdeuXenbty8EB8PTT8Mnn9j1kTt0gDffhMxMp0P1GE0ESim/sXLlSr799lsiIiIYOnQoIrkWUrzqKti2zRauu+MOuOQSOHjQuWA9SBOBUqrcM8bw7bffsnTpUtq3b88VV1xBQEABX39hYXb5y9dfh+++s7OTP/vM8wF7mCYCpVS5lpmZycKFC/nxxx/p3Lkzw4cPLzgJZBOxLYJffoHmze28gxtvhKQkzwXtYZoIlFLl2o8//kh0dDS9evXisssuKzoJ5Na2LaxYAQ8/DB98cLp14Kb1kZ2kiUApVS6ZrC/s7t27c+WVV3LRRRfl7RMoiQoV4KmnbEKoWdO2DoYPh7g4N0TsHE0ESqly59dff2XGjBmkp6cTGhpKhw4dzu6EPXtCdLRd8GbhQjuy6PPPy03rQBOBUqrcCQkJISAggNTUVNedNDjYlqaIjob69eHKK2HIECgHNYo0ESilfJ4xhk2bNrF69WoA2rRpw+jRo6lUqZLrLxYRYZPBiy/aiqYdOsALL5Ro4RtvJcbHmjZVm1c1XR/v6nQYXunaDtcytutYp8NQyqMOHz7M119/zR9//EHTpk25/vrrS98XUFYxMXaE0YIFEBVlC9l17uyZa5eSiKw3xkQW+J4mgvLhh70/ANCvaT9H49BkpDwlKSmJ77//ng0bNhAcHMyAAQOIjIws+aggVzEGZs6Ee++FI0dg0iR47DF7K8mLlKtEEBkZaaKjo50Ow+u8s/4dZv06y9EY3JmMNMGobElJSaxevZp169ZhjCEyMpI+ffpQuXJlZwNLSIB77oEPP4TzzoM33oALL3Q2plw0ESiPcFcyKmuC0eRRvmRmZvL555+zZcsWACIiIrjggguoUaOGw5Hl89VXcPfdsHs3/OMfdjU0L1jrQBOB8mllSTClSR6aMLxXSkoK+/bto02bNgB8/vnnVKpUiW7dulGzZk2HoyvCiRMwdapNAlWrwksvwbXX2rUQHKKJQPmdkiaP0rY2NGm438mTJwkKCiIoKIgffviB77//ngkTJlC1alWnQyu9bdtgzBhYu9Z2Jr/yCvTo4UgomgiUKkRpWhuaNNzDGENcXBx79+5l586d/PHHH4wYMYK2bdty7Ngxjh07RoMGDTw3EsjVMjLgv/+FBx+EQ4dg0CD41788nhA0ESjlAu5MGsUpT0klIyODgwcPsnfvXvbt28e+fftISUkBoFq1aoSHh9O1a1fq1KnjcKQuduyY7UB+4QVbouKKK+zto3btPHJ5TQRKeZgrO87dNRrLU8ll3759BAQEEBYWRmpqKi+88ELOjN9atWrRpEkTmjZtStOmTalRo4bv/uVfUseOwcsv23IVx47Z+kUPPwxd3TssXhOBUj7MHaOxXJFcru1wLTd3vpnExESOHDnCkSNHOHr0KEeOHCE0NJRhw4YB8Oabb1KjRg1GjRoFwPLly6lTpw5NmjTx6wXjOXzY9hm89JJNCP36wW232ZZCxYouv5xjiUBEhgAvA4HANGPMv/O9XwH4EOgKxAMjjTF7ijpnx44dzcaNGzl48CDr1q0rNoaoqCjOOeecnP379OlDjRo12Lt3L5s2bSr2+Pz7Dxw4kNDQUHbs2MFvv/1W7PH597/ssssA2LhxI/v27Sv2+Nz7Hzp0iEGDBgGwZs0aDh06VOSxoaGhefY/efIk/frZf/g//PADiYmJRR5fvXr1PPuHhobSvXt3AJYsWcLJYhb6rl+/fp7969evT8eOHQGYP39+kccCNG3aNM/+bdq0oU2bNpw8eZIlS5YUe3z+/Tt27EjTpk1JSEhg+fLlxR6ff/9u3brl/C6tXbu22OPz79+3b19q1KjBnj17SvS7l3//QYMG5fwu7dixo9jj8+9/+eWXA/Z3afH6xfxxtOgaOTtq22vUP16fKqlV+KOW3b9RUiM4CrWy/heQq1JNhmSQEpRCUoWknOMrp1YmPSCdU0Gnirxeebr9VSqJiXZG8htvwN69UL26HXZ65522FLaLFJUIglx2lTMvGgi8DgwEYoB1IjLfGLM11243AUeNMS1F5BrgGWBkUefNzFpHNDk5uURfxOHh4Xn279atGwCJiYklOj7//hdmTRCJj48v0fGF7X/o0KESHZ97/927d+e8jo2NZVcxi2znnmATGxvL8ePHc17v37+fv/76q8jj69Wrl2f/3H+97d69m+Tk5CKPz8y15uvu3bvzNPl37txZ5LEAFXP9VbRz586ce8bp6eklOj7//s2aNQPg1KlTJTo+//7tsu7lJicnl+j4/PtnJ8WkpKQSHZ9///79+wNw5MiREh1f2P5//fUXQQlBtJE2RR7/9pi3Afjmm2/YvXs37415D4B58+axJWMLB9IPsD9oPylBKaQEp3Ai6ASpgamQ785OckjRvydgWyg/7P3B5S0fn0gu1avDAw/A/ffDt9/C++/Du+/aVdIuvBCuvto+atVyWwhuaxGISE/gCWPM4KzXDwMYY57Otc/irH1WiUgQcBCoa4oISm8NKVX+eOvtL8ekpcGBA3aUUUqKXTWtVi06tenHS7f8r0yndKRFADQC9ud6HQN0L2wfY0y6iCQCtYHDuXcSkbHAWIAmTZq4K16llEPGdh3r8r/cvaHsSpkFB0PTpvZx/DgcjIUjRyHlhFsu585EUFDXf/6/9EuyD8aYd4B3wLYIzj40pVR5547kUl65c75zDNA41+sw4EBh+2TdGqoOHHFjTEoppfJxZyJYB7QSkeYiEgJcA+QfKjIfuD7r+d+Ab4vqH1BKKeV6brs1lHXP/y5gMXb46HRjzBYReRKINsbMB94DPhKRndiWwDXuikcppVTB3NlHgDFmIbAw37Z/5np+ErjKnTEopZQqmq5ZrJRSfk4TgVJK+TlNBEop5ec0ESillJ/zueqjIhIH7C3grepAUVXUCns///aiXhf0PPu/dcg3I7qEiou7qH18NfaSbHM69pL+zAvaVlS8ubd5W+yFfQ5fi7245/4aew1jTN0C3zXGlIsH8E5Z3s+/vajXBT3P9d9od8RdHmMvyTanYy/pz7yksReyzatiL+xz+FrsJfjd0djzPcrTraEFZXw///aiXhf0vLjrFqckx5e32EuyzenYS/ozL2hbcfF6a+yFfQ5fi70kz8ui3Mbuc7eGvJWIRJtCKvt5O43dGRq7MzT2M5WnFoHT3nE6gLOgsTtDY3eGxp6PtgiUUsrPaYtAKaX8nCYCpZTyc5oIlFLKz2ki8AARCRCRqSLyqohcX/wR3kNELhCRH0XkLRG5wOl4SktEKovIehG51OlYSkNE2mb9zOeKyO1Ox1MaIjJMRN4VkS9EZJDT8ZSGiLQQkfdEZK7TsRQn63f7g6yf9d/P5lyaCIohItNF5C8R2Zxv+xAR2SEiO0XkoWJOcwV2feY07KpsHuGi2A1wHAjF92IHeBD4xD1RFswVsRtjthljbgOuBjw21NFFsc8zxtwCjAFGujHcPFwU+y5jzE3ujbRwpfwMVwJzs37Wl5/VhcsyS82fHkBfoAuwOde2QOAPoAUQAmwEwoEOwJf5HvWAh4Bbs46d62OxB2QdVx+Y6WOxX4Rd7GgMcKkvxZ51zOXAT8C1vhZ71nEvAF18NHaP/Ts9i8/wMNApa59ZZ3Ndty5MUx4YY5aLSLN8m7sBO40xuwBEZDZwhTHmaeCMWxAiEgOkZr3McF+0ebki9lyOAhXcEWdBXPRzvxCojP1HkyIiC40xmW4NHNf93I1dxW++iHwFzHJfxHmu6YqfuwD/BhYZY352b8Snufj33RGl+QzYFnoYsIGzvLujiaBsGgH7c72OAboXsf9nwKsi0gdY7s7ASqBUsYvIlcBgoAbwmntDK1apYjfGTAIQkTHAYU8kgSKU9ud+AbbpX4F8q/w5oLS/73djW2PVRaSlMeYtdwZXjNL+3GsDU4HOIvJwVsJwWmGf4RXgNRG5hLMsQaGJoGykgG2FzswzxpwAHLvvmE9pY/8Mm8i8Qaliz9nBmBmuD6XUSvtz/x743l3BlFJpY38F+yXlDUobezxwm/vCKZMCP4MxJhm4wRUX0M7isokBGud6HQYccCiW0tLYnaGxO8OXY8/m9s+giaBs1gGtRKS5iIRgOyTnOxxTSWnsztDYneHLsWdz/2dwomfclx7Ax0Asp4d+3pS1fSjwG7Y3f5LTcWrs3vPQ2DV2X/sMWnROKaX8nN4aUkopP6eJQCml/JwmAqWU8nOaCJRSys9pIlBKKT+niUAppfycJgKlSkhEMkRkQ65Hs6z1GhJF5BcR2SYij2ftm3v7dhF53un4lSqM1hpSquRSjDGdcm/IqhT5ozHmUhGpDGwQkS+z3s7eXhH4RUQ+N8as9GzIShVPWwRKuYixRcDWA+fm256CLRXcyIm4lCqOJgKlSq5irttCn+d/M6uEcQ9gS77tNYFWOF+CXKkC6a0hpUrujFtDWfqIyC9AJvBvY8yWrPUE+ojIJqBN1vaDHoxVqRLTRKDU2fvRGFPQalfZfQStgRVZfQQbPB2cUsXRW0NKuZkx5jfgaeBBp2NRqiCaCJTyjLeAviLS3OlAlMpPy1ArpZSf0xaBUkr5OU0ESinl5zQRKKWUn9NEoJRSfk4TgVJK+TlNBEop5ec0ESillJ/TRKCUUn7u//wvZ+uxc+1uAAAAAElFTkSuQmCC\n", 257 | "text/plain": [ 258 | "
" 259 | ] 260 | }, 261 | "metadata": { 262 | "needs_background": "light" 263 | }, 264 | "output_type": "display_data" 265 | } 266 | ], 267 | "source": [ 268 | "sd_test_sim = np.zeros((len(sd_index), len(sd_index)))\n", 269 | "for tx , d in enumerate(sd_p_list):\n", 270 | " sx = int(d[2])\n", 271 | " for ty, d in enumerate(sd_p_list):\n", 272 | " sy = int(d[2])\n", 273 | " sd_test_sim[tx, ty] = sd_sim[sx,sy]\n", 274 | "sd_test_labels = np.array([int(x[1]) for x in sd_p_list])\n", 275 | "eer1, fnr1, fpr1, roc_auc, thresholds = cal_DET(sd_test_sim, sd_test_labels)\n", 276 | "\n", 277 | "sd_test_sim = np.zeros((len(sd_hq_names), len(sd_hq_names)))\n", 278 | "for tx , d in enumerate(sd_hq_names):\n", 279 | " sx = int(sd_index[d][1])\n", 280 | " for ty, d in enumerate(sd_hq_names):\n", 281 | " sy = int(sd_index[d][1])\n", 282 | " sd_test_sim[tx, ty] = sd_sim[sx,sy]\n", 283 | "sd_test_labels = np.array([int(sd_index[x][0]) for x in sd_hq_names])\n", 284 | "eer2, fnr2, fpr2, roc_auc, thresholds = cal_DET(sd_test_sim, sd_test_labels)\n", 285 | "\n", 286 | "plt.plot(fpr1,fnr1,c='r',label='Non-ideal eer={:.2f}%'.format(eer1*100))\n", 287 | "plt.plot(fpr2,fnr2,c='g',label='Ideal eer={:.2f}%'.format(eer2*100))\n", 288 | "plt.xscale('log')\n", 289 | "plt.xlabel('FPR')\n", 290 | "plt.ylabel('FNR')\n", 291 | "plt.legend(loc = 'upper right')\n", 292 | "plt.plot(np.arange(0,1,0.01),np.arange(0,1,0.01),linestyle='-.',c='gray',label='eer')\n", 293 | "plt.show()" 294 | ] 295 | }, 296 | { 297 | "cell_type": "code", 298 | "execution_count": 19, 299 | "metadata": {}, 300 | "outputs": [], 301 | "source": [ 302 | "with open('tj_train_quality.txt', 'r') as f:\n", 303 | " qdata = [x.strip() for x in f.readlines()]\n", 304 | "qdict = {x.split(',')[0]:[float(y) for y in x.split(',')[1].split(' ')[1:]] for x in qdata}\n", 305 | "\n", 306 | "qarray = np.zeros((len(qdict),5))\n", 307 | "for idx,n in enumerate(qdict.keys()):\n", 308 | " qarray[idx,:] = np.array(qdict[n])\n", 309 | "\n", 310 | "tj_fm = qarray[:, 0]\n", 311 | "tj_size = qarray[:, 1]\n", 312 | "tj_dilation = qarray[:, 2]\n", 313 | "tj_gls = qarray[:, 3]\n", 314 | "tj_uar = qarray[:, 4]\n", 315 | "\n", 316 | "with open('sd_train_quality.txt', 'r') as f:\n", 317 | " qdata = [x.strip() for x in f.readlines()]\n", 318 | "qdict = {x.split(',')[0]:[float(y) for y in x.split(',')[1].split(' ')[1:]] for x in qdata}\n", 319 | "\n", 320 | "qarray = np.zeros((len(qdict),5))\n", 321 | "for idx,n in enumerate(qdict.keys()):\n", 322 | " qarray[idx,:] = np.array(qdict[n])\n", 323 | "\n", 324 | "sd_fm = qarray[:, 0]\n", 325 | "sd_size = qarray[:, 1]\n", 326 | "sd_dilation = qarray[:, 2]\n", 327 | "sd_gls = qarray[:, 3]\n", 328 | "sd_uar = qarray[:, 4]" 329 | ] 330 | }, 331 | { 332 | "cell_type": "code", 333 | "execution_count": null, 334 | "metadata": {}, 335 | "outputs": [], 336 | "source": [] 337 | }, 338 | { 339 | "cell_type": "code", 340 | "execution_count": 36, 341 | "metadata": {}, 342 | "outputs": [ 343 | { 344 | "data": { 345 | "text/plain": [ 346 | "" 347 | ] 348 | }, 349 | "execution_count": 36, 350 | "metadata": {}, 351 | "output_type": "execute_result" 352 | }, 353 | { 354 | "data": { 355 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXoAAAELCAYAAADX3k30AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjEsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy8QZhcZAAAgAElEQVR4nO3dfXgV5Z3/8feXJw0giBhYBFKeVVpU2gD156qAKFFQQG1hWSuu7HLZC9xaH7pqW1tobVnRdttCLago7mpRfNikhYJPoKsLFhS3FSwaqUIgGhQFlSAkfH9/zCQ9HE6SOclJTjJ8Xtd1rpyZue+Z73jwe+5zz8x9m7sjIiLx1SrbAYiISONSohcRiTklehGRmFOiFxGJOSV6EZGYa5PtAJKdeOKJ3qdPn2yHISLSorzyyisfuHtuqm3NLtH36dOHDRs2ZDsMEZEWxczerWmbum5ERGJOiV5EJOaU6EVEYk6JXkQk5pToRURiToleRCTmmt3tlSLS9Pbu3UtZWRkHDx7MdiiSQtu2benWrRudOnWqV30lepGj3N69e3n//ffp2bMnOTk5mFm2Q5IE7k55eTk7duwAqFeyV9eNyFGurKyMnj170r59eyX5ZsjMaN++PT179qSsrKxe+1CLXiKbMqGA93duS6tO95PyWFq4spEikkw4ePAgOTk52Q5D6pCTk1PvrjUleons/Z3bWD2zX1p1Ri3Y2kjRSCapJd/8NeQzUteNiEjMKdGLiMScEr2IpNRv0CnkdOjY5K9+g07J2Dm8/vrrmBlr1qwBgu6P+fPnR65/xx13VNdtDGVlZfzwhz/knXfeabRjgProRaQGpTtK6H/j401+3LfvvKzR9r127Vr69u0bufwdd9zBrFmzGDlyZKPEU1ZWxuzZsxk5ciSNOQ+HEr2IHDW++tWvZjuErFDXjYjExq9//Wt69+5Nhw4duPjiiyktLT1se3LXzYsvvsjZZ59Np06d6NSpE2eccQbLli0DgkmQPvzwQ2bPno2ZHdYFdNdddzFs2DA6d+5M9+7dufjiiykuLj7sWCNHjuTyyy/n4YcfZsCAAXTq1IkLL7yQkpISAN555x2GDBkCwKhRo6qP0RiU6EUkFgoLC5k5cybjx4/niSeeYMiQIVx99dU1lt+7dy/jx4+nX79+PP744zz22GN84xvf4OOPPwbgySefpHPnzkyfPp21a9eydu1avvzlLwNQUlLCrFmzKCws5J577qGyspKzzjqLPXv2HHaMl19+mfnz53PXXXexaNEiXn31VWbMmAFAjx49eOihhwBYsGBB9TEag7puRCQWbr/9dgoKCrj77rsBGDt2LLt27eLee+9NWf7NN99kz549zJ8/n+OOOw6ACy64oHr70KFDadOmDb169Tqiy+fnP/959fvKykrOP/98unXrRmFhIVdeeWX1tr1797J8+XK6dOkCwHvvvce3v/1tysvLycnJ4bTTTgNg8ODBjdqtpBa9iLR4lZWVbNy4kQkTJhy2/tJLL62xTv/+/enYsSNTp06lsLCwuiUfxbp16zj//PPp2rUrbdq0oX379nz66ae8+eabh5UbNmxYdZKHIKED1ePWNJVIid7MCsxsi5kVm9nNKbZfY2Z/NrPXzOxFMxscru9jZuXh+tfM7DeZPgERkV27dlFRUUG3bt0OW5+8nKhLly489dRTHDx4kK9//evk5uYybtw4tm6t/Wnubdu2ccEFF+DuLFy4kJdeeon169fTrVs39u/ff1jZ448//rDldu3aARxRrrHV2XVjZq2BBcD5QAmw3syK3H1zQrGH3f03YflLgJ8BBeG2t939jMyGLSLyN7m5ubRp0+aIQb/qGgTszDPPZOXKlZSXl/PMM89w/fXXM3XqVNatW1djnZUrV7Jv3z4KCwvp0KEDABUVFezevbvhJ9JIovTRDweK3X0rgJktBSYA1Yne3fcmlO8AeCaDlJbr3W3bGTVscFp1NBCapKt169acccYZFBYWcs0111Svf+KJJyLVz8nJ4eKLL+b111/npz/9afX6du3aHdH6Li8vp1WrVrRp87f0+eijj1JRUZF23E3Vwo+S6HsC2xOWS4ARyYXMbCZwPdAOGJ2wqa+ZbQT2At9z9/9JUXcGMAMgLy8vcvDS/NmhgxoITZrErbfeyqWXXso3v/lNJk2axPPPP8/KlTU3GJYvX87ixYuZOHEieXl57Nixg4ULFzJ69N/S1ymnnMLy5cspKCigY8eOnHzyyYwePZrKykr+6Z/+ienTp7Np0ybuvPPOI7pposjLyyMnJ4clS5bQuXNn2rZtS35+fr3OvzZREn2qGzuPaLG7+wJggZlNBb4HTANKgTx3/9DMvgL8t5l9MekXAO6+CFgEkJ+fr18DIs1Aj569GvUp1dqOWx+TJk3iV7/6FXPnzmXJkiWMHDmS++67j7Fjx6YsP2DAAMyMW2+9lbKyMnJzcxk/fjw/+clPqsvMmzePmTNnMm7cOPbt28fq1asZOXIk999/P7Nnz+bJJ5/k9NNPZ9myZUyePDntmI899ljuueceZs+ezbnnnsvBgwdxz3wKtLp2amZnAj9097Hh8i0A7v7TGsq3Aj5y984ptq0BbnT3DTUdLz8/3zdsqHGzZNGoYYPTbp33v+kZ3p43Jr3jLNjK6vWb6y4oGfHGG29w6qmnZjsMiaC2z8rMXnH3lD8Hotx1sx4YaGZ9zawdMAUoSjrAwITFccBb4frc8GIuZtYPGAjod7mISBOqs+vG3SvMbBawCmgNLHb3TWY2B9jg7kXALDMbAxwEPiLotgE4B5hjZhVAJXCNuzffS9MiIjEU6clYd18BrEhad1vC+2/VUO9xoOmHvxMRkWp6MlZEJOaU6EVEYk6JXkQk5pToRURiToleRCTmlOhFRGJOiV5EYu+BBx7AzPj000+zHUpWaIYpEUlpyoQC3t+5rcmPq9FLM0+JXkRSen/ntrTHNsoEjV6aeeq6EZHYeOGFFxg1ahQdO3akc+fOjBw5ko0bN6Ys+8EHHzBt2jS6du1K+/btGTlyJMkDKhYVFfGVr3yFDh060KVLF0aMGMHzzz9fvf3QoUPMnTuXAQMGcMwxxzBo0CCWLFnSqOdYH0r0IhILa9as4bzzzqNt27YsWbKERx55hLPPPrvG+VknTpzIqlWruPPOO3nkkUc4dOgQo0aNori4GIC3336byy+/nNGjR/O73/2Ohx56iPHjxx82k9S1117Lj3/8Y2bMmMHy5cuZNGkSV199Nb///e+b5JyjUteNiMTCLbfcwumnn86qVaswC6bRKCgIZjR94IEHDiu7cuVKXnrpJdasWcO5554LwOjRo+nTpw/z5s1j4cKFbNy4keOOO4558+ZV17vooouq3xcXF3P33Xdz//33M21aMI7jmDFjKC0tZfbs2YwfP74xTzctatGLSIv32Wef8fLLLzNt2rTqJF+bP/7xj+Tm5lYneYAOHTowfvx4XnzxRQCGDBnCnj17mDZtGk899RSfffbZYft49tlnadWqFZMmTaKioqL6dd555/Haa69RWVmZ2ZNsACV6EWnxPvroI9ydHj16RCpfWlpK9+7dj1jfvXv36q6Zk08+mcLCQrZu3cpFF13EiSeeyNSpU9m1axcQ9PFXVlZWTwFY9brqqquoqKigtLQ0cyfYQOq6EZEWr0uXLrRq1Spycu3RowdlZWVHrH///fc54YQTqpfHjRvHuHHj2LNnD8uXL+e6667j2muvZenSpZxwwgm0adOGl156iVatjmwzd+vWrf4nlGFq0YtIi9ehQwdGjBjBgw8+GGnO1REjRlBWVsYLL7xQvW7fvn0sX76cv//7vz+ifOfOnZk6dSqTJk1i8+ZgmsuqScL37NlDfn7+Ea927dpl7gQbSC16EYmFuXPnMmbMGC688EJmzJhBhw4dWLt2Lfn5R06jOnbsWM466ywmT57M3Llz6dq1K3feeSfl5eXcdNNNACxcuJC1a9dSUFDASSedxFtvvcWyZcu48sorgaBr55prrmHKlCl85zvfIT8/n/3797Np0ybefPNN7r333iY9/9oo0YtISt1PysvKw0vdT8qrV71zzjmHp59+mu9///tcccUVtGvXjqFDhzJx4kQ++OCDI8o/+eST3HDDDVx33XXs37+f4cOH89xzzzFgwAAATjvtNIqKirj++uvZvXs3PXr04F/+5V+YM2dO9T4WLFjAoEGDuOeee7jtttvo1KkTgwcPZvr06fU7+UZiUX7mNKX8/HxPfmhBmodRwwan/aRk/5ue4e15Y9I7zoKtrF6/Oa06Un9vvPEGp556arbDkAhq+6zM7BV3P/LnCxH76M2swMy2mFmxmd2cYvs1ZvZnM3vNzF40s8EJ224J620xs7ERz0dERDKkzkRvZq2BBcCFwGDgHxITeehhdx/i7mcAdwA/C+sOBqYAXwQKgF+H+xMRkSYSpUU/HCh2963ufgBYCkxILODuexMWOwBV/UETgKXu/rm7/xUoDvcnIiJNJMrF2J7A9oTlEmBEciEzmwlcD7QDRifUXZdUt2eKujOAGQB5efW7ECMiIqlFadGnep74iCu47r7A3fsD/wZ8L826i9w9393zc3NzI4QkIpnU3G7KkCM15DOKkuhLgN4Jy72AnbWUXwpMrGddEWlibdu2pby8PNthSB3Ky8tp27ZtvepG6bpZDww0s77ADoKLq1MTC5jZQHd/K1wcB1S9LwIeNrOfAScBA4E/1itSyZj6zhy0o2Q70PQTUUjj6tatGzt27KBnz57k5OREGhRMmo67U15ezo4dO1KOzxNFnYne3SvMbBawCmgNLHb3TWY2B9jg7kXALDMbAxwEPgKmhXU3mdmjwGagApjp7s1nSLejVH1nDup/k2b+iaNOnToBsHPnTg4ePJjlaCSVtm3b0r179+rPKl2Rnox19xXAiqR1tyW8/1YtdW8Hbq9XdCLSJDp16lTvJCLNnwY1ExGJOSV6EZGY06Bm0uy8u207o4YlP3xdu+4n5bG0cGUjRSTSsinRS7Njhw6mfbE4G6MsirQU6roREYk5JXoRkZhTohcRiTklehGRmFOiFxGJOSV6EZGYU6IXEYk5JXoRkZhTohcRiTklehGRmFOiFxGJOSV6EZGYU6IXEYk5JXoRkZiLlOjNrMDMtphZsZndnGL79Wa22cz+ZGbPmtkXErZVmtlr4asok8GLiEjd6hyP3sxaAwuA84ESYL2ZFbn75oRiG4F8d99nZt8E7gAmh9vK3f2MDMctIiIRRWnRDweK3X2rux8AlgITEgu4+2p33xcurgN6ZTZMERGpryiJviewPWG5JFxXk+nAHxKWjzWzDWa2zswmpqpgZjPCMht27doVISQREYkqylSClmKdpyxodgWQD5ybsDrP3XeaWT/gOTP7s7u/fdjO3BcBiwDy8/NT7ltEROonSou+BOidsNwL2JlcyMzGAN8FLnH3z6vWu/vO8O9WYA0wtAHxiohImqIk+vXAQDPra2btgCnAYXfPmNlQYCFBki9LWN/FzI4J358InAUkXsQVEZFGVmfXjbtXmNksYBXQGljs7pvMbA6wwd2LgHlAR2CZmQFsc/dLgFOBhWZ2iOBLZW7S3ToiItLIovTR4+4rgBVJ625LeD+mhnr/CwxpSIAiItIwejJWRCTmlOhFRGJOiV5EJOaU6EVEYk6JXkQk5pToRURiToleRCTmlOhFRGJOiV5EJOaU6EVEYk6JXkQk5pToRURiToleRCTmlOhFRGJOiV5EJOaU6EVEYk6JXkQk5pToRURiToleRCTmIiV6Myswsy1mVmxmN6fYfr2ZbTazP5nZs2b2hYRt08zsrfA1LZPBi4hI3epM9GbWGlgAXAgMBv7BzAYnFdsI5Lv7acBjwB1h3ROAHwAjgOHAD8ysS+bCFxGRurSJUGY4UOzuWwHMbCkwAdhcVcDdVyeUXwdcEb4fCzzt7rvDuk8DBcBvGx66VOk36BRKd5RELt+l9X6efyEo3+6YYzhzxIjGCk1EmoEoib4nsD1huYSghV6T6cAfaqnbM7mCmc0AZgDk5eVFCEkSle4oof+Nj0cu/8mSGeT0Dj6G8u2vN1ZYItJMROmjtxTrPGVBsyuAfGBeOnXdfZG757t7fm5uboSQREQkqigt+hKgd8JyL2BnciEzGwN8FzjX3T9PqDsyqe6a+gQqjeOQO8+/8EKksgc+P3BYWXX7iLQMURL9emCgmfUFdgBTgKmJBcxsKLAQKHD3soRNq4CfJFyAvQC4pcFRS+a4k5M3JFrZ1hvI6f2l6kV1+4i0DHUmenevMLNZBEm7NbDY3TeZ2Rxgg7sXEXTVdASWmRnANne/xN13m9mPCL4sAOZUXZgVEZGmEaVFj7uvAFYkrbst4f2YWuouBhbXN0AREWkYPRkrIhJzkVr0Is3du9u2M2pY8nN8det+Uh5LC1c2QkQizYcSvcSCHTrI6pn90q43asHWRohGpHlR142ISMwp0YuIxJwSvYhIzCnRi4jEnBK9iEjM6a6bZiDdYYaTfX7gQAajEZG4UaJvBtIdZjjZptvHZzAaEYkbdd2IiMScEr2ISMyp6yZDGtLP3lL72KOMZZ88hn0VjWUv0nSU6DOkIf3sLbaPPcpY9klj2FfRWPYiTUddNyIiMadELyISc0r0IiIxp0QvIhJzkRK9mRWY2RYzKzazm1NsP8fMXjWzCjO7PGlbpZm9Fr6KMhW4iIhEU+ddN2bWGlgAnA+UAOvNrMjdNycU2wZcBdyYYhfl7n5GBmIVEZF6iHJ75XCg2N23ApjZUmACUJ3o3f2dcNuhRohRREQaIErXTU9ge8JySbguqmPNbIOZrTOziakKmNmMsMyGXbt2pbFrERGpS5REbynWeRrHyHP3fGAq8B9m1v+Inbkvcvd8d8/Pzc1NY9ciIlKXKIm+BOidsNwL2Bn1AO6+M/y7FVgDDE0jPhERaaAoiX49MNDM+ppZO2AKEOnuGTPrYmbHhO9PBM4ioW9fREQaX52J3t0rgFnAKuAN4FF332Rmc8zsEgAzG2ZmJcDXgIVmtimsfiqwwcz+D1gNzE26W0dERBpZpEHN3H0FsCJp3W0J79cTdOkk1/tfoI5Rr0REpDHpyVgRkZhTohcRiTklehGRmFOiFxGJOSV6EZGY01SCkhW1zTdb0zyzVTTfrEh6lOglO2qbb7aGeWaraL5ZkfSo60ZEJObUom/h9jz+Pf4up5JPlsyIXOfQJ7tIbwDS+Hp323ZGDRucVp3uJ+WxtHBlI0UkknlK9C1cq0/LePiy9nT4QvTEfdkvSxsxopbFDh1k9cx+adUZtWBrI0Uj0jjUdSMiEnNK9CIiMadELyISc0r0IiIxp0QvIhJzSvQiIjGnRC8iEnO6j15anFTj5NQ1Pk4ijZUjRxsleml5Uo2TU8f4OIk0Vo4cbSJ13ZhZgZltMbNiM7s5xfZzzOxVM6sws8uTtk0zs7fC17RMBS4iItHUmejNrDWwALgQGAz8g5klDw6yDbgKeDip7gnAD4ARwHDgB2bWpeFhi4hIVFG6boYDxe6+FcDMlgITgM1VBdz9nXDboaS6Y4Gn3X13uP1poAD4bYMjbwT9Bp1C6Y6SetX9/MCBDEcjIpIZURJ9T2B7wnIJQQs9ilR1jxh9y8xmADMA8vLyIu4680p3lND/xsfrVXfT7eMzHI2ISGZE6aO3FOs84v4j1XX3Re6e7+75ubm5EXctIiJRREn0JUDvhOVewM6I+29IXRERyYAoiX49MNDM+ppZO2AKUBRx/6uAC8ysS3gR9oJwnYiINJE6E727VwCzCBL0G8Cj7r7JzOaY2SUAZjbMzEqArwELzWxTWHc38COCL4v1wJyqC7MiItI0Ij0w5e4rgBVJ625LeL+eoFsmVd3FwOIGxCgiIg2gsW5ERGJOiV5EJOaU6EVEYk6DmslRJ3H0y3RGvYRg5EvQsx7SsijRy9EncfTLNEa9BI18KS2TEr1IGg65s2XLm+R06Jh23R49e7H1zb80QlQitVOiF0mHO21P6En/aYvSrvr2nZc1QkAiddPFWBGRmFOiFxGJOXXdiKTpwJ4yPlkyI606hzp2a6RoROqmRC+SpjZUsmzaEdMq1OprS3Y0UjQidVPXjYhIzCnRi4jEnLpuRJrIgYrKet1/D7oHXxpGiV6kiRyqrKD/zf9dr7q6B18aQl03IiIxp0QvIhJzSvQiIjEXqY/ezAqAXwCtgXvdfW7S9mOAB4GvAB8Ck939HTPrQzDP7Jaw6Dp3vyYzoYscPRpyIRd0MfdoV2eiN7PWwALgfKAEWG9mRe6+OaHYdOAjdx9gZlOAfwcmh9vedvczMhy3yFGlIRdyQRdzj3ZRum6GA8XuvtXdDwBLgQlJZSYAS8L3jwHnmZllLkwREamvKIm+J7A9YbkkXJeyjLtXAHuAruG2vma20cyeN7OzUx3AzGaY2QYz27Br1660TkBERGoXJdGnapl7xDKlQJ67DwWuBx42s05HFHRf5O757p6fm6tp2kREMilKoi8Beics9wJ21lTGzNoAnYHd7v65u38I4O6vAG8DgxoatIiIRBcl0a8HBppZXzNrB0wBipLKFAHTwveXA8+5u5tZbngxFzPrBwwEtmYmdBERiaLOu27cvcLMZgGrCG6vXOzum8xsDrDB3YuA+4D/NLNiYDfBlwHAOcAcM6sAKoFr3H13Y5yIiNRM4+wc3SLdR+/uK4AVSetuS3i/H/hainqPA483MEaRFu/AnjL+LqcyrQlLDnXsRufLfpyR42ucnaObBjUTaQJtqOTBy9rT4QvRJyzRZCWSKRoCQUQk5tSiF5FaqX+/5VOiF5FaqX+/5VPXjYhIzKlF34zsefx7tPq0LK06hz7Zhb6vRaQ2SvTNSKtPy1g2LfpdGQCX/bIUaNc4AYlILKgpKCISc2rRizRTB/aUVT9glc7DVpl80KqhdMdO86BEL9JMtaGyuivvs3c/jPywVXN60Ep37DQPsUv0/QadQumOknrV/fzAgQxHIyL1pV8DmRO7RF+6o4T+N9ZveJ1Nt4/PcDQiUl/6NZA5uhgrIhJzSvQiIjGnRC8iEnOx66MXOdol3pZZpa7bM5vTLZmSeUr0IjGTeFtmlbpuz2xOt2RK5inRi0jsNOTWTIjf7ZlK9CKSsrunSk3dPs25u6cht2ZC/G7PjJTozawA+AXB5OD3uvvcpO3HAA8CXwE+BCa7+zvhtluA6QSTg/+ru6/KWPQikhGpunuq1NTto+6elqPORG9mrYEFwPlACbDezIrcfXNCsenAR+4+wMymAP8OTDazwcAU4IvAScAzZjbI3SszfSLNTTpDDle1mIIhh9MbvVIkW2r7FVAl1a+B5vxLoEpDun4q3WhtXq+6jdVlFKVFPxwodvetAGa2FJgAJCb6CcAPw/ePAfPNzML1S939c+CvZlYc7m9tZsJvvtIZcriqxRQMOSzSMtT2K6BKql8DE365MdIAbYlfEgc+3UO7jp0jx/Z3OZV8uGByWnXgb19C6Xb9JDbsDny4nXZde0c+VqLG6jIy99q/eczscqDA3f85XP4GMMLdZyWUeT0sUxIuvw2MIEj+69z9v8L19wF/cPfHko4xA6j65E8GtjT81LLmROCDbAeRIXE6F9D5NGdxOhfIzvl8wd1zU22I0qK3FOuSvx1qKhOlLu6+CFgUIZZmz8w2uHt+tuPIhDidC+h8mrM4nQs0v/OJ8mRsCZD4O6QXsLOmMmbWBugM7I5YV0REGlGURL8eGGhmfc2sHcHF1aKkMkXAtPD95cBzHvQJFQFTzOwYM+sLDAT+mJnQRUQkijq7bty9wsxmAasIbq9c7O6bzGwOsMHdi4D7gP8ML7buJvgyICz3KMGF2wpg5lFwx00suqBCcToX0Pk0Z3E6F2hm51PnxVgREWnZNHqliEjMKdGLiMScEn0GmFlvM1ttZm+Y2SYz+1a2Y8oEM2ttZhvN7PfZjqWhzOx4M3vMzP4Sfk5nZjum+jKzb4f/zl43s9+a2bHZjikdZrbYzMrC52+q1p1gZk+b2Vvh3y7ZjDEdNZzPvPDf2p/M7EkzOz6bMSrRZ0YFcIO7nwp8FZgZDv/Q0n0LeCPbQWTIL4CV7n4KcDot9LzMrCfwr0C+u3+J4AaJKdmNKm0PAAVJ624GnnX3gcCz4XJL8QBHns/TwJfc/TTgTeCWpg4qkRJ9Brh7qbu/Gr7/hCCJtOhBa8ysFzAOuDfbsTSUmXUCziG4Owx3P+DuH2c3qgZpA+SEz6y0p4U9m+LuLxDcnZdoArAkfL8EmNikQTVAqvNx96fcvSJcXEfwDFHWKNFnmJn1AYYCL2c3kgb7D+A7wKFsB5IB/YBdwP1hV9S9ZtYh20HVh7vvAO4EtgGlwB53fyq7UWVEd3cvhaDhBHTLcjyZdDXwh2wGoESfQWbWEXgcuM7d92Y7nvoys/FAmbu/ku1YMqQN8GXgbncfCnxGy+oaqBb2XU8A+hKMCNvBzK7IblRSEzP7LkHX7kPZjEOJPkPMrC1Bkn/I3Z/IdjwNdBZwiZm9AywFRpvZf2U3pAYpAUrcvepX1mMEib8lGgP81d13uftB4Ang/2U5pkx438x6AIR/o43x3YyZ2TRgPPCPnuUHlpToMyAckvk+4A13/1m242kod7/F3Xu5ex+CC33PuXuLbTW6+3vAdjM7OVx1HocPs92SbAO+ambtw39359FCLywnSRxGZRpQmMVYGiycrOnfgEvcfV+241Giz4yzgG8QtHxfC18XZTsoOcy1wENm9ifgDOAnWY6nXsJfJY8BrwJ/Jvh/uFk9bl8XM/stwZwUJ5tZiZlNB+YC55vZWwSTHM2tbR/NSQ3nMx84Dng6zAe/yWqMGgJBRCTe1KIXEYk5JXoRkZhTohcRiTklehGRmFOiFxGJOSV6aZbM7Coze8XMPjGzj8KhC36WsL2PmXn4FK+I1EKJXpodM7uFYDC1VcClwJUED9Bcks24RFoq3UcvzY6Z7QD+291nJq23qkfJw8Hj/gpc7O4ZHy/fzHLcvTzT+xXJBrXopTk6HngveWUN44W0N7OFZrYnfCpxtplV/7s2s1PMbKmZbTezfeGEHdcllRkZdgONNbMiM/uU4MlGwvXXm6XTMQkAAAP1SURBVNkvzGy3mX1sZr8ys3YJ9a8Kyw0JJ834LJx04tLkYM1sgpltMLP9Zvaemd0RjpNUtb2XmT0aTmRRbmZvm9mPErZ/0cxWhrF8Fk6iMjP5OCKJ2mQ7AJEUXgWuNbNtwO/d/cNayt5BMJjc5QTjvtwGbAIeDbf3BLYQjB74CcHwB7OBHOCnSfu6D7ifYIjm/QnrbyAYU/wfgS8Ct4fbb0qq/zDBcATzCIZcWGpm/dy9BMDMvg78FlgI3Ar0D2NoBdwY7uPBMLYZwMcEQyyfknCMIuAvwBXA58DJQKda/vuIgLvrpVezegGnAVsBJxgPfxMwB+iUUKZPuP3BpLqvAUtr2K8RNG5uBbYmrB8Z7uvnKeo4QWJtlbDuu8A+4IRw+aqw3NUJZboSDE97TcKx3wXuT9r/1UA50DVc/pSgOypV/CeGxxmS7c9Ir5b1UteNNDvu/ifgVIKLr78mSJLfBzaEY/4nSp50YzMJs/mY2bFhd04xQQv4IEGLvG84Q1Oi5TWEVOjuiROwPEHQ6v5STbF48CukLCGWQUAe8KiZtal6Ac8Bxybs6zXgp2F3UF7S/ncD24HfmNlkM4vT5BzSiJTopVly98/d/XfuPsvdBwP/DAwEpicVTZ4S8ABB4qzy7wTdIouAi4BhwI/DbcmTar9fQzjJY6NXLfdII5YTw78rCL5sql5/Ddf3Dv9OBjYAPwfeDUc+PA8g/LK5gOD6xWLgPTP7HzMbWkPcIoASvbQQ7n4fQYv2lLrKJvka8Ct3v8Pdn3H3DQRdKikPU8P65JZz1XJpGnFUzSk6g+DLJvn1BwimCnT3qwi6fs4kSOpFZtY13P4Xd7+M4IL1GIIvkuWJF5dFkukfhzQ7qbokzCwX6EzNre6a5BB02VTtpzXBZCrpmJCUSC8l6Fd/PY19bAF2AH3cfUOK12EXnN39kLuvI7hw3B74QtL2g+7+HPAzgl8Wx6d5TnIU0V030hz92cwKCfq8ywiS3I0EF0CXpLmvp4GZYR/9bmAmcEya+zgOWGZm9xDcdXMbMN/dd9de7W/c/ZCZ3QD8p5l1ImjBHyC4q2YiwV1DbQkeEnsQeDOM8waCVv0bZnYawcTgjxBcrO5CMIvR/6UTixx9lOilOZpDMAH2L4ETCBLd/wKT3f2vtVVM4VrgN8ACglb4EuBJ0puV6S6ChPxbgl/B9xLcuZMWd3/EzPaGda8GKgkS9u8Jkn4lwaxR3yLos99HcFvnBe5ebmbvEfyi+S7BxOAfA6sJkr1IjfRkrEgtzMyBa919frZjEakv9dGLiMScEr2ISMyp60ZEJObUohcRiTklehGRmFOiFxGJOSV6EZGYU6IXEYm5/w9XCZFrGERZZAAAAABJRU5ErkJggg==\n", 356 | "text/plain": [ 357 | "
" 358 | ] 359 | }, 360 | "metadata": { 361 | "needs_background": "light" 362 | }, 363 | "output_type": "display_data" 364 | } 365 | ], 366 | "source": [ 367 | "sd_mu = np.mean(sd_fm)\n", 368 | "sd_sigma = np.std(sd_fm)\n", 369 | "tj_mu = np.mean(tj_fm)\n", 370 | "tj_sigma = np.std(tj_fm)\n", 371 | "\n", 372 | "tj_count, tj_bins, _ = plt.hist(tj_fm,bins=20, edgecolor='k', density=True,alpha=0.95, label='distant')\n", 373 | "sd_count, sd_bins, _ = plt.hist(sd_fm,bins=20, edgecolor='k', density=True,alpha=0.75, label='close')\n", 374 | "\n", 375 | "plt.xlabel('Sharpness', fontsize=15)\n", 376 | "plt.legend(fontsize=15)\n", 377 | "\n", 378 | "# plt.plot(tj_bins, 1./(np.sqrt(2*np.pi)*tj_sigma)*np.exp(-(tj_bins-tj_mu)**2/(2*tj_sigma**2)), lw=2, c='b')\n", 379 | "# plt.plot(sd_bins, 1./(np.sqrt(2*np.pi)*sd_sigma)*np.exp(-(sd_bins-tj_mu)**2/(2*sd_sigma**2)), lw=2, c='r')" 380 | ] 381 | }, 382 | { 383 | "cell_type": "code", 384 | "execution_count": 37, 385 | "metadata": {}, 386 | "outputs": [ 387 | { 388 | "data": { 389 | "text/plain": [ 390 | "" 391 | ] 392 | }, 393 | "execution_count": 37, 394 | "metadata": {}, 395 | "output_type": "execute_result" 396 | }, 397 | { 398 | "data": { 399 | "image/png": "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\n", 400 | "text/plain": [ 401 | "
" 402 | ] 403 | }, 404 | "metadata": { 405 | "needs_background": "light" 406 | }, 407 | "output_type": "display_data" 408 | } 409 | ], 410 | "source": [ 411 | "tj_count, tj_bins, _ = plt.hist(tj_size,bins=20, edgecolor='k', density=True,alpha=0.95, label='distant')\n", 412 | "sd_count, sd_bins, _ = plt.hist(sd_size,bins=20, edgecolor='k', density=True,alpha=0.75, label='close')\n", 413 | "\n", 414 | "plt.xlabel('Iris size', fontsize=15)\n", 415 | "plt.legend(fontsize=15)" 416 | ] 417 | }, 418 | { 419 | "cell_type": "code", 420 | "execution_count": 38, 421 | "metadata": {}, 422 | "outputs": [ 423 | { 424 | "data": { 425 | "text/plain": [ 426 | "" 427 | ] 428 | }, 429 | "execution_count": 38, 430 | "metadata": {}, 431 | "output_type": "execute_result" 432 | }, 433 | { 434 | "data": { 435 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXoAAAELCAYAAADX3k30AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjEsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy8QZhcZAAAgAElEQVR4nO3df3hU5Z338feXBDAEQUSgyA8BES2tihpAH6sC/oqCCyguiK1YaVn7QC9ZW13ttjzgVfug4rq2sBYqWLRWKFpLWii0FcSVBylxsatopTGLEEhJEAoi4UfC9/ljDukwmZAzSYZMDp/XdeXinPvcZ+Y7cfzMyT3n3MfcHRERia4WTV2AiIikl4JeRCTiFPQiIhGnoBcRiTgFvYhIxGU3dQGJzjrrLO/Vq1dTlyEi0qy8/fbbu9y9U7JtGRf0vXr1orCwsKnLEBFpVszs49q2aehGRCTiFPQiIhGnoBcRiTgFvYhIxCnoRUQiTkEvIhJxGXd6pYicfPv27aOsrIwjR440dSmSRMuWLencuTPt2rWr1/4KepFT3L59+9i5cyfdunUjJycHM2vqkiSOu1NRUcH27dsB6hX2GroROcWVlZXRrVs32rRpo5DPQGZGmzZt6NatG2VlZfV6DB3RSyT06XcBpdtLUtqna7fuFG/+c5oqaj6OHDlCTk5OU5chdcjJyan30FqooDezfOBpIAt41t1nJmxvDTwPXAZ8Aox19y1mdifwQFzXi4BL3f2delUrUovS7SWc++1XUtrno1m3pama5kdH8pmvIf+N6hy6MbMsYA5wE9AfuMPM+id0mwjscfe+wFPAYwDu/qK7D3D3AcBXgC0KeRGRkyvMGP0goMjdi939MLAIGJnQZySwMFh+GbjWan783AG81JBiRUQkdWGCvhuwLW69JGhL2sfdK4G9QMeEPmOpJejNbJKZFZpZYXl5eZi6RSTN+vS7gJzctif9p0+/CxrtNbz33nuYGa+//joQG/6YPXt26P0ff/zx6n3ToaysjOnTp7Nly5a0PQeEG6NPNjDkqfQxs8HAAXd/L9kTuPs8YB5AXl5e4mOLSBOoz/cejSGd352sW7eO3r17h+7/+OOPM2XKFIYMGZKWesrKypgxYwZDhgwhnffhCBP0JUCPuPXuwI5a+pSYWTbQHtgdt30cGrYRkSZ2+eWXN3UJTSLM0M0G4Dwz621mrYiFdkFCnwJgQrA8Bljl7g5gZi2A24mN7YuIpM1//Md/0KNHD3Jzc7nlllsoLS09bnvi0M2bb77JVVddRbt27WjXrh0DBgxgyZIlQOwmSJ988gkzZszAzI4bAnryyScZOHAg7du3p0uXLtxyyy0UFRUd91xDhgxhzJgx/PznP6dv3760a9eOm266iZKS2GnAW7Zs4cILLwRg6NCh1c+RDnUe0bt7pZlNAVYSO71ygbtvMrNHgEJ3LwDmAy+YWRGxI/lxcQ9xNVDi7sWNX76ISMzSpUuZPHky9957L6NGjWLNmjXcc889tfbft28fI0aMYOTIkUybNg1359133+Vvf/sbAK+++ipDhw5lzJgxfO1rXwOgf//YCYclJSVMmTKFc845h3379vHjH/+YK6+8ks2bN9O+ffvq51i/fj07duzgySefpKKigvvuu49JkyaxfPlyunbtyosvvsidd97JnDlzuPTSS9P2uwl1Hr27LweWJ7RNi1s+SOyoPdm+rwOn5t9LInLSPProo+Tn5/PMM88AcOONN1JeXs6zzz6btP/mzZvZu3cvs2fP5vTTTwfghhtuqN5+ySWXkJ2dTffu3WsM+Tz11FPVy1VVVVx//fV07tyZpUuXctddd1Vv27dvH8uWLaNDhw4A/PWvf+Wf//mfqaioICcnh4suugiIfYCkc1hJUyCISLNXVVXFxo0bGTny+DO/b7311lr3Offcc2nbti3jx49n6dKl1UfyYbz11ltcf/31dOzYkezsbNq0acP+/fvZvHnzcf0GDhxYHfLw978Ijs1bc7Io6EWk2SsvL6eyspLOnTsf1564Hq9Dhw787ne/48iRI/zjP/4jnTp1Yvjw4RQXn3iUeevWrdxwww24O3PnzmXt2rVs2LCBzp07c/DgweP6nnHGGcett2rVCqBGv3TTXDci0ux16tSJ7OzsGpN+1TUJ2BVXXMGKFSuoqKjgD3/4A/fffz/jx4/nrbfeqnWfFStWcODAAZYuXUpubi4AlZWV7N69u9Z9mpqO6EWk2cvKymLAgAEsXbr0uPZf/vKXofbPycnhlltu4Z577uH999+vbm/VqlWNo++KigpatGhBdvbfj5N/8YtfUFlZmXLdJ+sIX0f0IhIJ3/nOd7j11lv5xje+wejRo1mzZg0rVqyotf+yZctYsGABo0aNomfPnmzfvp25c+cybNiw6j4XXHABy5YtIz8/n7Zt23L++eczbNgwqqqq+OpXv8rEiRPZtGkTs2bNqjFME0bPnj3Jyclh4cKFtG/fnpYtW5KXl1ev138iCnrJSKlOO3zo8OE0VnNq6tqte5PM8Nm1W/d67Td69Gh+9KMfMXPmTBYuXMiQIUOYP38+N954Y9L+ffv2xcz4zne+Q1lZGZ06dWLEiBH84Ac/qO7zxBNPMHnyZIYPH86BAwdYvXo1Q4YM4bnnnmPGjBm8+uqrXHzxxSxZsoSxY8emXPNpp53GT37yE2bMmME111zDkSNHCC5BalSWjgdtiLy8PC8sLGzqMqSJ5eS2Teny+02PjuAL//qblJ7jo1m3UfHZ/lRLi5wPPviAz3/+801dhoRwov9WZva2uyf9c0Bj9CIiEaegFxGJOAW9iEjEKehFRCJOQS8iEnEKehGRiFPQi4hEnIJeRCTiFPQiIhGnoBeRyPvpT3+KmbF//6l5JbTmuhGRpMaNzGfnjq0n/Xm7nN2TRUtrn4xMUqegF5Gkdu7YyurJfU768w6do9tLNzYN3YhIZLzxxhsMHTqUtm3b0r59e4YMGcLGjRuT9t21axcTJkygY8eOtGnThiFDhpA4oWJBQQGXXXYZubm5dOjQgcGDB7NmzZrq7UePHmXmzJn07duX1q1b069fPxYuXJjW11gfoYLezPLN7EMzKzKzh5Jsb21mi4Pt682sV9y2i8xsnZltMrN3zey0xitfRCTm9ddf59prr6Vly5YsXLiQxYsXc9VVV9V6f9ZRo0axcuVKZs2axeLFizl69ChDhw6lqKgIgI8++ogxY8YwbNgwfv3rX/Piiy8yYsSI4+4k9c1vfpPvf//7TJo0iWXLljF69GjuuecefvOb1GZSTbc6h27MLAuYA1wPlAAbzKzA3d+P6zYR2OPufc1sHPAYMNbMsoGfAV9x9z+ZWUfgSKO/CpFTTH3Gz6M+9v3www9z8cUXs3LlSswMgPz8fCD2ZWy8FStWsHbtWl5//XWuueYaAIYNG0avXr144oknmDt3Lhs3buT000/niSeeqN7v5ptvrl4uKirimWee4bnnnmPChAkAXHfddZSWljJjxgxGjBiRzpebkjBj9IOAIncvBjCzRcBIID7oRwLTg+WXgdkW+03fAPy3u/8JwN0/aaS6RU5p9Rk/j/LY92effcb69et5+umnq0P+RP74xz/SqVOn6pAHyM3NZcSIEbz55psAXHjhhezdu5cJEyZw5513cuWVV1bfIxbgtddeo0WLFowePfq42whee+21vPTSS1RVVZGVldWIr7L+wgzddAO2xa2XBG1J+7h7JbAX6Aj0A9zMVprZf5nZg8mewMwmmVmhmRWWl5en+hpE5BS3Z88e3J2uXbuG6l9aWkqXLl1qtHfp0qV6aOb8889n6dKlFBcXc/PNN3PWWWcxfvx4jmXUrl27qKqqqr4F4LGfu+++m8rKSkpLSxvvBTZQmCP6ZB+Pibelqq1PNvAlYCBwAHgtuAvKa8d1dJ8HzIPYHaZC1CQiUq1Dhw60aNEidLh27dqVsrKyGu07d+7kzDPPrF4fPnw4w4cPZ+/evSxbtoypU6fyzW9+k0WLFnHmmWeSnZ3N2rVradGi5jFz586d6/+CGlmYI/oSoEfcendgR219gnH59sDuoH2Nu+9y9wPAcuDShhYtIhIvNzeXwYMH8/zzz4e65+rgwYMpKyvjjTfeqG47cOAAy5Yt40tf+lKN/u3bt2f8+PGMHj2a99+PjVofu0n43r17ycvLq/HTqlWrxnuBDRTmiH4DcJ6Z9Qa2A+OA8Ql9CoAJwDpgDLDK3d3MVgIPmlkb4DBwDfBUYxUv0hCHK6vIyW2b0j5du3WnePOf01SRNMTMmTO57rrruOmmm5g0aRK5ubmsW7eOvLyat1G98cYbufLKKxk7diwzZ86kY8eOzJo1i4qKCh544AEA5s6dy7p168jPz+fss8/mL3/5C0uWLOGuu+4CYkM79957L+PGjePBBx8kLy+PgwcPsmnTJjZv3syzzz57Ul//idQZ9O5eaWZTgJVAFrDA3TeZ2SNAobsXAPOBF8ysiNiR/Lhg3z1m9m/EPiwcWO7uy9L0WkRScrSqknMf+lVK+3w067Y0VZN5upzds0m+wO1yds967Xf11Vfz+9//nu9973t8+ctfplWrVlxyySWMGjWKXbt21ej/6quv8q1vfYupU6dy8OBBBg0axKpVq+jbty8AF110EQUFBdx///3s3r2brl278vWvf51HHnmk+jHmzJlDv379+MlPfsK0adNo164d/fv3Z+LEifV78WkS6spYd19ObNglvm1a3PJB4PZa9v0ZsVMsRaQZaY6nYl5zzTXHDcccM2DAAO6+++7j2jp16sTzzz9f62NdccUVLFt24uNSM2Pq1KlMnTq1XvWeLLoyVkQk4hT0IiIRp6AXEYk4Bb2ISMQp6EUk1Lnn0rQa8t9IQS9yimvZsiUVFRVNXYbUoaKigpYtW9ZrXwW9yCmuc+fObN++nQMHDujIPgO5OwcOHGD79u31nlZBd5gSOcW1a9cOgB07dnDkiGYRz0QtW7akS5cu1f+tUqWgFxHatWtX7xCRzKehGxGRiFPQi4hEnIJeRCTiFPQiIhGnoBcRiTgFvYhIxCnoRUQiTkEvIhJxCnoRkYjTlbEip4iPt25j6MD+Ke3T5eyezfKWgnI8Bb3IKcKOHmH15D4p7dMUNweXxhdq6MbM8s3sQzMrMrOHkmxvbWaLg+3rzaxX0N7LzCrM7J3g58eNW76IiNSlziN6M8sC5gDXAyXABjMrcPf347pNBPa4e18zGwc8BowNtn3k7gMauW4REQkpzNDNIKDI3YsBzGwRMBKID/qRwPRg+WVgtplZI9YpElnjRuazc8fWlPbZXrINSG0YRk5dYYK+G7Atbr0EGFxbH3evNLO9QMdgW28z2wjsA77r7v+Z+ARmNgmYBNCzZ8+UXoBIc7dzx9aUx87PfUBj5xJemDH6ZEfmibehqa1PKdDT3S8B7gd+bmY1Jr1293nunufueZ06dQpRkoiIhBXmiL4E6BG33h3YUUufEjPLBtoDuz12X7JDAO7+tpl9BPQDChtauEhTOFxZRU5u29D9u3brTvHmP6exIpG6hQn6DcB5ZtYb2A6MA8Yn9CkAJgDrgDHAKnd3M+tELPCrzKwPcB6gvzml2TpaVcm5D/0qdP+PZt2WxmpEwqkz6IMx9ynASiALWODum8zsEaDQ3QuA+cALZlYE7Cb2YQBwNfCImVUCVcC97r47HS9ERESSC3XBlLsvB5YntE2LWz4I3J5kv1eAVxpYo4iINIDmuhERiTgFvYhIxCnoRUQiTkEvIhJxCnoRkYhT0IuIRJyCXkQk4hT0IiIRp6AXEYk4Bb2ISMQp6EVEIk5BLyIScQp6EZGIU9CLiEScgl5EJOIU9CIiEaegFxGJOAW9iEjEKehFRCJOQS8iEnGhgt7M8s3sQzMrMrOHkmxvbWaLg+3rzaxXwvaeZrbfzL7dOGWLiEhYdQa9mWUBc4CbgP7AHWbWP6HbRGCPu/cFngIeS9j+FPDbhpcrIiKpCnNEPwgocvdidz8MLAJGJvQZCSwMll8GrjUzAzCzUUAxsKlxShYRkVSECfpuwLa49ZKgLWkfd68E9gIdzSwX+BdgxomewMwmmVmhmRWWl5eHrV1ERELIDtHHkrR5yD4zgKfcfX9wgJ+Uu88D5gHk5eUlPraINJGPt25j6MDEkdoT63J2TxYtXZGmiqQ+wgR9CdAjbr07sKOWPiVmlg20B3YDg4ExZvY4cAZw1MwOuvvsBlcuImlnR4+wenKflPYZOqc4TdVIfYUJ+g3AeWbWG9gOjAPGJ/QpACYA64AxwCp3d+CqYx3MbDqwXyEvUbb3le/SYn9Z9XqHrIN1HhFvL9kGpBamIqmoM+jdvdLMpgArgSxggbtvMrNHgEJ3LwDmAy+YWRGxI/lx6SxaJFO12F/Gkgl//wqrYtserrn6xCF+7gM6Apb0CnNEj7svB5YntE2LWz4I3F7HY0yvR30iItJAujJWRCTiFPQiIhGnoBcRiTgFvYhIxCnoRUQiTkEvIhJxCnoRkYhT0IuIRJyCXkQk4hT0IiIRp6AXEYk4Bb2ISMQp6EVEIk5BLyIScQp6EZGIU9CLiEScgl5EJOIU9CIiEaegFxGJOAW9iEjEhQp6M8s3sw/NrMjMHkqyvbWZLQ62rzezXkH7IDN7J/j5k5mNbtzyRUSkLnUGvZllAXOAm4D+wB1m1j+h20Rgj7v3BZ4CHgva3wPy3H0AkA/MNbPsxipeRETqFiZ0BwFF7l4MYGaLgJHA+3F9RgLTg+WXgdlmZu5+IK7PaYA3uGJpdvr0u4DS7SUp7XPo8OE0VSNy6gkT9N2AbXHrJcDg2vq4e6WZ7QU6ArvMbDCwADgH+Iq7VyY+gZlNAiYB9OzZM9XXIBmudHsJ5377lZT22fToiDRVI3LqCRP0lqQt8ci81j7uvh74gpl9HlhoZr9194PHdXSfB8wDyMvL01G/ZIS9r3yXFvvLjmv7XE4Vny6cVOs+Rz8tJ3bcI5I5wgR9CdAjbr07sKOWPiXBGHx7YHd8B3f/wMw+A74IFNa7YpGTpMX+MpZMOD60P/v4E3LPqT3Ib/thabrLEklZmLNuNgDnmVlvM2sFjAMKEvoUABOC5THAKnf3YJ9sADM7Bzgf2NIolYuISCh1HtEHY+5TgJVAFrDA3TeZ2SNAobsXAPOBF8ysiNiR/Lhg9y8BD5nZEeAo8L/dfVc6XoiIiCQX6lRHd18OLE9omxa3fBC4Pcl+LwAvNLBGERFpAF0ZKyIScQp6EZGIU9CLiEScgl5EJOIU9CIiEaegFxGJOAW9iEjEKehFRCJOQS8iEnEKehGRiFPQi4hEnIJeRCTiFPQiIhGnoBcRiTgFvYhIxCnoRUQiTkEvIhJxoe4wJSIS1sdbtzF0YP+U9ulydk8WLV2RpopEQS8ijcqOHmH15D4p7TN0TnGaqhFQ0Iuk1VF31rzxxgn7HD50+Lg+rVq35orBg9NdmpxCQgW9meUDTwNZwLPuPjNhe2vgeeAy4BNgrLtvMbPrgZlAK+Aw8IC7r2rE+kUymzs5PS88cZ+sQnJ6fLF6tWLbe2kuSk41dX4Za2ZZwBzgJqA/cIeZJQ7ATQT2uHtf4CngsaB9F3CLu18ITABeaKzCRUQknDBn3QwCity92N0PA4uAkQl9RgILg+WXgWvNzNx9o7vvCNo3AacFR/8iInKShAn6bsC2uPWSoC1pH3evBPYCHRP63AZsdPdDiU9gZpPMrNDMCsvLy8PWLiIiIYQJekvS5qn0MbMvEBvO+adkT+Du89w9z93zOnXqFKIkEREJK0zQlwA94ta7Aztq62Nm2UB7YHew3h14FbjL3T9qaMEiIpKaMEG/ATjPzHqbWStgHFCQ0KeA2JetAGOAVe7uZnYGsAx42N3XNlbRIiISXp1BH4y5TwFWAh8Av3D3TWb2iJn9Q9BtPtDRzIqA+4GHgvYpQF/ge2b2TvDTudFfhYiI1CrUefTuvhxYntA2LW75IHB7kv2+D3y/gTWKiEgD6MpYiby9r3yXFvvLarR/LqeKTxdOqnW/o5+WU/MEM5HmR0EvkddifxlLJtQM7M8+/oTcc2oP8tt+WJrOskROGk1TLCIScQp6EZGIU9CLiEScgl5EJOL0ZaxIhtEc9tLYFPQimUZz2EsjU9BLSvr0u4DS7SUp7XPo8OE0VSMiYSjoJSWl20s499uvpLTPpkdHpKkaEQlDX8aKiEScgl5EJOIU9CIiEaegFxGJOAW9iEjEKehFRCJOQS8iEnEKehGRiFPQi4hEnIJeRCTiQgW9meWb2YdmVmRmDyXZ3trMFgfb15tZr6C9o5mtNrP9Zja7cUsXEZEw6pzrxsyygDnA9UAJsMHMCtz9/bhuE4E97t7XzMYBjwFjgYPA94AvBj8iIjV8vHUbQwf2T2mfLmf3ZNHSFWmqKFrCTGo2CChy92IAM1sEjATig34kMD1YfhmYbWbm7p8Bb5pZ38YrWUSixo4eYfXkPintM3ROcZqqiZ4wQzfdgG1x6yVBW9I+7l4J7AU6hi3CzCaZWaGZFZaXl4fdTUREQghzRG9J2rwefWrl7vOAeQB5eXmh9xORmFTvSqU7Up1awgR9CdAjbr07sKOWPiVmlg20B3Y3SoUiUrcU70qlO1KdWsIM3WwAzjOz3mbWChgHFCT0KQAmBMtjgFXuriNzEZEMUOcRvbtXmtkUYCWQBSxw901m9ghQ6O4FwHzgBTMrInYkP+7Y/ma2BWgHtDKzUcANCWfsiIhIGoW6laC7LweWJ7RNi1s+CNxey769GlCfiIg0kK6MFRGJOAW9iEjEKehFRCJOQS8iEnEKehGRiAt11o1Iptj7yndpsb+sRvvncqr4dOGkpPsc/bScmrN2iJw6FPTSrLTYX8aSCTVD+7OPPyH3nORhftsPS9NdlkhG09CNiEjEKehFRCJOQS8iEnEKehGRiNOXsae4Pv0uoHR7Sej+hw4fTmM1IpIOCvpTXOn2Es799iuh+296dEQaqxGRdNDQjYhIxOmIXppMbRc/Qe0XQOniJ5HUKeilydR28RPUfgGULn4SSZ2CXkSapY+3bmPowP4p79fl7J4sWroiDRVlLgW9iDRLdvQIqyf3SXm/oXOK01BNZlPQi5yCjrqz5o036ux3+NDh6n6tWrfmisGD012apIGCXuRU5E5Ozwvr7pdVSE6PLwJQse29NBcl6RLq9EozyzezD82syMweSrK9tZktDravN7NecdseDto/NLMbG690EREJo84jejPLAuYA1wMlwAYzK3D39+O6TQT2uHtfMxsHPAaMNbP+wDjgC8DZwB/MrJ+7VzX2C5GmpVMlo0/DPc1XmKGbQUCRuxcDmNkiYCQQH/QjgenB8svAbDOzoH2Rux8C/sfMioLHW9c45deU6iX9Xbt1p3jzn9P6HABVbmSZZ1xdjTWlgU6VPAXUY7jns63vpvTh4ICFLOfYPql+mNTnbJ2/7iznc106pX2fdJ0RZO4nDh8zGwPku/vXgvWvAIPdfUpcn/eCPiXB+kfAYGLh/5a7/yxonw/81t1fTniOScCxQ77zgQ+D5bOAXQ15gSeZ6k0v1Zs+zalWUL3JnOPuST9ZwhzRJ/uATfx0qK1PmH1x93nAvBpPbFbo7nkhaswIqje9VG/6NKdaQfWmKsyXsSVAj7j17sCO2vqYWTbQHtgdcl8REUmjMEG/ATjPzHqbWStiX64WJPQpACYEy2OAVR4bEyoAxgVn5fQGzgP+2Dili4hIGHUO3bh7pZlNAVYCWcACd99kZo8Ahe5eAMwHXgi+bN1N7MOAoN8viH1xWwlMTvGMmxrDORlO9aaX6k2f5lQrqN6U1PllrIiING+aj15EJOIU9CIiEZexQV/XtAtNzcwWmFlZcA3BsbYzzez3ZvaX4N8OTVnjMWbWw8xWm9kHZrbJzO4L2jO13tPM7I9m9qeg3hlBe+9gio2/BFNutGrqWuOZWZaZbTSz3wTrGVuvmW0xs3fN7B0zKwzaMvL9AGBmZ5jZy2b25+B9fEUm1mtm5we/02M/+8xsalPXmpFBHzftwk1Af+COYDqFTPJTID+h7SHgNXc/D3gtWM8ElcC33P3zwOXA5OD3man1HgKGufvFwAAg38wuJza1xlNBvXuITb2RSe4DPohbz/R6h7r7gLjzuzP1/QDwNLDC3S8ALib2e864et39w+B3OgC4DDgAvEpT1+ruGfcDXAGsjFt/GHi4qetKUmcv4L249Q+BrsFyV+DDpq6xlrqXEpu7KOPrBdoA/0XsSutdQHay90hT/xC7RuQ1YBjwG2IXC2ZyvVuAsxLaMvL9ALQD/ofg5JFMrzeuvhuAtZlQa0Ye0ROb6Wpb3HoJzWP2qy7uXgoQ/Nu5ieupIZhZ9BJgPRlcbzAM8g5QBvwe+Aj4m7tXBl0y7T3x78CDwNFgvSOZXa8DvzOzt4MpSCBz3w99gHLguWBo7FkzyyVz6z1mHPBSsNyktWZq0IeaOkFSY2ZtgVeAqe6+r6nrORF3r/LYn7/diU2E9/lk3U5uVcmZ2QigzN3fjm9O0jUj6g1c6e6XEhsenWxmVzd1QSeQDVwKPOPulwCfkQHDNCcSfB/zD8CSpq4FMjfom+vUCTvNrCtA8G/yeXubgJm1JBbyL7r7L4PmjK33GHf/G/A6se8Wzgim2IDMek9cCfyDmW0BFhEbvvl3Mrde3H1H8G8ZsTHkQWTu+6EEKHH39cH6y8SCP1PrhdgH6H+5+85gvUlrzdSgDzPtQiaKnwpiArGx8CZnZkbs6uUP3P3f4jZlar2dzOyMYDkHuI7Yl2+riU2xARlUr7s/7O7d3b0XsffqKne/kwyt18xyzez0Y8vExpLfI0PfD+7+V2CbmZ0fNF1L7Gr7jKw3cAd/H7aBpq61qb+wOMEXGTcDm4mNzf5rU9eTpL6XgFLgCLEjjonExmVfA/4S/HtmU9cZ1PolYsMG/w28E/zcnMH1XgRsDOp9D5gWtPchNldSEbE/iVs3da1Jah8C/CaT6w3q+lPws+nY/1+Z+n4IahsAFAbviV8BHTK1XmInEHwCtI9ra9JaNQWCiEjEZerQjYiINBIFvYhIxCnoRUQiTkEvIhJxCnoRkYhT0EuzZmbTzcyDn6NmtsfMNopmLnEAAAL+SURBVJjZo2b2ubh+vYI+I+LatpjZrBSfb5CZTa+ljl0NejEiaaKglyjYS2zSsP9F7IKlXwJfAd41s8uCPqVBnzcb+FyDgP+TpP1Z4MYGPrZIWtR5z1iRZqDS3d+KW19pZs8AbwCLzex8dz8EvJV894Zz9xJiF86JZBwd0UskeWyOnAeBc4Hrkw3dJApuZlFgZjvM7LPgxhF3xm2/G/hRsHxsuOj1YL3G0E0whcevgptPfGpmvzazvgl93MzuM7MfmFm5xW5mM8fMWjfW70JER/QSZauJ3XTlcuDPIfqfA6wFfgwcJDZZ2XNmdtTdXwKWAU8C3yI2DASQdBbQIKhfIzZFxteDOmYAa8zsQnffHdf9W8Aq4MvEpn/4v8DHwOOhX6nICSjoJbLc/VBwlN0lZP9Fx5aDieDeIDbr5NeBl9y9PJihkoShomS+CvQE+rl7cfCY64Fi4J+IhfkxW9z97mB5pZldCdyKgl4aiYJeoi7ZvPDJO8bu4zkDGEnsJiFZwabt9XjeQcSmqS0+1uDuJWa2ltgkc/F+l7D+PpCHSCPRGL1ElpmdRmzWwJ119Q38FBgLPEFs6t6BwALgtHo8fddanncncGZC298S1g/X8zlFktIRvUTZUGLv8XV1dQw+FIYDU9z9x3Ht9T0YKgW+kKS9C7A7SbtI2uiIXiIpuHHJY8Tmgv9DiF1aExuqORT3GKcTux1cvMPBtrqOuNcDl5lZ77jH60bsXP+GnssvkhId0UsUZJvZ5cHy6cBlwDeI3QAi392rYt+t1s7d95rZBmCame0jdpPvh4hdjNUuruuxs3fuM7NVwD53/zDJQ/4U+Bfgt2Y2DagCpgO7gLkpv0KRBtARvURBe2LDM/+P2J2cxgA/Ay7042/YXZfxwP8AzwNPE7vH7vMJff6T2Bj+fcSO2pOGdnCB1nXEPhjmAwuJnTI5JOHUSpG00x2mREQiTkf0IiIRp6AXEYk4Bb2ISMQp6EVEIk5BLyIScQp6EZGIU9CLiEScgl5EJOL+P/0nvIddU2g/AAAAAElFTkSuQmCC\n", 436 | "text/plain": [ 437 | "
" 438 | ] 439 | }, 440 | "metadata": { 441 | "needs_background": "light" 442 | }, 443 | "output_type": "display_data" 444 | } 445 | ], 446 | "source": [ 447 | "tj_count, tj_bins, _ = plt.hist(tj_dilation,bins=20, edgecolor='k', density=True,alpha=0.95, label='distant')\n", 448 | "sd_count, sd_bins, _ = plt.hist(sd_dilation,bins=20, edgecolor='k', density=True,alpha=0.75, label='close')\n", 449 | "\n", 450 | "plt.xlabel('Dilation', fontsize=15)\n", 451 | "plt.legend(fontsize=15)" 452 | ] 453 | }, 454 | { 455 | "cell_type": "code", 456 | "execution_count": 39, 457 | "metadata": {}, 458 | "outputs": [ 459 | { 460 | "data": { 461 | "text/plain": [ 462 | "" 463 | ] 464 | }, 465 | "execution_count": 39, 466 | "metadata": {}, 467 | "output_type": "execute_result" 468 | }, 469 | { 470 | "data": { 471 | "image/png": "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\n", 472 | "text/plain": [ 473 | "
" 474 | ] 475 | }, 476 | "metadata": { 477 | "needs_background": "light" 478 | }, 479 | "output_type": "display_data" 480 | } 481 | ], 482 | "source": [ 483 | "tj_count, tj_bins, _ = plt.hist(tj_gls,bins=20, edgecolor='k', density=True,alpha=0.95, label='distant')\n", 484 | "sd_count, sd_bins, _ = plt.hist(sd_gls,bins=20, edgecolor='k', density=True,alpha=0.75, label='close')\n", 485 | "\n", 486 | "plt.xlabel('GLS', fontsize=15)\n", 487 | "plt.legend(fontsize=15)" 488 | ] 489 | }, 490 | { 491 | "cell_type": "code", 492 | "execution_count": 40, 493 | "metadata": {}, 494 | "outputs": [ 495 | { 496 | "data": { 497 | "text/plain": [ 498 | "" 499 | ] 500 | }, 501 | "execution_count": 40, 502 | "metadata": {}, 503 | "output_type": "execute_result" 504 | }, 505 | { 506 | "data": { 507 | "image/png": "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\n", 508 | "text/plain": [ 509 | "
" 510 | ] 511 | }, 512 | "metadata": { 513 | "needs_background": "light" 514 | }, 515 | "output_type": "display_data" 516 | } 517 | ], 518 | "source": [ 519 | "tj_count, tj_bins, _ = plt.hist(tj_uar,bins=20, edgecolor='k', density=True,alpha=0.95, label='distant')\n", 520 | "sd_count, sd_bins, _ = plt.hist(sd_uar,bins=20, edgecolor='k', density=True,alpha=0.75, label='close')\n", 521 | "\n", 522 | "plt.xlabel('Usable area', fontsize=15)\n", 523 | "plt.legend(fontsize=15)" 524 | ] 525 | }, 526 | { 527 | "cell_type": "code", 528 | "execution_count": 68, 529 | "metadata": {}, 530 | "outputs": [ 531 | { 532 | "name": "stdout", 533 | "output_type": "stream", 534 | "text": [ 535 | "info=v2 multi_linear sim 0~1 adam l1loss\n", 536 | "dataset_path=/home/dl/wangleyuan/dataset/cx1\n", 537 | "cp_path=\n", 538 | "cp_num=5\n", 539 | "visible=True\n", 540 | "model=MobileNetV2_Lite\n", 541 | "seed=2248\n", 542 | "debug=False\n", 543 | "mask_learn_rate=0.003125\n", 544 | "mask_lr_decay=0.5\n", 545 | "upout=True\n", 546 | "batch_size=24\n", 547 | "device=cuda:2\n", 548 | "num_workers=2\n", 549 | "max_epochs=500\n", 550 | "lr=0.0004\n", 551 | "momentum=0.9\n", 552 | "weight_decay=0.0005\n", 553 | "name=1203_202301_MobileNetV2_Lite\n", 554 | "\n" 555 | ] 556 | } 557 | ], 558 | "source": [ 559 | "test_data = monoSimDataset(path=sd_dataset_path, mode='test', seed=seed, debug_data=False,upsample=True)\n", 560 | "\n", 561 | "model = MobileNetV2_Lite_shower(True, True, 0.5)\n", 562 | "assert model is not None\n", 563 | "model.to('cpu')\n", 564 | "assert cp_path is not ''\n", 565 | "cp_data = torch.load(cp_path, map_location=device)\n", 566 | "try:\n", 567 | " model.load_state_dict(cp_data['model'])\n", 568 | "except Exception as e:\n", 569 | " model.load_state_dict(cp_data['model'], strict=False)\n", 570 | " print(e)\n", 571 | "\n", 572 | "cp_data['cfg'] = '' if 'cfg' not in cp_data else cp_data['cfg']\n", 573 | "print(cp_data['cfg'])" 574 | ] 575 | }, 576 | { 577 | "cell_type": "code", 578 | "execution_count": 69, 579 | "metadata": {}, 580 | "outputs": [ 581 | { 582 | "name": "stdout", 583 | "output_type": "stream", 584 | "text": [ 585 | "torch.Size([1, 3, 480, 640])\n", 586 | "0002_2_1_2_22_005.bmp tensor([0.7646])\n" 587 | ] 588 | } 589 | ], 590 | "source": [ 591 | "img, mask, target, name = test_data[15]\n", 592 | "img_tensor = torch.unsqueeze(img, 0).to('cpu')\n", 593 | "mask_tensor = torch.unsqueeze(mask, 0)\n", 594 | "print(img_tensor.shape)\n", 595 | "print(name,target)\n", 596 | "\n", 597 | "# img = transforms.to_pil_image(img)\n", 598 | "# mask = transforms.to_pil_image(mask*255)\n", 599 | "# plt.imshow(mask, cmap ='gray')\n", 600 | "# mask_tensor.max()" 601 | ] 602 | }, 603 | { 604 | "cell_type": "code", 605 | "execution_count": 125, 606 | "metadata": {}, 607 | "outputs": [ 608 | { 609 | "name": "stdout", 610 | "output_type": "stream", 611 | "text": [ 612 | "torch.Size([1, 1]) torch.Size([1, 2, 120, 160]) torch.Size([1, 32, 60, 80]) torch.Size([1, 1280, 15, 20])\n" 613 | ] 614 | } 615 | ], 616 | "source": [ 617 | "pred, heatmap, short, feat = model(img_tensor)\n", 618 | "model.eval()\n", 619 | "print(pred.shape, heatmap.shape, short.shape, feat.shape)" 620 | ] 621 | }, 622 | { 623 | "cell_type": "code", 624 | "execution_count": 127, 625 | "metadata": {}, 626 | "outputs": [ 627 | { 628 | "data": { 629 | "text/plain": [ 630 | "(-0.5, 159.5, 119.5, -0.5)" 631 | ] 632 | }, 633 | "execution_count": 127, 634 | "metadata": {}, 635 | "output_type": "execute_result" 636 | }, 637 | { 638 | "data": { 639 | "image/png": "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\n", 640 | "text/plain": [ 641 | "
" 642 | ] 643 | }, 644 | "metadata": { 645 | "needs_background": "light" 646 | }, 647 | "output_type": "display_data" 648 | } 649 | ], 650 | "source": [ 651 | "heatmap = torch.softmax(heatmap, 1)\n", 652 | "heatmap_img = transforms.to_pil_image(heatmap[0,0,:,:])\n", 653 | "plt.imshow(heatmap_img, cmap='gray_r')\n", 654 | "plt.axis('off')" 655 | ] 656 | }, 657 | { 658 | "cell_type": "code", 659 | "execution_count": 133, 660 | "metadata": {}, 661 | "outputs": [ 662 | { 663 | "data": { 664 | "text/plain": [ 665 | "(-0.5, 79.5, 59.5, -0.5)" 666 | ] 667 | }, 668 | "execution_count": 133, 669 | "metadata": {}, 670 | "output_type": "execute_result" 671 | }, 672 | { 673 | "data": { 674 | "image/png": "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\n", 675 | "text/plain": [ 676 | "
" 677 | ] 678 | }, 679 | "metadata": { 680 | "needs_background": "light" 681 | }, 682 | "output_type": "display_data" 683 | } 684 | ], 685 | "source": [ 686 | "idx = 5\n", 687 | "short1 = transforms.to_pil_image(short[0,idx:idx+3,:,:])\n", 688 | "plt.imshow(short1)\n", 689 | "plt.axis('off')" 690 | ] 691 | }, 692 | { 693 | "cell_type": "code", 694 | "execution_count": 138, 695 | "metadata": {}, 696 | "outputs": [ 697 | { 698 | "name": "stdout", 699 | "output_type": "stream", 700 | "text": [ 701 | "tensor([965, 846, 533])\n" 702 | ] 703 | }, 704 | { 705 | "data": { 706 | "text/plain": [ 707 | "(-0.5, 19.5, 14.5, -0.5)" 708 | ] 709 | }, 710 | "execution_count": 138, 711 | "metadata": {}, 712 | "output_type": "execute_result" 713 | }, 714 | { 715 | "data": { 716 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAATAAAADnCAYAAACZtwrQAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjEsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy8QZhcZAAAEQ0lEQVR4nO3cP6vWZRjA8fPPTFxCo8HhOOSfJpNoCqFJBKeWlpRWEXwJ7r6BIHAUmnwBDg1Bg0vQ0hKJvgD1CEpHNHrO4y6pcHny8MXPZ/1xcd/T97nhgWt1uVyuABSt7fUFAKYEDMgSMCBLwIAsAQOyNl738ezat/6iBPbUzzs3V1/1zQsMyBIwIEvAgCwBA7IEDMgSMCBLwIAsAQOyBAzIEjAgS8CALAEDsgQMyBIwIEvAgCwBA7IEDMgSMCBLwIAsAQOyBAzIEjAgS8CALAEDsgQMyBIwIEvAgCwBA7IEDMgSMCBLwIAsAQOyBAzIEjAgS8CALAEDsgQMyBIwIEvAgCwBA7IEDMgSMCBLwIAsAQOyBAzIEjAgS8CALAEDsgQMyBIwIEvAgCwBA7IEDMgSMCBLwIAsAQOyBAzIEjAgS8CALAEDsgQMyBIwIEvAgCwBA7IEDMgSMCBLwIAsAQOyBAzIEjAgS8CALAEDsjb2+gLwX9YPHxrP/vvZ5mhu44974zMXT56MZ5nzAgOyBAzIEjAgS8CALAEDsgQMyBIwIEvAgCwBA7IEDMgSMCBLwIAsAQOybKN4j6wdPDia29ne3uWbvNli69F49u7lo6O5ne2T4zNPXPptPMucFxiQJWBAloABWQIGZAkYkCVgQJaAAVkCBmQJGJAlYECWgAFZAgZkCRiQJWBAlnU6Mesnj41nN67/PZp7/vW7X6fzNvbd+3A0t3nr6S7fhP+bFxiQJWBAloABWQIGZAkYkCVgQJaAAVkCBmQJGJAlYECWgAFZAgZkCRiQZRtFzcNH49HFd7MtDXdufDE+8+hPs9/I/VvPxmde/OaX0dyZC3+Nz7z26anxLHNeYECWgAFZAgZkCRiQJWBAloABWQIGZAkYkCVgQJaAAVkCBmQJGJAlYECWgAFZ1unELLbm63Sma3GO/bgYn7k4sDqa++ej/eMzr37852ju/Odnx2eurDx4i1mmvMCALAEDsgQMyBIwIEvAgCwBA7IEDMgSMCBLwIAsAQOyBAzIEjAgS8CALNso3iPHv/99NHf/ylfjMx9/+Xw0d/jXD8Znnjtyejhpo0SNFxiQJWBAloABWQIGZAkYkCVgQJaAAVkCBmQJGJAlYECWgAFZAgZkCRiQJWBAlnU6vNEnP9yez+7iPeBlXmBAloABWQIGZAkYkCVgQJaAAVkCBmQJGJAlYECWgAFZAgZkCRiQJWBAloABWQIGZAkYkCVgQJaAAVkCBmQJGJAlYECWgAFZAgZkCRiQJWBAloABWQIGZAkYkCVgQJaAAVkCBmQJGJAlYECWgAFZAgZkCRiQJWBAloABWQIGZAkYkCVgQJaAAVkCBmQJGJAlYECWgAFZAgZkCRiQJWBAloABWQIGZAkYkCVgQJaAAVkCBmQJGJAlYEDW6nK53Os7AIx4gQFZAgZkCRiQJWBAloABWQIGZL0ANMtC29HXiAAAAAAASUVORK5CYII=\n", 717 | "text/plain": [ 718 | "
" 719 | ] 720 | }, 721 | "metadata": { 722 | "needs_background": "light" 723 | }, 724 | "output_type": "display_data" 725 | } 726 | ], 727 | "source": [ 728 | "\n", 729 | "featsum,index = torch.topk(feat[0].sum((1,2)), 7)\n", 730 | "print(index[-3:])\n", 731 | "idx = index[-1]\n", 732 | "feat1 = transforms.to_pil_image(feat[0,idx,:,:])\n", 733 | "plt.imshow(feat1)\n", 734 | "plt.axis('off')" 735 | ] 736 | }, 737 | { 738 | "cell_type": "code", 739 | "execution_count": null, 740 | "metadata": {}, 741 | "outputs": [], 742 | "source": [] 743 | } 744 | ], 745 | "metadata": { 746 | "kernelspec": { 747 | "display_name": "Python 3", 748 | "language": "python", 749 | "name": "python3" 750 | }, 751 | "language_info": { 752 | "codemirror_mode": { 753 | "name": "ipython", 754 | "version": 3 755 | }, 756 | "file_extension": ".py", 757 | "mimetype": "text/x-python", 758 | "name": "python", 759 | "nbconvert_exporter": "python", 760 | "pygments_lexer": "ipython3", 761 | "version": "3.7.3" 762 | } 763 | }, 764 | "nbformat": 4, 765 | "nbformat_minor": 2 766 | } -------------------------------------------------------------------------------- /evaluation/result/eer_irr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Debatrix/DFSNet/4e9d18ed8fe7f92dd89f3ea968389108d96638cb/evaluation/result/eer_irr.png -------------------------------------------------------------------------------- /evaluation/result/eer_irr_SD.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Debatrix/DFSNet/4e9d18ed8fe7f92dd89f3ea968389108d96638cb/evaluation/result/eer_irr_SD.png -------------------------------------------------------------------------------- /evaluation/result/eer_irr_TJ.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Debatrix/DFSNet/4e9d18ed8fe7f92dd89f3ea968389108d96638cb/evaluation/result/eer_irr_TJ.png -------------------------------------------------------------------------------- /evaluation/result/eer_irr_hd_SD.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Debatrix/DFSNet/4e9d18ed8fe7f92dd89f3ea968389108d96638cb/evaluation/result/eer_irr_hd_SD.png -------------------------------------------------------------------------------- /evaluation/result/eer_irr_hd_TJ.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Debatrix/DFSNet/4e9d18ed8fe7f92dd89f3ea968389108d96638cb/evaluation/result/eer_irr_hd_TJ.png -------------------------------------------------------------------------------- /evaluation/result/hd_SD.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Debatrix/DFSNet/4e9d18ed8fe7f92dd89f3ea968389108d96638cb/evaluation/result/hd_SD.png -------------------------------------------------------------------------------- /evaluation/result/heatmap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Debatrix/DFSNet/4e9d18ed8fe7f92dd89f3ea968389108d96638cb/evaluation/result/heatmap.png -------------------------------------------------------------------------------- /evaluation/result/network.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Debatrix/DFSNet/4e9d18ed8fe7f92dd89f3ea968389108d96638cb/evaluation/result/network.png -------------------------------------------------------------------------------- /evaluation/result/result.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Debatrix/DFSNet/4e9d18ed8fe7f92dd89f3ea968389108d96638cb/evaluation/result/result.pkl -------------------------------------------------------------------------------- /evaluation/result/result_tj.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Debatrix/DFSNet/4e9d18ed8fe7f92dd89f3ea968389108d96638cb/evaluation/result/result_tj.pkl -------------------------------------------------------------------------------- /log/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore -------------------------------------------------------------------------------- /model/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Debatrix/DFSNet/4e9d18ed8fe7f92dd89f3ea968389108d96638cb/model/__init__.py -------------------------------------------------------------------------------- /model/loss.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | import torch.nn.functional as F 4 | 5 | 6 | class CrossEntropy2d(nn.Module): 7 | 8 | def __init__(self, size_average="mean", ignore_label=255): 9 | super(CrossEntropy2d, self).__init__() 10 | self.size_average = size_average 11 | self.ignore_label = ignore_label 12 | 13 | def forward(self, predict, target, weight=None): 14 | ''' 15 | :param predict: (n, c, h, w) 16 | :param target: (n,[c=1], h, w) 17 | :param weight: (Tensor, optional): a manual rescaling weight given to each class. 18 | If given, has to be a Tensor of size "nclasses" 19 | :return: Loss, refer to deepblue 20 | ''' 21 | target = target.squeeze() 22 | assert not target.requires_grad 23 | assert predict.dim() == 4 24 | assert target.dim() == 3 25 | assert predict.size(0) == target.size(0), "{0} vs {1} ".format(predict.size(0), target.size(0)) 26 | assert predict.size(2) == target.size(1), "{0} vs {1} ".format(predict.size(2), target.size(1)) 27 | assert predict.size(3) == target.size(2), "{0} vs {1} ".format(predict.size(3), target.size(3)) 28 | n, c, h, w = predict.size() 29 | target_mask = (target >= 0) * (target != self.ignore_label) 30 | target = target[target_mask].to(torch.long) 31 | if not target.data.dim(): 32 | return torch.zeros(1) 33 | predict = predict.transpose(1, 2).transpose(2, 3).contiguous() 34 | predict = predict[target_mask.view(n, h, w, 1).repeat(1, 1, 1, c)].view(-1, c) 35 | loss = F.cross_entropy(predict, target, weight=weight, reduction=self.size_average) 36 | return loss 37 | 38 | 39 | class FocalLoss(nn.Module): 40 | def __init__(self, gamma=2, alpha=0.25, size_average=True): 41 | super(FocalLoss, self).__init__() 42 | 43 | """ 44 | Compute focal loss for predictions. 45 | Multi-labels Focal loss formula: 46 | FL = -alpha * (z-p)^gamma * log(p) -(1-alpha) * p^gamma * log(1-p) 47 | ,which alpha = 0.25, gamma = 2, p = sigmoid(x), z = target_tensor. 48 | """ 49 | self.gamma = gamma 50 | self.alpha = alpha 51 | self.size_average = size_average 52 | 53 | def forward(self, p, target): 54 | """ 55 | :param input: (n, c, h, w) 56 | :param target: (n, c, h, w) 57 | :return: focal loss 58 | """ 59 | p = torch.sigmoid(p) 60 | mask = (target == 0) 61 | pos_p = target.type(torch.float) - p 62 | pos_p[mask] = 0 63 | neg_p = p.new_tensor(p.data) 64 | neg_p[~mask] = 0 65 | 66 | loss = -1 * self.alpha * pos_p ** self.gamma * (p + 1e-8).log() \ 67 | - (1 - self.alpha) * neg_p ** self.gamma * (1 - p + 1e-8).log() 68 | 69 | if self.size_average: 70 | return loss.mean() 71 | else: 72 | return loss.sum() 73 | -------------------------------------------------------------------------------- /model/pretrained/1203_202301_MobileNetV2_Lite_CX1.pth: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Debatrix/DFSNet/4e9d18ed8fe7f92dd89f3ea968389108d96638cb/model/pretrained/1203_202301_MobileNetV2_Lite_CX1.pth -------------------------------------------------------------------------------- /model/pretrained/1211_202056_MobileNetV2_Lite_CX2.pth: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Debatrix/DFSNet/4e9d18ed8fe7f92dd89f3ea968389108d96638cb/model/pretrained/1211_202056_MobileNetV2_Lite_CX2.pth -------------------------------------------------------------------------------- /model/quality_model.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import torch 4 | import torch.nn as nn 5 | from torch.nn import init 6 | import torch.nn.functional as F 7 | import torchvision 8 | 9 | 10 | class MobileNetV2_encoder(nn.Module): 11 | def __init__(self, pretrained=True): 12 | super(MobileNetV2_encoder, self).__init__() 13 | model = torchvision.models.mobilenet_v2(pretrained=True) 14 | self.low_feature = model.features[:5] 15 | self.high_feature = model.features[5:] 16 | 17 | def forward(self, input): 18 | out1 = self.low_feature(input) 19 | out2 = self.high_feature(out1) 20 | return out1, out2 21 | 22 | 23 | class LRASPPV2(nn.Module): 24 | """Lite R-ASPP""" 25 | def __init__(self, nclass=2): 26 | super(LRASPPV2, self).__init__() 27 | self.b0 = nn.Sequential(nn.Conv2d(1280, 128, 1, bias=False), 28 | nn.BatchNorm2d(128), nn.ReLU(True)) 29 | self.b1 = nn.Sequential( 30 | nn.AdaptiveAvgPool2d((1, 1)), 31 | nn.Conv2d(1280, 128, 1, bias=False), 32 | nn.Sigmoid(), 33 | ) 34 | 35 | self.project = nn.Conv2d(128, nclass, 1) 36 | self.shortcut = nn.Conv2d(32, nclass, 1) 37 | 38 | self.init_params() 39 | 40 | def init_params(self): 41 | for m in self.modules(): 42 | if isinstance(m, nn.Conv2d): 43 | init.kaiming_normal_(m.weight, mode='fan_out') 44 | if m.bias is not None: 45 | init.constant_(m.bias, 0) 46 | elif isinstance(m, nn.BatchNorm2d): 47 | init.constant_(m.weight, 1) 48 | init.constant_(m.bias, 0) 49 | elif isinstance(m, nn.Linear): 50 | init.normal_(m.weight, std=0.001) 51 | if m.bias is not None: 52 | init.constant_(m.bias, 0) 53 | 54 | def forward(self, x, y): 55 | size = x.shape[2:] 56 | feat1 = self.b0(x) 57 | feat2 = self.b1(x) 58 | feat2 = F.interpolate(feat2, size, mode='bilinear', align_corners=True) 59 | x = feat1 * feat2 # check it 60 | x = self.project(x) 61 | y = self.shortcut(y) 62 | out = F.adaptive_avg_pool2d(y, size) + x 63 | return out 64 | 65 | 66 | class MobileNetV2_Lite(nn.Module): 67 | def __init__(self, pretrained=True, mask_learn_rate=0.5): 68 | super(MobileNetV2_Lite, self).__init__() 69 | self.encoder = MobileNetV2_encoder(pretrained) 70 | 71 | self.decoder = LRASPPV2() 72 | 73 | self.linear = nn.Sequential( 74 | nn.Linear(1280, 512, True), 75 | nn.Dropout(0.5), 76 | nn.ReLU(), 77 | nn.Linear(512, 64, True), 78 | nn.Dropout(0.5), 79 | nn.ReLU(), 80 | nn.Linear(64, 1), 81 | ) 82 | self.init_params(self.linear) 83 | 84 | for p in self.parameters(): 85 | p.requires_grad = True 86 | if mask_learn_rate == 1: 87 | for p in self.linear.parameters(): 88 | p.requires_grad = False 89 | elif mask_learn_rate == 0: 90 | for p in self.encoder.parameters(): 91 | p.requires_grad = False 92 | for p in self.decoder.parameters(): 93 | p.requires_grad = False 94 | 95 | def init_params(self, target): 96 | for m in target: 97 | if isinstance(m, nn.Conv2d): 98 | init.kaiming_normal_(m.weight, mode='fan_out') 99 | if m.bias is not None: 100 | init.constant_(m.bias, 0) 101 | elif isinstance(m, nn.BatchNorm1d): 102 | init.constant_(m.weight, 1) 103 | init.constant_(m.bias, 0) 104 | elif isinstance(m, nn.BatchNorm2d): 105 | init.constant_(m.weight, 1) 106 | init.constant_(m.bias, 0) 107 | elif isinstance(m, nn.Linear): 108 | init.normal_(m.weight, std=0.001) 109 | if m.bias is not None: 110 | init.constant_(m.bias, 0) 111 | 112 | def forward(self, input): 113 | low_fea, high_fea = self.encoder(input) 114 | 115 | mask = self.decoder(high_fea, low_fea) 116 | att_mask = torch.unsqueeze(torch.softmax(mask, 1)[:, 1, :, :], 1) 117 | out_mask = nn.functional.interpolate( 118 | mask, (input.shape[2] // 4, input.shape[3] // 4), 119 | mode='bilinear', 120 | align_corners=True) 121 | 122 | pred = torch.sum(high_fea * att_mask, 123 | dim=(2, 3)) / (torch.sum(att_mask, dim=(2, 3)) + 1e-8) 124 | pred = pred.view(pred.size(0), -1) 125 | pred = self.linear(pred) 126 | return pred, out_mask 127 | 128 | 129 | if __name__ == '__main__': 130 | vn = MobileNetV2_Lite(True, False) 131 | c = torch.randn(2, 3, 640, 480) 132 | out = vn(c) 133 | 134 | print(out[0], out[1].shape) 135 | from thop import profile, clever_format 136 | 137 | flops, params = profile(vn, inputs=(c, )) 138 | flops, params = clever_format([flops, params], "%.3f") 139 | print('flops:{} params:{}'.format(flops, params)) 140 | -------------------------------------------------------------------------------- /test.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | from argparse import ArgumentParser 3 | 4 | import pickle 5 | import numpy as np 6 | import os.path as osp 7 | from PIL import Image 8 | from glob import glob 9 | from tqdm import tqdm 10 | from scipy import stats 11 | 12 | import torch 13 | from torch import nn 14 | from torch.utils.data import DataLoader 15 | from torchvision.transforms import transforms 16 | 17 | from dataset import monoSimDataset 18 | from model.quality_model import MobileNetV2_Lite 19 | 20 | 21 | class LoadConfig(object): 22 | def __init__(self): 23 | 24 | self.mode = 'test' 25 | self.dataset_path = 'data/cx1' 26 | self.model_path = "model/pretrained/1211_202056_MobileNetV2_Lite_cx2.pth" 27 | self.cfg.result_path = "" 28 | 29 | self.seed = 2248 30 | 31 | self.batch_size = 24 32 | self.device = "cuda:2" 33 | self.num_workers = 2 34 | 35 | self._change_cfg() 36 | 37 | def _change_cfg(self): 38 | parser = ArgumentParser() 39 | for name, value in vars(self).items(): 40 | parser.add_argument('--' + name, type=type(value), default=value) 41 | args = parser.parse_args() 42 | 43 | for name, value in vars(args).items(): 44 | if self.__dict__[name] != value: 45 | self.__dict__[name] = value 46 | 47 | 48 | def test(cfg): 49 | # cpu or gpu? 50 | if torch.cuda.is_available() and cfg.device is not None: 51 | device = torch.device(cfg.device) 52 | else: 53 | if not torch.cuda.is_available(): 54 | print("hey man, buy a GPU!") 55 | device = torch.device("cpu") 56 | 57 | # data 58 | print('Loading Data') 59 | test_data = monoSimDataset(path=cfg.dataset_path, 60 | mode='test', 61 | seed=cfg.seed, 62 | debug_data=False) 63 | test_data_loader = DataLoader(test_data, 64 | cfg.batch_size, 65 | shuffle=False, 66 | drop_last=True, 67 | num_workers=cfg.num_workers) 68 | 69 | # configure model 70 | print('Loading Model') 71 | model = MobileNetV2_Lite() 72 | model.to(device) 73 | if cfg.model_path: 74 | cp_data = torch.load(cfg.model_path, map_location=device) 75 | try: 76 | model.load_state_dict(cp_data['model']) 77 | except Exception as e: 78 | model.load_state_dict(cp_data['model'], strict=False) 79 | print(e) 80 | 81 | cp_data['cfg'] = '' if 'cfg' not in cp_data else cp_data['cfg'] 82 | print(cp_data['cfg']) 83 | 84 | # Start! 85 | model.eval() 86 | with torch.no_grad(): 87 | test_pred_loss = 0 88 | scores = np.zeros((1)) 89 | prediction = np.zeros((1)) 90 | for img, mask, target, _ in tqdm( 91 | test_data_loader, 92 | desc='Test', 93 | bar_format='{desc}: {n_fmt}/{total_fmt} -{percentage:3.0f}%'): 94 | img = img.to(device) 95 | target = target.to(device) 96 | pred, _ = model(img) 97 | test_pred_loss += nn.functional.mse_loss(pred, 98 | target, 99 | reduction='sum') 100 | scores = np.append(scores, target.cpu().numpy().reshape((-1))) 101 | prediction = np.append(prediction, 102 | pred.cpu().numpy().reshape((-1))) 103 | test_pred_loss = test_pred_loss / len(test_data) 104 | prediction = np.nan_to_num(prediction) 105 | srocc = stats.spearmanr(prediction[1:], scores[1:])[0] 106 | lcc = stats.pearsonr(prediction[1:], scores[1:])[0] 107 | 108 | print("Test - MSE: {:.4e}".format(test_pred_loss)) 109 | print("Test - LCC: {:.4f}, SROCC: {:.4f}".format(lcc, srocc)) 110 | 111 | 112 | def predict(cfg): 113 | # cpu or gpu? 114 | if torch.cuda.is_available() and cfg.device is not None: 115 | device = torch.device(cfg.device) 116 | else: 117 | if not torch.cuda.is_available(): 118 | print("hey man, buy a GPU!") 119 | device = torch.device("cpu") 120 | 121 | # data 122 | img_list = glob(osp.join(cfg.dataset_path, '*.bmp')) + glob( 123 | osp.join(cfg.dataset_path, '*.png')) + glob( 124 | osp.join(cfg.dataset_path, '*.jpg')) 125 | transform = transforms.Compose([ 126 | transforms.Resize(size), 127 | transforms.ToTensor(), 128 | transforms.Normalize(mean=[0.480], std=[0.200], inplace=False) 129 | ]) 130 | 131 | # configure model 132 | print('Loading Model') 133 | model = MobileNetV2_Lite() 134 | model.to(device) 135 | if cfg.model_path: 136 | cp_data = torch.load(cfg.model_path, map_location=device) 137 | try: 138 | model.load_state_dict(cp_data['model']) 139 | except Exception as e: 140 | model.load_state_dict(cp_data['model'], strict=False) 141 | print(e) 142 | 143 | cp_data['cfg'] = '' if 'cfg' not in cp_data else cp_data['cfg'] 144 | print(cp_data['cfg']) 145 | 146 | # Start! 147 | model.eval() 148 | prediction = {} 149 | with torch.no_grad(): 150 | for path in tqdm(img_list): 151 | img_name = osp.basename(path).split('.')[0] 152 | img = transform(Image.open(path)) 153 | img = img.to(device) 154 | target = target.to(device) 155 | pred, heatmap = model(img) 156 | prediction[img_name] = pred.cpu().numpy().reshape((-1)) 157 | if cfg.result_path: 158 | heatmap = torch.softmax(heatmap, 0)[1, :, :].cpu().numpy() 159 | heatmap = Image.fromarray(heatmap) 160 | heatmap.save( 161 | osp.join(cfg.result_path, img_name + '_heatmap.png')) 162 | if cfg.result_path: 163 | pickle.dump(prediction, osp.join(cfg.result_path, 'prediction.pkl')) 164 | return prediction 165 | 166 | 167 | if __name__ == '__main__': 168 | cfg = LoadConfig() 169 | if cfg.mode == 'test': 170 | test(cfg) 171 | elif cfg.mode == 'predict': 172 | prediction = predict(cfg) 173 | -------------------------------------------------------------------------------- /train.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | import os 3 | import time 4 | from argparse import ArgumentParser 5 | 6 | import numpy as np 7 | import torch 8 | from scipy import stats 9 | from torch import nn 10 | from torch.utils.data import DataLoader 11 | from torch.utils.tensorboard import SummaryWriter 12 | from tqdm import tqdm 13 | 14 | from dataset import monoSimDataset 15 | from model.loss import FocalLoss, CrossEntropy2d 16 | from model.quality_model import MobileNetV2_Lite 17 | 18 | 19 | class LoadConfig(object): 20 | def __init__(self): 21 | self.info = "" 22 | 23 | self.dataset_path = 'data/cx2' 24 | self.cp_path = "checkpoints/1203_202301_MobileNetV2_Lite/421_1.3395e-03.pth" 25 | self.cp_num = 5 26 | self.visible = True 27 | 28 | self.model = 'MobileNetV2_Lite' 29 | self.seed = 2248 30 | self.debug = False 31 | self.mask_learn_rate = 0.5 32 | self.mask_lr_decay = 0.1 33 | 34 | self.batch_size = 24 35 | self.device = "cuda:2" 36 | self.num_workers = 2 37 | 38 | self.max_epochs = 150 39 | self.lr = 4e-4 40 | self.momentum = 0.9 41 | self.weight_decay = 5e-4 42 | 43 | self._change_cfg() 44 | 45 | def _change_cfg(self): 46 | parser = ArgumentParser() 47 | for name, value in vars(self).items(): 48 | parser.add_argument('--' + name, type=type(value), default=value) 49 | args = parser.parse_args() 50 | 51 | for name, value in vars(args).items(): 52 | if self.__dict__[name] != value: 53 | self.__dict__[name] = value 54 | 55 | if self.debug: 56 | self.cp_num = 0 57 | self.visible = False 58 | 59 | def __str__(self): 60 | config = "" 61 | for name, value in vars(self).items(): 62 | config += ('%s=%s\n' % (name, value)) 63 | return config 64 | 65 | 66 | def train(cfg): 67 | # configure train 68 | train_name = time.strftime("%m%d_%H%M%S", time.localtime( 69 | )) + '_' + cfg.model + '_' + os.path.basename(cfg.dataset_path) 70 | cfg.name = train_name 71 | log_interval = int(np.ceil(cfg.max_epochs * 0.1)) 72 | print(cfg) 73 | 74 | # cpu or gpu? 75 | if torch.cuda.is_available() and cfg.device is not None: 76 | device = torch.device(cfg.device) 77 | else: 78 | if not torch.cuda.is_available(): 79 | print("hey man, buy a GPU!") 80 | device = torch.device("cpu") 81 | 82 | # data 83 | print('Loading Data') 84 | train_data = monoSimDataset(path=cfg.dataset_path, 85 | mode='train', 86 | seed=cfg.seed, 87 | debug_data=cfg.debug) 88 | train_data_loader = DataLoader(train_data, 89 | cfg.batch_size, 90 | drop_last=True, 91 | shuffle=True, 92 | num_workers=cfg.num_workers) 93 | val_data = monoSimDataset(path=cfg.dataset_path, 94 | mode='val', 95 | seed=cfg.seed, 96 | debug_data=cfg.debug) 97 | val_data_loader = DataLoader(val_data, 98 | cfg.batch_size, 99 | shuffle=False, 100 | drop_last=True, 101 | num_workers=cfg.num_workers) 102 | 103 | # configure model 104 | print('Loading Model') 105 | model = MobileNetV2_Lite(True, cfg.mask_learn_rate) 106 | assert model is not None 107 | model.to(device) 108 | if cfg.cp_path: 109 | cp_data = torch.load(cfg.cp_path, map_location=device) 110 | try: 111 | model.load_state_dict(cp_data['model']) 112 | except Exception as e: 113 | model.load_state_dict(cp_data['model'], strict=False) 114 | print(e) 115 | 116 | cp_data['cfg'] = '' if 'cfg' not in cp_data else cp_data['cfg'] 117 | print(cp_data['cfg']) 118 | 119 | # criterion and optimizer 120 | optimizer = torch.optim.Adam( 121 | filter(lambda p: p.requires_grad, model.parameters()), 122 | lr=cfg.lr, 123 | # momentum=cfg.momentum, 124 | weight_decay=cfg.weight_decay) 125 | scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, 126 | 'min', 127 | factor=0.5, 128 | verbose=True) 129 | 130 | pred_criterion = nn.MSELoss() 131 | mask_criterion = CrossEntropy2d() 132 | 133 | # checkpoint 134 | if cfg.cp_num > 0: 135 | cp_dir_path = os.path.normcase(os.path.join('checkpoints', train_name)) 136 | os.mkdir(cp_dir_path) 137 | best_cp = [] 138 | history_dir_path = os.path.normcase( 139 | os.path.join(cp_dir_path, 'history')) 140 | os.mkdir(history_dir_path) 141 | with open(os.path.normcase(os.path.join(cp_dir_path, 'config.txt')), 142 | 'w') as f: 143 | info = str(cfg) + '#' * 30 + '\npre_cfg:\n' + str( 144 | cp_data['cfg']) if cfg.cp_path else str(cfg) 145 | f.write(info) 146 | 147 | # visble 148 | if cfg.visible: 149 | log_writer = SummaryWriter(os.path.join("log", train_name)) 150 | log_writer.add_text('cur_cfg', cfg.__str__()) 151 | if cfg.cp_path: 152 | log_writer.add_text('pre_cfg', cp_data['cfg'].__str__()) 153 | 154 | # Start! 155 | print("Start training!\n") 156 | for epoch in range(1, cfg.max_epochs + 1): 157 | if epoch % int(cfg.max_epochs / 10) == 0 and cfg.mask_lr_decay < 1: 158 | cfg.mask_learn_rate *= cfg.mask_lr_decay 159 | print("[{}] Mask learn rate: {:.4e}".format( 160 | epoch, cfg.mask_learn_rate)) 161 | 162 | # train 163 | model.train() 164 | epoch_loss = 0 165 | for img, mask, target in tqdm( 166 | train_data_loader, 167 | desc='[{}] mini_batch'.format(epoch), 168 | bar_format='{desc}: {n_fmt}/{total_fmt} -{percentage:3.0f}%'): 169 | img = img.to(device) 170 | mask = mask.to(device) 171 | target = target.to(device) 172 | optimizer.zero_grad() 173 | pred, heatmap = model(img) 174 | if cfg.mask_learn_rate == 0: 175 | loss = pred_criterion(pred, target) 176 | elif cfg.mask_learn_rate == 0: 177 | loss = mask_criterion(heatmap, mask) 178 | else: 179 | loss = (1 - cfg.mask_learn_rate) * pred_criterion( 180 | pred, target) + cfg.mask_learn_rate * mask_criterion( 181 | heatmap, mask) 182 | epoch_loss += loss.item() 183 | loss.backward() 184 | optimizer.step() 185 | train_loss = epoch_loss / len(train_data_loader) 186 | scheduler.step(train_loss) 187 | 188 | print("[{}] Training - loss: {:.4e}".format(epoch, train_loss)) 189 | if cfg.visible: 190 | log_writer.add_scalar('Train/Loss', train_loss, epoch) 191 | log_writer.add_scalar('Train/lr', optimizer.param_groups[0]['lr'], 192 | epoch) 193 | 194 | # val 195 | if epoch % 5 == 0 or cfg.debug: 196 | if cfg.model.split('_')[0] == 'MobileNetV3': 197 | model.train() 198 | else: 199 | model.eval() 200 | with torch.no_grad(): 201 | val_pred_loss = 0 202 | scores = np.zeros((1)) 203 | prediction = np.zeros((1)) 204 | for img, mask, target in tqdm( 205 | val_data_loader, 206 | desc='[{}] val_batch'.format(epoch), 207 | bar_format= 208 | '{desc}: {n_fmt}/{total_fmt} -{percentage:3.0f}%'): 209 | img = img.to(device) 210 | mask = mask.to(device) 211 | target = target.to(device) 212 | pred, heatmap = model(img) 213 | val_pred_loss += nn.functional.mse_loss(pred, 214 | target, 215 | reduction='sum') 216 | scores = np.append(scores, 217 | target.cpu().numpy().reshape((-1))) 218 | prediction = np.append(prediction, 219 | pred.cpu().numpy().reshape((-1))) 220 | val_pred_loss = val_pred_loss / len(val_data) 221 | prediction = np.nan_to_num(prediction) 222 | srocc = stats.spearmanr(prediction[1:], scores[1:])[0] 223 | lcc = stats.pearsonr(prediction[1:], scores[1:])[0] 224 | 225 | print("[{}] Val - MSE: {:.4e}".format(epoch, val_pred_loss)) 226 | print("[{}] Val - LCC: {:.4f}, SROCC: {:.4f}".format( 227 | epoch, lcc, srocc)) 228 | if cfg.visible: 229 | idx = np.random.randint(0, mask.shape[0]) 230 | heatmap_s = torch.softmax(heatmap, 1)[idx, 1, :, :] 231 | log_writer.add_scalar('Val/MSE', val_pred_loss, epoch) 232 | log_writer.add_scalar('Val/LCC', lcc, epoch) 233 | log_writer.add_scalar('Val/SROCC', srocc, epoch) 234 | log_writer.add_image('Val/img', img[idx], epoch) 235 | log_writer.add_image('Val/mask', 236 | torch.squeeze(mask[idx]), 237 | epoch, 238 | dataformats='HW') 239 | log_writer.add_image('Val/heatmap', 240 | torch.squeeze(heatmap_s), 241 | epoch, 242 | dataformats='HW') 243 | 244 | # checkpoint 245 | if cfg.cp_num > 0: 246 | # model.cpu() 247 | cp_name = "{}_{:.4e}.pth".format(epoch, train_loss) 248 | 249 | if epoch < cfg.cp_num + 1: 250 | best_cp.append([cp_name, train_loss]) 251 | best_cp.sort(key=lambda x: x[1]) 252 | best_cp_path = os.path.normcase( 253 | os.path.join(cp_dir_path, cp_name)) 254 | 255 | cp_data = dict( 256 | cfg=str(cfg), 257 | model=model.state_dict(), 258 | ) 259 | torch.save(cp_data, best_cp_path) 260 | else: 261 | if train_loss < best_cp[-1][1]: 262 | os.remove( 263 | os.path.normcase( 264 | os.path.join(cp_dir_path, best_cp[-1][0]))) 265 | best_cp[-1] = [cp_name, train_loss] 266 | best_cp.sort(key=lambda x: x[1]) 267 | best_cp_path = os.path.normcase( 268 | os.path.join(cp_dir_path, cp_name)) 269 | cp_data = dict( 270 | cfg=str(cfg), 271 | model=model.state_dict(), 272 | ) 273 | torch.save(cp_data, best_cp_path) 274 | 275 | if ((log_interval > 0) and (epoch % log_interval == 0 or epoch % 100 == 0)) or \ 276 | (epoch == cfg.max_epochs): 277 | history_cp_path = os.path.normcase( 278 | os.path.join(history_dir_path, cp_name)) 279 | cp_data = dict( 280 | cfg=str(cfg), 281 | model=model.state_dict(), 282 | ) 283 | torch.save(cp_data, history_cp_path) 284 | 285 | # model.to(device) 286 | 287 | return model.cpu() 288 | 289 | 290 | if __name__ == '__main__': 291 | cfg = LoadConfig() 292 | model = train(cfg) 293 | -------------------------------------------------------------------------------- /util/IrisQualityEvaluation.cpp: -------------------------------------------------------------------------------- 1 | #include "IrisQualityEvaluation.h" 2 | 3 | #include 4 | 5 | #ifndef maximum 6 | #define maximum(a,b) (((a) > (b)) ? (a) : (b)) 7 | #endif 8 | 9 | #ifndef minimum 10 | #define minimum(a,b) (((a) < (b)) ? (a) : (b)) 11 | #endif 12 | 13 | //************************************************************************************************************************* 14 | double qeFocusMeasure(cv::Mat &srcImage, cv::Rect Roi, int downsample_factor) 15 | { 16 | assert(downsample_factor > 0); 17 | assert(srcImage.channels() == 1); 18 | 19 | cv::Mat roiImage, gradientX, gradientY; 20 | 21 | if (Roi.area() > 0) 22 | { 23 | srcImage(Roi).copyTo(roiImage); 24 | } 25 | else 26 | { 27 | srcImage.copyTo(roiImage); 28 | } 29 | 30 | if (downsample_factor != 1) 31 | { 32 | double resize_ratio = 1 / (double)downsample_factor; 33 | cv::resize(roiImage, roiImage, cv::Size(), resize_ratio, resize_ratio); 34 | } 35 | 36 | //有一定帮助 但是速度不可接受 37 | //cv::equalizeHist(roiImage, roiImage); 38 | 39 | cv::Sobel(roiImage, gradientX, CV_32F, 1, 0); 40 | cv::Sobel(roiImage, gradientY, CV_32F, 0, 1); 41 | 42 | cv::pow(gradientX, 2, gradientX); 43 | cv::pow(gradientY, 2, gradientY); 44 | roiImage = gradientX + gradientY; 45 | double fm = -1; 46 | cv::sqrt(roiImage, roiImage); 47 | fm = cv::mean(roiImage)[0]; 48 | 49 | roiImage.release(); 50 | gradientX.release(); 51 | gradientY.release(); 52 | 53 | return fm; 54 | } 55 | 56 | cv::Rect qeFaceLocation(cv::Mat &srcImage, int threshold, int downsample_factor, double ystart, double hrange) 57 | { 58 | 59 | assert(downsample_factor > 0); 60 | assert(srcImage.channels() == 1); 61 | 62 | int width = srcImage.cols; 63 | int height = srcImage.rows; 64 | 65 | int x_range = int(width / downsample_factor); 66 | int y_range = int(height / downsample_factor); 67 | 68 | std::vector w_sum; 69 | std::vector h_sum; 70 | 71 | for (int x = 0; x < x_range; x++) 72 | { 73 | w_sum.push_back(0); 74 | } 75 | for (int y = 0; y < y_range; y++) 76 | { 77 | h_sum.push_back(0); 78 | } 79 | 80 | double color_count[256]; 81 | for (int i = 0; i < 256; i++) 82 | { 83 | color_count[i] = 0; 84 | } 85 | int value = 0; 86 | for (int x = 0; x < x_range; x++) 87 | { 88 | for (int y = 0; y < y_range; y++) 89 | { 90 | value = srcImage.data[(y * downsample_factor) * width + (x * downsample_factor)]; 91 | color_count[value] += 1; 92 | } 93 | } 94 | 95 | 96 | // 分别沿xy轴统计亮度大于阈值的像素数 97 | //int value = 0; 98 | for (int x = 0; x < x_range; x++) 99 | { 100 | for (int y = 0; y < y_range; y++) 101 | { 102 | value = srcImage.data[(y * downsample_factor) * width + (x * downsample_factor)]; 103 | //value = int(srcImage.at(y * downsample_factor, x * downsample_factor)); 104 | if (value > threshold) 105 | { 106 | w_sum[x] += 1; 107 | h_sum[y] += 1; 108 | } 109 | } 110 | } 111 | 112 | // 搜索选择区域范围 113 | int w_start = 0; 114 | int w_end = 0; 115 | for (int x = 1; x < x_range; x++) 116 | { 117 | if (w_sum[x] > 0) 118 | { 119 | w_start = x; 120 | break; 121 | } 122 | } 123 | for (int x = x_range - 1; x >= 0; x--) 124 | { 125 | if (w_sum[x] > 0) 126 | { 127 | w_end = x; 128 | break; 129 | } 130 | } 131 | int h_start = 0; 132 | int h_end = 0; 133 | for (int y = 1; y < y_range; y++) 134 | { 135 | if (h_sum[y] > 0) 136 | { 137 | h_start = y; 138 | break; 139 | } 140 | } 141 | for (int y = y_range - 1; y >= 0; y--) 142 | { 143 | if (h_sum[y] > 0) 144 | { 145 | h_end = y; 146 | break; 147 | } 148 | } 149 | 150 | // 计算roi 151 | int roi_x = w_start * downsample_factor; 152 | int roi_w = (w_end - w_start) * downsample_factor; 153 | int roi_y = int((h_start + (h_end - h_start) * ystart) * downsample_factor); 154 | int roi_h = int((h_end - h_start) * hrange * downsample_factor); 155 | 156 | cv::Rect roi = cv::Rect(roi_x, roi_y, roi_w, roi_h); 157 | 158 | return roi; 159 | } 160 | 161 | void qeMaskDenoise(cv::Mat &srcMask) 162 | { 163 | assert(srcMask.channels() == 1); 164 | 165 | cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(5, 5)); 166 | cv::morphologyEx(srcMask, srcMask, cv::MORPH_OPEN, kernel); 167 | cv::morphologyEx(srcMask, srcMask, cv::MORPH_CLOSE, kernel); 168 | 169 | kernel.release(); 170 | } 171 | 172 | cv::Rect qeIrisLocation(cv::Mat &srcIris) 173 | { 174 | int width = srcIris.cols; 175 | int height = srcIris.rows; 176 | 177 | cv::Rect roi = qeFaceLocation(srcIris, 128, 4, 0, 1); 178 | //roi = roi + cv::Point(-8, -5); 179 | //roi = roi + cv::Size(16, 10); 180 | 181 | return roi; 182 | } 183 | 184 | double qeImageEntropy(cv::Mat& srcImage, int downsample_factor) 185 | { 186 | 187 | assert(srcImage.channels() == 1); 188 | 189 | double ent = 0.0; 190 | int imgValue = 0; 191 | double p = 0.0; 192 | 193 | int width = srcImage.cols; 194 | int height = srcImage.rows; 195 | 196 | int x_range = int(width / downsample_factor); 197 | int y_range = int(height / downsample_factor); 198 | 199 | double color_count[256]; 200 | for (int i = 0; i < 256; i++) 201 | { 202 | color_count[i] = 0; 203 | } 204 | 205 | for (int x = 0; x < x_range; x++) 206 | { 207 | for (int y = 0; y < y_range; y++) 208 | { 209 | imgValue = srcImage.data[(y * downsample_factor) * width + (x * downsample_factor)]; 210 | color_count[imgValue] += 1; 211 | } 212 | } 213 | for (int i = 0; i < 256; i++) 214 | { 215 | p = color_count[i] / (x_range * y_range); 216 | if (p > 0) 217 | { 218 | ent -= p * log(p); 219 | } 220 | 221 | } 222 | 223 | return ent; 224 | } 225 | 226 | 227 | void qeMinAreaRect(cv::Mat& srcMask) 228 | { 229 | std::vector> contours; 230 | std::vector hierarchy; 231 | cv::Mat binaryImage; 232 | cv::threshold(srcMask, binaryImage, 100, 255, CV_THRESH_BINARY_INV); 233 | cv::findContours(binaryImage, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, cv::Point()); 234 | cv::RotatedRect rect = cv::minAreaRect(contours); 235 | 236 | } 237 | 238 | 239 | std::vector qeIrisQuality(cv::Mat &srcImage, cv::Mat &srcMask, cv::Mat &srcIris, cv::Mat &srcPupil) 240 | { 241 | //vector &quality[focus measure, gray, usable aera, dilation, iris shape, pupil shape] 242 | 243 | assert(srcImage.channels() == 1); 244 | assert(srcMask.channels() == 1); 245 | assert(srcIris.channels() == 1); 246 | assert(srcPupil.channels() == 1); 247 | 248 | cv::Mat roiImage, roiMask, roiIris, roiPupil; 249 | // cv::Mat gradientX, gradientY, gradient; 250 | 251 | srcIris.copyTo(roiIris); 252 | qeMaskDenoise(roiIris); 253 | cv::Rect IrisRect = qeIrisLocation(roiIris); 254 | double qeIrisradius = sqrt(pow(IrisRect.tl().x - IrisRect.br().x, 2) + pow(IrisRect.tl().y - IrisRect.br().y, 2)) / 2; 255 | cv::Point IrisCenter; 256 | IrisCenter.x = (IrisRect.tl().x + IrisRect.br().x) / 2; 257 | IrisCenter.y = (IrisRect.tl().y + IrisRect.br().y) / 2; 258 | 259 | srcPupil.copyTo(roiPupil); 260 | qeMaskDenoise(roiPupil); 261 | cv::Rect PupilRect = qeIrisLocation(roiPupil); 262 | cv::Point PupilCenter; 263 | PupilCenter.x = (PupilRect.tl().x + PupilRect.br().x) / 2; 264 | PupilCenter.y = (PupilRect.tl().y + PupilRect.br().y) / 2; 265 | 266 | double qeConcentricity = 1 - (sqrt(pow(IrisCenter.x - PupilCenter.x, 2) + pow(IrisCenter.y - PupilCenter.y, 2)) / qeIrisradius); 267 | 268 | // Margin adequacy 269 | double LM = (IrisCenter.x - qeIrisradius) / qeIrisradius; 270 | double RM = (srcImage.rows - (IrisCenter.x + qeIrisradius)) / qeIrisradius; 271 | double UM = (IrisCenter.y - qeIrisradius) / qeIrisradius; 272 | double DM = (srcImage.cols - (IrisCenter.y + qeIrisradius)) / qeIrisradius; 273 | double LEFT_MARGIN = maximum(0, minimum(1, LM / 0.6)); 274 | double RIGHT_MARGIN = maximum(0, minimum(1, RM / 0.6)); 275 | double UP_MARGIN = maximum(0, minimum(1, UM / 0.2)); 276 | double DOWN_MARGIN = maximum(0, minimum(1, DM / 0.2)); 277 | double qeMargin = minimum(minimum(LEFT_MARGIN, RIGHT_MARGIN), minimum(UP_MARGIN, DOWN_MARGIN)); 278 | 279 | srcImage(IrisRect).copyTo(roiImage); 280 | srcMask(IrisRect).copyTo(roiMask); 281 | srcIris(IrisRect).copyTo(roiIris); 282 | srcPupil(IrisRect).copyTo(roiPupil); 283 | 284 | 285 | const int width = roiImage.cols; 286 | const int height = roiImage.rows; 287 | 288 | 289 | double color_count[256]; 290 | for (int i = 0; i < 256; i++) 291 | { 292 | color_count[i] = 0; 293 | } 294 | 295 | double num_mask_pix = 0; 296 | double num_iris_pix = 0; 297 | double num_pupil_pix = 0; 298 | double focus_count = 0; 299 | 300 | int imgValue = 0; 301 | int maskValue = 0; 302 | int irisValue = 0; 303 | int pupilValue = 0; 304 | for (int x = 0; x < width; x++) 305 | { 306 | for (int y = 0; y < height; y++) 307 | { 308 | imgValue = roiImage.data[y * width + x]; 309 | maskValue = roiMask.data[y * width + x]; 310 | irisValue = roiIris.data[y * width + x]; 311 | pupilValue = roiPupil.data[y * width + x]; 312 | 313 | if (irisValue > 0) 314 | { 315 | num_iris_pix += 1; 316 | if (pupilValue < 1 && maskValue > 0) 317 | { 318 | num_mask_pix += 1; 319 | color_count[imgValue] += 1; 320 | } 321 | } 322 | if (pupilValue > 0) 323 | { 324 | num_pupil_pix += 1; 325 | } 326 | 327 | } 328 | } 329 | 330 | double p = 0; 331 | double ent = 0.0; 332 | for (int i = 0; i < 256; i++) 333 | { 334 | p = color_count[i] / num_mask_pix; 335 | if (p > 0) 336 | { 337 | ent -= p * log(p); 338 | } 339 | 340 | } 341 | 342 | std::vector quality; 343 | 344 | quality.push_back(qeFocusMeasure(srcImage, IrisRect, 1)); 345 | quality.push_back(ent); 346 | quality.push_back(num_mask_pix /(num_iris_pix - num_pupil_pix)); 347 | quality.push_back(sqrt(num_pupil_pix / num_iris_pix)); 348 | quality.push_back(qeIrisradius); 349 | quality.push_back(qeConcentricity); 350 | quality.push_back(qeMargin); 351 | 352 | 353 | roiImage.release(); 354 | roiMask.release(); 355 | roiIris.release(); 356 | roiPupil.release(); 357 | 358 | return quality; 359 | } 360 | 361 | //************************************************************************************************************************* 362 | 363 | int qeFaceValidCheck(cv::Mat &srcImage, cv::Rect &face_roi) 364 | { 365 | int flag = qeSuccess; 366 | try 367 | { 368 | face_roi = qeFaceLocation(srcImage, qeFaceBinarizationThreshold, qeFaceLocationDownsampleFactor, qeFaceLocationYAxisStart, qeFaceLocationHeightRange); 369 | 370 | } 371 | catch (...) 372 | { 373 | flag = qeFaceLocationError; 374 | } 375 | if (flag == qeSuccess) 376 | { 377 | if (face_roi.area() < qeMinFaceAera) { flag = qeFaceAeraTooSmall; } 378 | if (face_roi.area() > qeMaxFaceAera) { flag = qeFaceAeraTooLarge; } 379 | 380 | if (qeDebug == 1) { std::cout << face_roi.area() << ';'; } 381 | } 382 | 383 | return flag; 384 | } 385 | 386 | int qeFaceQualityCheck(cv::Mat &srcImage, cv::Rect &face_roi) 387 | { 388 | int flag = qeSuccess; 389 | double focus_score = -1; 390 | double ent = -1; 391 | try 392 | { 393 | focus_score = qeFocusMeasure(srcImage, face_roi, qeFaceFocusMeasureDownsampleFactor); 394 | if (qeDebug == 1) { std::cout << focus_score << ','; } 395 | } 396 | catch (...) 397 | { 398 | flag = qeFocusMeasureError; 399 | } 400 | if (flag == qeSuccess) 401 | { 402 | if (focus_score < qeMaxFaceFocusScore) { flag = qeFaceDefocusBlur; } 403 | if (focus_score > qeMinFaceFocusScore) { flag = qeFaceMotionBlur; } 404 | } 405 | try 406 | { 407 | ent = qeImageEntropy(srcImage, 8); 408 | if (qeDebug == 1) { std::cout << ent << ';'; } 409 | } 410 | catch (...) 411 | { 412 | flag = qeEntropyCalculateError; 413 | } 414 | if (flag == qeSuccess) 415 | { 416 | if (ent < qeMinFaceEntropy) { flag = qeFaceLowEntropy; } 417 | } 418 | return flag; 419 | } 420 | 421 | int qeIrisQualityCheck(cv::Mat &srcImage, cv::Mat &srcMask, cv::Mat &srcIris, cv::Mat &srcPupil) 422 | { 423 | int flag = qeSuccess; 424 | std::vector quality; 425 | try 426 | { 427 | quality = qeIrisQuality(srcImage, srcMask, srcIris, srcPupil); 428 | if (qeDebug == 1) { 429 | std::cout << quality[0] << ',' << quality[1] << ',' << quality[2] << ',' << quality[3] << ',' << quality[4] << ','; 430 | std::cout << quality[5] << ';' << quality[6] << ';'; 431 | } 432 | } 433 | catch (...) 434 | { 435 | flag = qeFocusMeasureError; 436 | } 437 | if (flag == qeSuccess) 438 | { 439 | if (quality[4] < qeMinIrisradius) { return qeIrisradiusTooSmall; } 440 | if (quality[2] > qeMaxIrisUsableAera) { return qeIrisSegmentError; } 441 | if (quality[2] < qeMinIrisUsableAera) { return qeIrisAeraTooSmall; } 442 | if (quality[1] < qeMinIrisEntropy) { return qeIrisLowEntropy; } 443 | if (quality[0] < qeMinIrisFocusScore) { return qeIrisDefocusBlur; } 444 | if (quality[0] > qeMaxIrisFocusScore) { return qeIrisMotionBlur; } 445 | if (quality[3] > qeMaxPupilDilation) { return qePupilAeraTooBig; } 446 | if (quality[3] < qeMinPupilDilation) { return qePupilAeraTooSmall; } 447 | if (quality[5] < qeMinConcentricity) { return qeConcentricityTooSmall; } 448 | if (quality[6] < qeMinMargin) { return qeMarginTooSmall; } 449 | } 450 | 451 | return flag; 452 | } 453 | -------------------------------------------------------------------------------- /util/IrisQualityEvaluation.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | //***************************************** 参数设定 ************************************************************** 12 | 13 | //控制设置 14 | #define qeDebug 1 15 | 16 | //常规参数 17 | #define qeFaceBinarizationThreshold 180 18 | #define qeFaceLocationDownsampleFactor 16 19 | #define qeFaceLocationYAxisStart 0.15 20 | #define qeFaceLocationHeightRange 0.5 21 | #define qeFaceFocusMeasureDownsampleFactor 2 22 | 23 | //阈值 24 | #define qeMinFaceAera 500000 25 | #define qeMaxFaceAera 6266880 26 | #define qeMinFaceEntropy 3.4 27 | #define qeMaxFaceFocusScore 38.0 28 | #define qeMinFaceFocusScore 20.0 29 | #define qeMaxIrisFocusScore 47.0 30 | #define qeMinIrisFocusScore 28.0 31 | #define qeMinIrisEntropy 6 32 | #define qeMaxIrisUsableAera 1.0 33 | #define qeMinIrisUsableAera 0.7 34 | #define qeMaxPupilDilation 0.7 35 | #define qeMinPupilDilation 0.2 36 | #define qeMinIrisradius 80 37 | #define qeMinConcentricity 0.9 38 | #define qeMinMargin 0.8 39 | 40 | //********************************************* 错误代码 ************************************************************** 41 | 42 | //正常 43 | #define qeSuccess 0 44 | 45 | //运行错误 46 | #define qeFocusMeasureError -1001 47 | #define qeFaceLocationError -1002 48 | #define qeEntropyCalculateError -1003 49 | 50 | //低质量图像 51 | #define qeFaceAeraTooSmall -1011 52 | #define qeFaceAeraTooLarge -1012 53 | #define qeFaceLowEntropy -1013 54 | #define qeFaceDefocusBlur -1021 55 | #define qeFaceMotionBlur -1022 56 | #define qeIrisDefocusBlur -1023 57 | #define qeIrisMotionBlur -1024 58 | #define qeIrisLowEntropy -1031 59 | #define qeIrisSegmentError -1032 60 | #define qeIrisAeraTooSmall -1033 61 | #define qePupilAeraTooSmall -1034 62 | #define qePupilAeraTooBig -1035 63 | #define qeIrisradiusTooSmall -1036 64 | #define qeConcentricityTooSmall -1037 65 | #define qeMarginTooSmall -1038 66 | 67 | /********************************************************************************************************* 68 | 函数类型:int 69 | 函数参数: 70 | 输入 71 | cv::Mat& srcImage 72 | 含义:单通道脸部图像 73 | 74 | 输出 75 | cv::Rect& face_roi 76 | 含义:可能含有眼部的区域,大小不定 77 | 78 | 返回值类型:int 79 | 含义:状态值,参见错误代码 80 | 81 | 函数功能:排除不含有效人脸或人脸面积过大的无效图像,并返回眼部区域粗估计结果. 82 | **********************************************************************************************************/ 83 | int qeFaceValidCheck(cv::Mat& srcImage, cv::Rect& face_roi); 84 | 85 | /********************************************************************************************************* 86 | 函数类型:int 87 | 函数参数: 88 | 输入 89 | 1.cv::Mat& srcImage 90 | 含义:单通道脸部图像 91 | 92 | 2.cv::Rect& face_roi 93 | 含义:可能含有眼部的区域,大小不定 94 | 95 | 输出 96 | 97 | 返回值类型:int 98 | 含义:状态值,参见错误代码 99 | 100 | 函数功能:排除脸部区域模糊和欠曝/过曝图像 101 | **********************************************************************************************************/ 102 | int qeFaceQualityCheck(cv::Mat& srcImage, cv::Rect& face_roi); 103 | 104 | /********************************************************************************************************* 105 | 函数类型:int 106 | 函数参数: 107 | 输入 108 | 1. cv::Mat &srcImage 109 | 含义:单通道眼部图像 110 | 111 | 2. cv::Mat &srcMask 112 | 含义:单通道mask,0为黑色(遮挡),255为白色 113 | 114 | 3. cv::Mat &srcIris 115 | 含义:单通道Iris mask,0为黑色(遮挡),255为白色 116 | 117 | 4. cv::Mat &srcPupil 118 | 含义:单通道Pupil mask,0为黑色(遮挡),255为白色 119 | 120 | 输出 121 | 122 | 返回值类型:int 123 | 含义:状态值,参见错误代码 124 | 125 | 函数功能:排除虹膜区域模糊,欠曝/过曝,有效面积比小和瞳孔缩放过度图像 126 | 备注: 输入的图像需要为原始比例(不能被缩放为方形) 127 | **********************************************************************************************************/ 128 | int qeIrisQualityCheck(cv::Mat& srcImage, cv::Mat& srcMask, cv::Mat& srcIris, cv::Mat& srcPupil); 129 | 130 | 131 | 132 | /********************************************************************************************************* 133 | 函数类型:double 134 | 函数参数: 135 | 输入 136 | 1. cv::Mat &srcImage 137 | 含义:原始图像,未经过缩放等操作。 138 | 139 | 2.cv::Rect Roi 140 | 含义:进行质量评价的区域。 141 | 142 | 3.int downsample_factor 143 | 含义:图像缩小的倍数,不应当小于1。 144 | 145 | 输出 146 | 返回值类型:double 147 | 含义:模糊度分数。 148 | 149 | 函数功能: 150 | 计算图像离焦模糊的程度。 151 | 152 | 备注:图像中包含大量头发区域和运动模糊等因素会导致得分过高。 153 | **********************************************************************************************************/ 154 | double qeFocusMeasure(cv::Mat &srcImage, cv::Rect Roi, int downsample_factor = 2); 155 | 156 | /********************************************************************************************************* 157 | 函数类型:cv::Rect 158 | 函数参数: 159 | 输入 160 | 1. cv::Mat &srcImage 161 | 含义:原始图像,未经过缩放等操作。 162 | 163 | 2.uchar threshold 164 | 含义:二值化阈值,实验测试80可以有效确定脸部区域。 165 | 166 | 3.double downsample_factor 167 | 含义:图像缩小的倍数,不应当小于1。计算时是隔downsample_factor行/列遍历像素统计,设置到16以上可以提升性能。 168 | 169 | 4.double ystart, double hrange 170 | 含义:roi左上角下移比例和高度缩小比例,用于调整roi区域位置和大小。ystart=0.15,hrange=0.5可以有效确定脸部区域。 171 | 172 | 输出 173 | 174 | 1. cv::Rect &roi 175 | 含义:脸部区域 176 | 177 | 返回值类型:cv::Rect 178 | 含义:脸部区域roi. 179 | 180 | 函数功能: 181 | 根据图像二值化结果粗估计人脸位置和大小。 182 | 备注:当ystart=0.15,hrange=0.5时,roi尺寸小于800*400时,可认为图像中不包含有效人脸。 183 | **********************************************************************************************************/ 184 | cv::Rect qeFaceLocation(cv::Mat &srcImage, int threshold = 180, int downsample_factor = 16, double ystart = 0.15, double hrange = 0.5); 185 | 186 | /********************************************************************************************************* 187 | 函数类型:std::vector 188 | 函数参数: 189 | 输入 190 | 1. cv::Mat &srcImage 191 | 含义:单通道眼部图像 192 | 193 | 2. cv::Mat &srcMask 194 | 含义:单通道mask,0为黑色(遮挡),255为白色 195 | 196 | 3. cv::Mat &srcIris 197 | 含义:单通道Iris mask,0为黑色(遮挡),255为白色 198 | 199 | 4. cv::Mat &srcPupil 200 | 含义:单通道Pupil mask,0为黑色(遮挡),255为白色 201 | 202 | 输出 203 | 204 | 返回值类型:std::vector 205 | 含义:质量分数,共7个元素,分别为虹膜区域清晰度,虹膜区域灰度分布,虹膜区域有效面积比,瞳孔缩放度,虹膜半径,虹膜-瞳孔同心度,边界余量 206 | 注:输入的vector &quality必须为空 207 | 208 | 函数功能:在虹膜定位分割的基础上对虹膜进行质量评价 209 | 210 | 备注:质量分数可能会增加其他元素,但已有的顺序不变 211 | **********************************************************************************************************/ 212 | std::vector qeIrisQuality(cv::Mat &srcImage, cv::Mat &srcMask, cv::Mat &srcIris, cv::Mat &srcPupil); 213 | 214 | /********************************************************************************************************* 215 | 函数类型:double 216 | 函数参数: 217 | 输入 218 | 1. cv::Mat &srcImage 219 | 含义:单通道图像 220 | 221 | 2.int downsample_factor 222 | 含义:图像缩小的倍数,不应当小于1。 223 | 224 | 输出 225 | 226 | 返回值类型:double 227 | 含义:图像熵值 228 | 229 | 函数功能:评估整个图像的灰度(亮度)分布. 230 | **********************************************************************************************************/ 231 | double qeImageEntropy(cv::Mat& srcImage, int downsample_factor = 1); 232 | 233 | /********************************************************************************************************* 234 | 函数类型:void 235 | 函数参数: 236 | 输入 237 | cv::Mat &srcMask 238 | 含义:单通道掩膜图像 239 | 240 | 输出 241 | 无 242 | 243 | 函数功能:去除掩膜的噪点与填补小的漏洞,通过一次开运算与闭运算完成. 244 | 245 | 注:它是原地修改的. 246 | **********************************************************************************************************/ 247 | void qeMaskDenoise(cv::Mat &srcMask); 248 | 249 | /********************************************************************************************************* 250 | 函数类型:cv::Rect 251 | 函数参数: 252 | 输入 253 | cv::Mat &srcIris 254 | 含义:单通道图像 255 | 256 | 输出 257 | 258 | 返回值类型:cv::Rect 259 | 含义:补全的虹膜区域 260 | 261 | 函数功能:根据掩膜图像确定虹膜区域,减少计算量. 262 | **********************************************************************************************************/ 263 | cv::Rect qeIrisLocation(cv::Mat &srcIris); 264 | 265 | -------------------------------------------------------------------------------- /util/eye_quality_fact.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import cv2 3 | 4 | 5 | def ellipse2circle(param): 6 | if len(param) == 5: 7 | r = int((param[2] + param[3]) / 2) 8 | new_param = (param[0], param[1], r) 9 | elif len(param) == 3: 10 | new_param = param 11 | else: 12 | new_param = () 13 | return new_param 14 | 15 | 16 | def points_in_circle(mask, circle): 17 | points = [] 18 | radius = circle[2]**2 19 | for y, x in np.where(mask == True): 20 | if (x - circle[0])**2 + (y - circle[1])**2 <= radius: 21 | points.append((x, y)) 22 | return set(points) 23 | 24 | 25 | def points_out_circle(mask, circle): 26 | points = [] 27 | radius = circle[2]**2 28 | for y, x in np.where(mask == True): 29 | if (x - circle[0])**2 + (y - circle[1])**2 > radius: 30 | points.append((x, y)) 31 | return set(points) 32 | 33 | 34 | def points_between_circle(mask, circle1, circle2): 35 | points = [] 36 | radius1 = circle1[2]**2 37 | radius2 = circle2[2]**2 38 | for x in range(mask.shape[1]): 39 | for y in range(mask.shape[0]): 40 | conditions = (mask[y, x] == True) and ( 41 | (x - circle1[0])**2 + (y - circle1[1])**2 > radius1) and ( 42 | (x - circle2[0])**2 + (y - circle2[1])**2 <= radius2) 43 | if conditions: 44 | points.append((x, y)) 45 | return set(points) 46 | 47 | 48 | # ############################################################################# 49 | 50 | 51 | def sharpness(img): 52 | # Sharpness (defocus/motion) 53 | gaussianX = cv2.Sobel(img, cv2.CV_16U, 1, 0) 54 | gaussianY = cv2.Sobel(img, cv2.CV_16U, 1, 0) 55 | fm = np.mean(np.sqrt(gaussianX**2 + gaussianY**2)) 56 | return fm 57 | 58 | 59 | def iris_size(iris_param): 60 | # Iris size (iris radius in pixel) 61 | if len(iris_param) == 3: 62 | r = iris_param[2] 63 | elif len(iris_param) == 5: 64 | r = int((iris_param[2] + iris_param[3]) / 2) 65 | else: 66 | r = 0 67 | return r 68 | 69 | 70 | def dilation(iris_param, pupil_param): 71 | # Pupil iris ratio (ratio of pupil diameter over iris diameter) 72 | if len(iris_param) == 3 and len(pupil_param) == 3: 73 | ri = iris_param[2] 74 | pi = pupil_param[2] 75 | elif len(iris_param) == 5 and len(pupil_param) == 5: 76 | ri = int((iris_param[2] + iris_param[3]) / 2) 77 | pi = int((pupil_param[2] + pupil_param[3]) / 2) 78 | else: 79 | ri, pi = 0, 0 80 | 81 | if ri != 0 and pi != 0: 82 | dilation_ratio = pi / ri * 100 83 | else: 84 | dilation_ratio = -1 85 | return dilation_ratio 86 | 87 | 88 | def gray_level_spread(img, mask): 89 | # Gray level spread 90 | img = img.astype(np.int) 91 | img[mask != True] = -1 92 | usable_pix_num = np.sum(mask) 93 | ent = 0.0 94 | for i in range(256): 95 | p = np.sum(img == i) / usable_pix_num 96 | if p != 0: 97 | ent -= p * np.log2(p) 98 | return ent 99 | 100 | 101 | def usable_area(mask, iris_param, pupil_param): 102 | # Usable iris area (percentage of usable iris area) 103 | 104 | # usable_area = points_between_circle(mask, pupil_param, iris_param) 105 | # all_area = points_between_circle( 106 | # np.ones_like(mask).astype(np.bool), pupil_param, iris_param) 107 | # usable_area_ratio = len(usable_area) / len(all_area) * 100 108 | # return usable_area_ratio 109 | 110 | usable_area = mask.sum() 111 | all_area = np.pi * (iris_param[2]**2 - pupil_param[2]**2) 112 | usable_area_ratio = usable_area / all_area * 100 113 | return usable_area_ratio 114 | 115 | 116 | def iris_sclera_contrast(img, mask, iris_param, pupil_param): 117 | pass 118 | 119 | 120 | def iris_pupil_contrast(img, mask, iris_param, pupil_param): 121 | pass 122 | 123 | 124 | # ############################################################################ 125 | def ini_reader(filepath): 126 | with open(filepath, 'r') as f: 127 | data = [x.strip() for x in f.readlines()] 128 | if len(data) == 15: 129 | # ellipse 130 | iris_param = [float(x.split('=')[1]) for x in data[2:7]] 131 | pupil_param = [float(x.split('=')[1]) for x in data[10:15]] 132 | flag = 'ellipse' 133 | elif len(data) == 11: 134 | # circle 135 | iris_param = [float(x.split('=')[1]) for x in data[2:5]] 136 | pupil_param = [float(x.split('=')[1]) for x in data[8:11]] 137 | flag = 'circle' 138 | else: 139 | # None 140 | iris_param = None 141 | pupil_param = None 142 | flag = None 143 | return flag, iris_param, pupil_param 144 | 145 | 146 | if __name__ == "__main__": 147 | import os 148 | from glob import glob 149 | from tqdm import tqdm 150 | import shutil 151 | 152 | with open('data/cx2/train.txt', 'r') as f: 153 | namelist = [x.split('.')[0] for x in f.readlines()] 154 | 155 | quality_map = [] 156 | errors = [] 157 | for filename in tqdm(namelist, ncols=79, ascii=True): 158 | try: 159 | img = cv2.imread( 160 | 'data/cx2/Image/{}.bmp'.format(filename), 0) 161 | mask = cv2.imread( 162 | 'data/cx2/Result/Mask/{}.png'.format(filename), 0) 163 | if mask.shape != img.shape: 164 | mask = cv2.resize(mask, 165 | (img.shape[1], img.shape[0])).astype(np.bool) 166 | else: 167 | mask = mask.astype(np.bool) 168 | flag, iris_param, pupil_param = ini_reader( 169 | 'data/cx2/Result/seg_param/{}.ini'.format(filename)) 170 | 171 | fm = sharpness(img) 172 | ir = iris_size(iris_param) 173 | dr = dilation(iris_param, pupil_param) 174 | gls = gray_level_spread(img, mask) 175 | uar = usable_area(mask, iris_param, pupil_param) 176 | quality_map.append((filename + '.bmp', fm, ir, dr, gls, uar)) 177 | except Exception as e: 178 | print(e) 179 | 180 | with open('cx2_train_quality.txt', 'w') as f: 181 | for line in quality_map: 182 | f.write('{}, {} {} {} {} {}\n'.format(*line)) 183 | 184 | 185 | with open('data/cx1/train.txt', 'r') as f: 186 | namelist = [x.split('.')[0] for x in f.readlines()] 187 | 188 | quality_map = [] 189 | errors = [] 190 | for filename in tqdm(namelist, ncols=79, ascii=True): 191 | try: 192 | img = cv2.imread( 193 | 'data/cx1/Image/{}.bmp'.format(filename), 0) 194 | mask = cv2.imread( 195 | 'data/cx1/Mask/{}.png'.format(filename), 0) 196 | if mask.shape != img.shape: 197 | mask = cv2.resize(mask, 198 | (img.shape[1], img.shape[0])).astype(np.bool) 199 | else: 200 | mask = mask.astype(np.bool) 201 | flag, iris_param, pupil_param = ini_reader( 202 | 'data/cx1/seg_param/{}.ini'.format(filename)) 203 | 204 | fm = sharpness(img) 205 | ir = iris_size(iris_param) 206 | dr = dilation(iris_param, pupil_param) 207 | gls = gray_level_spread(img, mask) 208 | uar = usable_area(mask, iris_param, pupil_param) 209 | quality_map.append((filename + '.bmp', fm, ir, dr, gls, uar)) 210 | except Exception as e: 211 | print(e) 212 | 213 | with open('cx1_train_quality.txt', 'w') as f: 214 | for line in quality_map: 215 | f.write('{}, {} {} {} {} {}\n'.format(*line)) -------------------------------------------------------------------------------- /util/fmeasure.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | 5 | def fmeasure(img, measure='GRAS', roi=None): 6 | if roi is not None: 7 | img = img[roi[1]:roi[1] + roi[3], roi[0]:roi[0] + roi[2]] 8 | 9 | img = img.astype(np.double) 10 | 11 | if measure == 'GRAT': 12 | # >5.5 13 | Th = 0 14 | img_x = img.copy() 15 | img_y = img.copy() 16 | img_y[:-1, :] = np.diff(img, axis=0) 17 | img_x[:, :-1] = np.diff(img, axis=1) 18 | fm = np.maximum(np.abs(img_x), np.abs(img_y)) 19 | fm[fm < Th] = 0 20 | fm = np.sum(fm / np.sum(np.sum(fm != 0))) 21 | 22 | elif measure == 'GLVN': 23 | # < 17 24 | fm = np.std(img)**2 / np.mean(img) 25 | 26 | elif measure == 'GRAE': 27 | img_x = img.copy() 28 | img_y = img.copy() 29 | img_y[:-1, :] = np.diff(img, axis=0) 30 | img_x[:, :-1] = np.diff(img, axis=1) 31 | fm = np.mean(img_x**2 + img_y**2) 32 | 33 | elif measure == 'GRAS': 34 | # >20.5 35 | img_x = np.diff(img, axis=1) 36 | img_x[img_x < 0] = 0 37 | fm = img_x**2 38 | fm = np.mean(fm) 39 | 40 | elif measure == 'LAPV': 41 | """ 42 | Implements the Variance of Laplacian (LAP4) focus measure 43 | operator. Measures the amount of edges present in the image. 44 | """ 45 | fm = np.std(cv2.Laplacian(img, cv2.CV_64F))**2 46 | 47 | elif measure == "LAPM": 48 | """ 49 | Implements the Modified Laplacian (LAP2) focus measure 50 | operator. Measures the amount of edges present in the image. 51 | """ 52 | kernel = np.array([-1, 2, -1]) 53 | laplacianX = np.abs(cv2.filter2D(img, -1, kernel)) 54 | laplacianY = np.abs(cv2.filter2D(img, -1, kernel.T)) 55 | fm = np.mean(laplacianX + laplacianY) 56 | 57 | elif measure == "TENG": 58 | """ 59 | Implements the Tenengrad (TENG) focus measure operator. 60 | Based on the gradient of the image. 61 | """ 62 | gaussianX = cv2.Sobel(img, cv2.CV_64F, 1, 0) 63 | gaussianY = cv2.Sobel(img, cv2.CV_64F, 1, 0) 64 | fm = np.mean(gaussianX**2 + gaussianY**2) 65 | 66 | elif measure == "TENV": 67 | gaussianX = cv2.Sobel(img, cv2.CV_64F, 1, 0) 68 | gaussianY = cv2.Sobel(img, cv2.CV_64F, 1, 0) 69 | fm = np.std(gaussianX**2 + gaussianY**2)**2 70 | 71 | elif measure == 'SFRQ': 72 | img_x = img.copy() 73 | img_y = img.copy() 74 | img_y[:-1, :] = np.diff(img, axis=0) 75 | img_x[:, :-1] = np.diff(img, axis=1) 76 | fm = np.mean(np.sqrt(img_x**2 + img_y**2)) 77 | 78 | elif measure == 'ISO': 79 | kernel = np.array([ 80 | [0, 1, 1, 2, 2, 2, 1, 1, 0], 81 | [1, 2, 4, 5, 5, 5, 4, 2, 1], 82 | [1, 4, 5, 3, 0, 3, 5, 4, 1], 83 | [2, 5, 3, -12, -24, -12, 3, 5, 2], 84 | [2, 5, 0, -24, -40, -24, 0, 5, 2], 85 | [2, 5, 3, -12, -24, -12, 3, 5, 2], 86 | [1, 4, 5, 3, 0, 3, 5, 4, 1], 87 | [1, 2, 4, 5, 5, 5, 4, 2, 1], 88 | [0, 1, 1, 2, 2, 2, 1, 1, 0], 89 | ]) 90 | fm = cv2.filter2D(img, -1, kernel, borderType=cv2.BORDER_REPLICATE) 91 | fm = np.mean(fm * fm) 92 | fm = int(np.round(fm)) 93 | # fm = 100 * fm * fm / (fm * fm + 1800000) 94 | 95 | else: 96 | raise ValueError 97 | 98 | return fm 99 | 100 | 101 | if __name__ == "__main__": 102 | pass 103 | --------------------------------------------------------------------------------