0

I'm trying to index a 3 channel image in opencv.

When I read in image files this code works

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]; 

But it crashes when I use a webcam input. The webcam has 3 channels and u,v starts at 0,0. I have no idea why it won't work. I've tried all variations of Vec3b, Vec3i, Vec3s, Vec3f, Vec3d

I'm lost.... why can't I index this webcam image?

EDIT

Right so after many hours this is where I've got to...here's an outline of the program. I was having the problem I mentioned above inside a function. So I've gone back to basic, trying to look at the matrix before the function...

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

Right I have got it working but it's not ideal. I'm creating a temp Mat to read the files into it then cloning them.

        Mat TempLeft;
        Mat TempRight;

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

        CapLeft  >> TempLeft;
        CapRight >> TempRight;

        LeftCol = TempLeft.clone();
        RightCol = TempRight.clone();
Angie Quijano
  • 4,167
  • 3
  • 25
  • 30
YMDW
  • 411
  • 1
  • 5
  • 16

3 Answers3

2

OpenCV makes soft copies of images whenever possible. From the documentation:

the array assignment is an O(1) operation because it only copies the header and increases the reference counter. The Mat::clone() method can be used to get a full (deep) copy of the array when you need it.

I suspect what is happening is LeftCol uses data which still belongs with the VideoCapture object. If this is the case then when CapLeft and CapRight go out of scope at the end of the if they are closed by the destructor and the image data which LeftCol is still pointing to is destroyed.

Possible solutions would be to clone the image as you are doing, or declare VideoCapture CapLeft, CapRight; outside of the if block (you can still open them inside if needed).

Chris
  • 8,030
  • 4
  • 37
  • 56
  • Making soft copies by default means that OpenCV doesn't perform the timely operation of copying lots of image data unless explicitly asked to, in theory speeding things up. This is discussed in the [Introduction of the documentation](http://opencv.itseez.com/modules/core/doc/intro.html#automatic-memory-management). – Chris Sep 19 '12 at 08:31
  • Although I guess the data shouldn't be removed if it's still being referred to... – Chris Sep 19 '12 at 08:36
1

You can check the type with cv::Mat.type() and the number of channels with cv::Mat.channels()

The data returned from the camera will be converted into Vec3b (ie uchar * 3) in B,G,R order.

Are you sure the image is valid- is there a mistake somewhere else?

Martin Beckett
  • 94,801
  • 28
  • 188
  • 263
  • .channels() returns 3, .type() returns 16... not sure what that 16 relates to though... The image looks ok, I can view it using imshow("WindowName", LeftCol) and it looks fine. – YMDW Sep 17 '12 at 15:32
  • you need to compare type() with the codes for image type eg. CV_8UC3 (ps 16==CV_8UC3). Sure that u,v are in range? – Martin Beckett Sep 17 '12 at 15:37
  • yeah LeftCol is a Mat that's either populated from a .png or a webcam. In either case its type()==16 (CV_8UC3) and channels==3. u and v are in for loops and both start at 0, it crashes on the first time round the loop, i.e. u=v=0. – YMDW Sep 17 '12 at 15:50
  • So it works from the camera but not from file? did the file read work? imread() doesn't give an error but the resulting image will be "empty()" – Martin Beckett Sep 17 '12 at 21:40
  • If ProgramMode=="File" everything works. If ProgramMode=="Camera" it will display the pixel values inside the IF code, but as soon as it gets outside it crashes when displaying the pixel values. – YMDW Sep 18 '12 at 08:22
  • Look at the code in this post for a way to convert the `.type()=16` into a readable string: http://stackoverflow.com/questions/12335663/getting-enum-names-e-g-cv-32fc1-of-opencv-image-types – solvingPuzzles Sep 20 '12 at 07:41
1

Just because you tried all Vec* combinations, here is the full list, my 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)
TimZaman
  • 2,689
  • 2
  • 26
  • 36