构建cv :: Mat有哪些不同的方法?

时间:2017-08-22 08:16:04

标签: opencv

OpenCV版本3.2.0

我正在阅读Bradski并尝试制作不同的cv :: Mat构造函数 - 单通道。 有人可以告诉,为什么构造函数不起作用?

float data1[6] = {1,2,3,4,5,6};
float data2[6] = {10,20,30,40,50,60};
float data3[6] = {100,200,300,400,500,600};

cv::Mat mat1(3,4,CV_32FC1); //OK
cv::Mat mat2(3,4,CV_32FC1,cv::Scalar(33.3)); //OK
cv::Mat mat3(3,4,CV_32FC1,data1,sizeof(float)); //OK
cv::Mat mat4(cv::Size(3,4),CV_32FC1); //OK
cv::Mat mat5(cv::Size(3,4),CV_32FC1,cv::Scalar(66.6)); //OK
cv::Mat mat6(cv::Size(3,4),CV_32FC1,data2,sizeof(float)); //OK
int sz[] = {8, 8, 8};
cv::Mat bigCube1(3, sz, CV_32FC1); // OK
cv::Mat bigCube2(3, sz, CV_32FC1, cv::Scalar::all(99)); // OK 
cv::Mat bigCube3(3, sz, CV_32FC1, data3, 4); // Not OK, How to initialise a 3D from data?
std::cout << mat1 << std::endl << mat2 << std::endl << mat3 << std::endl << mat4 << std::endl << mat5 << std::endl << mat6 << std::endl; // OK                                                                   
std::cout << bigCube1.at<float>(10,10,10)  << std::endl << bigCube2.at<float>(10,10,10) << std::endl; // OK

cv::Mat img_rgb = cv::imread("lena.jpg", CV_LOAD_IMAGE_COLOR);
std::vector<cv::Range> ranges(3, cv::Range(2,3));

cv::Mat roiRange( img_rgb, cv::Range(100, 300), cv::Range(0, 512)); //OK
cv::Mat roiRect( img_rgb, cv::Rect(0,100,512,200)); // OK
cv::Mat roiRangeMultiple( bigCube1, ranges); // OK

cv::namedWindow("range", CV_WINDOW_AUTOSIZE);
imshow("range", roiRange);  // OK
cv::namedWindow("rect", CV_WINDOW_AUTOSIZE);
imshow("rect", roiRect); // OK
std::cout << roiRangeMultiple.at<float>(0,1,1); // Not OK. Expecting a float value as answer
cv::waitKey(0);

相应的答案是:

[4.6634629e-10, 0, 0, 0;
 0, 0, 0, 0;
 127.62516, 2.8025969e-45, 0, 0]

[33.299999, 33.299999, 33.299999, 33.299999;
 33.299999, 33.299999, 33.299999, 33.299999;
 33.299999, 33.299999, 33.299999, 33.299999]

[1, 2, 3, 4;
 2, 3, 4, 5;
 3, 4, 5, 6]

[0, 0, 0;
 0, 0, 0;
 0, 0, 0;
 0, 0, 0]

[66.599998, 66.599998, 66.599998;
 66.599998, 66.599998, 66.599998;
 66.599998, 66.599998, 66.599998;
 66.599998, 66.599998, 66.599998]

[10, 20, 30;
 20, 30, 40;
 30, 40, 50;
 40, 50, 60]
 0  // bigCube1
 99 // bigCube2

然后lena.jpg的相应答案是Range和Rect的裁剪版本。我不知道如何使用范围。

1 个答案:

答案 0 :(得分:0)

多个问题。

cv::Mat mat3(3,4,CV_32FC1,data1,sizeof(float));

这将在调试模式下崩溃,失败an assertion。即使文档中没有,步长也必须至少为行的长度(即不允许重叠)。

此方案的正确代码类似于。

float data1[12] = { 1, 2, 3, 4, 2, 3, 4, 5, 3, 4, 5, 6 };
cv::Mat mat3(3, 4, CV_32FC1, data1, 4 * sizeof(float));
cv::Mat mat6(cv::Size(3,4),CV_32FC1,data2,sizeof(float));

与先前案例类似的情况。另请注意,这会产生一个形状不同的数组 - 前一个是3行,4列,这个列有4行3列(参见docs of cv::Size)。

float data2[12] = { 10, 20, 30, 40, 20, 30, 40, 50, 30, 40, 50, 60 };
cv::Mat mat6(cv::Size(3, 4), CV_32FC1, data2, 3 * sizeof(float));
cv::Mat bigCube1(3, sz, CV_8UC1);
std::cout << bigCube1 << std::endl;

具有2个以上维度的数组格式为not supported

您可以通过手动打印所有值来测试数组是否已正确创建:

for (auto const& v : cv::Mat1b(bigCube2)) {
    std::cout << uint(v) << " ";
}
std::cout << "\n";
cv::Mat bigCube3(3, sz, CV_32FC1, data3, 4);

这里的问题是最后一个参数。来自the docs

cv::Mat::Mat(int ndims,
    const int *   sizes,
    int type,
    void * data,
    const size_t * steps = 0 
    )
     

步骤 - 在多维数组的情况下,ndims-1步骤的数组(最后一步始终设置为元素大小)。如果未指定,则假定矩阵是连续的。

  • 您没有传递一系列步骤作为最后一个参数(只有一个整数)
  • 您没有传递足够的数据
  • 并且行将再次重叠。

执行此操作的一种方法是

float data3[8 * 8 * 8];
// Populate the data with sequence 0..511
std::iota(std::begin(data3), std::end(data3), 0.0f);

int sz[] = { 8, 8, 8 };
size_t steps[] = { 8 * 8 * sizeof(float), 8 * sizeof(float) };
cv::Mat bigCube3(3, sz, CV_32FC1, data3, steps);
cv::Mat bigCube1(3, sz, CV_8UC1);
// ...
std::cout << roiRangeMultiple.at<float>(0,1,1); // Not OK. Expecting a float value as answer

数据类型为CV_8UC1,因此每个元素都是unsigned char。这意味着您不应该从中提取float值。你的期望是不正确的。 (现在我看到你改变了问题中的代码)。

另外,请注意,cv::Range&#34; start是范围的包含左边界,end是范围&#34;的专有右边界。由于您在每个轴中提取cv::Range(2,3),因此生成的Mat为1 x 1 x 1.因此,您将访问超出范围的元素(同样,这将触发调试模式断言)。

std::cout << roiRangeMultiple.at<unsigned char>(0,0,0);

更改后,您的类型正确。但请注意,您永远不会初始化bigCube1。结果最有可能得到0.0f,将打印为0。您可以自己尝试,只需执行std::cout << 0.0f;并查看。