1

I am rather new to OpenCV and need to translate some Python code to OpenCV (C++). Given a certain matrix, I need to create a larger matrix with a specific pattern. Suppose the original matrix is a matrix with random integers:

>>> import numpy as np
>>> a = np.random.randint(0, 10, (3,3))
>>> a
array([[2, 7, 0],
       [3, 7, 5],
       [7, 2, 0]])

Then the Python code uses the repeat command to construct a larger matrix in the following way:

>>> a.repeat(3, 0).repeat(3,1)
array([[2, 2, 2, 7, 7, 7, 0, 0, 0],
       [2, 2, 2, 7, 7, 7, 0, 0, 0],
       [2, 2, 2, 7, 7, 7, 0, 0, 0],
       [3, 3, 3, 7, 7, 7, 5, 5, 5],
       [3, 3, 3, 7, 7, 7, 5, 5, 5],
       [3, 3, 3, 7, 7, 7, 5, 5, 5],
       [7, 7, 7, 2, 2, 2, 0, 0, 0],
       [7, 7, 7, 2, 2, 2, 0, 0, 0],
       [7, 7, 7, 2, 2, 2, 0, 0, 0]])

In my C++ code, I am thinking of using OpenCV's Mat class to store the matrices, because I need to do some operations like transposing, elementwise multiplication, matrix-vector multiplication etc...

I know how to create the smaller matrix, e.g. something like the following:

double data[3][3] = { {1, 2, 3}, {4, 5, 6}, {7, 8, 9} };
cv::Mat m = cv::Mat(3, 3, CV_64FC1, &data);

But I haven't figured out a way to construct the larger matrix out of this smaller one. I cannot find an equivalent of NumPy's repeat command for OpenCV's Mat class. How could this be done?

4 Answers4

1

cv::repeat function is what you need

0

From the OpenCV docs, it suggests that repeat should be possible with a Mat class,

Any function of matrix or matrices and scalars that returns a matrix or a scalar, such as norm, mean, sum, countNonZero, trace, determinant, repeat, and others.

Failing this, there is a discussion on different numpy style arrays in c++ here, although most don't seem to provide all the same functionality. The actual source code for numpy will also be in c, so you could extract the functionality or use this for repeat. However, it would probably be simpler to write your own repeat function...

Community
  • 1
  • 1
Ed Smith
  • 12,716
  • 2
  • 43
  • 55
  • I've looked at http://docs.opencv.org/modules/core/doc/operations_on_arrays.html#void%20repeat%28InputArray%20src,%20int%20ny,%20int%20nx,%20OutputArray%20dst%29 but that is not the functionality that I want. The functionality that OpenCV's repeat offers is similar to NumPy's tile command. – Bart Vandewoestyne May 27 '15 at 08:44
0

In the meanwhile, I was able to come up with this solution:

#include <iostream>
#include <opencv2/core/core.hpp>

int main() {

    double data[3][3] = { {1, 2, 3}, {4, 5, 6}, {7, 8, 9} };

    cv::Mat m = cv::Mat(3, 3, CV_64F, data);
    std::cout << "m = "<< std::endl << " "  << m << std::endl << std::endl;

    cv::Mat m_expanded = cv::Mat::zeros(9, 9, CV_64F);
    for (int row = 0; row < m.rows; row++)
    {
        for (int col = 0; col < m.cols; col++)
        {
            m_expanded(cv::Range(row*3,(row+1)*3), cv::Range(col*3,(col+1)*3)) = m.at<double>(row, col);
        }
    }
    std::cout << "m_expanded = "<< std::endl << " "  << m_expanded << std::endl << std::endl;

    return 1;
}

but something tells me there is a more elegant way to do it. I would still be happy to hear about the elegant way.

0

The command cv::resize gives you the desired result. Just make sure to use the right interpolation method (INTER_NEAREST). This way, OpenCV will just repeat the pixels in your matrix.

Example:

cv::Mat mat(10, 10, CV_32F);
cv::Mat scaledMat(100, 100, CV_32F);
cv::resize(mat, scaledMat, cv::Size(100, 100), 0, 0, cv::InterpolationFlags::INTER_NEAREST);
Brun
  • 65
  • 1
  • 6