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

Add subtraction operation #33

Merged
merged 3 commits into from
Sep 16, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
6 changes: 3 additions & 3 deletions datalab/datalab_session/data_operations/median.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from datalab.datalab_session.data_operations.data_operation import BaseDataOperation
from datalab.datalab_session.exceptions import ClientAlertException
from datalab.datalab_session.file_utils import create_fits, stack_arrays, create_jpgs
from datalab.datalab_session.file_utils import create_fits, crop_arrays, create_jpgs
from datalab.datalab_session.s3_utils import save_fits_and_thumbnails

log = logging.getLogger()
Expand Down Expand Up @@ -51,7 +51,8 @@ def operate(self):

image_data_list = self.get_fits_npdata(input, percent=0.4, cur_percent=0.0)

stacked_data = stack_arrays(image_data_list)
cropped_data_list = crop_arrays(image_data_list)
stacked_data = np.stack(cropped_data_list, axis=2)

# using the numpy library's median method
median = np.median(stacked_data, axis=2)
Expand All @@ -64,6 +65,5 @@ def operate(self):

output = {'output_files': [output_file]}

self.set_percent_completion(1.0)
self.set_output(output)
log.info(f'Median output: {self.get_output()}')
7 changes: 5 additions & 2 deletions datalab/datalab_session/data_operations/rgb_stack.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import logging

from astropy.io import fits
import numpy as np

from datalab.datalab_session.data_operations.data_operation import BaseDataOperation
from datalab.datalab_session.exceptions import ClientAlertException
from datalab.datalab_session.file_utils import get_fits, stack_arrays, create_fits, create_jpgs
from datalab.datalab_session.file_utils import get_fits, crop_arrays, create_fits, create_jpgs
from datalab.datalab_session.s3_utils import save_fits_and_thumbnails

log = logging.getLogger()
Expand Down Expand Up @@ -70,7 +71,9 @@ def operate(self):

# color photos take three files, so we store it as one fits file with a 3d SCI ndarray
arrays = [fits.open(file)['SCI'].data for file in fits_paths]
stacked_data = stack_arrays(arrays)
cropped_data_list = crop_arrays(arrays)
stacked_data = np.stack(cropped_data_list, axis=2)

fits_file = create_fits(self.cache_key, stacked_data)

output_file = save_fits_and_thumbnails(self.cache_key, fits_file, large_jpg_path, small_jpg_path)
Expand Down
90 changes: 90 additions & 0 deletions datalab/datalab_session/data_operations/subtraction.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import logging

import numpy as np

from datalab.datalab_session.data_operations.data_operation import BaseDataOperation
from datalab.datalab_session.exceptions import ClientAlertException
from datalab.datalab_session.file_utils import create_fits, create_jpgs, crop_arrays
from datalab.datalab_session.s3_utils import save_fits_and_thumbnails

log = logging.getLogger()
log.setLevel(logging.INFO)


class Subtraction(BaseDataOperation):

@staticmethod
def name():
return 'Subtraction'

@staticmethod
def description():
return """
The Subtraction operation takes in 1..n input images and calculated the subtraction value pixel-by-pixel.
The output is a subtraction image for the n input images. This operation is commonly used for background subtraction.
"""

@staticmethod
def wizard_description():
return {
'name': Subtraction.name(),
'description': Subtraction.description(),
'category': 'image',
'inputs': {
'input_files': {
'name': 'Input Files',
'description': 'The input files to operate on',
'type': 'file',
'minimum': 1,
'maximum': 999
},
'subtraction_file': {
'name': 'Subtraction File',
'description': 'This file will be subtracted from the input images.',
'type': 'file',
'minimum': 1,
'maximum': 1
}
},
}

def operate(self):

input_files = self.input_data.get('input_files', [])
print(f'Input files: {input_files}')
subtraction_file_input = self.input_data.get('subtraction_file', [])
print(f'Subtraction file: {subtraction_file_input}')

if not subtraction_file_input:
raise ClientAlertException('Missing a subtraction file')

if len(input_files) < 1:
raise ClientAlertException('Need at least one input file')

log.info(f'Executing subtraction operation on {len(input_files)} files')

input_image_data_list = self.get_fits_npdata(input_files)
self.set_percent_completion(.30)

subtraction_image = self.get_fits_npdata(subtraction_file_input)[0]
self.set_percent_completion(.40)

outputs = []
for index, input_image in enumerate(input_image_data_list):
# crop the input_image and subtraction_image to the same size
input_image, subtraction_image = crop_arrays([input_image, subtraction_image])

difference_array = np.subtract(input_image, subtraction_image)

fits_file = create_fits(self.cache_key, difference_array)
large_jpg_path, small_jpg_path = create_jpgs(self.cache_key, fits_file)

output_file = save_fits_and_thumbnails(self.cache_key, fits_file, large_jpg_path, small_jpg_path, index)
outputs.append(output_file)

self.set_percent_completion(self.get_percent_completion() + .50 * (index + 1) / len(input_files))

output = {'output_files': outputs}

self.set_output(output)
log.info(f'Subtraction output: {self.get_output()}')
5 changes: 2 additions & 3 deletions datalab/datalab_session/file_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ def create_jpgs(cache_key, fits_paths: str, color=False) -> list:

return large_jpg_path, thumbnail_jpg_path

def stack_arrays(array_list: list):
def crop_arrays(array_list: list):
"""
Takes a list of numpy arrays from fits images and stacks them to be a 3d numpy array
cropped since fits images can be different sizes
Expand All @@ -88,8 +88,7 @@ def stack_arrays(array_list: list):
min_y = min(arr.shape[1] for arr in array_list)

cropped_data_list = [arr[:min_x, :min_y] for arr in array_list]

return np.stack(cropped_data_list, axis=2)
return cropped_data_list

def scale_points(height_1: int, width_1: int, height_2: int, width_2: int, x_points=[], y_points=[], flip_y = False, flip_x = False):
"""
Expand Down
2 changes: 1 addition & 1 deletion datalab/datalab_session/s3_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ def save_fits_and_thumbnails(cache_key, fits_path, large_jpg_path, thumbnail_jpg
'fits_url': fits_url,
'large_url': large_jpg_url,
'thumbnail_url': thumbnail_jpg_url,
'basename': f'{cache_key}',
'basename': f'{cache_key}-{index}' if index else cache_key,
'source': 'datalab'}
)

Expand Down
9 changes: 4 additions & 5 deletions datalab/datalab_session/tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,10 @@ def test_stack_arrays(self):
test_array_1 = np.zeros((10, 20))
test_array_2 = np.ones((20, 10))

stacked_array = stack_arrays([test_array_1, test_array_2])
self.assertIsInstance(stacked_array, np.ndarray)
self.assertEqual(stacked_array.shape, (10, 10, 2))
self.assertEqual(stacked_array[:, :, 0].tolist(), np.zeros((10, 10)).tolist())
self.assertEqual(stacked_array[:, :, 1].tolist(), np.ones((10, 10)).tolist())
cropped_array = crop_arrays([test_array_1, test_array_2])
self.assertEqual(len(cropped_array), 2)
self.assertEqual(cropped_array[0].tolist(), np.zeros((10, 10)).tolist())
self.assertEqual(cropped_array[1].tolist(), np.ones((10, 10)).tolist())

def test_scale_points(self):
x_points = [1, 2, 3]
Expand Down
Loading