Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pretty image title #610

Merged
merged 8 commits into from
Sep 21, 2018
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions pocs/camera/camera.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,8 @@ def take_observation(self, observation, headers=None, filename=None, *args, **kw
observation.exposure_list[image_id] = file_path

# Process the exposure once readout is complete
t = Thread(target=self.process_exposure, args=(metadata, observation_event, exposure_event))
t = Thread(target=self.process_exposure, args=(
metadata, observation_event, exposure_event))
t.name = '{}Thread'.format(self.name)
t.start()

Expand Down Expand Up @@ -238,12 +239,16 @@ def process_exposure(self, info, observation_event, exposure_event=None):
image_id = info['image_id']
seq_id = info['sequence_id']
file_path = info['file_path']
self.logger.debug("Processing {}".format(image_id))
field_name = info['field_name']

image_title = '{} {} {}'.format(field_name,
seq_id.replace('_', ' '),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW, this implies to me that we should have two ways of tracking sequence id: the string needed for file paths and another for presentation.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the Observation object itself should have a __str__ method that is better, but that wouldn't help much here as this is what is being passed around for the eventual FITS headers. But yes, fundamentally I agree. We pull this replace a lot.

current_time(pretty=True))

try:
self.logger.debug("Extracting pretty image")
self.logger.debug("Processing {}".format(image_title))
img_utils.make_pretty_image(file_path,
title=info['field_name'],
title=image_title,
primary=info['is_primary'])
except Exception as e:
self.logger.warning('Problem with extracting pretty image: {}'.format(e))
Expand Down
60 changes: 31 additions & 29 deletions pocs/utils/images/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,32 +63,31 @@ def crop_data(data, box_width=200, center=None, verbose=False):
return center


def make_pretty_image(fname, timeout=15, **kwargs): # pragma: no cover
""" Make a pretty image
def make_pretty_image(fname, title=None, timeout=15, **kwargs): # pragma: no cover
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about adding an issue to add testing of this? It doesn't strike me as that hard to test.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#608 also contains an item about adding testing for images. We currently don't test more of our images.

"""Make a pretty image.

This will create a jpg file from either a CR2 (Canon) or FITS file.

Notes:
See `$POCS/scripts/cr2_to_jpg.sh` for CR2 process
See `/scripts/cr2_to_jpg.sh` for CR2 process.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you remove $POCS? Assuming well founded, why not also remove the leading slash?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure why I did this. Will fix.


Arguments:
fname {str} -- Name of image file, may be either .fits or .cr2
**kwargs {dict} -- Additional arguments to be passed to external script

Keyword Arguments:
timeout {number} -- Process timeout (default: {15})
title (None|str, optional): Title to be placed on image, default None.
timeout (int, optional): Timeout for conversion, default 15 seconds.
**kwargs {dict} -- Additional arguments to be passed to external script.

Returns:
str -- Filename of image that was created
str -- Filename of image that was created.

"""
assert os.path.exists(fname),\
warn("File doesn't exist, can't make pretty: {}".format(fname))

if fname.endswith('.cr2'):
pretty_path = _make_pretty_from_cr2(fname, timeout=timeout, **kwargs)
pretty_path = _make_pretty_from_cr2(fname, title=title, timeout=timeout, **kwargs)
elif fname.endswith('.fits'):
pretty_path = _make_pretty_from_fits(fname, **kwargs)
pretty_path = _make_pretty_from_fits(fname, title=title, **kwargs)
else:
warn("File must be a Canon CR2 or FITS file.")
return None
Expand All @@ -110,25 +109,30 @@ def make_pretty_image(fname, timeout=15, **kwargs): # pragma: no cover
return None


def _make_pretty_from_fits(
fname=None, figsize=(10, 10 / 1.325), dpi=150, alpha=0.2, number=7, **kwargs):
def _make_pretty_from_fits(fname=None,
title=None,
figsize=(10, 10 / 1.325),
dpi=150,
alpha=0.2,
number_ticks=7,
clip_percent=99.9,
**kwargs):

with open_fits(fname) as hdu:
header = hdu[0].header
data = hdu[0].data
data = focus_utils.mask_saturated(data)
wcs = WCS(header)

title = kwargs.get('title', header.get('FIELD', 'Unknown'))
exp_time = header.get('EXPTIME', 'Unknown')

filter_type = header.get('FILTER', 'Unknown filter')
date_time = header.get('DATE-OBS', current_time(pretty=True)).replace('T', ' ', 1)
if not title:
field = header.get('FIELD', 'Unknown')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps 'Unknown field' and 'Unknown duration'?

exp_time = header.get('EXPTIME', 'Unknown')
filter_type = header.get('FILTER', 'Unknown filter')
date_time = header.get('DATE-OBS', current_time(pretty=True)).replace('T', ' ', 1)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could read the file time as a source of a date.


percent_value = kwargs.get('normalize_clip_percent', 99.9)
title = '{} ({}s {}) {}'.format(field, exp_time, filter_type, date_time)

title = '{} ({}s {}) {}'.format(title, exp_time, filter_type, date_time)
norm = ImageNormalize(interval=PercentileInterval(percent_value), stretch=LogStretch())
norm = ImageNormalize(interval=PercentileInterval(clip_percent), stretch=LogStretch())

fig = plt.figure(figsize=figsize, dpi=dpi)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A reminder about my request that we have images (plots) that can display on both white and black backgrounds.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would normally happen with the fig.savefig method, which is part of the OO interface. I've added a note in #608.

Expand All @@ -140,7 +144,7 @@ def _make_pretty_from_fits(
ra_axis.set_axislabel('Right Ascension')
ra_axis.set_major_formatter('hh:mm')
ra_axis.set_ticks(
number=number,
number=number_ticks,
color='white',
exclude_overlapping=True
)
Expand All @@ -149,7 +153,7 @@ def _make_pretty_from_fits(
dec_axis.set_axislabel('Declination')
dec_axis.set_major_formatter('dd:mm')
dec_axis.set_ticks(
number=number,
number=number_ticks,
color='white',
exclude_overlapping=True
)
Expand All @@ -171,16 +175,14 @@ def _make_pretty_from_fits(
return new_filename


def _make_pretty_from_cr2(fname, timeout=15, **kwargs): # pragma: no cover
def _make_pretty_from_cr2(fname, title=None, timeout=15, **kwargs): # pragma: no cover
verbose = kwargs.get('verbose', False)

title = '{} {}'.format(kwargs.get('title', ''), current_time().isot)

solve_field = "{}/scripts/cr2_to_jpg.sh".format(os.getenv('POCS'))
cmd = [solve_field, fname, title]
script_name = os.path.join(os.getenv('POCS'), 'scripts', 'cr2_to_jpg.sh')
cmd = [script_name, fname]

if kwargs.get('primary', False):
cmd.append('link')
if title:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No default title?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, see PR description.

cmd.append(title)

if verbose:
print(cmd)
Expand Down
14 changes: 7 additions & 7 deletions scripts/cr2_to_jpg.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ usage() {
# If exiftool is present this merely extracts the thumbnail from
# the CR2 file, otherwise use dcraw to create a jpeg.
#
# If present the CAPTION is added as a caption to the jpeg.
# If present the TITLE is added as a title to the jpeg.
##################################################
$ $(basename $0) FILENAME [CAPTION]
$ $(basename $0) FILENAME [TITLE]

Options:
FILENAME Name of CR2 file that holds jpeg.
CAPTION Optional caption to be placed on jpeg.
TITLE Optional tilte to be placed on jpeg.

Example:
scripts/cr2_to_jpg.sh /var/panoptes/images/temp.cr2 \"M42 (Orion's Nebula)\"
Expand All @@ -26,7 +26,7 @@ if [ $# -eq 0 ]; then
fi

FNAME=$1
CAPTION="${2}"
TITLE="${2}"

JPG="${FNAME%.cr2}.jpg"

Expand All @@ -45,12 +45,12 @@ else
fi
fi

if [[ -n "$CAPTION" ]]
if [[ -n "$TITLE" ]]
then
echo "Adding caption \"${CAPTION}\""
echo "Adding title \"${TITLE}\""
# Make thumbnail from jpg.
convert "${JPG}" -background black -fill red \
-font ubuntu -pointsize 60 label:"${CAPTION}" \
-font ubuntu -pointsize 60 label:"${TITLE}" \
-gravity South -append "${JPG}"
fi

Expand Down