This repository has been archived by the owner on Feb 11, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 26
/
bm_comp_perform.py
249 lines (205 loc) · 9.1 KB
/
bm_comp_perform.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
"""
Simple benchmarks measuring basic computer performances
We run image registration in single thread and then in all available thread
in parallel and measure the execution time.
The tested image registration scenario is as following
1. load both images
2. perform som simple denoising
3. extract ORB features
4. estimate affine transform via RANSAC
5. warp and export image
Example run::
pip install --user tqdm numpy scikit-image https://github.com/Borda/BIRL/archive/master.zip
python bm_comp_perform.py -o ../output -n 3
Copyright (C) 2018 Jiri Borovec <jiri.borovec@fel.cvut.cz>
"""
import os
import sys
import time
import json
import argparse
import datetime
import logging
import platform
import hashlib
import multiprocessing as mproc
from functools import partial
import tqdm
import numpy as np
import skimage
from skimage import data, io
from skimage.transform import resize, warp, AffineTransform
from skimage.color import rgb2gray
from skimage.measure import ransac
from skimage.util import random_noise
from skimage.restoration import denoise_bilateral, denoise_wavelet
from skimage.feature import ORB, match_descriptors
sys.path += [os.path.abspath('.'), os.path.abspath('..')] # Add path to root
from birl.utilities.experiments import computer_info
IMAGE_SIZE = (2000, 2000)
IMAGE_NOISE = 0.01
SKIMAGE_VERSION = (0, 14, 0)
CPU_COUNT = int(mproc.cpu_count())
NAME_REPORT = 'computer-performances.json'
NAME_IMAGE_TARGET = 'temp_regist-image_target.png'
NAME_IMAGE_SOURCE = 'temp_regist-image_source.png'
NAME_IMAGE_WARPED = 'temp_regist-image_warped-%i.jpg'
def arg_parse_params():
""" parse the input parameters
:return dict: parameters
"""
# SEE: https://docs.python.org/3/library/argparse.html
parser = argparse.ArgumentParser()
parser.add_argument('-o', '--path_out', type=str, required=False,
help='path to the output folder', default='')
parser.add_argument('-n', '--nb_runs', type=int, required=False,
help='number of run experiments', default=5)
args = vars(parser.parse_args())
logging.info('ARGUMENTS: \n%r' % args)
return args
def _prepare_images(path_out, im_size=IMAGE_SIZE):
""" generate and prepare synth. images for registration
:param str path_out: path to the folder
:param tuple(int,int) im_size: desired image size
:return tuple(str,str): paths to target and source image
"""
image = resize(data.astronaut(), output_shape=im_size, mode='constant')
img_target = random_noise(image, var=IMAGE_NOISE)
path_img_target = os.path.join(path_out, NAME_IMAGE_TARGET)
io.imsave(path_img_target, img_target)
# warp synthetic image
tform = AffineTransform(scale=(0.9, 0.9),
rotation=0.2,
translation=(200, -50))
img_source = warp(image, tform.inverse, output_shape=im_size)
img_source = random_noise(img_source, var=IMAGE_NOISE)
path_img_source = os.path.join(path_out, NAME_IMAGE_SOURCE)
io.imsave(path_img_source, img_source)
return path_img_target, path_img_source
def _clean_images(image_paths):
""" remove temporary images
:param str image_paths: path to images
"""
for p_img in image_paths:
os.remove(p_img)
def register_image_pair(idx, path_img_target, path_img_source, path_out):
""" register two images together
:param int idx: empty parameter for using the function in parallel
:param str path_img_target: path to the target image
:param str path_img_source: path to the source image
:param str path_out: path for exporting the output
:return tuple(str,float):
"""
start = time.time()
# load and denoise reference image
img_target = io.imread(path_img_target)
img_target = denoise_wavelet(img_target, wavelet_levels=7, multichannel=True)
img_target_gray = rgb2gray(img_target)
# load and denoise moving image
img_source = io.imread(path_img_source)
img_source = denoise_bilateral(img_source, sigma_color=0.05,
sigma_spatial=2, multichannel=True)
img_source_gray = rgb2gray(img_source)
# detect ORB features on both images
detector_target = ORB(n_keypoints=150)
detector_source = ORB(n_keypoints=150)
detector_target.detect_and_extract(img_target_gray)
detector_source.detect_and_extract(img_source_gray)
matches = match_descriptors(detector_target.descriptors,
detector_source.descriptors)
# robustly estimate affine transform model with RANSAC
model, _ = ransac((detector_target.keypoints[matches[:, 0]],
detector_source.keypoints[matches[:, 1]]),
AffineTransform, min_samples=25, max_trials=500,
residual_threshold=0.95)
# warping source image with estimated transformations
img_warped = warp(img_target, model.inverse, output_shape=img_target.shape[:2])
path_img_warped = os.path.join(path_out, NAME_IMAGE_WARPED % idx)
io.imsave(path_img_warped, img_warped)
# summarise experiment
execution_time = time.time() - start
return path_img_warped, execution_time
def measure_registration_single(path_out, nb_iter=5):
""" measure mean execration time for image registration running in 1 thread
:param str path_out: path to the temporary output space
:param int nb_iter: number of experiments to be averaged
:return dict: dictionary of float values results
"""
path_img_target, path_img_source = _prepare_images(path_out, IMAGE_SIZE)
paths = [path_img_target, path_img_source]
execution_times = []
for i in tqdm.tqdm(range(nb_iter), desc='using single-thread'):
path_img_warped, t = register_image_pair(i, path_img_target,
path_img_source,
path_out)
paths.append(path_img_warped)
execution_times.append(t)
_clean_images(set(paths))
logging.info('registration @1-thread: %f +/- %f',
np.mean(execution_times), np.std(execution_times))
res = {'registration @1-thread': np.mean(execution_times)}
return res
def measure_registration_parallel(path_out, nb_iter=3, nb_workers=CPU_COUNT):
""" measure mean execration time for image registration running in N thread
:param str path_out: path to the temporary output space
:param int nb_iter: number of experiments to be averaged
:param int nb_workers: number of thread available on the computer
:return dict: dictionary of float values results
"""
path_img_target, path_img_source = _prepare_images(path_out, IMAGE_SIZE)
paths = [path_img_target, path_img_source]
execution_times = []
_regist = partial(register_image_pair, path_img_target=path_img_target,
path_img_source=path_img_source, path_out=path_out)
nb_tasks = int(nb_workers * nb_iter)
logging.info('>> running %i tasks in %i threads', nb_tasks, nb_workers)
tqdm_bar = tqdm.tqdm(total=nb_tasks, desc='parallel @ %i threads' % nb_workers)
pool = mproc.Pool(nb_workers)
for path_img_warped, t in pool.map(_regist, (range(nb_tasks))):
paths.append(path_img_warped)
execution_times.append(t)
tqdm_bar.update()
pool.close()
pool.join()
tqdm_bar.close()
_clean_images(set(paths))
logging.info('registration @%i-thread: %f +/- %f', nb_workers,
np.mean(execution_times), np.std(execution_times))
res = {'registration @n-thread': np.mean(execution_times)}
return res
def main(path_out='', nb_runs=5):
""" the main entry point
:param str path_out: path to export the report and save temporal images
:param int nb_runs: number of trails to have an robust average value
"""
logging.info('Running the computer benchmark.')
skimage_version = skimage.__version__.split('.')
skimage_version = tuple(map(int, skimage_version))
if skimage_version < SKIMAGE_VERSION:
logging.warning('You are using older version of scikit-image then we expect.'
' Please upadte by `pip install -U --user scikit-image>=%s`',
'.'.join(map(str, SKIMAGE_VERSION)))
hasher = hashlib.sha256()
hasher.update(open(__file__, 'rb').read())
report = {
'computer': computer_info(),
'created': str(datetime.datetime.now()),
'file': hasher.hexdigest(),
'number runs': nb_runs,
'python-version': platform.python_version(),
'skimage-version': skimage.__version__,
}
report.update(measure_registration_single(path_out, nb_iter=nb_runs))
nb_runs_ = max(1, int(nb_runs / 2.))
report.update(measure_registration_parallel(path_out, nb_iter=nb_runs_))
path_json = os.path.join(path_out, NAME_REPORT)
logging.info('exporting report: %s', path_json)
with open(path_json, 'w') as fp:
json.dump(report, fp)
logging.info('\n\t '.join('%s: \t %r' % (k, report[k]) for k in report))
if __name__ == '__main__':
logging.basicConfig(level=logging.INFO)
arg_params = arg_parse_params()
logging.info('running...')
main(**arg_params)
logging.info('Done :]')