Skip to content

Commit

Permalink
Commit version v0.15.0
Browse files Browse the repository at this point in the history
  • Loading branch information
mixxen committed May 4, 2023
1 parent 81d0808 commit befc2cf
Show file tree
Hide file tree
Showing 15 changed files with 137 additions and 67 deletions.
14 changes: 11 additions & 3 deletions HISTORY.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
History
=======

0.15.0
---------------------

* Add support to save ground truth image data to the Annotations directory. Set sim option `save_ground_truth` to `true`.
* Add support for running on CPU with no GPU acceleration.
* Add CZML options for sensor visualization and object billboard image.


0.14.0
---------------------

Add vector math library.
Add CZML output for sensor visualization.
Fix objects not updating properly when image renderer is off.
* Add vector math library.
* Add CZML output for sensor visualization.
* Fix objects not updating properly when image renderer is off.


0.13.1
Expand Down
10 changes: 8 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,12 @@ coverage: ## check code coverage quickly with the default python3
coverage html
$(BROWSER) htmlcov/index.html

cpucoverage: ## check code coverage quickly with the default python3
CUDA_VISIBLE_DEVICES="" && coverage run --source satsim -m pytest
coverage report -m
coverage html
$(BROWSER) htmlcov/index.html

docs: ## generate Sphinx HTML documentation, including API docs
rm -f docs/satsim.rst
rm -f docs/modules.rst
Expand Down Expand Up @@ -105,11 +111,11 @@ install: clean ## install the package to the active python3's site-packages
@echo IMPORTANT: You may need to close and restart your shell after running "make install".

docker: docs dist
docker build -t satsim:0.14.0 -t satsim:latest -f docker/ubuntu20.04_cuda11.2_py3.8.dockerfile .
docker build -t satsim:0.15.0 -t satsim:latest -f docker/ubuntu20.04_cuda11.2_py3.8.dockerfile .

dind:
docker run --rm -it -v $(CURDIR):/workspace/ -w /workspace python:3.8-bullseye ./build.sh
docker build -t satsim:0.14.0 -t satsim:latest -f docker/ubuntu20.04_cuda11.2_py3.8.dockerfile .
docker build -t satsim:0.15.0 -t satsim:latest -f docker/ubuntu20.04_cuda11.2_py3.8.dockerfile .

uninstall: clean
cat .install.log | xargs rm -rf
12 changes: 6 additions & 6 deletions docker/ubuntu20.04_cuda11.2_py3.8.dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -25,25 +25,25 @@ ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' LC_ALL='en_US.UTF-8'
RUN pip3 install --no-cache-dir --upgrade pip setuptools

# copy and install satsim wheel file
ENV SATSIM_VERSION='0.14.0'
COPY dist/satsim-0.14.0-py2.py3-none-any.whl /tmp
ENV SATSIM_VERSION='0.15.0'
COPY dist/satsim-0.15.0-py2.py3-none-any.whl /tmp

# install python prereqs and satsim
RUN pip3 --no-cache-dir install \
imageio==2.15.0 \
tensorflow~=2.8.0 \
tensorflow-addons~=0.16.1 \
tmp/satsim-0.14.0-py2.py3-none-any.whl
tmp/satsim-0.15.0-py2.py3-none-any.whl

RUN pip3 --no-cache-dir install \
jupyterlab \
scikit-learn \
virtualenv

# copy and install satsim wheel file
ENV SATSIM_VERSION='0.14.0'
COPY dist/satsim-0.14.0-py2.py3-none-any.whl /tmp
RUN pip3 install tmp/satsim-0.14.0-py2.py3-none-any.whl
ENV SATSIM_VERSION='0.15.0'
COPY dist/satsim-0.15.0-py2.py3-none-any.whl /tmp
RUN pip3 install tmp/satsim-0.15.0-py2.py3-none-any.whl

RUN mkdir /workspace
WORKDIR /workspace
Expand Down
4 changes: 2 additions & 2 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,9 @@
# the built documents.
#
# The short X.Y version.
version = '0.14.0'
version = '0.15.0'
# The full version, including alpha/beta/rc tags.
release = '0.14.0'
release = '0.15.0'

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
Expand Down
2 changes: 1 addition & 1 deletion satsim/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

