UnesBeig19
UnesBeig19

Reputation: 37

How to convert a OpenCV 2D matrix into a 1D array in C++?

I have some difficulties converting a Mat OpenCV matrix (2D) into a 1D array in OpenCV. I am implementing my code in C++ with Visual Studio and my environment is Windows 10. This is my code

include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include "opencv2/opencv.hpp"
#include <iostream>
#include <vector>

using namespace std;
using namespace cv;

int countt = 1;
int main()
{
    std::cout << "The program starts!\n";
    // Create a VideoCapture object and open the input file
  // If the input is the web camera, pass 0 instead of the video file name
    VideoCapture cap("Control1.avi");

    // Check if camera opened successfully
    if (!cap.isOpened()) {
        cout << "Error opening video stream or file" << endl;
        return -1;
    }
    // Size of the video
    Size capSize = Size((int)cap.get(CAP_PROP_FRAME_WIDTH),
        (int)cap.get(CAP_PROP_FRAME_HEIGHT));
    cout << "Frame Size: " << capSize << endl;
    cout << "Number of Frames: " << cap.get(CAP_PROP_FRAME_COUNT) << endl;

    while (1) {

        Mat frame;
        // Capture frame-by-frame
        cap >> frame;
       
        // If the frame is empty, break immediately
        if (frame.empty())
            break;
        
        //converting Mat frame into 1D array
        int* testData1D = (int*)frame.data;
        cout << "1Darray: " << testData1D[22] << endl;

        // Display the resulting frame
        imshow("Frame", frame);
        cout << "Count = " << countt << endl;
        countt = countt + 1;

        // Press  ESC on keyboard to exit
        char c = (char)waitKey(25);
        if (c == 27)
            break;
    }

    // When everything done, release the video capture object
    cap.release();

    // Closes all the frames
    destroyAllWindows();

    return 0;
}

This code was unsuccessful. I am not able to print a reasonable data from the array. This is a kind of thing I get when I run the code: 1Darray: 134742016. This suppose to be the intensity of a pixel (something between 0 and 255).

I also replaced int* testData1D = (int*)frame.data; with the below code in order to convert the matrix content one by one into the array:

int numCols = frame.cols;
int numRows = frame.rows;
const int frameSize = frame.cols * frame.rows;
double frameArray[201*204];
for (int x = 0; x < numCols; x++) {          // x-axis, cols
    for (int y = 0; y < numRows; y++) {          // y-axis rows
        double intensity = frame.at<uchar>(Point(x, y));
        frameArray[x * frame.cols + y] = intensity;
    }
}

But I end up with an infinite for loop that never ends. (The program runs for ever) I checked bunch of other codes on Stackoverflow such as c++ OpenCV Turn a Mat into a 1 Dimensional Array and Convert Mat to Array/Vector in OpenCV

but they are not helpful. For the latter, the array size is not correct. I don't know if it really build the right array. I get array lenght: 124236, but it should be 204*203 = 41412 I would appreciate it if you show me how I can simply convert a Mat openCV matrix into a normal 1D array in C++.

Thanks.

Upvotes: 0

Views: 1230

Answers (1)

stateMachine
stateMachine

Reputation: 5815

Try looping through the matrix using pointer arithmetic. First, we create a random BGR matrix of size 9, to test the procedure. The data type stored in the mat are BGR pixels represented as cv::Scalars:

//Create random test mat:
cv::Mat3b randomMat(3,3);
cv::randu( randomMat, cv::Scalar(0,0,0), cv::Scalar(256,256,256) );    
cv::Mat testMat = randomMat;

//Get mat total elements:
int matElements = testMat.cols * testMat.rows;

//Prepare output array:
cv::Scalar matArray[ matElements ];

This is the test matrix:

enter image description here

The raw values will be stored in the matArray container. Loop through the matrix using pointer arithmetic and store each pixel in the array:

//Loop trhough the mat, insert into array:
cv::MatIterator_<cv::Vec3b> it, end;
int i = 0;

for ( it = testMat.begin<cv::Vec3b>(), end = testMat.end<cv::Vec3b>(); it != end; ++it ) {

    //get current bgr pixels:
    uchar &r = (*it)[2];
    uchar &g = (*it)[1];
    uchar &b = (*it)[0];

    //Store them into array, as a cv::Scalar:
    matArray[i] = cv::Scalar(b,g,r);
    i++;

}

We can check the data stored in the array like this:

for ( int i = 0; i < matElements; i++ ){
    std::cout<<"i: "<<i<<" - "<<matArray[i]<<std::endl;
}

This yields:

i: 0 - [246, 156, 192, 0]
i: 1 - [7, 165, 166, 0]
i: 2 - [2, 179, 231, 0]
i: 3 - [212, 171, 230, 0]
i: 4 - [93, 138, 123, 0]
i: 5 - [80, 105, 242, 0]
i: 6 - [231, 239, 174, 0]
i: 7 - [174, 176, 191, 0]
i: 8 - [134, 25, 124, 0]

Upvotes: 1

Related Questions