Skip to content

Commit

Permalink
Add the --camera-center option to cam_gen
Browse files Browse the repository at this point in the history
  • Loading branch information
oleg-alexandrov committed Oct 22, 2024
1 parent aa18749 commit c96cf75
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 39 deletions.
3 changes: 3 additions & 0 deletions NEWS.rst
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ point2dem (:numref:`point2dem`):
image_align (:numref:`image_align`):
* Let the default alignment method be ``rigid`` rather than ``translation``.

cam_gen (:numref:`cam_gen`):
* Added the option ``--camera-center``.

misc:
* In ``bundle_adjust`` and ``jitter_solve``, save the lists of images and
optimized camera file names (or adjustments). Can be passed in back to
Expand Down
3 changes: 2 additions & 1 deletion docs/correlation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ squares Bundle Adjustment, which is described in detail in

Next, the left and right images are roughly aligned using one of
the four methods: (1) a homography transform of the right image
based on automated tie-point measurements, (2) an affine epipolar
based on automated tie-point measurements (interest point matches),
(2) an affine epipolar
transform of both the left and right images (also based on tie-point
measurements as earlier), the effect of which is equivalent to
rotating the original cameras which took the pictures, (3) a 3D
Expand Down
14 changes: 7 additions & 7 deletions docs/outputfiles.rst
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ Other files created at all stages
\*-<program name>-resource-usage.txt - resource usage files
For Linux, write such a file for each ``parallel_stereo`` subprocess. It
contains the elapsed time and memory usage, as output by ``/usr/bin/time``.
As for log files, these can be written to tile subdirectories and can be
As for log files, these can be written to tile subdirectories that are
deleted after a successful run.

.. _poly_files:
Expand All @@ -215,13 +215,13 @@ a ``.txt`` or ``.csv`` extension. The x and y coordinates are stored as columns
side-by side. Individual polygons are separated by an empty line. A color for
the polygons is specified as a line of the form: ``color = red``. The given
color applies to all polygons on subsequent lines until overridden by another
such statement. An example use is in :numref:`plot_poly`.
such statement. How to create and save such files is shown in :numref:`plot_poly`.

When such polygons are saved, a header will be added to the file, as lines
starting with the pound sign, containing the WKT string for the georeference,
the value of ``--csv-format`` to interpret the vertices, and the style (usually
set to ``poly``). This allows for overlaying polygons with different
georeferences in ``stereo_gui``.
When such polygons are saved, a header will be added to the file, consisting of
lines starting with the pound sign, containing the WKT string for the
georeference, the value of ``--csv-format`` to interpret the vertices, and the
style (usually set to ``poly``). This allows for overlaying polygons with
different georeferences in ``stereo_gui``.


Inspection and properties of the output files
Expand Down
10 changes: 8 additions & 2 deletions docs/tools/cam_gen.rst
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,10 @@ This procedure is not as accurate as approximating an existing camera
(:numref:`cam_gen_prior`).

Some other pixels can be used instead of corners, if using the
``--pixel-values`` option.
``--pixel-values`` option.

The camera center, if known, can be set with the option ``--camera-center``.
Otherwise the program will solve for it.

Lens distortion parameters, if needed, can be added manually to the produced
files (:numref:`pinholemodels`).
Expand Down Expand Up @@ -359,7 +362,7 @@ Command-line options
The camera focal length. If ``--pixel-pitch`` is in millimeters, this
must be in millimeters as well.

--optical-center <float (default: NaN NaN)>
--optical-center <float float (default: NaN NaN)>
The camera optical center. If ``--pixel-pitch`` is in millimeters, this must
be in millimeters as well. If not specified for pinhole cameras, it will be
set to image center (half of image dimensions) times the pixel pitch. The
Expand All @@ -385,6 +388,9 @@ Command-line options
Set the distortion type. Options: ``radtan``, ``transverse``. Only
applicable when creating CSM Frame cameras (:numref:`cam_gen_frame`).

--camera-center <double double double (default: NaN NaN NaN)>
The camera center in ECEF coordinates. If not set, the program will solve for it.