__author__ = """Alex Cabello"""
__email__ = '[email protected]'
__version__ = '0.14.0'
__version__ = '0.15.0'

from .satsim import gen_images, gen_multi, image_generator
from .config import load_json, load_yaml
2 changes: 1 addition & 1 deletion satsim/dataset/augment.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def _augment_satnet_with_satsim(image, bboxs, filename=None, annotational_filena
sspc['augment']['image']['post'] = tf.squeeze(image)

ig = image_generator(sspc, with_meta=True)
fpa_digital, frame_num, astrometrics, obs_os_pix, fpa_conv_star, fpa_conv_targ, bg_tf, dc_tf, rn_tf, num_shot_noise_samples, obs_cache = ig.__next__()
fpa_digital, frame_num, astrometrics, obs_os_pix, fpa_conv_star, fpa_conv_targ, bg_tf, dc_tf, rn_tf, num_shot_noise_samples, obs_cache, ground_truth = ig.__next__()

anno = init_annotation('.', 0, h, w, y_fov, x_fov)
snr = signal_to_noise_ratio(fpa_conv_targ, tf.squeeze(image) * a2d_gain, rn)
Expand Down
27 changes: 13 additions & 14 deletions satsim/image/fpa.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import numpy as np

from satsim.geometry.transform import rotate_and_translate
from satsim.util import get_semantic_version
from satsim.util import get_semantic_version, is_tensorflow_running_on_cpu
from satsim.math import fftconv2p


Expand Down Expand Up @@ -253,19 +253,18 @@ def add_counts(fpa, r, c, cnt, r_offset=0, c_offset=0):
Returns:
A `Tensor`, a reference to the modified input `fpa` image
"""
r = tf.cast(r, tf.int32)
c = tf.cast(c, tf.int32)

# TODO no bounds checking in TF-GPU if fpa is int32 type
# h,w = fpa.get_shape().as_list()
# valid = (r >= 0) & (r < h) & (c >= 0) & (c < w)
# r = tf.boolean_mask(r, valid)
# c = tf.boolean_mask(c, valid)
# cnt = tf.boolean_mask(tf.convert_to_tensor(cnt, dtype=fpa.dtype), valid)

# r_offset = r_offset
# c_offset = c_offset
rc = tf.stack([r + r_offset, c + c_offset], axis=1)
r = tf.cast(r, tf.int32) + tf.cast(r_offset, tf.int32)
c = tf.cast(c, tf.int32) + tf.cast(c_offset, tf.int32)

# fix for no bounds checking if fpa is int32 or if running CPU
if is_tensorflow_running_on_cpu() or fpa.dtype == 'int32':
h, w = fpa.get_shape().as_list()
valid = (r >= 0) & (r < h) & (c >= 0) & (c < w)
r = tf.boolean_mask(r, valid)
c = tf.boolean_mask(c, valid)
cnt = tf.boolean_mask(tf.convert_to_tensor(cnt, dtype=fpa.dtype), valid)

rc = tf.stack([r, c], axis=1)
return tf.compat.v1.tensor_scatter_nd_add(fpa, rc, cnt)


Expand Down
3 changes: 2 additions & 1 deletion satsim/image/noise.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,9 @@ def add_read_noise(fpa, rn, en=0):
Returns:
A `Tensor`, the 2D tensor with read noise applied.
A `Tensor`, the 2D tensor read noise.
"""
rn = tf.cast(rn, tf.float32)
en = tf.cast(rn, tf.float32)
noise = tf.random.normal(tf.shape(fpa)) * tf.math.sqrt(rn * rn + en * en)
return fpa + noise
return fpa + noise, noise
66 changes: 37 additions & 29 deletions satsim/io/czml.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,14 @@ def save_czml(ssp, obs_cache, astrometrics, filename):
alt = site['alt'] * u.m

name = site['name'] if 'name' in site else None
label_show = False

if 'czml' in site:
label_show = site['czml'].get('path_show', label_show)
# czml
czml_config = site['czml'] if 'czml' in site else {}
label_show = czml_config.get('label_show', False)
cone_show = czml_config.get('cone_show', True)
cone_color = czml_config.get('cone_color', [255, 255, 0, 64])
billboard_show = czml_config.get('billboard_show', True)
billboard_image = czml_config.get('billboard_image', PIC_GROUNDSTATION)

sensor = {
'y_fov': astrometrics[0]['y_fov'],
Expand All @@ -84,7 +88,9 @@ def save_czml(ssp, obs_cache, astrometrics, filename):
'range': [x['range'] for x in astrometrics],
}

extractor.add_ground_station([latitude, longitude, alt], sensor, label_text=name, label_show=label_show)
extractor.add_ground_station([latitude, longitude, alt], sensor, label_text=name, label_show=label_show,
cone_show=cone_show, cone_color=cone_color, billboard_show=billboard_show,
billboard_image=billboard_image)

# extract objects data
for i, o in enumerate(ssp['geometry']['obs']['list']):
Expand All @@ -102,27 +108,24 @@ def save_czml(ssp, obs_cache, astrometrics, filename):

name = o['name'] if 'name' in o else None

path_show = (ts_start_ob == t0)
path_color = [255, 255, 0]
billboard_show = True
start_interval = time.to_astropy(t0)
end_interval = time.to_astropy(t2)
label_show = False

if 'czml' in o:
label_show = o['czml'].get('label_show', label_show)
path_show = o['czml'].get('path_show', path_show)
path_color = o['czml'].get('path_color', path_color)
billboard_show = o['czml'].get('billboard_show', billboard_show)
if 'start_interval' in o['czml']:
start_interval = time.to_astropy(time.utc_from_list_or_scalar(o['czml']['start_interval']))
if 'end_interval' in o['czml']:
end_interval = time.to_astropy(time.utc_from_list_or_scalar(o['czml']['end_interval']))

extractor.add_object(sat, N=N, label_text=name, label_show=label_show,
start_interval=start_interval, end_interval=end_interval,

# czml
czml_config = o['czml'] if 'czml' in o else {}
label_show = czml_config.get('label_show', False)
path_show = czml_config.get('path_show', (ts_start_ob == t0))
path_color = czml_config.get('path_color', [255, 255, 0])
billboard_show = czml_config.get('billboard_show', True)
billboard_image = czml_config.get('billboard_image', PIC_SATELLITE)

start_interval = time.to_astropy(time.utc_from_list_or_scalar(o['czml']['start_interval'])) if 'start_interval' in czml_config else time.to_astropy(t0)
end_interval = time.to_astropy(time.utc_from_list_or_scalar(o['czml']['end_interval'])) if 'end_interval' in czml_config else time.to_astropy(t2)

extractor.add_object(sat, N=N, label_text=name, start_interval=start_interval, end_interval=end_interval,
start_available=time.to_astropy(ts_start_ob), end_available=time.to_astropy(ts_end_ob),
path_show=path_show, id_name=name, billboard_show=billboard_show, path_color=path_color)
label_show=label_show, path_show=path_show, path_color=path_color, billboard_show=billboard_show,
billboard_image=billboard_image)

# convert document to json
j = extractor.get_document().dumps()
Expand Down Expand Up @@ -208,7 +211,11 @@ def add_ground_station(
label_outline_color=[255, 255, 0, 255],
label_font="16pt Lucida Console",
label_text=None,
label_show=False
label_show=False,
billboard_show=True,
billboard_image=PIC_GROUNDSTATION,
cone_color=[255, 255, 0, 64],
cone_show=True,
):
"""
Adds a ground station
Expand All @@ -235,7 +242,7 @@ def add_ground_station(
label=Label(
show=True,
),
billboard=Billboard(image=PIC_GROUNDSTATION, show=True),
billboard=Billboard(image=billboard_image, show=True),
)

self.packets.append(pckt)
Expand Down Expand Up @@ -263,13 +270,13 @@ def add_ground_station(
backwardExtrapolationType=ExtrapolationTypes.EXTRAPOLATE
),
agi_rectangularSensor=RectangularSensor(
show=True,
show=cone_show,
showIntersection=False,
intersectionColor=Color(rgba=[255, 255, 255, 255]),
intersectionWidth=2,
portionToDisplay="COMPLETE",
lateralSurfaceMaterial=Material(solidColor=SolidColorMaterial(color=Color(rgba=[255, 255, 0, 128]))),
domeSurfaceMaterial=Material(solidColor=SolidColorMaterial(color=Color(rgba=[255, 255, 0, 128]))),
lateralSurfaceMaterial=Material(solidColor=SolidColorMaterial(color=Color(rgba=cone_color))),
domeSurfaceMaterial=Material(solidColor=SolidColorMaterial(color=Color(rgba=cone_color))),
xHalfAngle=np.radians(sensor['x_fov'] / 2),
yHalfAngle=np.radians(sensor['y_fov'] / 2),
radius=Double(
Expand Down Expand Up @@ -302,7 +309,8 @@ def add_object(
end_interval=None,
start_available=None,
end_available=None,
billboard_show=True
billboard_show=True,
billboard_image=PIC_SATELLITE,
):
"""
Adds a SatSim Skyfield object
Expand Down Expand Up @@ -372,7 +380,7 @@ def add_object(
fillColor=Color(rgba=label_fill_color),
outlineColor=Color(rgba=label_outline_color),
),
billboard=Billboard(image=PIC_SATELLITE, show=billboard_show),
billboard=Billboard(image=billboard_image, show=billboard_show),
)

self.packets.append(pckt)
Expand Down
2 changes: 1 addition & 1 deletion satsim/io/fits.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def save(filename, fpa, exposure_time=0, dt_start=datetime.now(), header={}, ove
filename: `string`, the FITS filename.
fpa: `np.array`, input image as a 2D numpy array.
exposure_time: `float`, exposure time for header.
dt_start: `datatime`, datetime of start of exposure.
dt_start: `datetime`, datetime of start of exposure.
header: `dict`, placeholder, not implemented
overwrite: `boolean`, if True overwrite file if it exists
dtype: `string`, 'int16', 'uint16', 'int32', 'uint32', or 'float32'. default: 'int16'
Expand Down
23 changes: 22 additions & 1 deletion satsim/io/satnet.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from collections import OrderedDict

import numpy as np
import tifffile

from satsim.io import fits, image
from satsim.config import save_json
Expand Down Expand Up @@ -156,7 +157,7 @@ def is_ob(a, b):
return data


def write_frame(dir_name, sat_name, fpa_digital, meta_data, frame_num, exposure_time, time_stamp, ssp, show_obs_boxes=True, astrometrics=None, save_pickle=False, dtype='uint16', save_jpeg=True):
def write_frame(dir_name, sat_name, fpa_digital, meta_data, frame_num, exposure_time, time_stamp, ssp, show_obs_boxes=True, astrometrics=None, save_pickle=False, dtype='uint16', save_jpeg=True, ground_truth=None, ground_truth_min=0):
"""Write image and annotation files compatible with SatNet. In addition,
writes annotated images and SatSim configuration file for reference.
Expand All @@ -170,6 +171,9 @@ def write_frame(dir_name, sat_name, fpa_digital, meta_data, frame_num, exposure_
time_stamp: `datetime`, reference time
ssp: `dict`: SatSim parameters to be saved to JSON file
dtype: `string`: Data type to save FITS pixel data as
save_jpeg: `boolean`: specify to save a JPEG annotated image
ground_truth: `OrderedDict`: an ordered dictionary of arrays or numbers
ground_truth_min: `float`, set any value less than this number in ground_truth to 0
"""

file_name = '{}.{:04d}'.format(sat_name, frame_num)
Expand Down Expand Up @@ -201,3 +205,20 @@ def write_frame(dir_name, sat_name, fpa_digital, meta_data, frame_num, exposure_

# save sim config
save_json(os.path.join(dir_name,'config.json'), ssp, save_pickle=save_pickle)

# save ground truth
if ground_truth is not None:

keys = ','.join(ground_truth.keys())

# broadcast scalars
def f(x):
return x if x.shape == fpa_digital.shape else np.resize(x, fpa_digital.shape)

ground_truth = np.stack(list(map(f, ground_truth.values())))

# clip values
ground_truth[ground_truth < ground_truth_min] = 0

tifffile.imwrite(os.path.join(annotation_dir, '{}.tiff'.format(file_name)), np.stack(ground_truth), dtype='float32', bigtiff=True, compression='lzw',
metadata={'ImageDescription': keys})
Loading

0 comments on commit befc2cf

Please sign in to comment.