diff --git a/README.md b/README.md index 5bbfdb8..d09bf75 100644 --- a/README.md +++ b/README.md @@ -80,5 +80,5 @@ For inquiries about the commercial licensing of the OpenFace toolkit please cont # Final remarks -I did my best to make sure that the code runs out of the box but there are always issues and I would be grateful for your understanding that this is research code and not full fledged product. However, if you encounter any problems/bugs/issues please contact me on github or by emailing me at Tadas.Baltrusaitis@cl.cam.ac.uk for any bug reports/questions/suggestions. +I did my best to make sure that the code runs out of the box but there are always issues and I would be grateful for your understanding that this is research code and not full fledged product. However, if you encounter any problems/bugs/issues please contact me on github or by emailing me at Tadas.Baltrusaitis@cl.cam.ac.uk for any bug reports/questions/suggestions. I prefer questions and bug reports on github as that provides visibility to others who might be encountering same issues or who have the same questions. diff --git a/exe/FaceLandmarkImg/FaceLandmarkImg.cpp b/exe/FaceLandmarkImg/FaceLandmarkImg.cpp index 0c97339..502ddbb 100644 --- a/exe/FaceLandmarkImg/FaceLandmarkImg.cpp +++ b/exe/FaceLandmarkImg/FaceLandmarkImg.cpp @@ -79,69 +79,6 @@ vector get_arguments(int argc, char **argv) return arguments; } -// TODO rem -void create_display_image(const cv::Mat& orig, cv::Mat& display_image, LandmarkDetector::CLNF& clnf_model) -{ - - // Draw head pose if present and draw eye gaze as well - - // preparing the visualisation image - display_image = orig.clone(); - - // Creating a display image - cv::Mat xs = clnf_model.detected_landmarks(cv::Rect(0, 0, 1, clnf_model.detected_landmarks.rows/2)); - cv::Mat ys = clnf_model.detected_landmarks(cv::Rect(0, clnf_model.detected_landmarks.rows/2, 1, clnf_model.detected_landmarks.rows/2)); - double min_x, max_x, min_y, max_y; - - cv::minMaxLoc(xs, &min_x, &max_x); - cv::minMaxLoc(ys, &min_y, &max_y); - - double width = max_x - min_x; - double height = max_y - min_y; - - int minCropX = max((int)(min_x-width/3.0),0); - int minCropY = max((int)(min_y-height/3.0),0); - - int widthCrop = min((int)(width*5.0/3.0), display_image.cols - minCropX - 1); - int heightCrop = min((int)(height*5.0/3.0), display_image.rows - minCropY - 1); - - double scaling = 350.0/widthCrop; - - // first crop the image - display_image = display_image(cv::Rect((int)(minCropX), (int)(minCropY), (int)(widthCrop), (int)(heightCrop))); - - // now scale it - cv::resize(display_image.clone(), display_image, cv::Size(), scaling, scaling); - - // Make the adjustments to points - xs = (xs - minCropX)*scaling; - ys = (ys - minCropY)*scaling; - - cv::Mat shape = clnf_model.detected_landmarks.clone(); - - xs.copyTo(shape(cv::Rect(0, 0, 1, clnf_model.detected_landmarks.rows/2))); - ys.copyTo(shape(cv::Rect(0, clnf_model.detected_landmarks.rows/2, 1, clnf_model.detected_landmarks.rows/2))); - - // Do the shifting for the hierarchical models as well - for (size_t part = 0; part < clnf_model.hierarchical_models.size(); ++part) - { - cv::Mat xs = clnf_model.hierarchical_models[part].detected_landmarks(cv::Rect(0, 0, 1, clnf_model.hierarchical_models[part].detected_landmarks.rows / 2)); - cv::Mat ys = clnf_model.hierarchical_models[part].detected_landmarks(cv::Rect(0, clnf_model.hierarchical_models[part].detected_landmarks.rows / 2, 1, clnf_model.hierarchical_models[part].detected_landmarks.rows / 2)); - - xs = (xs - minCropX)*scaling; - ys = (ys - minCropY)*scaling; - - cv::Mat shape = clnf_model.hierarchical_models[part].detected_landmarks.clone(); - - xs.copyTo(shape(cv::Rect(0, 0, 1, clnf_model.hierarchical_models[part].detected_landmarks.rows / 2))); - ys.copyTo(shape(cv::Rect(0, clnf_model.hierarchical_models[part].detected_landmarks.rows / 2, 1, clnf_model.hierarchical_models[part].detected_landmarks.rows / 2))); - - } - - //LandmarkDetector::Draw(display_image, clnf_model); - -} - int main (int argc, char **argv) { @@ -271,7 +208,10 @@ int main (int argc, char **argv) open_face_rec.WriteObservation(); } - visualizer.ShowObservation(); + if(face_detections.size() > 0) + { + visualizer.ShowObservation(); + } // Grabbing the next frame in the sequence captured_image = image_reader.GetNextImage(); diff --git a/lib/local/Utilities/Utilities.vcxproj b/lib/local/Utilities/Utilities.vcxproj index ded345a..41dc0ed 100644 --- a/lib/local/Utilities/Utilities.vcxproj +++ b/lib/local/Utilities/Utilities.vcxproj @@ -159,6 +159,7 @@ + diff --git a/lib/local/Utilities/Utilities.vcxproj.filters b/lib/local/Utilities/Utilities.vcxproj.filters index 65b28a5..eadc61c 100644 --- a/lib/local/Utilities/Utilities.vcxproj.filters +++ b/lib/local/Utilities/Utilities.vcxproj.filters @@ -68,5 +68,8 @@ Header Files + + Header Files + \ No newline at end of file diff --git a/lib/local/Utilities/include/ImageCapture.h b/lib/local/Utilities/include/ImageCapture.h index 5d715be..f2a10e6 100644 --- a/lib/local/Utilities/include/ImageCapture.h +++ b/lib/local/Utilities/include/ImageCapture.h @@ -57,8 +57,6 @@ namespace Utilities // Default constructor ImageCapture() {}; - // TODO block copy, move etc. - // Opening based on command line arguments bool Open(std::vector& arguments); @@ -94,9 +92,15 @@ namespace Utilities private: + // Blocking copy and move, as it doesn't make sense to have several readers pointed at the same source + ImageCapture & operator= (const ImageCapture& other); + ImageCapture & operator= (const ImageCapture&& other); + ImageCapture(const ImageCapture&& other); + ImageCapture(const ImageCapture& other); + // Storing the latest captures cv::Mat latest_frame; - cv::Mat latest_gray_frame; + cv::Mat_ latest_gray_frame; // Keeping track of how many files are read and the filenames size_t frame_num; @@ -110,7 +114,6 @@ namespace Utilities bool image_focal_length_set; bool image_optical_center_set; - // TODO make sure the error message makes sense bool no_input_specified; }; diff --git a/lib/local/Utilities/include/ImageManipulationHelpers.h b/lib/local/Utilities/include/ImageManipulationHelpers.h new file mode 100644 index 0000000..6b2be4c --- /dev/null +++ b/lib/local/Utilities/include/ImageManipulationHelpers.h @@ -0,0 +1,124 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2017, Tadas Baltrusaitis all rights reserved. +// +// ACADEMIC OR NON-PROFIT ORGANIZATION NONCOMMERCIAL RESEARCH USE ONLY +// +// BY USING OR DOWNLOADING THE SOFTWARE, YOU ARE AGREEING TO THE TERMS OF THIS LICENSE AGREEMENT. +// IF YOU DO NOT AGREE WITH THESE TERMS, YOU MAY NOT USE OR DOWNLOAD THE SOFTWARE. +// +// License can be found in OpenFace-license.txt +// +// * Any publications arising from the use of this software, including but +// not limited to academic journal and conference publications, technical +// reports and manuals, must cite at least one of the following works: +// +// OpenFace: an open source facial behavior analysis toolkit +// Tadas Baltrušaitis, Peter Robinson, and Louis-Philippe Morency +// in IEEE Winter Conference on Applications of Computer Vision, 2016 +// +// Rendering of Eyes for Eye-Shape Registration and Gaze Estimation +// Erroll Wood, Tadas Baltrušaitis, Xucong Zhang, Yusuke Sugano, Peter Robinson, and Andreas Bulling +// in IEEE International. Conference on Computer Vision (ICCV), 2015 +// +// Cross-dataset learning and person-speci?c normalisation for automatic Action Unit detection +// Tadas Baltrušaitis, Marwa Mahmoud, and Peter Robinson +// in Facial Expression Recognition and Analysis Challenge, +// IEEE International Conference on Automatic Face and Gesture Recognition, 2015 +// +// Constrained Local Neural Fields for robust facial landmark detection in the wild. +// Tadas Baltrušaitis, Peter Robinson, and Louis-Philippe Morency. +// in IEEE Int. Conference on Computer Vision Workshops, 300 Faces in-the-Wild Challenge, 2013. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef __IMAGE_MANIPULATION_HELPERS_h_ +#define __IMAGE_MANIPULATION_HELPERS_h_ + +#include +#include + +namespace Utilities +{ + //=========================================================================== + // Converting between color spaces and bit depths + //=========================================================================== + + // Perform the conversion inplace + static void ConvertToRGB_8bit(cv::Mat& in_out) + { + if (in_out.channels() == 3 && in_out.depth() == CV_16U) + { + in_out = in_out / 256; + } + else if (in_out.channels() == 4) + { + if (in_out.depth() == CV_16U) + { + in_out = in_out / 256; + cv::cvtColor(in_out, in_out, CV_BGRA2BGR); + } + else + { + cv::cvtColor(in_out, in_out, CV_BGRA2BGR); + } + } + else if (in_out.channels() == 1) + { + if (in_out.depth() == CV_16U) + { + in_out = in_out / 256; + cv::cvtColor(in_out, in_out, CV_GRAY2BGR); + } + else + { + cv::cvtColor(in_out, in_out, CV_GRAY2BGR); + } + } + } + + static void ConvertToGrayscale_8bit(const cv::Mat& in, cv::Mat& out) + { + if (in.channels() == 3) + { + // Make sure it's in a correct format + if (in.depth() == CV_16U) + { + cv::Mat tmp = in / 256; + tmp.convertTo(out, CV_8U); + cv::cvtColor(out, out, CV_BGR2GRAY); + } + else + { + cv::cvtColor(in, out, CV_BGR2GRAY); + } + } + else if (in.channels() == 4) + { + if (in.depth() == CV_16U) + { + cv::Mat tmp = in / 256; + tmp.convertTo(out, CV_8U); + cv::cvtColor(out, out, CV_BGRA2GRAY); + } + else + { + cv::cvtColor(in, out, CV_BGRA2GRAY); + } + } + else + { + if (in.depth() == CV_16U) + { + cv::Mat tmp = in / 256; + tmp.convertTo(out, CV_8U); + } + else if (in.depth() == CV_8U) + { + out = in.clone(); + } + } + } + + +} +#endif \ No newline at end of file diff --git a/lib/local/Utilities/include/RecorderCSV.h b/lib/local/Utilities/include/RecorderCSV.h index 743c402..7a625d5 100644 --- a/lib/local/Utilities/include/RecorderCSV.h +++ b/lib/local/Utilities/include/RecorderCSV.h @@ -68,10 +68,14 @@ namespace Utilities const cv::Point3f& gazeDirection0, const cv::Point3f& gazeDirection1, const cv::Vec2d& gaze_angle, const std::vector& eye_landmarks2d, const std::vector& eye_landmarks3d, const std::vector >& au_intensities, const std::vector >& au_occurences); - // TODO have set functions? - private: + // Blocking copy and move, as it doesn't make sense to read to write to the same file + RecorderCSV & operator= (const RecorderCSV& other); + RecorderCSV & operator= (const RecorderCSV&& other); + RecorderCSV(const RecorderCSV&& other); + RecorderCSV(const RecorderCSV& other); + // The actual output file stream that will be written std::ofstream output_file; diff --git a/lib/local/Utilities/include/RecorderHOG.h b/lib/local/Utilities/include/RecorderHOG.h index 69a31ae..e091bff 100644 --- a/lib/local/Utilities/include/RecorderHOG.h +++ b/lib/local/Utilities/include/RecorderHOG.h @@ -68,6 +68,12 @@ namespace Utilities private: + // Blocking copy and move, as it doesn't make sense to read to write to the same file + RecorderHOG & operator= (const RecorderHOG& other); + RecorderHOG & operator= (const RecorderHOG&& other); + RecorderHOG(const RecorderHOG&& other); + RecorderHOG(const RecorderHOG& other); + std::ofstream hog_file; // Internals for recording diff --git a/lib/local/Utilities/include/RecorderOpenFace.h b/lib/local/Utilities/include/RecorderOpenFace.h index b6884d9..25bdd13 100644 --- a/lib/local/Utilities/include/RecorderOpenFace.h +++ b/lib/local/Utilities/include/RecorderOpenFace.h @@ -61,8 +61,6 @@ namespace Utilities ~RecorderOpenFace(); - // TODO copy, assignment and move operators? Do not allow - // Closing and cleaning up the recorder void Close(); @@ -100,6 +98,12 @@ namespace Utilities private: + // Blocking copy, assignment and move operators, as it does not make sense to save to the same location + RecorderOpenFace & operator= (const RecorderOpenFace& other); + RecorderOpenFace & operator= (const RecorderOpenFace&& other); + RecorderOpenFace(const RecorderOpenFace&& other); + RecorderOpenFace(const RecorderOpenFace& other); + // Keeping track of what to output and how to output it const RecorderOpenFaceParameters params; diff --git a/lib/local/Utilities/include/SequenceCapture.h b/lib/local/Utilities/include/SequenceCapture.h index 8995b7b..97f7629 100644 --- a/lib/local/Utilities/include/SequenceCapture.h +++ b/lib/local/Utilities/include/SequenceCapture.h @@ -57,7 +57,8 @@ namespace Utilities // Default constructor SequenceCapture() {}; - // TODO block copy, move etc. + // Destructor + ~SequenceCapture(); // Opening based on command line arguments bool Open(std::vector& arguments); @@ -104,12 +105,18 @@ namespace Utilities private: + // Blocking copy and move, as it doesn't make sense to have several readers pointed at the same source, and this would cause issues, especially with webcams + SequenceCapture & operator= (const SequenceCapture& other); + SequenceCapture & operator= (const SequenceCapture&& other); + SequenceCapture(const SequenceCapture&& other); + SequenceCapture(const SequenceCapture& other); + // Used for capturing webcam and video cv::VideoCapture capture; // Storing the latest captures cv::Mat latest_frame; - cv::Mat latest_gray_frame; + cv::Mat_ latest_gray_frame; // Keeping track of frame number and the files in the image sequence size_t frame_num; diff --git a/lib/local/Utilities/include/Visualizer.h b/lib/local/Utilities/include/Visualizer.h index 787624d..22ebaa6 100644 --- a/lib/local/Utilities/include/Visualizer.h +++ b/lib/local/Utilities/include/Visualizer.h @@ -55,11 +55,7 @@ namespace Utilities // The constructor for the visualizer that specifies what to visualize Visualizer(std::vector arguments); Visualizer(bool vis_track, bool vis_hog, bool vis_align); - - //~Visualizer(); - - // TODO copy, assignment and move operators? Do not allow - + // Adding observations to the visualizer // Pose related observations diff --git a/lib/local/Utilities/src/ImageCapture.cpp b/lib/local/Utilities/src/ImageCapture.cpp index 21d9c88..d9074c6 100644 --- a/lib/local/Utilities/src/ImageCapture.cpp +++ b/lib/local/Utilities/src/ImageCapture.cpp @@ -32,7 +32,7 @@ /////////////////////////////////////////////////////////////////////////////// #include "ImageCapture.h" - +#include "ImageManipulationHelpers.h" #include // Boost includes @@ -177,8 +177,6 @@ bool ImageCapture::Open(std::vector& arguments) return false; } -// TODO proper destructors and move constructors - bool ImageCapture::OpenImageFiles(const std::vector& image_files, float fx, float fy, float cx, float cy) { @@ -318,48 +316,6 @@ bool ImageCapture::OpenDirectory(std::string directory, std::string bbox_directo } -// TODO this should be shared somewhere -void convertToGrayscale(const cv::Mat& in, cv::Mat& out) -{ - if (in.channels() == 3) - { - // Make sure it's in a correct format - if (in.depth() != CV_8U) - { - if (in.depth() == CV_16U) - { - cv::Mat tmp = in / 256; - tmp.convertTo(tmp, CV_8U); - cv::cvtColor(tmp, out, CV_BGR2GRAY); - } - } - else - { - cv::cvtColor(in, out, CV_BGR2GRAY); - } - } - else if (in.channels() == 4) - { - cv::cvtColor(in, out, CV_BGRA2GRAY); - } - else - { - if (in.depth() == CV_16U) - { - cv::Mat tmp = in / 256; - out = tmp.clone(); - } - else if (in.depth() != CV_8U) - { - in.convertTo(out, CV_8U); - } - else - { - out = in.clone(); - } - } -} - void ImageCapture::SetCameraIntrinsics(float fx, float fy, float cx, float cy) { // If optical centers are not defined just use center of image @@ -389,6 +345,7 @@ void ImageCapture::SetCameraIntrinsics(float fx, float fy, float cx, float cy) } } +// Returns a read image in 3 channel RGB format, also prepares a grayscale frame if needed cv::Mat ImageCapture::GetNextImage() { if (image_files.empty() || frame_num >= image_files.size()) @@ -398,14 +355,18 @@ cv::Mat ImageCapture::GetNextImage() return latest_frame; } - latest_frame = cv::imread(image_files[frame_num], -1); + // Load the image as an 8 bit RGB + latest_frame = cv::imread(image_files[frame_num], CV_LOAD_IMAGE_COLOR); if (latest_frame.empty()) { - ERROR_STREAM("Could not open the image: " + image_files[frame_num - 1]); + ERROR_STREAM("Could not open the image: " + image_files[frame_num]); exit(1); } + // Convert the latest frame to 3 channel 8 bit format if it is not in it already + //ConvertToRGB_8bit(latest_frame); TODO check + image_height = latest_frame.size().height; image_width = latest_frame.size().width; @@ -431,7 +392,7 @@ cv::Mat ImageCapture::GetNextImage() SetCameraIntrinsics(_fx, _fy, _cx, _cy); // Set the grayscale frame - convertToGrayscale(latest_frame, latest_gray_frame); + ConvertToGrayscale_8bit(latest_frame, latest_gray_frame); this->name = image_files[frame_num]; diff --git a/lib/local/Utilities/src/RecorderCSV.cpp b/lib/local/Utilities/src/RecorderCSV.cpp index 0df69c6..a8a90ad 100644 --- a/lib/local/Utilities/src/RecorderCSV.cpp +++ b/lib/local/Utilities/src/RecorderCSV.cpp @@ -46,8 +46,6 @@ using namespace Utilities; // Default constructor initializes the variables RecorderCSV::RecorderCSV():output_file(){}; -// TODO the other 4 constructors + destructors? - // Making sure full stop is used for decimal point separation struct fullstop : std::numpunct { char do_decimal_point() const { return '.'; } @@ -178,7 +176,6 @@ bool RecorderCSV::Open(std::string output_file_name, bool is_sequence, bool outp } -// TODO check if the stream is open void RecorderCSV::WriteLine(int observation_count, double time_stamp, bool landmark_detection_success, double landmark_confidence, const cv::Mat_& landmarks_2D, const cv::Mat_& landmarks_3D, const cv::Mat_& pdm_model_params, const cv::Vec6d& rigid_shape_params, cv::Vec6d& pose_estimate, const cv::Point3f& gazeDirection0, const cv::Point3f& gazeDirection1, const cv::Vec2d& gaze_angle, const std::vector& eye_landmarks2d, const std::vector& eye_landmarks3d, @@ -187,7 +184,8 @@ void RecorderCSV::WriteLine(int observation_count, double time_stamp, bool landm if (!output_file.is_open()) { - std::cout << "The output CSV file is not open" << std::endl; + std::cout << "The output CSV file is not open, exiting" << std::endl; + exit(1); } // Making sure fixed and not scientific notation is used diff --git a/lib/local/Utilities/src/RecorderHOG.cpp b/lib/local/Utilities/src/RecorderHOG.cpp index ea0a218..eb469ec 100644 --- a/lib/local/Utilities/src/RecorderHOG.cpp +++ b/lib/local/Utilities/src/RecorderHOG.cpp @@ -40,8 +40,6 @@ using namespace Utilities; // Default constructor initializes the variables RecorderHOG::RecorderHOG() :hog_file() {}; -// TODO the other 4 constructors + destructors? - // Opening the file and preparing the header for it bool RecorderHOG::Open(std::string output_file_name) { diff --git a/lib/local/Utilities/src/RecorderOpenFace.cpp b/lib/local/Utilities/src/RecorderOpenFace.cpp index 9356d83..ee9c221 100644 --- a/lib/local/Utilities/src/RecorderOpenFace.cpp +++ b/lib/local/Utilities/src/RecorderOpenFace.cpp @@ -187,7 +187,7 @@ RecorderOpenFace::RecorderOpenFace(const std::string in_filename, RecorderOpenFa } else { - this->media_filename = path(filename).concat(".jpg").string(); + this->media_filename = path(filename).concat(".bmp").string(); // TODO change back to jpg metadata_file << "Output image:" << this->media_filename << endl; this->media_filename = (path(record_root) / this->media_filename).string(); } diff --git a/lib/local/Utilities/src/SequenceCapture.cpp b/lib/local/Utilities/src/SequenceCapture.cpp index 65edd40..c839a96 100644 --- a/lib/local/Utilities/src/SequenceCapture.cpp +++ b/lib/local/Utilities/src/SequenceCapture.cpp @@ -32,6 +32,7 @@ /////////////////////////////////////////////////////////////////////////////// #include "SequenceCapture.h" +#include "ImageManipulationHelpers.h" #include @@ -248,7 +249,12 @@ bool SequenceCapture::OpenWebcam(int device, int image_width, int image_height, } -// TODO proper destructors and move constructors +// Destructor that releases the capture +SequenceCapture::~SequenceCapture() +{ + if (capture.isOpened()) + capture.release(); +} bool SequenceCapture::OpenVideoFile(std::string video_file, float fx, float fy, float cx, float cy) { @@ -327,7 +333,7 @@ bool SequenceCapture::OpenImageSequence(std::string directory, float fx, float f } // Assume all images are same size in an image sequence - cv::Mat tmp = cv::imread(image_files[0], -1); + cv::Mat tmp = cv::imread(image_files[0], CV_LOAD_IMAGE_COLOR); this->frame_height = tmp.size().height; this->frame_width = tmp.size().width; @@ -346,47 +352,6 @@ bool SequenceCapture::OpenImageSequence(std::string directory, float fx, float f } -void convertToGrayscale(const cv::Mat& in, cv::Mat& out) -{ - if (in.channels() == 3) - { - // Make sure it's in a correct format - if (in.depth() != CV_8U) - { - if (in.depth() == CV_16U) - { - cv::Mat tmp = in / 256; - tmp.convertTo(tmp, CV_8U); - cv::cvtColor(tmp, out, CV_BGR2GRAY); - } - } - else - { - cv::cvtColor(in, out, CV_BGR2GRAY); - } - } - else if (in.channels() == 4) - { - cv::cvtColor(in, out, CV_BGRA2GRAY); - } - else - { - if (in.depth() == CV_16U) - { - cv::Mat tmp = in / 256; - out = tmp.clone(); - } - else if (in.depth() != CV_8U) - { - in.convertTo(out, CV_8U); - } - else - { - out = in.clone(); - } - } -} - void SequenceCapture::SetCameraIntrinsics(float fx, float fy, float cx, float cy) { // If optical centers are not defined just use center of image @@ -450,13 +415,13 @@ cv::Mat SequenceCapture::GetNextFrame() } else { - latest_frame = cv::imread(image_files[frame_num], -1); + latest_frame = cv::imread(image_files[frame_num], CV_LOAD_IMAGE_COLOR); } time_stamp = 0; } - + // Set the grayscale frame - convertToGrayscale(latest_frame, latest_gray_frame); + ConvertToGrayscale_8bit(latest_frame, latest_gray_frame); frame_num++; diff --git a/lib/local/Utilities/src/Visualizer.cpp b/lib/local/Utilities/src/Visualizer.cpp index ae453ca..5fbbd12 100644 --- a/lib/local/Utilities/src/Visualizer.cpp +++ b/lib/local/Utilities/src/Visualizer.cpp @@ -34,6 +34,7 @@ #include "Visualizer.h" #include "VisualizationUtils.h" #include "RotationHelpers.h" +#include "ImageManipulationHelpers.h" // For drawing on images #include @@ -82,10 +83,15 @@ Visualizer::Visualizer(bool vis_track, bool vis_hog, bool vis_align) this->vis_align = vis_align; } + + // Setting the image on which to draw void Visualizer::SetImage(const cv::Mat& canvas, float fx, float fy, float cx, float cy) { + // Convert the image to 8 bit RGB captured_image = canvas.clone(); + ConvertToRGB_8bit(captured_image); + this->fx = fx; this->fy = fy; this->cx = cx; diff --git a/samples/sample3_16bit_gray.png b/samples/sample3_16bit_gray.png new file mode 100644 index 0000000..32cad7f Binary files /dev/null and b/samples/sample3_16bit_gray.png differ diff --git a/samples/sample3_16bit_rgb.png b/samples/sample3_16bit_rgb.png new file mode 100644 index 0000000..15d4011 Binary files /dev/null and b/samples/sample3_16bit_rgb.png differ diff --git a/samples/sample4.jpg b/samples/sample4.jpg index 35523d8..fb0c5b6 100644 Binary files a/samples/sample4.jpg and b/samples/sample4.jpg differ