Help for MARSXYZFOCUS

PURPOSE:
WATSON, just like MSL MAHLI, computes and returns depth-from-focus products such 
as the 'EDM' depth map along with the corresponding 'EZS' z-stack image.  The 
goal of this program is to use these maps to create an actual mesh, for which an
XYZ image needs to be created first and the run through the usual mesh processes.
The same process applies to MSL MAHLI, except for how searching is done, and 
also may apply to the ACI camera.

MARSXYZFOCUS takes a list of EZS/EDM parent images, typically eight, and 
first extracts their focus values. It then creates a DN to range curve based on
those values, given working distance values specified in meters. This curve is 
used to determine a ray which intersects a plane parallel to the instrument's 
sapphire window. The intersection point is saved as the output XYZ coordinate 
for each pixel.

EXECUTION:
marsxyzfocus inp=edm_image out=xyz_image parents=parentimages.list
 -OR-
marsxyzfocus inp=edm_image out=xyz_image focusvalues=array

where:
 - edm_image is the input EDM grayscale image
 - xyz_image is the output XYZ image
 - parentimages.list is a list of parent images for a given EZS/EDM pair
 - array is a comma-separeted set of focus values for each of the parent images. 
This array is optional, and should be used in case the input images themselves
are unavailable.


METHOD:
Given a set of parent images (typically 2-31) and/or their associated focus 
motor counts, this software first converts these values to range from the front 
surface of the lens, or the surface of the sapphire window for cameras such as
WATSON and ACI. In particular, for M20 the WATSON and ACI toolframes' origins 
are at this surface. The formulas for range conversion were obtained here:  
     https://link.springer.com/article/10.1007/s11214-021-00812-z
     https://zenodo.org/record/5555292#.Yi-qjBDMLZ4

More specifically, the coefficients for the WATSON case were obtained
from data acquired on both Mars and Earth and describe the relation between 
working distance (dw, originally in CENTIMETERS but converted to meters in the
program) and stepper motor count (mopen) when the WATSON 
dust cover is open and elements of the WATSON image are in focus. Those  
coefficients are:

	a = 1.09106×10^6
	b = –332.921
	c = 3.82592×10^(–2)
	d = –1.96922×10^(–6)
	e = 3.84562×10^(–11)
	dw = (a*mopen^(–1) + b + c*mopen + d*mopen^2 + e*mopen^3)^–1

For ACI, the formula is as follows:

	a = 0.005
	b = 20.34
	dw = a*mopen - b

As of now these values are hard-coded, but can be parameterized, preferably with 
something in $MARS_CONFIG_PATH, so it can be adjusted if needed in the future.

NOTE: Just to re-iterate since this is important, the centimeter values are 
converted to meters within the code, to be consistent with the units used in 
XYZ maps.

Next, there is a table which describes the relationship between the grayscale
data value (DN) in the EDM and which image corresponds to the the best focus,
which is a function of the nmber of parent images. For the i-th parent image out
of N in total, the DN value is computed per:
	DN = floor(255-i*255/N)

Now, we fit a curve which allows for the conversion of DN to range, given 
the DN vector as well as the correpsonding motor counts per parent image. 
Piecewise linear interpolation is an acceptable first-order solution, but this 
program performs a more-accurate 2nd-order polynomial fit. The fit is performed
via a least-squares solve using Eigen.

Finally, converting range (in m) to XYZ involves several steps:

1) Range is relative to the front surface of the sapphire window. This is the 
origin of the WATSON/ACI tool frame on M20. On MSL, the origin of the frame is 
where the camera optic axis intersects the plane defined by the top of the 
contact sensor pokers, which is 19mm (0.019m) in front of the lens cover. 
Alternatively, an arbitrary offset can be provided via the "PROJ_ORIGIN"
parameter. Given the projection origin and the 'A' camera orientation vector, 
also computed previously, we can create a plane that is coincident with the 
sapphire and is perpendicular to the optical axis. The origin and 'A' vector are
used in Step 5 below.
	 
2) For each pixel, we find the closest input image, using the DN vector, and 
extract the camera model from that image.  Currently, we have only one camera 
model across all focuses, but in the future we may get focus-dependent camera 
models, so we'll pull from the correct image. Also, camera model interpolation 
between focus values likely won't make a difference, so the closest value should 
suffice.

3) Use the chosen camera model to project a ray into space for the current pixel.

4) Use the computed range to offset the plane from (1) as defined by the origin
and 'A' vector along the plane's normal. 

5) Intersect the projected ray with the offset plane, which defines the XYZ 
coordinate for that pixel and save the XYZ coordinate in an XYZ image.

Finally, the XYZ coordinates for all pixels are saved as an XYZ image, from 
which a mesh can be created using for example 'marsmesh':

     $MARSLIB/marsmesh inp=xyz.VIC out=mesh.obj in_skin=image.png
	  - where image.png corresponds to the input EDM depth map, used for texture

ADDITIONAL NOTES:

The code does not current work well with thumbnails provided as parent images.
Another future improvement could be to handle cases where thumbnails are 
provided for most of the images but one full frame. That frame can be used to 
determine the coordinate system and other functions, but the focus values should
still be picked up from the rest of the thumbs.


COGNIZANT PROGRAMMER: Mauricio Hess-Flores

HISTORY:
  2022-04-01 M. Hess-Flores - Initial marsxyzfocus 


PARAMETERS:


INP

Input EDM image file.

OUT

Output XYZ image file.

PARENTS

Input parent image list. Typically 8 parent images for an EZS/EDM pair, but can vary from 2-31.

FOCUSARRAY

Optional array containing focus values for each parent image (comma- separated), typically 8 values but can vary from 2-31.

MISSION

Choose between MSL and M20 (default).

CAMERA

Choose betwen ACI and WATSON (default) in case the mission is M20. If it's MSL, the camera is always MAHLI.

ORDER

Polynomial order for range curve fitting.

CAMOFFSET

Distance between the camera model and the sapphire window.

ORIGIN

3D origin point override for ranges.

CONFIG_PATH

Path used to find configuration/calibration files.

POINT_METHOD

Specifies a mission- specific pointing method to use

NOSITE

Disables coordinate system sites.

RSF

Rover State File(s) to use.

DEBUG_RSF

Turns on debugging of RSF parameter.

COORD

Coordinate system to use.

COORD_INDEX

Coordinate system index for some COORD/mission combos.

FIXED_SITE

Which site is FIXED for rover missions.

SOLUTION_ID

Solution ID to use for COORD_INDEX

DATA_SET_NAME

Specifies the full name given to a data set or a data product.

DATA_SET_ID

Specifies a unique alphanumeric identifier for a data set or data product.

RELEASE_ID

Specifies the unique identifier associated with the release to the public of all or part of a data set. The release number is associated with the data set, not the mission.

PRODUCT_ID

Specifies a permanent, unique identifier assigned to a data product by its producer.

PRODUCER_ID

Specifies the unique identifier of an entity associated with the production a data set.

PRODUCER_INST

Specifies the full name of the identity of an entity associated with the production of a data set.

TARGET_NAME

Specifies a target.

TARGET_TYPE

Specifies the type of a named target.

WRITE_CM

Writes the output camera model to the output depth file.

PROJ_ORIGIN

User-provided projection origin which overrides the center of projection.

PO_COORD

Coordinate system used to define the PROJ_ORIGIN parameter.

See Examples:


Cognizant Programmer: