在 OpenCV 中确定矩阵的类型

Posted

技术标签:

【中文标题】在 OpenCV 中确定矩阵的类型【英文标题】:Determining the type of Matrix in OpenCV 【发布时间】:2012-09-17 14:20:39 【问题描述】:

我正在尝试在 opencv 中索引 3 通道图像。

当我读入图像文件时,此代码有效

int Blue  = LeftCol.at<cv::Vec3b>(v,u)[0];
int Green = LeftCol.at<cv::Vec3b>(v,u)[1]; 
int Red   = LeftCol.at<cv::Vec3b>(v,u)[2]; 

但是当我使用网络摄像头输入时它会崩溃。网络摄像头有 3 个频道,u,v0,0 开始。 我不知道为什么它不起作用。 我已经尝试了Vec3bVec3iVec3sVec3fVec3d 的所有变体。

我迷路了....为什么我不能索引这个网络摄像头图像?

编辑

好几个小时后,这就是我必须要去的地方……这是该计划的大纲。我在函数内部遇到了上面提到的问题。所以我又回到了基础,尝试在函数之前查看矩阵...

void main (int argc, char** argv) 
Mat LeftCol;
while (1==1) 
    if (ProgramMode == "Files") 
        //read in the colour images
        LeftCol  = imread(ColImLeft.c_str(),1);
        RightCol = imread(ColImRight.c_str(),1);

     else if (ProgramMode == "Camera") 
        VideoCapture CapLeft, CapRight;
        CapLeft.open(1);
        CapRight.open(2);

        CapLeft  >> LeftCol;
        CapRight >> RightCol;

                    //THIS WORKS, THIS PIXEL VALUES ARE DISPLAYED
        cout << "uchar" << endl;
        for (int x=0;x<10;x++) 
            for (int y=0;y<10;y++) 
                int pixel = LeftCol.at<cv::Vec3b>(x,y)[0];
                cout << pixel;
            
            cout << endl;
        
     //end if

            ///////ADDED THIS BIT ////////
    cout << "channels = " << LeftCol.channels() << endl;
            //^^This bit works, output shows "channels = 3"

            //vv This bit doesn't work.... so there's a problem with LeftCol.
            //I wonder if reading the data like CapLeft  >> LeftCol; is changing something
    imshow("Test",LeftCol);
            ///////ADDED THIS BIT ////////

           //THIS DOES NOT WORK WHEN USING THE CAMERA INPUT, PROGRAM CRASHES
    cout << "uchar" << endl;
    for (int x=0;x<10;x++) 
        for (int y=0;y<10;y++) 
            int pixel = LeftCol.at<cv::Vec3b>(x,y)[0];
            cout << pixel;
         //end for
        cout << endl;
     //end for

    //end while
 //end main

是的,我已经让它工作了,但它并不理想。我正在创建一个临时 Mat 来将文件读入其中然后克隆它们。

        Mat TempLeft;
        Mat TempRight;

        VideoCapture CapLeft, CapRight;
        CapLeft.open(1);
        CapRight.open(2);

        CapLeft  >> TempLeft;
        CapRight >> TempRight;

        LeftCol = TempLeft.clone();
        RightCol = TempRight.clone();

【问题讨论】:

【参考方案1】:

OpenCV 尽可能制作图像的软拷贝。 From the documentation:

数组赋值是一个 O(1) 操作,因为它只复制标题并增加引用计数器。 Mat::clone() 方法可用于在需要时获取数组的完整(深层)副本。

我怀疑正在发生的事情是 LeftCol 使用仍然属于 VideoCapture 对象的数据。如果是这种情况,那么当CapLeftCapRightif 末尾超出范围时,它们会被析构函数关闭并且LeftCol 仍然指向的图像数据将被销毁。

可能的解决方案是按照您的操作克隆图像,或者在 if 块之外声明 VideoCapture CapLeft, CapRight;(如果需要,您仍然可以在内部打开它们)。

【讨论】:

默认情况下制作软拷贝意味着OpenCV不会及时执行复制大量图像数据的操作,除非明确要求这样做,理论上可以加快速度。这在Introduction of the documentation 中进行了讨论。 虽然我猜如果数据还在被引用的话就不应该被删除......【参考方案2】:

您可以使用 cv::Mat.type() 检查类型和使用 cv::Mat.channels() 的通道数

相机返回的数据会按照B,G,R的顺序转换成Vec3b(即uchar * 3)。

你确定图片是有效的 - 其他地方有错误吗?

【讨论】:

.channels() 返回 3,.type() 返回 16...虽然不确定 16 与什么相关...图像看起来不错,我可以使用 imshow("WindowName" , LeftCol) 看起来不错。 您需要将 type() 与图像类型的代码进行比较,例如。 CV_8UC3 (ps 16==CV_8UC3)。确定 u,v 在范围内? 是的,LeftCol 是一个从 .png 或网络摄像头填充的 Mat。无论哪种情况,它的 type()==16 (CV_8UC3) 和 channels==3。 u 和 v 在 for 循环中,并且都从 0 开始,它在第一次循环时崩溃,即 u=v=0。 所以它可以从相机工作但不能从文件?文件读取工作了吗? imread() 不会出错,但生成的图像将是“empty()” 如果 ProgramMode=="File" 一切正常。如果 ProgramMode=="Camera" 它将在 IF 代码内显示像素值,但一旦超出它就会在显示像素值时崩溃。【参考方案3】:

因为您尝试了所有 Vec* 组合,所以这是完整列表,我的 2ct:

typedef Vec< uchar, 3 >     Vec3b   (so normal 8 bit)
typedef Vec< double,3 >     Vec3d   (so normal double precision)
typedef Vec< float, 3 >     Vec3f   (so normal floating point)
typedef Vec< int,   3 >     Vec3i   (normal int)
typedef Vec< short, 3 >     Vec3s
typedef Vec< ushort 3 >     Vec3w   (so normal 16 bit)

【讨论】:

以上是关于在 OpenCV 中确定矩阵的类型的主要内容,如果未能解决你的问题,请参考以下文章

opencv中如何将两个类型为Mat的矩阵合为一个矩阵?

在opencv中划分两个矩阵

opencv - 如何返回与比较矩阵相同类型的比较矩阵

如何在openCV中修改部分多维矩阵?

opencv编程中cvMat到Mat如何进行数据转换?

如何用opencv提取一张图片的像素矩阵