Skip to content

Commit a323334

Browse files
committed
Improvements to cmd line.
1 parent 60aa77e commit a323334

File tree

6 files changed

+104
-79
lines changed

6 files changed

+104
-79
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,10 @@ out_gpu = hist.histeq_exact(im_gpu)
3030

3131
The code can be run as a standalone program:
3232
```sh
33-
python3 -m hist.main input.png output.png
34-
python3 -m hist.main input output # converts a 3d image stored in a folder
33+
python3 -m hist input.png output.png
34+
python3 -m hist input # converts a 3d image stored in a folder
3535
```
36-
See `python3 -m hist.main --help` for more information.
36+
See `python3 -m hist --help` for more information.
3737

3838
References
3939
----------

hist/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@
77
from .exact import histeq_exact
88
from .metrics import (contrast_per_pixel, distortion, count_differences, psnr, ssim,
99
enhancement_measurement)
10+

hist/__main__.py

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
"""
2+
Simple main program to perform histogram equalization.
3+
"""
4+
5+
from . import histeq, histeq_exact
6+
7+
def main():
8+
"""Main function that runs histogram equalization on an image."""
9+
import argparse
10+
import os.path
11+
import re
12+
import hist._cmd_line_util as cui
13+
14+
# Extra imports to make sure everything is available now
15+
import numpy, scipy.ndimage # pylint: disable=unused-import, multiple-imports
16+
17+
parser = argparse.ArgumentParser(prog='python3 -m hist',
18+
description='Perform histogram equalization on an image')
19+
cui.add_input_image(parser)
20+
parser.add_argument('output', nargs='?',
21+
help='output image file, defaults to input file name with _out before '
22+
'the extension')
23+
cui.add_method_arg(parser)
24+
cui.add_kwargs_arg(parser)
25+
parser.add_argument('--nbins', '-n', type=int, default=256, metavar='N',
26+
help='number of bins in the intermediate histogram, default is 256')
27+
args = parser.parse_args()
28+
29+
# Load image
30+
im = cui.open_input_image(args)
31+
32+
# Run HE
33+
if args.method == 'classic':
34+
out = histeq(im, args.nbins, **dict(args.kwargs))
35+
else:
36+
out = histeq_exact(im, args.nbins, method=args.method, **dict(args.kwargs))
37+
38+
# Save (if not testing)
39+
filename = args.output
40+
if filename == '': return # hidden feature for "testing" mode, no saving
41+
if filename is None:
42+
if os.path.isdir(args.input):
43+
filename = args.input + '_out'
44+
elif os.path.exists(args.input) and ('?' in args.input or '*' in args.input or
45+
('[' in args.input and ']' in args.input)):
46+
filename = re.sub(r'\*|\?|\[.+\]', '#', args.input)
47+
elif args.input.lower().endswith('.npy.gz'):
48+
filename = args.input[:-7] + '_out' + args.input[-7:]
49+
else:
50+
filename = '_out'.join(os.path.splitext(args.input))
51+
__save(filename, out)
52+
53+
def __save(filename, out):
54+
import gzip
55+
import numpy
56+
import imageio
57+
from .util import is_on_gpu
58+
if is_on_gpu(out):
59+
out = out.get()
60+
if filename.lower().endswith('.npy'):
61+
numpy.save(filename, out)
62+
elif filename.lower().endswith('.npy.gz'):
63+
with gzip.GzipFile(filename, 'wb') as file:
64+
numpy.save(filename, file)
65+
elif out.ndim == 3 and '#' in filename:
66+
start = filename.index('#')
67+
end = start + 1
68+
while end < len(filename) and filename[end] == '#':
69+
end += 1
70+
num_str, fmt_str = filename[start:end], '%0'+str(end-start)+'d'
71+
for i in range(out.shape[0]):
72+
imageio.imwrite(filename.replace(num_str, fmt_str % i), out[i, :, :])
73+
else:
74+
imageio.imwrite(filename, out)
75+
76+
77+
if __name__ == "__main__":
78+
main()

hist/_cmd_line_util.py

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,25 +8,27 @@
88

99
def add_method_arg(parser):
1010
"""Add the method argument to an argument parser object."""
11-
parser.add_argument('method', choices=METHODS, help='method of histogram equalization')
11+
parser.add_argument('--method', '-m', choices=METHODS, default='va',
12+
help='method of histogram equalization, default is "va"')
1213

