Skip to content

Commit

Permalink
adding docs. moving parameters for easier visiblity
Browse files Browse the repository at this point in the history
  • Loading branch information
ramanakumars committed Aug 19, 2024
1 parent 232085d commit e10ffb1
Show file tree
Hide file tree
Showing 4 changed files with 196 additions and 111 deletions.
99 changes: 30 additions & 69 deletions projection/camera_funcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@


class CameraModel():
'''Holds the camera model and filter specific variables
'''
holds the camera model and filter specific
variables
'''

def __init__(self, filt):
def __init__(self, filt: int):
"""Initialize the camera and load the corresponding variables from the SPICE kernel pool
:param filt: The filter number (0 for blue, 1 for green and 2 for red)
"""
self.filter = filt
self.id = CAMERA_IDS[filt]

Expand All @@ -32,47 +34,25 @@ def __init__(self, filt):
self.iframe_delay = spice.gdpool(
'INS%s_INTERFRAME_DELTA' % self.id, 0, 32)[0]

'''
functions to obtain positions in JUNOCAM frame
see: https://naif.jpl.nasa.gov/pub/naif/JUNO/kernels/ik/juno_junocam_v03.ti
'''
def pix2vec(self, px: list[float]) -> np.ndarray:
'''Convert from pixel coordinate to vector in the JUNO_JUNOCAM reference frame. See: https://naif.jpl.nasa.gov/pub/naif/JUNO/kernels/ik/juno_junocam_v03.ti
def pix2vec(self, px):
'''
Convert from pixel coordinate to vector in the
JUNO_JUNOCAM reference frame
Parameters
----------
px : array-like
x and y position of pixel centers in the camera
Output
------
v : numpy.ndarray
vector in the JUNO_JUNOCAM reference frame
:param px: x and y position of pixel centers in the camera
:return: vector in the JUNO_JUNOCAM reference frame
'''
camx = px[0] - self.cx
camy = px[1] - self.cy
cam = self.undistort([camx, camy])
v = np.asarray([cam[0], cam[1], self.f1])
return v

def undistort(self, c):
'''
Removes the barrel distortion in the JunoCam image
Parameters
----------
c : array-like
x and y position of pixel centers in the camera
Output
------
xd : float
x position of the pixel after removing barrel distortion
yd : float
y position of the pixel after removing barrel distortion
def undistort(self, c: list[float]) -> tuple[float]:
''' Removes the barrel distortion in the JunoCam image
:param c: x and y position of pixel centers in the camera
:return: tuple containing the x- and y-position of the pixel after removing barrel distortion
'''
xd, yd = c[0], c[1]
for i in range(5):
Expand All @@ -82,45 +62,26 @@ def undistort(self, c):
yd = c[1] / dr
return (xd, yd)

def distort(self, c):
'''
Adds barrel distortion to the image
Parameters
----------
c : array-like
x and y position of undistorted pixel centers in the camera
Output
------
xd : float
x position of the pixel after adding barrel distortion
yd : float
y position of the pixel after adding barrel distortion
def distort(self, c: list[float]) -> tuple[float]:
'''Adds barrel distortion to the image
:param c: x and y position of undistorted pixel centers in the camera
:return: x- and y- position of the pixel after adding barrel distortion
'''
xd, yd = c[0], c[1]
r2 = (xd**2 + yd**2)
dr = 1 + self.k1 * r2 + self.k2 * r2 * r2
xd *= dr
yd *= dr
return [xd, yd]
return (xd, yd)

