Skip to content
This repository has been archived by the owner on Feb 11, 2023. It is now read-only.

Commit

Permalink
support for Windows & CI (#32)
Browse files Browse the repository at this point in the history
* CI: test Win
* add badge
* req. GCO 3.0.8
* fix pandas
* fix Win
  • Loading branch information
Borda authored Jul 11, 2021
1 parent 2ef3348 commit b55146c
Show file tree
Hide file tree
Showing 21 changed files with 171 additions and 199 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci-testing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ubuntu-20.04, macOS-10.15] # , windows-2019
os: [ubuntu-20.04, macOS-10.15, windows-2019]
python-version: [3.6, 3.8, 3.9]
requires: ['latest']
include:
Expand Down Expand Up @@ -81,7 +81,7 @@ jobs:
mkdir output
mkdir results
# run tests with coverage
coverage run --source imsegm -m pytest imsegm tests --durations=25 --junitxml=junit/test-results-${{ runner.os }}-${{ matrix.python-version }}-${{ matrix.requires }}.xml
python -m pytest imsegm tests --cov=imsegm --durations=25 --junitxml=junit/test-results-${{ runner.os }}-${{ matrix.python-version }}-${{ matrix.requires }}.xml
- name: Upload pytest test results
uses: actions/upload-artifact@master
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
[![Documentation Status](https://readthedocs.org/projects/pyimsegm/badge/?version=latest)](https://pyimsegm.readthedocs.io/en/latest/?badge=latest)
[![Gitter](https://badges.gitter.im/pyImSegm/community.svg)](https://gitter.im/pyImSegm/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
![CI experiments](https://github.com/Borda/pyImSegm/workflows/CI%20experiments/badge.svg?branch=master&event=push)
[![pre-commit.ci status](https://results.pre-commit.ci/badge/github/Borda/pyImSegm/master.svg)](https://results.pre-commit.ci/latest/github/Borda/pyImSegm/master)

<!--
[![Run Status](https://api.shippable.com/projects/5962ea48a125960700c197f8/badge?branch=master)](https://app.shippable.com/github/Borda/pyImSegm)
Expand Down
29 changes: 10 additions & 19 deletions experiments_ovary_centres/run_center_candidate_training.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import argparse
import logging
import os
import platform
import sys
from functools import partial

Expand Down Expand Up @@ -78,7 +79,7 @@
CROSS_VAL_LEAVE_OUT_EVAL = 0.1

CENTER_PARAMS = {
'computer': os.uname(),
'computer': platform.uname(),
'slic_size': 25,
'slic_regul': 0.3,
# 'fts_hist_diams': None,
Expand Down Expand Up @@ -194,8 +195,7 @@ def arg_parse_params(params):
# load saved configuration
if params['path_config'] is not None:
ext = os.path.splitext(params['path_config'])[-1]
assert (ext == '.yaml' or ext == '.yml'), \
'wrong extension for %s' % params['path_config']
assert ext in ('.yaml', '.yml'), 'wrong extension for %s' % params['path_config']
data = tl_expt.load_config_yaml(params['path_config'])
params.update(data)
params.update(paths)
Expand All @@ -209,8 +209,7 @@ def is_drawing(path_out):
:param str path_out:
:return bool:
# """
bool_res = path_out is not None and os.path.exists(path_out) \
and logging.getLogger().isEnabledFor(logging.DEBUG)
bool_res = path_out is not None and os.path.exists(path_out) and logging.getLogger().isEnabledFor(logging.DEBUG)
return bool_res


Expand Down Expand Up @@ -284,8 +283,7 @@ def load_image_segm_center(idx_row, path_out=None, dict_relabel=None):
if dict_relabel is not None:
segm = seg_lbs.relabel_by_dict(segm, dict_relabel)

if row_path['path_centers'] is not None \
and os.path.isfile(row_path['path_centers']):
if row_path['path_centers'] is not None and os.path.isfile(row_path['path_centers']):
ext = os.path.splitext(os.path.basename(row_path['path_centers']))[-1]
if ext == '.csv':
centers = tl_data.load_landmarks_csv(row_path['path_centers'])
Expand Down Expand Up @@ -384,8 +382,7 @@ def estim_points_compute_features(name, img, segm, params):
:return (str, ndarray, [(int, int)], [[float]], list(str)):
"""
# superpixels on image
assert img.shape[:2] == segm.shape[:2], \
'not matching shapes: %r : %r' % (img.shape, segm.shape)
assert img.shape[:2] == segm.shape[:2], 'not matching shapes: %r : %r' % (img.shape, segm.shape)
slic = seg_spx.segment_slic_img2d(img, params['slic_size'], params['slic_regul'])
slic_centers = seg_spx.superpixel_centers(slic)
# slic_edges = seg_spx.make_graph_segm_connect_grid2d_conn4(slic)
Expand Down Expand Up @@ -469,9 +466,7 @@ def label_close_points(centers, points, params):
else:
logging.warning('not relevant centers info of type "%s"', type(centers))
labels = [-1] * len(points)
assert len(points) == len(labels), \
'not equal lenghts of points (%i) and labels (%i)' \
% (len(points), len(labels))
assert len(points) == len(labels), 'not equal lenghts of points (%i) and labels (%i)' % (len(points), len(labels))
return labels


Expand Down Expand Up @@ -713,8 +708,7 @@ def experiment_loo(
def prepare_experiment_folder(params, dir_template):
params['path_expt'] = os.path.join(params['path_output'], dir_template % params['name'])
if not os.path.exists(params['path_expt']):
assert os.path.isdir(os.path.dirname(params['path_expt'])), \
'missing: %s' % os.path.dirname(params['path_expt'])
assert os.path.isdir(os.path.dirname(params['path_expt'])), 'missing: %s' % os.path.dirname(params['path_expt'])
logging.debug('creating missing folder: %s', params['path_expt'])
os.mkdir(params['path_expt'])
return params
Expand Down Expand Up @@ -757,8 +751,7 @@ def main_train(params):

path_dump_data = os.path.join(params['path_expt'], NAME_DUMP_TRAIN_DATA)
if not os.path.isfile(path_dump_data) or FORCE_RECOMP_DATA:
(dict_imgs, dict_segms, dict_slics, dict_points, dict_centers,
dict_features, dict_labels, feature_names) = \
dict_imgs, dict_segms, dict_slics, dict_points, dict_centers, dict_features, dict_labels, feature_names = \
dataset_load_images_segms_compute_features(params, df_paths, params['nb_workers'])
assert len(dict_imgs) > 0, 'missing images'
save_dump_data(
Expand Down Expand Up @@ -788,9 +781,7 @@ def main_train(params):
# remove all bad values from features space
features[np.isnan(features)] = 0
features[np.isinf(features)] = -1
assert np.sum(sizes) == len(labels), \
'not equal sizes (%d) and labels (%i)' \
% (int(np.sum(sizes)), len(labels))
assert np.sum(sizes) == len(labels), 'not equal sizes (%d) and labels (%i)' % (int(np.sum(sizes)), len(labels))

# feature norm & train classification
nb_holdout = int(np.ceil(len(sizes) * CROSS_VAL_LEAVE_OUT_SEARCH))
Expand Down
3 changes: 2 additions & 1 deletion experiments_ovary_centres/run_center_prediction.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import gc
import logging
import os
import platform
import sys
import time
from functools import partial
Expand Down Expand Up @@ -128,7 +129,7 @@ def main(params):

# run_train.check_pathes_patterns(paths)
tl_expt.set_experiment_logger(params['path_expt'])
logging.info('COMPUTER: \n%r', os.uname())
logging.info('COMPUTER: \n%r', platform.uname())
logging.info(tl_expt.string_dict(params, desc='PARAMETERS'))

tl_expt.create_subfolders(params['path_expt'], LIST_SUBFOLDER)
Expand Down
9 changes: 3 additions & 6 deletions experiments_ovary_detect/run_cut_segmented_objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,7 @@ def arg_parse_params(dict_paths):
_fn_path = lambda k: os.path.join(tl_data.update_path(os.path.dirname(args[k])), os.path.basename(args[k]))
dict_paths = {k.split('_')[-1]: _fn_path(k) for k in args if k.startswith('path_')}
for k in dict_paths:
assert os.path.exists(os.path.dirname(dict_paths[k])), \
'missing (%s) "%s"' % (k, os.path.dirname(dict_paths[k]))
assert os.path.exists(os.path.dirname(dict_paths[k])), 'missing (%s) "%s"' % (k, os.path.dirname(dict_paths[k]))
return dict_paths, args


Expand All @@ -85,8 +84,7 @@ def export_cut_objects(df_row, path_out, padding, use_mask=True, bg_color=None):
"""
annot, _ = tl_data.load_image_2d(df_row['path_1'])
img, name = tl_data.load_image_2d(df_row['path_2'])
assert annot.shape[:2] == img.shape[:2], \
'image sizes not match %r vs %r' % (annot.shape, img.shape)
assert annot.shape[:2] == img.shape[:2], 'image sizes not match %r vs %r' % (annot.shape, img.shape)

uq_objects = np.unique(annot)
if len(uq_objects) == 1:
Expand All @@ -107,8 +105,7 @@ def main(dict_paths, padding=0, use_mask=False, bg_color=None, nb_workers=NB_WOR
:param int nb_workers:
"""
if not os.path.isdir(dict_paths['output']):
assert os.path.isdir(os.path.dirname(dict_paths['output'])), \
'"%s" should be folder' % dict_paths['output']
assert os.path.isdir(os.path.dirname(dict_paths['output'])), '"%s" should be folder' % dict_paths['output']
logging.debug('creating dir: %s', dict_paths['output'])
os.mkdir(dict_paths['output'])

Expand Down
12 changes: 4 additions & 8 deletions experiments_segmentation/run_segm_slic_classif_graphcut.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,8 +233,7 @@ def dataset_load_images_annot_compute_features(params, show_debug_imgs=SHOW_DEBU
:return ({str: ndarray} * 6, list(str)):
"""
dict_images, dict_annots = dict(), dict()
dict_slics, dict_features, dict_labels, dict_label_hist = \
dict(), dict(), dict(), dict()
dict_slics, dict_features, dict_labels, dict_label_hist = dict(), dict(), dict(), dict()
feature_names = list()

# compute features
Expand Down Expand Up @@ -367,8 +366,7 @@ def segment_image(imgs_idx_path, params, classif, path_out, path_visu=None, show
np.savez_compressed(path_npz, segm_soft)

# plt.imsave(os.path.join(path_out, idx_name + '_rgb.png'), seg_pipe)
if params.get('visual', False) and path_visu is not None \
and os.path.isdir(path_visu):
if params.get('visual', False) and path_visu is not None and os.path.isdir(path_visu):
export_draw_image_segm_contour(img, segm_gc, path_visu, idx_name, '_GC')
export_draw_image_segm_contour(img, segm_map, path_visu, idx_name, '_MAP')
if show_debug_imgs and debug_visual is not None:
Expand Down Expand Up @@ -404,8 +402,7 @@ def eval_segment_with_annot(
if dict_label_hist is not None:
visu_histogram_labels(params, dict_label_hist)
assert sorted(dict_annot.keys()) == sorted(dict_segm.keys()), \
'mismatch in dictionary keys: \n%s \n%s' % (sorted(dict_annot.keys()),
sorted(dict_segm.keys()))
'mismatch in dictionary keys: \n%s \n%s' % (sorted(dict_annot.keys()), sorted(dict_segm.keys()))
list_annot = [dict_annot[n] for n in dict_annot]
list_segm = [dict_segm[n] for n in dict_annot]
df_stat = seg_clf.compute_stat_per_image(
Expand Down Expand Up @@ -438,8 +435,7 @@ def retrain_lpo_segment_image(
:param bool show_debug_imgs: whether show debug images
:return (str, ndarray, ndarray):
"""
dict_imgs, _, _, dict_features, dict_labels, _, _ = \
load_dump_data(path_dump)
dict_imgs, _, _, dict_features, dict_labels, _, _ = load_dump_data(path_dump)
dict_classif = seg_clf.load_classifier(path_classif)
classif = dict_classif['clf_pipeline']
params = dict_classif['params']
Expand Down
4 changes: 2 additions & 2 deletions imsegm/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@
import traceback
traceback.print_exc()

__version__ = '0.1.8'
__version__ = '0.1.9'
__author__ = 'Jiri Borovec'
__author_email__ = 'jiri.borovec@fel.cvut.cz'
__license__ = 'BSD 3-clause'
__homepage__ = 'https://borda.github.io/pyImSegm'
__copyright__ = 'Copyright (c) 2014-2020, %s.' % __author__
__copyright__ = 'Copyright (c) 2014-2021, %s.' % __author__
__doc__ = 'General superpixel image segmentation: (un)supervised, center detection, region growing'
__long_doc__ = "# %s" % __doc__ + """
Expand Down
10 changes: 5 additions & 5 deletions imsegm/annotation.py
Original file line number Diff line number Diff line change
Expand Up @@ -232,12 +232,12 @@ def image_color_2_labels(img, colors=None):
>>> np.random.seed(0)
>>> rand = np.random.randint(0, 2, (5, 7)).astype(np.uint8)
>>> img = np.rollaxis(np.array([rand] * 3), 0, 3)
>>> image_color_2_labels(img)
>>> image_color_2_labels(img) # doctest: +ELLIPSIS
array([[1, 0, 0, 1, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 0],
[1, 1, 1, 1, 1, 0, 1],
[0, 0, 1, 1, 0, 0, 0],
[0, 1, 0, 1, 0, 1, 0]])
[0, 1, 0, 1, 0, 1, 0]]...)
"""
if not colors:
colors = image_frequent_colors(img).keys()
Expand Down Expand Up @@ -330,9 +330,9 @@ def load_info_group_by_slices(path_txt, stages, pos_columns=COLUMNS_POSITION, di
:return: DF
>>> from imsegm.utilities.data_io import update_path
>>> path_txt = os.path.join(update_path('data-images'),
... 'drosophila_ovary_slice', 'info_ovary_images.txt')
>>> load_info_group_by_slices(path_txt, [4]) # doctest: +NORMALIZE_WHITESPACE
>>> path_txt = os.path.join(update_path('data-images'), 'drosophila_ovary_slice', 'info_ovary_images.txt')
>>> df = load_info_group_by_slices(path_txt, [4])
>>> df.sort_index(axis=1) # doctest: +NORMALIZE_WHITESPACE
ant_x ant_y lat_x lat_y post_x post_y
image
insitu7569 [298] [327] [673] [411] [986] [155]
Expand Down
49 changes: 21 additions & 28 deletions imsegm/classification.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,9 @@ def create_classifiers(nb_workers=-1):
>>> classifs = create_classifiers()
>>> classifs # doctest: +ELLIPSIS
{...}
>>> sum([isinstance(create_clf_param_search_grid(k), dict)
... for k in classifs.keys()])
>>> sum([isinstance(create_clf_param_search_grid(k), dict) for k in classifs.keys()])
7
>>> sum([isinstance(create_clf_param_search_distrib(k), dict)
... for k in classifs.keys()])
>>> sum([isinstance(create_clf_param_search_distrib(k), dict) for k in classifs.keys()])
7
"""
clfs = {
Expand Down Expand Up @@ -383,20 +381,17 @@ def compute_classif_stat_segm_annot(annot_segm_name, drop_labels=None, relabel=F
>>> np.random.seed(0)
>>> annot = np.random.randint(0, 2, (5, 10))
>>> segm = np.random.randint(0, 2, (5, 10))
>>> d = compute_classif_stat_segm_annot((annot, annot, 'ttt'), relabel=True,
... drop_labels=[5])
>>> d = compute_classif_stat_segm_annot((annot, annot, 'ttt'), relabel=True, drop_labels=[5])
>>> d['(FP+FN)/(TP+FN)'] # doctest: +ELLIPSIS
0.0
>>> d['(TP+FP)/(TP+FN)'] # doctest: +ELLIPSIS
1.0
>>> d = compute_classif_stat_segm_annot((annot, segm, 'ttt'), relabel=True,
... drop_labels=[5])
>>> d = compute_classif_stat_segm_annot((annot, segm, 'ttt'), relabel=True, drop_labels=[5])
>>> d['(FP+FN)/(TP+FN)'] # doctest: +ELLIPSIS
0.846...
>>> d['(TP+FP)/(TP+FN)'] # doctest: +ELLIPSIS
1.153...
>>> d = compute_classif_stat_segm_annot((annot, segm + 1, 'ttt'),
... relabel=False, drop_labels=[0])
>>> d = compute_classif_stat_segm_annot((annot, segm + 1, 'ttt'), relabel=False, drop_labels=[0])
>>> d['confusion']
[[13, 17], [0, 0]]
"""
Expand Down Expand Up @@ -487,14 +482,13 @@ def feature_scoring_selection(features, labels, names=None, path_out=''):
:return tuple(list(int),DF): indices, Dataframe with scoring
>>> from sklearn.datasets import make_classification
>>> features, labels = make_classification(n_samples=250, n_features=5,
... n_informative=3, n_redundant=0,
... n_repeated=0, n_classes=2,
... random_state=0, shuffle=False)
>>> indices, df_scoring = feature_scoring_selection(features, labels)
>>> features, labels = make_classification(
... n_samples=250, n_features=5, n_informative=3, n_redundant=0, n_repeated=0,
... n_classes=2, random_state=0, shuffle=False)
>>> indices, df_scoring = feature_scoring_selection(features, labels) # doctest: +ELLIPSIS
>>> indices
array([1, 0, 2, 3, 4])
>>> df_scoring # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS
array([1, 0, 2, 3, 4]...)
>>> df_scoring.sort_index(axis=1) # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS
ExtTree F-test k-Best variance
feature
1 0.24... 0.75... 0.75... 2.49...
Expand All @@ -506,8 +500,8 @@ def feature_scoring_selection(features, labels, names=None, path_out=''):
>>> path_out = 'test_fts-select'
>>> os.mkdir(path_out)
>>> indices, df_scoring = feature_scoring_selection(features.tolist(), labels.tolist(), path_out=path_out)
>>> indices
array([1, 0, 3, 4, 2])
>>> indices # doctest: +ELLIPSIS
array([1, 0, 3, 4, 2]...)
>>> import shutil
>>> shutil.rmtree(path_out, ignore_errors=True)
"""
Expand Down Expand Up @@ -562,8 +556,8 @@ def save_classifier(path_out, classif, clf_name, params, feature_names=None, lab
>>> clf = create_classifiers()['RandForest']
>>> p_clf = save_classifier('.', clf, 'TESTINNG', {})
>>> p_clf
'./classifier_TESTINNG.pkl'
>>> os.path.basename(p_clf)
'classifier_TESTINNG.pkl'
>>> d_clf = load_classifier(p_clf)
>>> sorted(d_clf.keys())
['clf_pipeline', 'features', 'label_names', 'name', 'params']
Expand Down Expand Up @@ -703,14 +697,14 @@ def create_classif_search_train_export(
Fitting ...
>>> clf # doctest: +ELLIPSIS
Pipeline(...)
>>> p_clf
'./classifier_RandForest.pkl'
>>> os.path.basename(p_clf)
'classifier_RandForest.pkl'
>>> os.remove(p_clf)
>>> import glob
>>> files = glob.glob(os.path.join('.', 'classif_*.txt'))
>>> sorted(files) # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS
['./classif_RandForest_search_params_best.txt',
'./classif_RandForest_search_params_scores.txt']
>>> sorted([os.path.basename(fp) for fp in files]) # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS
['classif_RandForest_search_params_best.txt',
'classif_RandForest_search_params_scores.txt']
>>> for p in files: os.remove(p)
"""
assert list(labels), 'some labels has to be given'
Expand Down Expand Up @@ -1189,8 +1183,7 @@ def balance_dataset_by_(features, labels, balance_type='random', min_samples=Non
:return tuple(ndarray,ndarray):
>>> np.random.seed(0)
>>> fts, lbs = balance_dataset_by_(np.random.random((25, 3)),
... np.random.randint(0, 2, 25))
>>> fts, lbs = balance_dataset_by_(np.random.random((25, 3)), np.random.randint(0, 2, 25))
>>> fts.shape
(24, 3)
>>> lbs
Expand Down
3 changes: 1 addition & 2 deletions imsegm/descriptors.py
Original file line number Diff line number Diff line change
Expand Up @@ -1701,8 +1701,7 @@ def numpy_ray_features_seg2d(seg_binary, position, angle_step=5., edge='up'):
last = seg_binary[position[0], position[1]]
for _ in range(segm_diag):
pos += grad
if pos[0] < 0 or round(pos[0]) >= height \
or pos[1] < 0 or round(pos[1]) >= width:
if pos[0] < 0 or round(pos[0]) >= height or pos[1] < 0 or round(pos[1]) >= width:
break
actual = seg_binary[int(round(pos[0])), int(round(pos[1]))]
if (edge == 'up' and actual) or (edge == 'down' and last and not actual):
Expand Down
Loading

0 comments on commit b55146c

Please sign in to comment.