From 38ef8a2eb7148b8d0153ac8cef9d91ffc2e3ea3b Mon Sep 17 00:00:00 2001 From: Michael Broxton Date: Mon, 27 Nov 2006 19:38:49 +0000 Subject: [PATCH] Vision Workbench release week synchronization. Added a lookat and H vector to the Linescan model. Added HDR documentation first draft. --- docs/workbook/camera_module.tex | 94 ++++++- docs/workbook/hdr_module.tex | 345 +++++++++++++++++++++++++ docs/workbook/workbook.tex | 1 + src/vw/Camera/LinearPushbroomModel.h | 3 + src/vw/Camera/LinescanModel.h | 30 ++- src/vw/Camera/OrbitingPushbroomModel.h | 6 + src/vw/Stereo/StereoModel.cc | 8 +- src/vw/Stereo/StereoModel.h | 17 +- 8 files changed, 476 insertions(+), 28 deletions(-) create mode 100644 docs/workbook/hdr_module.tex diff --git a/docs/workbook/camera_module.tex b/docs/workbook/camera_module.tex index e2abbf41d..5ad453664 100644 --- a/docs/workbook/camera_module.tex +++ b/docs/workbook/camera_module.tex @@ -196,11 +196,6 @@ \subsection{Built-in Camera Models} \subsubsection{Pinhole Cameras} - % Yakimovsky, Y. and Cunningham R., "A System for Extracting - % Three-Dimensional Measurements from a Stereo Pair of TV - % Cameras". Computer Graphics and Image Processing 7, - % pp. 195-210. (1978) - The {\em CAHV camera model} has been widely used in NASA planetary mission for rover navigation and scientific camera systems \cite{yakimovsky78}. It is a basic pinhole camera model: it does not @@ -275,13 +270,9 @@ \subsubsection{Linescan Cameras} \end{center} \label{fig:pinhole} \caption{Geometry of the Linear Pushbroom Camera Model. Credit: - Rajiv Gupta and Richard Hartley \cite{Gupta97}.} + Rajiv Gupta and Richard Hartley \cite{gupta97}.} \end{figure} -% Rajiv Gupta and Richard Hartley. Linear Pushbroom Cameras. IEEE -% Transactions on Pattern Analysis and Machine Intelligence. Vol.19 -% No. 9. September 1997 - The geometry of the linescan imager is subtly different from the geometry of the pinhole camera. See Figure \ref{fig:pushbroom}. Although there is still a center of projection created by the camera's @@ -306,3 +297,86 @@ \subsubsection{Linescan Cameras} orientations. + +\subsection{Exif Exposure Data} +Digital cameras store data about the settings used to take a picture +in the image file according to the Exif standard \cite{exif}. Exif +data is stored using the Image File Directory system described in the +TIFF 6.0 standard \cite{tiff}. Exif tags such as FNumber and +ExposureTime can be used to calculate the exposure the picture was +taken with. Unfortunately the standard is redundant and often poorly +supported by camera manufacturers (for example, many hide the ISO +setting in the maker note instead of storing it in the ISOSpeedRatings +tag). + +The HDR module includes C++ classes ExifData (defined in ExifData.h and ExifData.cc) and +ExifView (defined in ExifView.h and ExifView.cc) for extracting Exif data from images. +Currently they can handle JPEG and TIFF image files. ExifData gives relatively low-level +access to any data stored as an Exif tag, keyed by its unique tag ID (most of these have +\#define's in ExifData.h for readability). ExifView has functions to determine some more +commonly used camera info, checking all relevant Exif tags. ExifData and ExifView were +based on code from jhead, an Exif Jpeg header and thumbnail manipular program in the +public domain \cite{jhead}. + +\begin{verbatim} +/* Attempt to read flash setting. */ +ExifData data; +int flash; +if (data.import_data(``img.tif'')) { + if (data.get_tag_value(TAG_Flash, flash)) { + // ... + } +} + +/* Reliably get F number. */ +ExifView view; +if (view.load_exif(``img.jpg'')) { + double f = view.get_f_number(); + // ... +} +\end{verbatim} + +\subsection{Using HDR Stacks} +The HDR module has a set of free functions that make stitching a stack of LDR +images into an HDR image as simple as one function call. process\_ldr\_images (in +LDRtoHDR.h) takes a std::vector of ImageViews (with grayscale or RGB pixels +and a floating point channel type), sorted from darkest to brightest. This +function assumes a constant exposure ratio between images; it can be specified +or the default of $\sqrt{2}$ can be used for stacks with a ratio of 1 EV. An +overloaded version also accepts a std::vector$<$vw::Vector$<$double$>$ $>$ by reference, +to return the estimated response curves for each channel. + +\begin{verbatim} +/* Generate HDR image from HDR stack. */ +typedef ImageView > Image; +vector images(num_images); +// ... Read input images ... +// Assume default exposure ratio. +Image hdr_image = process_ldr_images(images); +\end{verbatim} + +LDRtoHDRExif.h further defines process\_ldr\_images\_exif, which generates an HDR +image from an array of filenames of LDR images, computing brightness values +from the files' Exif data. Example code usingthis function is in Appendix B. It +also defines another overloaded version of process\_ldr\_images that takes a +std::vector$<$double$>$ of brightness values (as defined by the APEX system \cite{apex}) +instead of a constant exposure ratio. These functions do not require the images +to be in any particular order of have a constant exposure ratio. + +\begin{thebibliography}{1} + +\bibitem{exif} ``Exchangeable image file format for digital still cameras: Exif Version 2.2'', +(Japan Electronics and Information Technology Industries Assocation, 2002), +http://www.exif.org/specifications.html. + +\bibitem{gupta} Gupta, Rajiv and Hartley, Richard. ``Linear Pushbroom Cameras''. IEEE + Transactions on Pattern Analysis and Machine Intelligence. Vol.19 No. 9. September 1997 + +\bibitem{jhead} Wandel, Matthias, ``Exif Jpeg header and thumbnail manipulator program,'' 2006, +http://www.sentex.net/~mwandel/jhead/. + +\bibitem{yakimovsky78} Yakimovsky, Y. and Cunningham R., ``A System for Extracting + Three-Dimensional Measurements from a Stereo Pair of TV Cameras '' + Computer Graphics and Image Processing 7, pp. 195-210. (1978) + +\end{thebibliography} diff --git a/docs/workbook/hdr_module.tex b/docs/workbook/hdr_module.tex new file mode 100644 index 000000000..ca60b4bd6 --- /dev/null +++ b/docs/workbook/hdr_module.tex @@ -0,0 +1,345 @@ +\chapter{High Dynamic Range Imaging} + +Photographers have long understood that the range brightness levels in +a real-world scene is considerably larger than the range that can be +captured by a camera's film or imaging sensor. The luminance of a +outdoor scene can easily span five orders of magnitdue, however +typical digital cameras encode the brightness at a single pixel +location using a modest 8-bits (2 orders of magnitude). Pixels that +fall outside the {\em dynamic range} of the camera sensor will either +be underexposed or overexposed; their values will be at the minimum or +maximum pixel value of the camera, respectively. + +Some digital cameras can save RAW images with higher dynamic range +than normal. These cameras can capture 12 bits per pixel, or 4096 +brightness levels. This expanded dynamic range is often sufficient to +capture scenes with a moderate amount of contrast. To capture scenes +with very high dynamic range you can generate an HDR image from a set +of {\em bracketed} exposures: a group of low dynamic range images of +the exact same scene taken with a set of different exposure settings +that varies from under-exposed to over-exposed. This technique is +subject of section \ref{sec:hdr_merge}. + +The resulting HDR image is generally stored with a channel type of +{\tt float} or {\t int16} to accomodate the expanded dynamic range. +To store HDR images on disk we recommend using the OpenEXR or TIFF +file formats, both of which support 32-bit floating point channel +types. + +Just as capturing HDR images can be challenging, visualizing them is +also difficult. Print media and most display devices can only manage +about 2 orders of magnitude of dynamic range, whereas an HDR image may +have 5 or more orders of magnitude. Simply scaling the image to the +display range will cause it to look overly dark or washed-out. Section +\ref{sec:tonemapping} discusses a technique called {\em tone mapping} +that reduces the dynamic range of an image while preserving as much as +possible the visual contrasts of the original scene. + +\subsection{Merging Bracketed Exposures} +\label{sec:hdr_merge} + +As discussed in the introduction to this chapter, the limited dynamic +range of the sensors on modern cameras necessitates a different +strategy for building true HDR images: exposure backeting. This frees +us from hardware limitations and allows us to set the dynamic range of +the output image by adjusting the range of exposures in the bracket. +If more dynamic range is needed, one can simply add additional +exposures on either side of the bracket. + +For convenience, the exposure ratio between consecutive images is +usually fixed {\em a priori} to guarantee a wide exposure range while +maintaning even brightness overlap between adjacent images in the +bracket. A factor of two is generally recommended. The shutter speed +in generally the preferred method of varying the exposure in a +bracket; changing the aperture or ISO setting can have the same effect +on exposure but they may change the focus or increase noise. + +\subsubsection{Alignment} +It is crucial for the images in an HDR stack to be aligned, both so +that the resulting HDR image is not blurry and so that the camera +response curve can be estimated accurately. The best solution is to +take the HDR stack on a tripod, ideally using remote capture. {\em If + you are able to take the images on a stationary platform, there is + no need to perform image alignment in software.} However, for +handheld photographs, or if dynamic disturbances, such as wind, shake +the camera on the tribpod, software alignment is then likely to be +necessary. + +For HDR stacks shot with a hand-held camera or otherwise unaligned, +the HDR module includes MTBAlign.h, an implementation of the Mean +Threshold Bitmap (although it actually uses the median) alignment +technique \cite{hdrbook}. MTB alignment thresholds two images on their +respective medians and finds the x- and y-shifts that minimize the +difference of the resulting bitmaps. This technique is well-suited for +HDR stacks as the median threshold bitmap is relatively invariant with +respect to the exposure used to take the photo, whereas edges may fade +in and out. The weakness of MTB alignment is that it only considers +translation. This should be sufficient even for most photos taken +hand-held, but to align images that are rotated or otherwise warped, a +more sophisticated alignment technique should be used (the +InterestPoint module, for example). + +\begin{verbatim} +// Find the shift to be applied to img2 to match it most +// closely with img1. + +int shift_bits = 6; // Maximum shift of 64 pixels +int shift[2]; // Will hold (x,y) shift + +// img1 and img2 assumed to be of type +// ImageView >. +get_exp_shift(img1, img2, shift_bits, shift); +\end{verbatim} + +\subsubsection{Camera Response Curves} +The relation between light entering a camera sensor and the pixel +value that is ultimately recorded is non-linear. The function that +maps the amount of light on the sensor (the luminance) to the pixel +value is referred to as the camera response curve. [TODO: Add camera + response curve figure.] + +To create an HDR image that truly represent the physical brightness +levels in a scene, it is necessary to estimate the inverse of the +camera response curves (we assume a separate curve for each channel) +and apply it to the image data. That is, we would like to find a +function that, given a pixel value in the image and its exposure +information, returns the luminance of the scene at that point. +CameraCurve.h and CameraCurve.cc implement {\tt + estimate\_camera\_curve()}, a free function that estimates the +inverse response curve as a polynomial. This routine takes a matrix +of aligned pixel channel values from an HDR stack and their brightness +ratios. This function is used by LDRtoHDR.h and its relatives; most +users will probably not need to call it directly. + +The CameraCurve sources also supply {\tt invert\_curve()}, a free +function that approximates the inverse of a polynomial curve, also as +a polynomial. This is useful to recover the actual camera response +curve (mapping a scaled luminance value to a pixel value) from the +inverse response curve determined by {\t + estimate\_camera\_curve()}. Re-applying the camera response curve to +an HDR image after tone-mapping can improve the colors and overall +visual appeal. See the code example in Appendix B for an example. + +\section{Tone Mapping} + +< need intro > + +\subsection{Global Operators} +Global tone-mapping operators apply the same compressive function to +all pixels in the image. Such operators are implemented in +GlobalToneMap.h/.cc. Currently one such operator is implemented, the +Drago Adaptive Logarithmic Mapping operator. For algorithm details +see \emph{High Dynamic Range Imaging} \cite{hdrbook} or the original +paper \cite{drago}. The Drago operator is currently the operator of +choice in the HDR module. It is quite fast, produces good results for +a wide range of images, and can usually be used with its parameters at +default values. Optionally, the parameters bias (controlling contrast, +usually between 0.7 and 0.9), exposure factor (a simple multiplier to +control the overall brightness of the image), and max display +luminance (usually about 100) can be specified. + +\begin{verbatim} +/* Apply Drago tone-mapping operator */ +ImageView > tone_mapped = drago_tone_map(hdr_image); +\end{verbatim} + +\subsection{Local Operators} +Local tone-mapping operators compress a pixel's dynamic range in a way +dependent on the neighborhood of pixels around it. These operators +mimic the local adaptation of the human eye and are capable of more +striking or artistic results than global operators, but they are also +susceptible to artifacts such as excessive haloing and reverse +gradients. LocalToneMap.h/.cc currently implements the Ashikhmin local +tone-mapping operator \cite{ashikhmin}. It is much slower than the +Drago operator and more prone to artifacts, but may be useful for some +images. Its only parameter is a threshold value (0.5 by default) which +roughly controls the size of the neighborhood used for each pixel. A +threshold value too large will result in haloing. + +\begin{verbatim} +/* Apply Ashikhmin tone-mapping operator */ +ImageView > tone_mapped = ashikhmin_tone_map(hdr_image); +\end{verbatim} + +\section{Panoramic HDR} +Applying HDR techniques to panoramic images is extremely challenging, +as it is necessary to consider how each individual image is placed in +the full panorama. LDRtoHDRPano.h contains prototype code for +computing the response curves from a set of panoramic images and +projecting the individual images into the same luminance +space. Blending the resulting images together into a full panorama is +left to a separate blender. + +The difficult part is computing the camera response curves from the +panoramic images; it would be simpler to compute and cache the +response curves using a standard HDR stack, but on digital cameras the +response curves may vary with settings. Basically, the areas of the +panorama where two or more individual images overlap are used as HDR +stacks for sampling. The panorama is traversed considering one square +section at a time, so that only those images overlapping that section +need to be loaded (keeping all of the individual images in memory at +once would be too memory-inefficient). Brightness data is extracted +from the Exif data in the original images. + +LDRtoHDRPano.h defines the free function +process\_ldr\_images\_pano. The inputs will likely need to be changed +to accept whatever variety of ImageView(Ref) the panorama alignment +algorithm produces. Currently the inputs are a vector of PanoImage +structs, an optional vector of brightness values for the images +(otherwise Exif is used), the width and height of the full panorama, +and a vector of vw::Vectors to store the computed camera response +curves. PanoImage holds the image's file name, a Rect struct which +holds its dimensions and offset within the panorama, and a +brightness\_multiplier field in which process\_ldr\_images\_pano +stores a multiplier that will project the image into the same +luminance space as the others (after applying the camera curves using +the function psi from LDRtoHDR.h). The outputs are the camera response +curves and the brightness multipliers. + +\section{Command Line Utilities} +There are a number of freely available command line utilities which are useful for working +with HDR images. The OpenEXR distribution \cite{openexr} includes several utilities, +including exrdisplay for displaying OpenEXR images. exrtools \cite{exrtools} provides +utilities for converting between OpenEXR and other formats, performing basic operations +on OpenEXR images, and a couple of tone-mapping utilities. pfstools \cite{pfstools} is a +well-integrated set of utilities for reading, writing, manipulating and viewing HDR images. +It has an associated pfstmo project that implements seven of the more prominent tone +mapping operators. + +\begin{verbatim} +/* Create a PanoImage struct */ +PanoImage img = PanoImage(``img.jpg'', Rect(img_x, + img_y, width, height), 0); + +/* Compute response curves and brightness multipliers */ +vector images; +vector > curves; +// ... load images .. +process_ldr_images_pano(images, pano_width, + pano_height, curves); +\end{verbatim} + +\section{List of Files} +\begin{description} +\item[CameraCurve.h, cc] Functions for estimating camera response curves and inverting curves. +\item[ExifData.h, cc] Class for reading Exif data from JPEG or TIFF images. Offers access to +any tag referenced by tag ID. +\item[ExifView.h, cc] Class providing a convenient interface for extracting exposure data +from Exif. +\item[GlobalToneMap.h, cc] Functions for applying global tone-mapping operators. Currently +implements the Drago operator. +\item[GradientDomain.h, cc] Functions for applying gradient domain tone-mapping operator. +Currently implements the Fattal operator. +\item[LDRtoHDR.h] Functions for generating an HDR image from an HDR stack of LDR images +using either a constant exposure ratio. +\item[LDRtoHDRExif.h] Extends functionality of LDRtoHDR.h to use exposure data from Exif. +\item[LDRtoHDRPano.h] Estimates response curves and brightness multipliers for aligned +images in a panorama. +\item[LocalToneMap.h, cc] Functions for applying local tone-mapping operators. Currently +implements the Ashikhmin operator. +\item[print\_exif.cc] An example program which uses ExifView to display some Exif data. +\end{description} + +\section{Full Code Example} +\begin{verbatim} +/* ExifHDR_test.cc + * + * This is a simple test program that stitches an + * Exif-tagged HDR stack into an HDR image, + * performs tone-mapping, and saves several + * versions with different post-processing applied + * for comparison. Usually the best image is + * produced by re-applying the camera response + * curves and then gamma correcting. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace std; +using namespace vw; +using namespace vw::HDR; + +int main(int argc, char** argv) { + typedef ImageView > Image; + + vector > curves; + // Process HDR stack using Exif tags + Image hdr_exif = process_ldr_images_exif(argc - 1, + argv + 1, curves); + write_image("hdr.exr", hdr_exif); + + // Apply Drago tone-mapping operator. + Image tone_mapped = drago_tone_map(hdr_exif); + write_image("tm.jpg", tone_mapped); + + // Apply gamma correction and save. + Image gamma = pow(copy(tone_mapped), 1.0/2.2); + write_image("tm_gamma.jpg", gamma); + + // Re-apply camera response curves and save. + // First must invert curves calculated earlier. + vector > inverse_curves(curves.size()); + for (int i = 0; i < curves.size(); i++) { + invert_curve(curves[i], inverse_curves[i], + RESPONSE_POLYNOMIAL_ORDER); + } + psi(tone_mapped, inverse_curves); + write_image("tm_curved.jpg", tone_mapped); + + // Apply gamma correction after response curves. + // Usually gives best results. + Image tm_c_g = pow(tone_mapped, 1.0/2.2); + write_image("tm_c_g.jpg", tm_c_g); + + return 0; +} +\end{verbatim} + +\begin{thebibliography}{1} + +\bibitem{ashikhmin} Ashikhmin, Michael, ``A Tone Mapping Algorithm for High Contrast Images,'' +{\em Eurographics Workshop on Rendering}, 2002: 1--11. + +\bibitem{exrtools} Biggs, Billy, ``exrtools: a collection of utilities for manipulating +OpenEXR images,'', 2004, http://scanline.ca/exrtools/. + +\bibitem{drago} Drago et al., ``Adaptive Logarithmic Mapping For Displaying High Contrast Scenes,'' +{\em Eurographics}, {\bf 22}(3), 2003. + +\bibitem{exif} ``Exchangeable image file format for digital still cameras: Exif Version 2.2'', +(Japan Electronics and Information Technology Industries Assocation, 2002), +http://www.exif.org/specifications.html. + +\bibitem{fattal} Fattal, Raanan, et. al, ``Gradient Domain High Dynamic Range Compression,'' +{\em ACM Transactions on Graphics}, 2002. + +\bibitem{openexr} Industrial Light and Magic, ``OpenEXR,'' (Lucasfilm Ltd., 2006), +http://www.openexr.com. + +\bibitem{apex} Kerr, Douglas, ``APEX--The Additive System of Photographic Exposure,'' 2006, +http://doug.kerr.home.att.net/pumpkin/APEX.pdf. + +\bibitem{pfstools} Mantiuk, Rafal, and Grzegorz Krawczyk, ``pfstools for HDR processing,'' 2006, +http://www.mpi-inf.mpg.de/resources/pfstools/. + +\bibitem{reinhard} Reinhard, Erik, et. al. ``Photographic Tone Reproduction for Digital Images,'' +{\em ACM Transactions on Graphics}, 2002. + +\bibitem{hdrbook} Reinhard, Erik, Greg Ward, Sumanta Pattanaik, and Paul Debevec, +{\em High Dynamic Range Imaging}, (Boston: Elsevier, 2006). + +\bibitem{jhead} Wandel, Matthias, ``Exif Jpeg header and thumbnail manipulator program,'' 2006, +http://www.sentex.net/~mwandel/jhead/. + +\bibitem{ward} Ward, Greg, et al., ``A Visibility Matching Tone Reproduction Operator for High Dynamic Range Scenes,'' +{\em IEEE Transactions on Visualization and Computer Graphics}, 1997. + +\end{thebibliography} diff --git a/docs/workbook/workbook.tex b/docs/workbook/workbook.tex index 8828b8110..4b3090f42 100644 --- a/docs/workbook/workbook.tex +++ b/docs/workbook/workbook.tex @@ -42,6 +42,7 @@ \include{imageprocessing} \include{typesystem} \include{camera_module} +\include{hdr_module} \chapter{Advanced Topics}\label{ch:advanced-topics} \section{Working with Shallow Views}\label{sec:advanced.shallow} diff --git a/src/vw/Camera/LinearPushbroomModel.h b/src/vw/Camera/LinearPushbroomModel.h index 02d0ebbe1..a9dcb6e2a 100644 --- a/src/vw/Camera/LinearPushbroomModel.h +++ b/src/vw/Camera/LinearPushbroomModel.h @@ -55,6 +55,8 @@ namespace camera { double focal_length, double along_scan_pixel_size, double across_scan_pixel_size, + Vector3 pointing_vec, + Vector3 u_vec, Quaternion const& camera_pose, Vector3 const& initial_position, Vector3 const& velocity_vector) : @@ -66,6 +68,7 @@ namespace camera { along_scan_pixel_size, across_scan_pixel_size, scan_duration / number_of_lines, + pointing_vec, u_vec, LinearPositionInterpolation(initial_position, velocity_vector), ConstantPoseInterpolation(camera_pose)) {} diff --git a/src/vw/Camera/LinescanModel.h b/src/vw/Camera/LinescanModel.h index 17c928b39..6951fe01d 100644 --- a/src/vw/Camera/LinescanModel.h +++ b/src/vw/Camera/LinescanModel.h @@ -53,6 +53,8 @@ namespace camera { double m_across_scan_pixel_size; double m_along_scan_pixel_size; std::vector m_line_times; + Vector3 m_pointing_vec; + Vector3 m_u_vec; public: //------------------------------------------------------------------ @@ -70,6 +72,8 @@ namespace camera { double along_scan_pixel_size, double across_scan_pixel_size, std::vector const& line_times, + Vector3 pointing_vec, + Vector3 u_vec, PositionFuncT const& position_func, PoseFuncT const& pose_func) : m_position_func(position_func), m_pose_func(pose_func) { @@ -86,6 +90,9 @@ namespace camera { m_across_scan_pixel_size = across_scan_pixel_size; m_line_times = line_times; + + m_pointing_vec = normalize(pointing_vec); + m_u_vec = normalize(u_vec); } /// This version of the constructor assumes that the line @@ -97,6 +104,8 @@ namespace camera { double along_scan_pixel_size, double across_scan_pixel_size, double line_integration_time, + Vector3 pointing_vec, + Vector3 u_vec, PositionFuncT const& position_func, PoseFuncT const& pose_func) : m_position_func(position_func), m_pose_func(pose_func) { @@ -115,6 +124,9 @@ namespace camera { m_line_times[i] = sum; sum += line_integration_time; } + + m_pointing_vec = normalize(pointing_vec); + m_u_vec = normalize(u_vec); } virtual ~LinescanModel() {} @@ -151,18 +163,16 @@ namespace camera { Quaternion pose = m_pose_func(m_line_times[int(round(v))]); Matrix rotation_matrix = transpose(pose.rotation_matrix()); - // The viewplane is the y-z plane of the camera coordinate system. - // Assuming the origin of the coordinate system is at the center - // of projection, the image plane is z = +f, and the pixel - // position in camera coordinates is: - double pixel_pos_y = (u + m_sample_offset) * m_across_scan_pixel_size; - Vector pixel_pos(0.0, pixel_pos_y, m_focal_length); + // The viewplane is the [pointing_vec cross u_vec] plane of the + // camera coordinate system. Assuming the origin of the + // coordinate system is at the center of projection, the image + // plane is at pointing_vec = +f, and the pixel position in + // camera coordinates is: + double pixel_pos_u = (u + m_sample_offset) * m_across_scan_pixel_size; + Vector pixel_direction = pixel_pos_u * m_u_vec + m_focal_length * m_pointing_vec; // Transform to world coordinates using the rigid rotation - Vector direction_vec = rotation_matrix * pixel_pos; - return normalize(Vector3 ( direction_vec[0], - direction_vec[1], - direction_vec[2] )); + return normalize(rotation_matrix * pixel_direction); } virtual Vector3 camera_center(Vector2 const& pix = Vector2() ) const { diff --git a/src/vw/Camera/OrbitingPushbroomModel.h b/src/vw/Camera/OrbitingPushbroomModel.h index ee9f7da22..d9d99050b 100644 --- a/src/vw/Camera/OrbitingPushbroomModel.h +++ b/src/vw/Camera/OrbitingPushbroomModel.h @@ -74,6 +74,8 @@ namespace camera { double dt_camera_pose, double t0_position, double dt_position, + Vector3 pointing_vec, + Vector3 u_vec, std::vector > const& camera_poses, std::vector const& positions) : LinescanModel > const& camera_poses, std::vector const& positions) : LinescanModel StereoModel::operator()(ImageView > const& disparity_map, ImageView &error) { - error.set_size(disparity_map.cols(), disparity_map.rows()); - // Error analysis double mean_error = 0.0; double max_error = 0.0; @@ -24,8 +22,10 @@ namespace stereo { // Compute 3D position for each pixel in the disparity map cout << "StereoModel: Applying camera models\n"; for (unsigned int y = 0; y < disparity_map.rows(); y++) { - printf("\tStereoModel computing points: %0.2f%% complete.\r", 100.0f*float(y)/disparity_map.rows()); - fflush(stdout); + if (y % 100 == 0) { + printf("\tStereoModel computing points: %0.2f%% complete.\r", 100.0f*float(y)/disparity_map.rows()); + fflush(stdout); + } for (unsigned int x = 0; x < disparity_map.cols(); x++) { if ( !disparity_map(x,y).missing() ) { xyz(x,y) = (*this)(Vector2( x, y ), diff --git a/src/vw/Stereo/StereoModel.h b/src/vw/Stereo/StereoModel.h index 964fb5eb0..8ac4d79e7 100644 --- a/src/vw/Stereo/StereoModel.h +++ b/src/vw/Stereo/StereoModel.h @@ -45,10 +45,19 @@ namespace stereo { Vector3 originB = m_camera2->camera_center(pix2); Vector3 vecFromB = m_camera2->pixel_to_vector(pix2); - - return triangulate_point(originA, vecFromA, - originB, vecFromB, - error); + + Vector3 result = triangulate_point(originA, vecFromA, + originB, vecFromB, + error); + +// if (pix1.x() == 300 && pix1.y() == 4000) { +// std::cout << "Pix 1: " << pix1 << " pix2: " << pix2 << "\n"; +// std::cout << "A: " << originA << " " << (originA/norm_2(originA)) << " " << vecFromA << "\n"; +// std::cout << "B: " << originB << " " << (originB/norm_2(originB)) << " " << vecFromB << "\n"; +// std::cout << "Result: " << result << " " << (result/norm_2(result)) << "\n\n"; +// } + + return result; } catch (vw::camera::PixelToRayErr &e) { error = 0; return Vector3();