def vec2pix(self, v):
'''
Convert a vector in the JUNO_JUNOCAM reference frame
to pixel coordinates on the plate
Parameters
----------
v : array-like
vector in the JUNO_JUNOCAM reference frame
Output
------
x : float
x-center of the pixel in the plate
y : float
y-center of the pixel in the plate
def vec2pix(self, v: list[float]) -> tuple[float]:
'''Convert a vector in the JUNO_JUNOCAM reference frame to pixel coordinates on the plate
:param v: vector in the JUNO_JUNOCAM reference frame
:return: x- and y-center of the pixel in the plate
'''
alpha = v[2] / self.f1
cam = [v[0] / alpha, v[1] / alpha]
Expand Down
54 changes: 41 additions & 13 deletions projection/frameletdata.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,14 @@


class FrameletData:
"""Holds information and methods pertaining to all the framelets in the image
"""
def __init__(self, metadata: dict, imgfolder: str):
"""Initialize the structure by reading in the metadata and separating the framelets in the image
:param metadata: input image metadata
:param imgfolder: path to the folder where the image is stored
"""
self.nframelets = int(metadata["LINES"] / FRAME_HEIGHT)
# number of RGB frames
self.nframes = int(self.nframelets / 3)
Expand Down Expand Up @@ -63,7 +70,11 @@ def __init__(self, metadata: dict, imgfolder: str):

self.fullimg = np.concatenate([frame.rawimg for frame in self.framelets], axis=0)

def get_backplane(self, num_procs: int):
def get_backplane(self, num_procs: int) -> None:
"""Retrieve backplane information for all framelets (i.e., get pixel coordinates in the mid-plane frame and also incidence/emission angles)
:param num_procs: number of processors to use for multi-threaded processing
"""
tmid = self.tmid

if num_procs > 1:
Expand All @@ -84,42 +95,61 @@ def get_backplane(self, num_procs: int):
for frame in tqdm.tqdm(self.framelets):
frame.project_to_midplane(tmid)

def update_jitter(self, jitter: float):
def update_jitter(self, jitter: float) -> None:
"""Update the jitter in the spacecraft clock for each framelet
:param jitter: the new jitter value in seconds
"""
self.jitter = jitter
for framelet in self.framelets:
framelet.jitter = jitter

@property
def tmid(self) -> float:
"""The mid-plane clock time"""
return np.mean([frame.et for frame in self.framelets])

@property
def image(self) -> np.ndarray:
"""The concatenated illumination-corrected image in all the framelets"""
return np.stack([frame.image for frame in self.framelets], axis=0).reshape((self.nframes, 3, FRAME_HEIGHT, FRAME_WIDTH))

@property
def coords(self) -> np.ndarray:
"""The concatenated coordinate of each pixel in the mid-plane frame for each pixel in the camera frame"""
return np.stack([frame.coords for frame in self.framelets], axis=0).reshape((self.nframes, 3, FRAME_HEIGHT, FRAME_WIDTH, 2))

@property
def emission(self) -> np.ndarray:
"""The concatenated emission angles for each pixel in the mid-plane frame"""
return np.stack([frame.emission for frame in self.framelets], axis=0).reshape((self.nframes, 3, FRAME_HEIGHT, FRAME_WIDTH))

@property
def incidence(self) -> np.ndarray:
"""The concatenated incidence angles for each pixel in the mid-plane frame"""
return np.stack([frame.incidence for frame in self.framelets], axis=0).reshape((self.nframes, 3, FRAME_HEIGHT, FRAME_WIDTH))

@property
def longitude(self) -> np.ndarray:
"""The concatenated Sys III longitude values for each pixel in the mid-plane frame"""
return np.stack([frame.lon for frame in self.framelets], axis=0).reshape((self.nframes, 3, FRAME_HEIGHT, FRAME_WIDTH))

@property
def latitude(self) -> np.ndarray:
"""The concatenated planetographic latitude value for each pixel in the mid-plane frame"""
return np.stack([frame.lat for frame in self.framelets], axis=0).reshape((self.nframes, 3, FRAME_HEIGHT, FRAME_WIDTH))


class Framelet:
"""Holds information and methods for a single framelet in the JunoCam image"""
def __init__(self, start_et: float, frame_delay: float, frame_no: int, color: int, img: np.ndarray):
"""Initialize the framelet with relevant spacecraft data and camera information
:param start_et: the spacecraft clock time for the start of the exposure in ET
:param frame_delay: the inter-frame delay for this camera
:param frame_no: the index of the 3-color subframe (i.e., the 4th framelet is blue frame #2)
:param color: the filter for this framelet (i.e., 0 for blue, 1 for green and 2 for red)
"""
self.start_et = start_et
self.frame_delay = frame_delay
self.frame_no = frame_no
Expand All @@ -130,12 +160,17 @@ def __init__(self, start_et: float, frame_delay: float, frame_no: int, color: in

@property
def et(self) -> float:
"""Get the observation time for this framelet"""
jitter = 0 if self.jitter is None else self.jitter
return (
self.start_et + self.camera.time_bias + jitter + (self.frame_delay + self.camera.iframe_delay) * self.frame_no
)

def project_to_midplane(self, tmid: float) -> None:
def project_to_midplane(self, tmid: float):
"""Get the backplane information at the mid-plane frame for this framelet. Returns self for multi-processing
:param tmid: the spacecraft clock at the mid-plane frame
"""
coords = np.nan * np.zeros((FRAME_HEIGHT, FRAME_WIDTH, 2))
lat = np.nan * np.zeros((FRAME_HEIGHT, FRAME_WIDTH))
lon = np.nan * np.zeros((FRAME_HEIGHT, FRAME_WIDTH))
Expand Down Expand Up @@ -187,19 +222,12 @@ def project_to_midplane(self, tmid: float) -> None:


def decompand(image: np.ndarray) -> np.ndarray:
"""
Decompands the image from the 8-bit in the public release
"""Decompands the image from the 8-bit in the public release
to the original 12-bit shot by JunoCam
Parameters
----------
image : numpy.ndarray
8-bit input image
:param image: 8-bit input image
Outputs
-------
data : numpy.ndarray
Original 12-bit image
:return: Original 12-bit image
"""
data = np.array(255 * image, dtype=np.uint8)
ny, nx = data.shape
Expand Down
Loading

0 comments on commit e10ffb1

Please sign in to comment.