Ask Your Question

Charles Tallman's profile - activity

2016-08-30 12:52:10 -0600 commented answer chamerMatching malloc error

It's good to know about cv::Ptr. However, it seems to be lacking std::enable_shared_from_this, and the std::make_shared has better template support for construction of arbitrary objects.

2016-08-29 21:55:37 -0600 received badge  Student (source)
2016-08-29 14:53:47 -0600 answered a question Nothrow move constructors for Point, Size, Point3, Rect

Not a perfect solution, but I created my own simple geometric types that can be converted to and from the cv types. For example:

namespace nice {
template<typename _Tp> class NicePoint_
{

public:
constexpr NicePoint_();
constexpr NicePoint_(_Tp _x, _Tp _y);

// Regular and move constructors
constexpr NicePoint_(const NicePoint_& rhs) = default;
NicePoint_(NicePoint_&& rhs) noexcept;

// Regular and move assignment
NicePoint_& operator=(const NicePoint_& rhs) = default;
NicePoint_& operator=(NicePoint_&& rhs) noexcept;

// Allow back-and-forth conversion to cv::Point_
NicePoint_(cv::Point_<_Tp>) noexcept;
operator cv::Point_<_Tp>() const noexcept;

// Dot product
_Tp dot(const NicePoint_ & pt) const;

// Dot product in double precision
double ddot(const NicePoint_ & pt) const;

// Cross product
double cross(const NicePoint_ & pt) const;

template<typename _U>
NicePoint_ scale(const _U &s) const
{
    return NicePoint_(x * s, y * s);
}; 

_Tp x, y; //< the point coordinates
};

typedef NicePoint_<int> Point2i;
typedef NicePoint_<float> Point2f;
typedef NicePoint_<double> Point2d;
typedef Point2i Point;
} // end of namespace nice
2016-08-29 14:29:34 -0600 received badge  Editor (source)
2016-08-29 14:27:04 -0600 answered a question chamerMatching malloc error

I found that the Template ownership and lifetime issues get quite complicated. At the heart of the problem is the ChamferMatcher::Template::rescale function, which can either return "this" or a new-allocated Template object. A template can also hold scaled templates in an internal vector. Template pointers can also be copied to Matching, etc.

If one is willing to use the modern C++11 standard library, the problems can be resolved with std::shared_ptr, which does reference counting and only destroys an object when the last pointer to it is destroyed.

std::shared_ptr<ChamferMatcher::Template> ChamferMatcher::Template::rescale(float new_scale)
{

if (fabs(scale - new_scale) < 1e-6) return shared_from_this();

for (size_t i=0;i<scaled_templates.size();++i) {
    if (fabs(scaled_templates[i]->scale-new_scale)<1e-6) {
        return scaled_templates[i];
    }
}

float scale_factor = new_scale/scale;

auto tpl = std::make_shared<Template>();
tpl->scale = new_scale;

tpl->center.x = int(center.x*scale_factor+0.5);
tpl->center.y = int(center.y*scale_factor+0.5);

tpl->size.width = int(size.width*scale_factor+0.5);
tpl->size.height = int(size.height*scale_factor+0.5);

tpl->coords.resize(coords.size());
tpl->orientations.resize(orientations.size());
for (size_t i=0;i<coords.size();++i) {
    tpl->coords[i].first = int(coords[i].first*scale_factor+0.5);
    tpl->coords[i].second = int(coords[i].second*scale_factor+0.5);
    tpl->orientations[i] = orientations[i];
}
scaled_templates.push_back(tpl);

return tpl;

}

All uses of Template* should be replaced with std::shared_ptr<Template> and all uses of const Template * with std::shared_ptr< const Template >. Then all the raw delete operations are not necessary, and the matches can be used safely.

2015-12-16 12:13:42 -0600 received badge  Enthusiast
2015-12-10 11:10:34 -0600 received badge  Supporter (source)
2015-12-08 23:41:19 -0600 asked a question Nothrow move constructors for Point, Size, Point3, Rect

The static asserts currently fail with opencv-3.0.0 with gcc (GCC) 5.1.1 20150618 (Red Hat 5.1.1-4)

#include <type_traits>                  // for is_nothrow_move_constructible
#include <vector>                       // for vector
#include "opencv2/core/types.hpp"       // for Point2d, Rect2d, etc.

struct x_polyline {
    cv::Point2d start;
    std::vector<double> polyline;

    x_polyline(const x_polyline&) = default;
    x_polyline(x_polyline&& rhs) = default;
};

int main()
{
    static_assert(std::is_nothrow_move_constructible<cv::Point2d>::value, "cv::Point2d move constructor could throw");
    static_assert(std::is_nothrow_move_constructible<cv::Point3d>::value, "cv::Point3d move constructor could throw");
    static_assert(std::is_nothrow_move_constructible<cv::Size2d>::value, "cv::Size2d move constructor could throw");
    static_assert(std::is_nothrow_move_constructible<cv::Rect2d>::value, "cv::Rect2d move constructor could throw");

    static_assert(std::is_nothrow_move_constructible<x_polyline>::value, "x_polyline move constructor could throw");

    return 0;
}

The current hand-written copy constructors for these simple classes block the compiler from generating its own move constructors. As the example above shows, this applies to any class that includes them. Such classes will be hard to use in a std::vector, which decides whether to move or copy its contents on reallocation by testing this type trait (using std::move_if_noexcept).

If the copy constructors for cv::Point_, cv::Size_, cv::Point3_ and cv::Rect_ are commented out, or set to "= default", then the asserts will not fail. Would it be possible to do this for a future release of openCV?