1314
def add_kwargs_arg(parser):
14-
"""Add the kwargs arg to an argument parser object which accepts a series of k=v arguments."""
15-
parser.add_argument('kwargs', type=__kwargs_arg, nargs='*', help='any special keyword '+
16-
'arguments to pass to the method, formated as key=value with value being '+
17-
'a valid Python literal or one of the special values nan, inf, -inf, N4, '+
18-
'N8, N8_DIST, N6, N18, N18_DIST, N26, N26_DIST')
15+
"""Add the kwargs arg to an argument parser object which accepts many k=v arguments."""
16+
parser.add_argument('--arg', '-a', type=__kwargs_arg, metavar='K=V', action='append',
17+
dest='kwargs', default=[],
18+
help='any special keyword arguments to pass to the method, formated as '
19+
'key=value with value being a valid Python literal or one of the special '
20+
'values nan, inf, -inf, N4, N8, N8_DIST, N6, N18, N18_DIST, N26, N26_DIST')
1921

20-
def add_input_image(parser):
22+
def add_input_image(parser, output=False):
2123
"""
2224
Add a required input argument and an optional --float argument. Use the open_input_image
23-
function to read the image. This supports filenames with glob wildcards or directories to read a
24-
series of images in as a 3D image.
25+
function to read the image. This supports filenames with glob wildcards or directories to read
26+
a series of images in as a 3D image.
2527
"""
2628
parser.add_argument('input', help='input image file (including .npy, .npy.gz, and '
2729
'directories/wildcard names for 3D images)')
28-
parser.add_argument('--float', action='store_true', help='convert image to float')
29-
parser.add_argument('--gpu', action='store_true', help='utilize the GPU when able')
30+
parser.add_argument('--float', '-f', action='store_true', help='convert image to float')
31+
parser.add_argument('--gpu', '-g', action='store_true', help='utilize the GPU when able')
3032

3133
def open_input_image(args_or_filename, conv_to_float=False, use_gpu=False):
3234
"""
@@ -39,6 +41,7 @@ def open_input_image(args_or_filename, conv_to_float=False, use_gpu=False):
3941
import os
4042
from glob import glob
4143
from numpy import stack
44+
4245
if isinstance(args_or_filename, str):
4346
filename = args_or_filename
4447
else:
@@ -66,10 +69,10 @@ def __load_image(filename, conv_to_float=False, use_gpu=False):
6669
import imageio
6770
from numpy import load
6871
from hist.util import as_float
69-
if filename.endswith('.npy.gz'):
72+
if filename.lower().endswith('.npy.gz'):
7073
with gzip.GzipFile(filename, 'rb') as file:
7174
im = load(file)
72-
elif filename.endswith('.npy'):
75+
elif filename.lower().endswith('.npy'):
7376
im = load(filename)
7477
else:
7578
im = imageio.imread(filename)

hist/main.py

Lines changed: 0 additions & 60 deletions
This file was deleted.

hist/metric_battery.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from .metrics import (contrast_per_pixel, enhancement_measurement, distortion,
77
contrast_enhancement, count_differences, psnr, ssim)
88

9-
def metric_battery(original, method, csv=False, plot=False, **kwargs):
9+
def metric_battery(original, method, nbins=256, csv=False, plot=False, **kwargs):
1010
"""
1111
Runs a battery of metrics while historgram equalizing the original image and then attempting to
1212
reconstruct the original image using the given method (either 'classic' or one of the methods
@@ -20,14 +20,14 @@ def metric_battery(original, method, csv=False, plot=False, **kwargs):
2020
# pylint: disable=too-many-locals, too-many-statements
2121
hist_orig = imhist(original)
2222
if method == 'classic':
23-
enhanced = histeq(original, 256, **kwargs)
23+
enhanced = histeq(original, nbins, **kwargs)
2424
recon = histeq(enhanced, hist_orig, **kwargs)
2525
fails_forward = fails_reverse = -1
2626
else:
2727
kwargs['method'] = method
2828
kwargs['return_fails'] = True
2929
if 'reconstruction' in kwargs: kwargs['reconstruction'] = False
30-
enhanced, fails_forward = histeq_exact(original, 256, **kwargs)
30+
enhanced, fails_forward = histeq_exact(original, nbins, **kwargs)
3131
if 'reconstruction' in kwargs: kwargs['reconstruction'] = True
3232
recon, fails_reverse = histeq_exact(enhanced, hist_orig, **kwargs)
3333

@@ -110,6 +110,9 @@ def main():
110110
parser.add_argument('--csv', action='store_true', help='output data as CSV with no header')
111111
parser.add_argument('--plot', action='store_true',
112112
help='plot original, enhanced, and reconstructed images with histograms')
113+
parser.add_argument('--nbins', '-n', type=int, default=256, metavar='N',
114+
help='number of bins in the intermediate histogram, default is 256 '
115+
'(reverse direction always uses a full histogram)')
113116
cui.add_kwargs_arg(parser)
114117
args = parser.parse_args()
115118

0 commit comments

Comments
 (0)