Ask Your Question
0

extract a mat which have address in a mat from another mat

asked 2015-03-22 05:06:15 -0600

dinhtuyen gravatar image

updated 2015-03-22 05:09:35 -0600

berak gravatar image

Example in matlab:

A =

     4     9     8
    10     3     7
     5     8     4

>> b = [2 3; 4 5]

b =

     2     3
     4     5

>> A(b)

ans =

    10     5
     9     3

how to find A(b) in OpenCV???? Thank!!!!

edit retag flag offensive close merge delete

2 answers

Sort by ยป oldest newest most voted
3

answered 2015-03-22 11:56:06 -0600

matman gravatar image

updated 2015-03-29 06:59:51 -0600

I have done a little example, so there are some things to notice:

(i.) In Matlab the index starts with 1, in C++ it starts with 0

(ii.) 'b' is your array of indices for an 1D array

(iii.) In OpenCV the read out of the pixels is row by row, in Matlab it seems to be column by column

// include header for OpenCV3
#include <opencv2/opencv.hpp>

using namespace cv;

int main() {
    // Fill arrays by hand, this is just for this example
    Mat A(3, 3, CV_32SC1);
    A.at<int>(0, 0) = 4;
    A.at<int>(1, 0) = 10;
    A.at<int>(2, 0) = 5;
    A.at<int>(0, 1) = 9;
    A.at<int>(1, 1) = 3;
    A.at<int>(2, 1) = 8;
    A.at<int>(0, 2) = 8;
    A.at<int>(1, 2) = 7;
    A.at<int>(2, 2) = 4;

    Mat b(2, 2, CV_32SC1);
    // Note that the indices are decreased by 1 (see above)
    b.at<int>(0, 0) = 1;
    b.at<int>(1, 0) = 2;
    b.at<int>(0, 1) = 3;
    b.at<int>(1, 1) = 4;

    // Transpose array, because of row by row problem
    A = A.t();
    b = b.t();

    // Reshape arrays from 2D to 1D. Note that the 1 is not for dimension, but for number of rows (9 cols, 1 row)
    A = A.reshape(0, 1);
    b = b.reshape(0, 1);

    // Creating 1D Result array
    Mat ans(b.size(), b.type());

    // Fill the result array with A at the indices from b
    for(int i=0; i<b.cols; i++) {
        ans.at<int>(0, i) = A.at<int>( 0, b.at<int>(0, i) );
    }

    // Reshape it back to 2D. The 2 is for the number of rows: 2 cols, 2 rows
    ans = ans.reshape(0, 2);
    // Transpose it back, because of OpenCV conventions
    ans = ans.t();

    // Print out the result
    for(int i=0; i<ans.rows; i++) {
        for(int j=0; j<ans.cols; j++) {
            cout << (int)ans.at<int>(j, i) << " ";
        }
        cout << endl;
    }
return 0;
}

For matrix operations OpenCV is not the first choice. Take a look at the Eigen libraries. In OpenCV there is also a module to share data with Eigen.

EDIT: Answer to the comment below: I recommend you to use cv::InputArray instead of cv::Mat to pass arrays in functions. Check out InputArray.

The sample code is just an example (I hope I did no mistake, I could not check this at the moment) and you have to catch some more cases if needed, for example that the index value doesn't exceed the array limits,... Take a look in the source code from OpenCV to learn more about InputArrays and how to proof it.

// Use cv::InputArray, cv::OutputArray or cv::InputOutputArray
cv::Mat extract(cv::InputArray SRC, cv::InputArray IDX, bool isIdxContinous)
{
    // check that IDX format is of type std::vector or cv:Mat
    cv::CV_Assert(IDX.kind() _InputArray::STD_VECTOR || IDX.kind() == _InputArray::MAT);

    // check that IDX is of type int (You should convert ...
(more)
edit flag offensive delete link more
0

answered 2015-03-28 21:28:02 -0600

dinhtuyen gravatar image

updated 2015-03-29 03:26:36 -0600

Thank you for your help! I have written a function to "extract a mat which have address in a mat from another mat":

cv::Mat extract(cv::Mat SRC, cv::Mat IDX)
{
    cv::Mat src = SRC.clone();
    cv::Mat idx = IDX.clone();
    cv::Mat dst = cv::Mat(idx.size(), src.type());
    src = src.t();
    idx.convertTo(idx, 4);
    for (int i = 0; i < idx.total(); i++)
    {
    //  dst.at<>(i) = src.at<>(idx.at<int>(i));
        switch (src.type())
            {
            case 0:
                dst.at<uchar>(i) = src.at<uchar>(idx.at<int>(i));
                break;
            case 1:
                dst.at<char>(i) = src.at<char>(idx.at<int>(i));
                break;
            case 2:
                dst.at<ushort>(i) = src.at<ushort>(idx.at<int>(i));
                break;
            case 3:
                dst.at<short>(i) = src.at<short>(idx.at<int>(i));
                break;
            case 4:
                dst.at<int>(i) = src.at<int>(idx.at<int>(i));
                break;
            case 5:
                dst.at<float>(i) = src.at<float>(idx.at<int>(i));
                break;
            default:
                dst.at<double>(i) = src.at<double>(idx.at<int>(i));
                break;
            }
    }
    return dst;
}

and call it in main function:

cv::Mat src = (cv::Mat_<double>(3, 3) << 4, 9, 8, 10, 3, 7, 5, 8, 4);
cv::Mat idx = (cv::Mat_<int>(2, 2) << 1, 2, 3, 4);

cv::Mat dst = extract(src, idx);
cout << "src = " << endl << " " << src << endl;
cout << "idx = " << endl << " " << idx << endl;
cout << "dst = " << endl << " " << dst << endl;

and result is similar to your program but i don't know my function had Optimized??? Can you please improve my function? Thank a lot !!!!

edit flag offensive delete link more

Question Tools

1 follower

Stats

Asked: 2015-03-22 05:06:15 -0600

Seen: 714 times

Last updated: Mar 29 '15