From fe3d5901c18088804abc1d179504089e65689e9f Mon Sep 17 00:00:00 2001 From: Davis King Date: Sat, 8 Feb 2014 17:46:35 -0500 Subject: [PATCH] Clarified the spec for extract_image_chips() and also made it so the user can explicitly specify the dimensions of the extracted chips. --- dlib/image_transforms/interpolation.h | 55 +++++++--- .../image_transforms/interpolation_abstract.h | 101 ++++++++++++++---- 2 files changed, 126 insertions(+), 30 deletions(-) diff --git a/dlib/image_transforms/interpolation.h b/dlib/image_transforms/interpolation.h index 8aeba38a6..4c4840b4a 100644 --- a/dlib/image_transforms/interpolation.h +++ b/dlib/image_transforms/interpolation.h @@ -1398,15 +1398,49 @@ namespace dlib // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- + struct chip_dims + { + chip_dims ( + unsigned long rows_, + unsigned long cols_ + ) : rows(rows_), cols(cols_) { } + + unsigned long rows; + unsigned long cols; + }; + struct chip_details { - chip_details() : size(0), angle(0) {} - chip_details(const rectangle& rect_, unsigned long size_) : rect(rect_),size(size_),angle(0) {} - chip_details(const rectangle& rect_, unsigned long size_, double angle_) : rect(rect_),size(size_),angle(angle_) {} + chip_details() : angle(0), rows(0), cols(0) {} + chip_details(const rectangle& rect_, unsigned long size) : rect(rect_),angle(0) + { compute_dims_from_size(size); } + chip_details(const rectangle& rect_, unsigned long size, double angle_) : rect(rect_),angle(angle_) + { compute_dims_from_size(size); } + + chip_details(const rectangle& rect_, const chip_dims& dims) : + rect(rect_),angle(0),rows(dims.rows), cols(dims.cols) {} + chip_details(const rectangle& rect_, const chip_dims& dims, double angle_) : + rect(rect_),angle(angle_),rows(dims.rows), cols(dims.cols) {} rectangle rect; - unsigned long size; double angle; + unsigned long rows; + unsigned long cols; + + inline unsigned long size() const + { + return rows*cols; + } + + private: + void compute_dims_from_size ( + unsigned long size + ) + { + const double relative_size = std::sqrt(size/(double)rect.area()); + rows = static_cast(rect.height()*relative_size + 0.5); + cols = static_cast(size/(double)rows + 0.5); + } }; // ---------------------------------------------------------------------------------------- @@ -1425,11 +1459,11 @@ namespace dlib #ifdef ENABLE_ASSERTS for (unsigned long i = 0; i < chip_locations.size(); ++i) { - DLIB_CASSERT(chip_locations[i].size != 0 && + DLIB_CASSERT(chip_locations[i].size() != 0 && chip_locations[i].rect.is_empty() == false, "\t void extract_image_chips()" << "\n\t Invalid inputs were given to this function." - << "\n\t chip_locations["< chip_locations[i].size) + while (rect.area() > chip_locations[i].size()) { rect = pyr.rect_down(rect); ++depth; @@ -1468,15 +1502,12 @@ namespace dlib chips.resize(chip_locations.size()); for (unsigned long i = 0; i < chips.size(); ++i) { - const double relative_size = std::sqrt(chip_locations[i].size/(double)chip_locations[i].rect.area()); - const long chip_height = static_cast(chip_locations[i].rect.height()*relative_size + 0.5); - const long chip_width = static_cast(chip_locations[i].size/(double)chip_height + 0.5); - chips[i].set_size(chip_height, chip_width); + chips[i].set_size(chip_locations[i].rows, chip_locations[i].cols); // figure out which level in the pyramid to use to extract the chip int level = -1; rectangle rect = chip_locations[i].rect; - while (pyr.rect_down(rect).area() > chip_locations[i].size) + while (pyr.rect_down(rect).area() > chip_locations[i].size()) { ++level; rect = pyr.rect_down(rect); diff --git a/dlib/image_transforms/interpolation_abstract.h b/dlib/image_transforms/interpolation_abstract.h index 0505401b8..034af3798 100644 --- a/dlib/image_transforms/interpolation_abstract.h +++ b/dlib/image_transforms/interpolation_abstract.h @@ -858,6 +858,25 @@ namespace dlib !*/ // ---------------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------------------- + + struct chip_dims + { + /*! + WHAT THIS OBJECT REPRESENTS + This is a simple tool for passing in a pair of row and column values to the + chip_details constructor. + !*/ + + chip_dims ( + unsigned long rows_, + unsigned long cols_ + ) : rows(rows_), cols(cols_) { } + + unsigned long rows; + unsigned long cols; + }; + // ---------------------------------------------------------------------------------------- struct chip_details @@ -868,8 +887,8 @@ namespace dlib another image. In particular, it specifies that the image chip is contained within the rectangle this->rect and that prior to extraction the image should be rotated counter-clockwise by this->angle radians. Finally, - the extracted chip should have this->size pixels in it regardless of the - size of this->rect. + the extracted chip should have this->rows rows and this->cols columns in it + regardless of the shape of this->rect. !*/ @@ -878,8 +897,10 @@ namespace dlib /*! ensures - #rect.is_empty() == true - - #size == 0 + - #size() == 0 - #angle == 0 + - #rows == 0 + - #cols == 0 !*/ chip_details( @@ -889,8 +910,18 @@ namespace dlib /*! ensures - #rect == rect_ - - #size == size_ + - #size() == size_ - #angle == 0 + - #rows and #cols is set such that the total size of the chip is as close + to size_ as possible but still matches the aspect ratio of rect_. + - As long as size_ and the aspect ratio of of rect_ stays constant then + #rows and #cols will always have the same values. This means that, for + example, if you want all your chips to have the same dimensions then + ensure that size_ is always the same and also that rect_ always has the + same aspect ratio. Otherwise the calculated values of #rows and #cols + may be different for different chips. Alternatively, you can use the + chip_details constructor below that lets you specify the exact values for + rows and cols. !*/ chip_details( @@ -901,13 +932,57 @@ namespace dlib /*! ensures - #rect == rect_ - - #size == size_ + - #size() == size_ - #angle == angle_ + - #rows and #cols is set such that the total size of the chip is as close + to size_ as possible but still matches the aspect ratio of rect_. + - As long as size_ and the aspect ratio of of rect_ stays constant then + #rows and #cols will always have the same values. This means that, for + example, if you want all your chips to have the same dimensions then + ensure that size_ is always the same and also that rect_ always has the + same aspect ratio. Otherwise the calculated values of #rows and #cols + may be different for different chips. Alternatively, you can use the + chip_details constructor below that lets you specify the exact values for + rows and cols. + !*/ + + chip_details( + const rectangle& rect_, + const chip_dims& dims + ); + /*! + ensures + - #rect == rect_ + - #size() == dims.rows*dims.cols + - #angle == 0 + - #rows == dims.rows + - #cols == dims.cols + !*/ + + chip_details( + const rectangle& rect_, + const chip_dims& dims, + double angle_ + ); + /*! + ensures + - #rect == rect_ + - #size() == dims.rows*dims.cols + - #angle == angle_ + - #rows == dims.rows + - #cols == dims.cols + !*/ + + inline unsigned long size() const { return rows*cols; } + /*! + ensures + - returns the number of pixels in this chip. This is just rows*cols. !*/ rectangle rect; - unsigned long size; double angle; + unsigned long rows; + unsigned long cols; }; // ---------------------------------------------------------------------------------------- @@ -940,21 +1015,11 @@ namespace dlib - for all valid i: - #chips[i] == The image chip extracted from the position chip_locations[i].rect in img. - - #chips[i].nr()/#chips[i].nc() is approximately equal to - chip_locations[i].rect.height()/chip_locations[i].rect.width() (i.e. the - aspect ratio of the chip is as similar as possible to the aspect ratio of - the rectangle that defines the chip's location in the original image) - - #chips[i].size() is as close to chip_locations[i].size as possible given that - we attempt to keep the chip's aspect ratio similar to chip_locations[i].rect. + - #chips[i].nr() == chip_locations[i].rows + - #chips[i].nc() == chip_locations[i].cols - The image will have been rotated counter-clockwise by chip_locations[i].angle radians, around the center of chip_locations[i].rect, before the chip was extracted. - - As long as chip_locations[i].size and the aspect ratio of of - chip_locations[i].rect stays constant then the dimensions of #chips[i] is - always the same. This means that, for example, if you want all your - chips to have the same dimensions then ensure that chip_location[i].size - is always the same and also that chip_location[i].rect always has the - same aspect ratio. - Any pixels in an image chip that go outside img are set to 0 (i.e. black). !*/