【问题标题】:OpenCV data of two mats are the same but values when retrieved with Mat::at are corrupted两个垫子的 OpenCV 数据相同,但使用 Mat::at 检索时的值已损坏
【发布时间】:2020-10-01 04:04:04
【问题描述】:

我使用自定义函数对 Mat 进行序列化然后反序列化。当您比较两个函数的uchar* Mat.data 时,它们是相同的,但是当我尝试在第三个元素之后直接使用Mat.at<> 检查值时,元素值会停留在一些损坏的浮点值上。我尝试将元素更改为其他所有值,但没有任何改变。当我序列化-反序列化图像垫和直方图垫时,问题也不会发生。下面是代码,下面是输出。

cv::Mat kernelx = (cv::Mat_<float>(3, 3) << 1, 0, -1, 1, 0, -1, 1, 0, -1);
std::string stroper = dbop::serializeMat(kernelx);
cv::Mat matoper = dbop::deserializeMat(stroper);
for (int i = 0; i < matoper.rows; i++) {
    for (int j = 0; j < matoper.cols; j++) {
        float f1 = (float)kernelx.data[i + j];
        float f2 = (float)matoper.data[i + j];
        std::cout << kernelx.at<float>(i, j) << " " << matoper.at<float>(i, j) << " " << f1 << " " << f2 << " " << std::endl;
    }
}

这是输出。第一个值是原始 Mat 的元素,第二个值是序列化-反序列化 Mat 的元素,第三个值是原始 Mat 转换为 float 的数据值,第四个值是 s-d Mat 的数据值。

1       1               0       0
0       0               0       0
-1      -4.31596e+08    128     128
1       -4.31602e+08    0       0
0       -4.31602e+08    128     128
-1      -4.31602e+08    63      63
1       -4.31602e+08    128     128
0       -4.31602e+08    63      63
-1      -4.31602e+08    0       0

我猜 serializeMat 和 deserializeMat 函数在这里是相关的,所以这里都是。

std::string dbop::serializeMat(cv::Mat operand) {
    std::ostringstream srlzstrstream;
    uchar* pixelPtr = (uchar*)operand.data;
    int cn = operand.channels();
    cv::Scalar_<uchar> cnPixel;

    srlzstrstream << operand.dims << " ";
    for (int i = 0; i < operand.dims; i++) {
        srlzstrstream << operand.size[i] << " ";
    }
    srlzstrstream << operand.type() << " ";

    for (int i = 0; i < operand.total(); i++) {
            for (int k = 0; k < cn; k++) {
                srlzstrstream << (float)pixelPtr[i * cn + k] << " ";
            }
    }
    std::string srlzdstr = srlzstrstream.str();
    return srlzdstr;
}
cv::Mat dbop::deserializeMat(std::string operand){
    std::istringstream desrlzstrstream(operand);
    int mdims, mtype;

    desrlzstrstream >> mdims;
    int* msize = new int[mdims];
    for (int i = 0; i < mdims; i++)
        desrlzstrstream >> msize[i];
    desrlzstrstream >> mtype;

    cv::Mat matoper(mdims, msize, mtype);
    delete [] msize;

    uchar* pixelPtr = (uchar*)matoper.data;
    float cnpixoper;

    for (int i = 0; i < matoper.total(); i++) {
        for (int k = 0; k < matoper.channels(); k++) {
            desrlzstrstream >> cnpixoper;
            pixelPtr[i * matoper.channels() + k] = cnpixoper;
        }
    }
    return matoper;
}

【问题讨论】:

  • (float)pixelPtr[i * cn + k] -- 你忘记了 uchar 是 1 个字节,float 是 4 个字节。演员表太晚了——你已经在错误的位置读取了一个字节。

标签: c++ opencv matrix


【解决方案1】:

+ 编辑
由于您想为泛型类型保存字节,您可以像这样迭代每个字节。

在serializeMat

for (int i = 0; i < operand.total() * operand.elemSize(); i++) {
    srlzstrstream << pixelPtr[i] << " ";
}

在deserializeMat

for (int i = 0; i < matoper.total() * matoper.elemSize(); i++) {
    desrlzstrstream >> cnpixoper;
    pixelPtr[i] = cnpixoper;
}

operand.total() * operand.elemSize() 会给你operand 的字节大小

在这两种情况下,输出都是

   1    1    0    0 
   0    0    0    0 
  -1   -1  128  128 
   1    1    0    0 
   0    0  128  128 
  -1   -1   63   63 
   1    1  128  128 
   0    0   63   63 
  -1   -1    0    0 

【讨论】:

  • 我希望这些函数是适用于各种 Mats 的通用函数。 uchar Mats、float Mats 等。因此,如果这是一个带有 uchar 类型元素的图像 Mat,那么 BIT_RATIO 会是什么?会一样吗?
  • @OneBadStudent 不,会有所不同,因为sizezof(float) 是4,而sizeof(uchar 是1。我会更新我的答案以处理其他类型。
猜你喜欢
  • 1970-01-01
  • 2013-05-08
  • 1970-01-01
  • 1970-01-01
  • 2023-03-09
  • 2014-01-07
  • 2011-10-02
  • 1970-01-01
  • 2019-07-27
相关资源
最近更新 更多