diff --git a/dlib/image_transforms/interpolation.h b/dlib/image_transforms/interpolation.h index 436d0e385..2373c7389 100644 --- a/dlib/image_transforms/interpolation.h +++ b/dlib/image_transforms/interpolation.h @@ -2145,6 +2145,98 @@ namespace dlib return res; } +// ---------------------------------------------------------------------------------------- + + template < + typename image_type + > + void extract_image_4points ( + const image_type& img_, + image_type& out_, + const std::vector& pts + ) + { + DLIB_CASSERT(pts.size() == 4); + + const_image_view img(img_); + image_view out(out_); + if (out.size() == 0) + return; + + drectangle bounding_box; + for (auto& p : pts) + bounding_box += p; + + const std::array corners = {bounding_box.tl_corner(), bounding_box.tr_corner(), + bounding_box.bl_corner(), bounding_box.br_corner()}; + + matrix dists(4,4); + for (long r = 0; r < dists.nr(); ++r) + { + for (long c = 0; c < dists.nc(); ++c) + { + dists(r,c) = length_squared(corners[r] - pts[c]); + } + } + + matrix idists = matrix_cast(-round(std::numeric_limits::max()*(dists/max(dists)))); + + + const drectangle area = get_rect(out); + std::vector from_points = {area.tl_corner(), area.tr_corner(), + area.bl_corner(), area.br_corner()}; + + // find the assignment of corners to pts + auto assignment = max_cost_assignment(idists); + std::vector to_points(4); + for (size_t i = 0; i < assignment.size(); ++i) + to_points[i] = pts[assignment[i]]; + + auto tform = find_projective_transform(from_points, to_points); + transform_image(img_, out_, interpolate_bilinear(), tform); + } + + template < + typename image_type + > + void extract_image_4points ( + const image_type& img, + image_type& out, + const std::vector& lines + ) + { + DLIB_CASSERT(lines.size() == 4); + + // first find the pair of lines that are most parallel to each other + size_t best_i=0, best_j=1; + double best_angle = 1000; + for (size_t i = 0; i < lines.size(); ++i) + { + for (size_t j = i+1; j < lines.size(); ++j) + { + double angle = angle_between_lines(lines[i],lines[j]); + if (angle < best_angle) + { + best_angle = angle; + best_i = i; + best_j = j; + } + } + } + + std::vector pts; + // now find the corners of the best quadrilateral we can make from these lines. + for (size_t k = 0; k < lines.size(); ++k) + { + if (k == best_i || k == best_j) + continue; + pts.emplace_back(intersect(lines[k], lines[best_i])); + pts.emplace_back(intersect(lines[k], lines[best_j])); + } + + extract_image_4points(img, out, pts); + } + // ---------------------------------------------------------------------------------------- template < diff --git a/dlib/image_transforms/interpolation_abstract.h b/dlib/image_transforms/interpolation_abstract.h index f2da2fb02..e7c400c71 100644 --- a/dlib/image_transforms/interpolation_abstract.h +++ b/dlib/image_transforms/interpolation_abstract.h @@ -1448,6 +1448,60 @@ namespace dlib one for each input full_object_detection. !*/ +// ---------------------------------------------------------------------------------------- + + template < + typename image_type + > + void extract_image_4points ( + const image_type& img, + image_type& out, + const std::vector& pts + ); + /*! + requires + - image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h + - pixel_traits::pixel_type>::has_alpha == false + - pts.size() == 4 + ensures + - The 4 points in pts define a convex quadrilateral and this function extracts + that part of the image and stores it into #out. Therefore, each corner of + the quadrilateral is associated to a corner of #out and bilinear + interpolation and a projective mapping is used to transform the pixels in the + quadrilateral in img into #out. To determine which corners of the + quadrilateral map to which corners of #out we fit the tightest possible + rectangle to the quadrilateral and map its vertices to their nearest + rectangle corners. These corners are then trivially mapped to #out (i.e. + upper left corner to upper left corner, upper right corner to upper right + corner, etc.). + - #out.nr() == out.nr() && #out.nc() == out.nc(). + I.e. out should already be sized to whatever size you want it to be. + !*/ + + template < + typename image_type + > + void extract_image_4points ( + const image_type& img, + image_type& out, + const std::vector& lines + ); + /*! + requires + - image_type == an image object that implements the interface defined in + dlib/image_processing/generic_image.h + - pixel_traits::pixel_type>::has_alpha == false + - lines.size() == 4 + ensures + - This routine simply finds the 4 intersecting points of the given lines and + uses them in a call to the version of extract_image_4points() defined above. + i.e. extract_image_chips(img, out, intersections_between_lines) + - Since 4 lines might intersect at more than 4 locations, we select the + intersections that give a quadrilateral with opposing sides that are as + parallel as possible. + !*/ + // ---------------------------------------------------------------------------------------- template <