4

我想以某种聪明的方式访问我在 opencv 2 中的像素。为此,我定义了以下像素结构:

struct mypixels
{
    unsigned char red;
    unsigned char green;
    unsigned char blue;
};

现在我尝试了以下方法并且它有效:

int sz[3] = {2,2};
cv::Mat XL(2,sz, CV_8UC3, cv::Scalar::all(0));
cv::Mat_<cv::Vec3b> pixiter = XL;
pixiter.at<mypixels>(0,0).green = 22;

现在此代码在发布模式下运行良好,但在调试模式下我收到访问冲突错误。我不想破解或重写 opencv 类。我只是想了解我应该怎么做才能让这段代码在发布和调试模式下工作。我想也许我应该像这里写的那样定义我的像素:http: //docs.opencv.org/trunk/modules/core/doc/basic_structures.html#datatype 但我不明白我应该怎么做或应该做什么这里。也许这里有人知道更多。

- 编辑 -

借助 user2151446 的工作解决方案和一些额外的脑力,我得出了这个解决方案:

template<> class cv::DataType<mypixels>
{
public:
    typedef mypixels value_type;
    typedef int work_type;
    typedef unsigned char channel_type;
    typedef value_type vec_type;
    enum { depth = CV_8U, channels = 3,
           type = CV_MAKETYPE(depth, channels), fmt=(int)'u' };
};
4

3 回答 3

4

您的代码在发布模式下“工作”的原因是以下断言被禁用:

template<typename _Tp> inline _Tp& Mat::at(int i0, int i1)
{
    CV_DbgAssert( dims <= 2 && data && (unsigned)i0 < (unsigned)size.p[0] &&
        (unsigned)(i1*DataType<_Tp>::channels) < (unsigned)(size.p[1]*channels()) &&
        CV_ELEM_SIZE1(DataType<_Tp>::depth) == elemSize1());
    return ((_Tp*)(data + step.p[0]*i0))[i1];
}

您可以在 mypixels 的定义之后添加它(虽然我不确定我是否推荐它):

template<> class DataType<mypixels>
{
public:
    typedef mypixels value_type;
    typedef int work_type;
    typedef value_type channel_type;
    typedef value_type vec_type;
    enum { depth = 1, channels = 3,
           type = CV_MAKETYPE(depth, channels) };
};

然后你可以这样做:

Mat_<mypixels>& M1 = (Mat_<mypixels>&)pixiter;
M1.at<mypixels>(0,0).green = 22;
于 2013-06-13T14:33:33.023 回答
2

您应该使用cv::Vec3b类型作为模板参数pixiter.at<T>(row,col)。由于您的自定义类型对应cv::Vec3boyu 的定义,如果您需要,可以直接转换结果。

哦,对了,OpenCV的默认颜色排序是BGR。

于 2013-06-13T14:20:10.117 回答
0

可能有两个问题。

  1. 确保您使用正确的发布模式二进制文件来运行程序。

  2. 您对包含 cv::Vec3b 类型元素的矩阵使用 mypixels 模板化的迭代器是不正确的。尽管它们是类似定义的类型,但不能假定它们是相同的。

最干净的方法是

int sz[3] = {2,2};
cv::Mat XL(2,sz, CV_8UC3, cv::Scalar::all(0));
cv::Mat_<cv::Vec3b> pixiter = XL;
pixiter.at<cv::Vec3b>(0,0).val[1] = 22;

如果你真的想以你的方式做,你可以做这样的事情。但这会在 OpenCV 更改其数据结构时中断,如果偶然的话。

int sz[3] = {2,2};
cv::Mat XL(2,sz, CV_8UC3, cv::Scalar::all(0));
cv::Mat_<cv::Vec3b> pixiter = XL;
cv::Vec3b& aVec = pixiter.at<cv::Vec3b>(0,0);
mypixels& aMyPixel = reinterpret_cast<mypixels&>(aVec);
aMyPixel.green = 22;
于 2013-06-13T14:24:31.067 回答