diff --git a/include/vcl/Image.h b/include/vcl/Image.h index bd643724..1ea468eb 100644 --- a/include/vcl/Image.h +++ b/include/vcl/Image.h @@ -84,7 +84,7 @@ namespace VCL { * * @param cv_img An OpenCV Mat that contains an image */ - Image(const cv::Mat &cv_img); + Image(const cv::Mat &cv_img, bool copy=true); /** * Creates an Image object from an encoded buffer @@ -112,11 +112,21 @@ namespace VCL { /** * Creates a new Image object from an existing Image object + * This will make a deep copy of the arrays. * * @param img An existing Image object */ Image(const Image &img); + /** + * Move constructor, needed to avoid copies of the arrays. + * noexcept is needed to let vectors grow and call the move + * instead of copy constructor. + * + * @param img An existing Image object + */ + Image(const Image &&img) noexcept; + /** * Sets an Image object equal to another Image object * @@ -178,9 +188,11 @@ namespace VCL { /** * Gets an OpenCV Mat that contains the image data * + * @param copy Specify if a deep copy of the cvmat will be made before + * returning the cvmat object. * @return An OpenCV Mat */ - cv::Mat get_cvmat() const; + cv::Mat get_cvmat(bool copy=true); /** * Gets the raw image data diff --git a/src/vcl/Image.cc b/src/vcl/Image.cc index 3c413f30..dbca2ecd 100644 --- a/src/vcl/Image.cc +++ b/src/vcl/Image.cc @@ -46,13 +46,13 @@ Image::Image(const std::string &image_id) _image->read(image_id); } -Image::Image(const cv::Mat &cv_img) +Image::Image(const cv::Mat &cv_img, bool copy) { if ( cv_img.empty() ) { throw VCLException(ObjectEmpty, "Image object is empty"); } - _image = new ImageData(cv_img); + _image = new ImageData(cv_img, copy); } @@ -77,6 +77,11 @@ Image::Image(const Image &img) _image = new ImageData(*img._image); } +Image::Image(const Image &&img) noexcept +{ + _image = new ImageData(*img._image, false); +} + void Image::operator=(const Image &img) { ImageData *temp = _image; @@ -84,14 +89,11 @@ void Image::operator=(const Image &img) delete temp; } - Image::~Image() { delete _image; } - - /* *********************** */ /* GET FUNCTIONS */ /* *********************** */ @@ -130,11 +132,14 @@ Image Image::get_area(const Rectangle &roi) const return img_copy; } -cv::Mat Image::get_cvmat() const +cv::Mat Image::get_cvmat(bool copy) { cv::Mat mat = _image->get_cvmat(); - return mat.clone(); + if (copy) + return mat.clone(); + else + return mat; } void Image::get_raw_data(void* buffer, long buffer_size ) const diff --git a/src/vcl/ImageData.cc b/src/vcl/ImageData.cc index f46bb4dc..264e4d16 100644 --- a/src/vcl/ImageData.cc +++ b/src/vcl/ImageData.cc @@ -35,7 +35,6 @@ #include "ImageData.h" - using namespace VCL; /* *********************** */ @@ -45,6 +44,7 @@ using namespace VCL; /* *********************** */ /* READ OPERATION */ /* *********************** */ + ImageData::Read::Read(const std::string& filename, Image::Format format) : Operation(format), _fullpath(filename) @@ -64,7 +64,8 @@ void ImageData::Read::operator()(ImageData *img) img->_channels = img->_tdb->get_image_channels(); } else { - img->copy_cv(cv::imread(_fullpath, cv::IMREAD_ANYCOLOR)); + cv::Mat img_read = cv::imread(_fullpath, cv::IMREAD_ANYCOLOR); + img->shallow_copy_cv(img_read); if ( img->_cv_img.empty() ) throw VCLException(ObjectEmpty, _fullpath + " could not be read, \ object is empty"); @@ -74,6 +75,7 @@ void ImageData::Read::operator()(ImageData *img) /* *********************** */ /* WRITE OPERATION */ /* *********************** */ + ImageData::Write::Write(const std::string& filename, Image::Format format, Image::Format old_format, bool metadata) : Operation(format), @@ -128,7 +130,7 @@ void ImageData::Resize::operator()(ImageData *img) if ( !img->_cv_img.empty() ) { cv::Mat cv_resized; cv::resize(img->_cv_img, cv_resized, cv::Size(_rect.width, _rect.height)); - img->copy_cv(cv_resized); + img->shallow_copy_cv(cv_resized); } else throw VCLException(ObjectEmpty, "Image object is empty"); @@ -152,7 +154,7 @@ void ImageData::Crop::operator()(ImageData *img) if ( img->_cv_img.rows < _rect.height + _rect.y || img->_cv_img.cols < _rect.width + _rect.x ) throw VCLException(SizeMismatch, "Requested area is not within the image"); cv::Mat roi_img(img->_cv_img, _rect); - img->copy_cv(roi_img); + img->shallow_copy_cv(roi_img); } else throw VCLException(ObjectEmpty, "Image object is empty"); @@ -192,7 +194,7 @@ void ImageData::Flip::operator()(ImageData *img) cv::Mat dst = cv::Mat(img->_cv_img.rows, img->_cv_img.cols, img->_cv_img.type()); cv::flip(img->_cv_img, dst, _code); - img->_cv_img = dst.clone(); + img->shallow_copy_cv(dst); } else throw VCLException(ObjectEmpty, "Image object is empty"); @@ -239,7 +241,7 @@ void ImageData::Rotate::operator()(ImageData *img) cv::Mat dst; cv::warpAffine(img->_cv_img, dst, r, bbox.size()); - img->_cv_img = dst.clone(); + img->shallow_copy_cv(dst); } } else @@ -269,9 +271,12 @@ ImageData::ImageData() _image_id = ""; } -ImageData::ImageData(const cv::Mat &cv_img) +ImageData::ImageData(const cv::Mat &cv_img, bool copy) { - copy_cv(cv_img); + if (copy) + deep_copy_cv(cv_img); + else + shallow_copy_cv(cv_img); _format = Image::Format::NONE_IMAGE; _compress = CompressionType::LZ4; @@ -300,7 +305,6 @@ ImageData::ImageData(const std::string &image_id) } else _tdb = NULL; - } ImageData::ImageData(void* buffer, cv::Size dimensions, int cv_type) @@ -318,14 +322,20 @@ ImageData::ImageData(void* buffer, cv::Size dimensions, int cv_type) _tdb->set_compression(_compress); } -ImageData::ImageData(const ImageData &img) +ImageData::ImageData(const ImageData &img, bool copy) { _format = img._format; _compress = img._compress; _image_id = img._image_id; - if ( !(img._cv_img).empty() ) - copy_cv(img._cv_img); + if ( !(img._cv_img).empty() ) { + if (copy) { + deep_copy_cv(img._cv_img); + } + else { + shallow_copy_cv(img._cv_img); + } + } if ( img._tdb != NULL ) _tdb = new TDBImage(*img._tdb); @@ -333,11 +343,13 @@ ImageData::ImageData(const ImageData &img) _tdb = NULL; int start; + if ( img._operations.size() > 0 ) { std::shared_ptr front = img._operations.front(); if (front->get_type() == OperationType::READ) { start = 1; - copy_cv(cv::imread(img._image_id, cv::IMREAD_ANYCOLOR)); + cv::Mat img_read = cv::imread(img._image_id, cv::IMREAD_ANYCOLOR); + shallow_copy_cv(img_read); } else start = 0; @@ -352,7 +364,7 @@ void ImageData::operator=(const ImageData &img) TDBImage *temp = _tdb; if ( !(img._cv_img).empty() ) - copy_cv(img._cv_img); + deep_copy_cv(img._cv_img); else { _channels = img._channels; @@ -381,7 +393,8 @@ void ImageData::operator=(const ImageData &img) std::shared_ptr front = img._operations.front(); if (front->get_type() == OperationType::READ) { start = 1; - copy_cv(cv::imread(img._image_id, cv::IMREAD_ANYCOLOR)); + cv::Mat img_read = cv::imread(img._image_id, cv::IMREAD_ANYCOLOR); + shallow_copy_cv(img_read); } else start = 0; @@ -421,8 +434,6 @@ int ImageData::get_type() const cv::Size ImageData::get_dimensions() { - // TODO: iterate over operations themsevles to determine - // image size, rather than performing the operations if ( _operations.size() > 0 ) perform_operations(); return cv::Size(_width, _height); @@ -545,8 +556,10 @@ std::vector ImageData::get_encoded(Image::Format format, if ( _cv_img.empty() ) { if ( _tdb == NULL) throw VCLException(ObjectEmpty, "No data to encode"); - else - copy_cv(_tdb->get_cvmat()); + else { + cv::Mat img = _tdb->get_cvmat(); + shallow_copy_cv(img); + } } std::vector buffer; @@ -653,7 +666,8 @@ void ImageData::set_data_from_raw(void* buffer, long size) void ImageData::set_data_from_encoded(const std::vector &buffer) { - copy_cv(cv::imdecode(buffer, cv::IMREAD_ANYCOLOR)); + cv::Mat img_read = cv::imdecode(buffer, cv::IMREAD_ANYCOLOR); + shallow_copy_cv(img_read); } void ImageData::set_minimum(int dimension) @@ -666,7 +680,6 @@ void ImageData::set_minimum(int dimension) } } - /* *********************** */ /* IMAGEDATA INTERACTION */ /* *********************** */ @@ -752,16 +765,28 @@ void ImageData::delete_object() /* COPY FUNCTIONS */ /* *********************** */ -void ImageData::copy_cv(const cv::Mat &cv_img) +void ImageData::deep_copy_cv(const cv::Mat &cv_img) { _channels = cv_img.channels(); _height = cv_img.rows; - _width = cv_img.cols; + _width = cv_img.cols; _cv_type = cv_img.type(); - _cv_img = cv_img.clone(); + _cv_img = cv_img.clone(); // deep copy +} + +void ImageData::shallow_copy_cv(const cv::Mat &cv_img) +{ + _channels = cv_img.channels(); + + _height = cv_img.rows; + _width = cv_img.cols; + + _cv_type = cv_img.type(); + + _cv_img = cv_img; // shallow copy } template @@ -819,4 +844,3 @@ std::string ImageData::create_fullpath(const std::string &filename, else return filename + "." + ext; } - diff --git a/src/vcl/ImageData.h b/src/vcl/ImageData.h index 466a8b33..3337c318 100644 --- a/src/vcl/ImageData.h +++ b/src/vcl/ImageData.h @@ -370,11 +370,12 @@ namespace VCL { ImageData(); /** - * Creates an ImageData object from the OpenCV Mat. + * Creates an ImageData object from the OpenCV Mat, + * making a deep copy. * * @param cv_img An OpenCV Mat that contains an image */ - ImageData(const cv::Mat &cv_img); + ImageData(const cv::Mat &cv_img, bool copy=true); /** * Creates an ImageData object from the filename @@ -400,7 +401,7 @@ namespace VCL { * * @param img A reference to an existing ImageData object */ - ImageData(const ImageData &img); + ImageData(const ImageData &img, bool copy=true); /** * Sets an ImageData object equal to another ImageData object @@ -643,18 +644,23 @@ namespace VCL { */ void delete_object(); - - private: /* *********************** */ /* COPY FUNCTIONS */ /* *********************** */ /** - * Copies an OpenCV Mat into the ImageData OpenCV Mat + * Copies (deep copy) an OpenCV Mat into the ImageData OpenCV Mat + * + * @param cv_img An existing OpenCV Mat + */ + void deep_copy_cv(const cv::Mat &cv_img); + + /** + * Copies (shallow copy) an OpenCV Mat into the ImageData OpenCV Mat * * @param cv_img An existing OpenCV Mat */ - void copy_cv(const cv::Mat &cv_img); + void shallow_copy_cv(const cv::Mat &cv_img); /** * Copies the ImageData OpenCV Mat into a buffer diff --git a/src/vcl/VideoData.cc b/src/vcl/VideoData.cc index 1a9abfbd..835d2eda 100644 --- a/src/vcl/VideoData.cc +++ b/src/vcl/VideoData.cc @@ -91,7 +91,7 @@ void VideoData::Read::operator()(VideoData *video) if (mat_frame.empty()) break; - frames.push_back(VCL::Image(mat_frame)); + frames.push_back(VCL::Image(mat_frame, false)); } inputVideo.release(); @@ -137,7 +137,7 @@ void VideoData::Write::operator()(VideoData *video) std::vector& frames = video->get_frames(); for (auto& frame : frames) { - outputVideo << frame.get_cvmat(); + outputVideo << frame.get_cvmat(false); } outputVideo.release();