--refine-camera
After a rough initial camera is obtained, refine it using least squares.
This does not support distortion. For CSM Frame cameras, a more powerful
Expand Down
67 changes: 38 additions & 29 deletions src/asp/Tools/cam_gen.cc
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,7 @@ class CameraSolveLMA_Ht: public vw::math::LeastSquaresModelBase<CameraSolveLMA_H
}; // End class CameraSolveLMA_Ht

/// Find the best camera that fits the current GCP
void fit_camera_to_xyz_ht(bool parse_ecef,
Vector3 const& parsed_camera_center, // may not be known
void fit_camera_to_xyz_ht(Vector3 const& parsed_camera_center, // may not be known
Vector3 const& input_camera_center, // may not be known
std::string const& camera_type,
bool refine_camera,
Expand Down Expand Up @@ -194,9 +193,8 @@ void fit_camera_to_xyz_ht(bool parse_ecef,
((PinholeModel*)out_cam.get())->apply_transform(rotation, translation, scale);
}

if (parse_ecef) {
// Overwrite the solved camera center with what is found from the
// frame index file.
if (parsed_camera_center != Vector3(0, 0, 0)) {
// Overwrite the solved camera center with what was passed in
((PinholeModel*)out_cam.get())->set_camera_center(parsed_camera_center);
}
}
Expand Down Expand Up @@ -304,11 +302,12 @@ void parse_values(std::string list, std::vector<T> & values) {
struct Options : public vw::GdalWriteOptions {
std::string image_file, out_camera, lon_lat_values_str, pixel_values_str, datum_str,
reference_dem, frame_index, gcp_file, camera_type, sample_file, input_camera,
stereo_session, bundle_adjust_prefix, parsed_cam_ctr_str, parsed_cam_quat_str,
stereo_session, bundle_adjust_prefix, parsed_camera_center_str, parsed_cam_quat_str,
distortion_str, distortion_type, refine_intrinsics, extrinsics_file;
double focal_length, pixel_pitch, gcp_std, height_above_datum,
cam_height, cam_weight, cam_ctr_weight;
Vector2 optical_center;
vw::Vector3 camera_center;
std::vector<double> lon_lat_values, pixel_values, distortion;
bool refine_camera, parse_eci, parse_ecef, planet_pinhole;
int num_pixel_samples;
Expand Down Expand Up @@ -359,8 +358,11 @@ void handle_arguments(int argc, char *argv[], Options& opt) {
"in x and y. Only applicable when creating CSM cameras. The default is zero "
"distortion. See also --distortion-type.")
("distortion-type", po::value(&opt.distortion_type)->default_value("radtan"),
"Set the distortion type. Options: radtan (default) and transverse. Only applicable "
"when creating CSM Frame cameras.")
"Set the distortion type. Options: radtan (default) and transverse. Only applicable "
"when creating CSM Frame cameras.")
("camera-center",
po::value(&opt.camera_center)->default_value(Vector3(nan, nan, nan),"NaN NaN NaN"),
"The camera center in ECEF coordinates. If not set, the program will solve for it.")
("refine-camera", po::bool_switch(&opt.refine_camera)->default_value(false)->implicit_value(true),
"After a rough initial camera is obtained, refine its pose using least squares.")
("refine-intrinsics", po::value(&opt.refine_intrinsics)->default_value(""),
Expand Down Expand Up @@ -607,9 +609,9 @@ void handle_arguments(int argc, char *argv[], Options& opt) {
std::string x = vals[5];
std::string y = vals[6];
std::string z = vals[7];
opt.parsed_cam_ctr_str = x + " " + y + " " + z;
opt.parsed_camera_center_str = x + " " + y + " " + z;
vw_out() << "Parsed the ECI camera center in km: "
<< opt.parsed_cam_ctr_str <<".\n";
<< opt.parsed_camera_center_str <<".\n";

std::string q0 = vals[8];
std::string q1 = vals[9];
Expand All @@ -627,9 +629,9 @@ void handle_arguments(int argc, char *argv[], Options& opt) {
std::string x = vals[12];
std::string y = vals[13];
std::string z = vals[14];
opt.parsed_cam_ctr_str = x + " " + y + " " + z;
opt.parsed_camera_center_str = x + " " + y + " " + z;
vw_out() << "Parsed the ECEF camera center in km: "
<< opt.parsed_cam_ctr_str <<".\n";
<< opt.parsed_camera_center_str <<".\n";

std::string q0 = vals[15];
std::string q1 = vals[16];
Expand Down Expand Up @@ -1079,24 +1081,31 @@ void form_camera(Options & opt, vw::cartography::GeoReference & geo,

// If we have camera center in ECI or ECEF coordinates in km, convert
// it to meters, then find the height above datum.
Vector3 parsed_cam_ctr(0, 0, 0);
if (opt.parsed_cam_ctr_str != "") {
Vector3 parsed_camera_center(0, 0, 0);
if (opt.parsed_camera_center_str != "") {
std::vector<double> vals;
parse_values<double>(opt.parsed_cam_ctr_str, vals);
parse_values<double>(opt.parsed_camera_center_str, vals);
if (vals.size() != 3)
vw_throw(ArgumentErr() << "Could not parse 3 values from: "
<< opt.parsed_cam_ctr_str << ".\n");
<< opt.parsed_camera_center_str << ".\n");

parsed_cam_ctr = Vector3(vals[0], vals[1], vals[2]);
parsed_cam_ctr *= 1000.0; // convert to meters
vw_out() << "Parsed camera center (meters): " << parsed_cam_ctr << "\n";

Vector3 llh = geo.datum().cartesian_to_geodetic(parsed_cam_ctr);

// If parsed_cam_ctr is in ECI coordinates, the lon and lat won't be accurate
parsed_camera_center = Vector3(vals[0], vals[1], vals[2]);
parsed_camera_center *= 1000.0; // convert to meters
vw_out() << "Parsed camera center (meters): " << parsed_camera_center << "\n";
}

// The camera center can be also set on the command line
if (!std::isnan(opt.camera_center[0])) {
parsed_camera_center = opt.camera_center;
vw_out() << "Using the camera center set on the command line: "
<< std::setprecision(17) << parsed_camera_center << "\n";
}

if (parsed_camera_center != Vector3() && opt.cam_weight > 0) {
// If parsed_camera_center is in ECI coordinates, the lon and lat won't be accurate
// but the height will be.
if (opt.cam_weight > 0)
opt.cam_height = llh[2];
Vector3 llh = geo.datum().cartesian_to_geodetic(parsed_camera_center);
opt.cam_height = llh[2];
}

vw::Quat parsed_cam_quat;
Expand All @@ -1117,7 +1126,7 @@ void form_camera(Options & opt, vw::cartography::GeoReference & geo,
<< " meters with a weight strength of " << opt.cam_weight << ".\n";
}
if (opt.cam_ctr_weight > 0 && opt.refine_camera)
vw_out() << "Will try to have the camera center change little during camera refinement.\n";
vw_out() << "Will constrain the camera center with the camera weight.\n";

Vector3 input_cam_ctr(0, 0, 0); // estimated camera center from input camera
std::vector<double> cam_heights;
Expand All @@ -1132,8 +1141,8 @@ void form_camera(Options & opt, vw::cartography::GeoReference & geo,

// Overwrite the estimated center with what is parsed from vendor's data,
// if this data exists.
if (opt.parse_ecef && parsed_cam_ctr != Vector3())
input_cam_ctr = parsed_cam_ctr;
if (parsed_camera_center != Vector3(0, 0, 0))
input_cam_ctr = parsed_camera_center;

if (opt.lon_lat_values.size() < 3)
vw_throw(ArgumentErr() << "Expecting at least three longitude-latitude pairs.\n");
Expand Down Expand Up @@ -1215,7 +1224,7 @@ void form_camera(Options & opt, vw::cartography::GeoReference & geo,

// Transform it and optionally refine it
bool verbose = true;
fit_camera_to_xyz_ht(opt.parse_ecef, parsed_cam_ctr, input_cam_ctr,
fit_camera_to_xyz_ht(parsed_camera_center, input_cam_ctr,
opt.camera_type, opt.refine_camera,
xyz_vec, opt.pixel_values,
opt.cam_height, opt.cam_weight, opt.cam_ctr_weight, geo.datum(),
Expand Down

0 comments on commit c96cf75

Please sign in to comment.