1 | initial version |
I have done a very dirty 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
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) );
}
// Create a 2D array of the result
Mat ans2D(2, 2, CV_32SC1);
// Fill the 2D array with the values of the 1D array
// (This is a very dirty solution and there should be better solutions, but I didn't found one in a short time
for(int i=0; i<ans.cols; i++) {
int nCol = i%2;
int nRow = i/2;
ans2D.at<int>(nCol, nRow) = ans.at<int>(0, i);
}
// Transpose it back to OpenCV convention
ans2D = ans2D.t();
// Print out the result
for(int i=0; i<ans2D.rows; i++) {
for(int j=0; j<ans2D.cols; j++) {
cout << (int)ans2D.at<int>(i, j) << " ";
}
cout << endl;
}
return 0;
}
I think this is not realy a clean solution, but perhabs you can use it or parts of it.
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.
2 | No.2 Revision |
I have done a very dirty 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
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) );
}
// Create a 2D array of the result
Mat ans2D(2, 2, CV_32SC1);
// Fill the 2D array with the values of the 1D array
// (This is a very dirty solution and there should be better solutions, but I didn't found one in a short time
for(int i=0; i<ans.cols; i++) {
int nCol = i%2;
int nRow = i/2;
ans2D.at<int>(nCol, nRow) = ans.at<int>(0, i);
}
// Transpose Reshape it back to 2D
ans = ans.reshape(0, 2);
// Transpose it back, because of OpenCV convention
ans2D = ans2D.t();
conventions
ans = ans.t();
// Print out the result
for(int i=0; i<ans2D.rows; i++) {
for(int j=0; j<ans2D.cols; j++) {
cout << (int)ans2D.at<int>(i, j) (int)ans2D.at<int>(j, i) << " ";
}
cout << endl;
}
return 0;
}
I think this is not realy a clean solution, but perhabs you can use it or parts of it.
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.
3 | No.3 Revision |
I have done a very dirty 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
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
ans = ans.reshape(0, 2);
// Transpose it back, because of OpenCV conventions
ans = ans.t();
// Print out the result
for(int i=0; i<ans2D.rows; i<ans.rows; i++) {
for(int j=0; j<ans2D.cols; j<ans.cols; j++) {
cout << (int)ans2D.at<int>(j, (int)ans.at<int>(j, i) << " ";
}
cout << endl;
}
return 0;
}
I think this is not realy a clean solution, but perhabs you can use it or parts of it.
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.
4 | No.4 Revision |
I have done a very dirty 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
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
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;
}
I think this is not realy a clean solution, but perhabs you can use it or parts of it.
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.
5 | No.5 Revision |
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
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
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.
6 | No.6 Revision |
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 exeed the array limits,...
// 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_VECTOR || IDX.kind() == _InputArray::STD_VECTOR_MAT);
// check that IDX is of type int (You should convert it outside)
cv::CV_Assert(IDX.type() == CV_32S)
// clone() will do a deep copy and costs some time.
// If data aren't changed, just pass Mat header instead to internal Mat
cv::Mat src = SRC.getMat();
cv::Mat idx = IDX.getMat();
src = src.t();
// I think this costs no time, because only the header is changed not the data
src = src.reshape(0,1);
cv::Mat dst = cv::Mat(idx.size(), src.type());
if(isIDXContinous) {
// In this case you can copy data very efficient, using cv::Range
// I'm not sure, if all types are supported.
int nRows = dst.rows;
dst = dst.reshape(0, 1);
dst = src( cv::Range(idx.at<int>(0), idx.at<int>(idx.total()-1)) ).clone();
dst = dst.reshape(0, nRows);
return dst;
}
// Not necessary, because it should be checked outside the function to be int
// Otherwise you can cast it with (int)idx.at<T>(i)
// idx.convertTo(idx, 4);
// outsource switch from for loop
switch(src.type())
{
case 0:
for (int i = 0; i < idx.total(); i++)
dst.at<uchar>(i) = src.at<uchar>(idx.at<int>(i));
break;
case 1:
for (int i = 0; i < idx.total(); i++)
dst.at<char>(i) = src.at<char>(idx.at<int>(i));
break;
case 2:
for (int i = 0; i < idx.total(); i++)
dst.at<ushort>(i) = src.at<ushort>(idx.at<int>(i));
break;
case 3:
for (int i = 0; i < idx.total(); i++)
dst.at<short>(i) = src.at<short>(idx.at<int>(i));
break;
case 4:
for (int i = 0; i < idx.total(); i++)
dst.at<int>(i) = src.at<int>(idx.at<int>(i));
break;
case 5:
for (int i = 0; i < idx.total(); i++)
dst.at<float>(i) = src.at<float>(idx.at<int>(i));
break;
default:
for (int i = 0; i < idx.total(); i++)
dst.at<double>(i) = src.at<double>(idx.at<int>(i));
break;
}
return dst;
You can also use T srcArray[] = (T*)src.data; srcArray[i];
instead of src.at<T>(i);
, but this will not check limits of the array and should be handled with care.
7 | No.7 Revision |
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 exeed the array limits,...
// 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_VECTOR || IDX.kind() == _InputArray::STD_VECTOR_MAT);
// check that IDX is of type int (You should convert it outside)
cv::CV_Assert(IDX.type() == CV_32S)
// clone() will do a deep copy and costs some time.
// If data aren't changed, just pass Mat header instead to internal Mat
cv::Mat src = SRC.getMat();
cv::Mat idx = IDX.getMat();
src = src.t();
// I think this costs no time, because only the header is changed not the data
src = src.reshape(0,1);
cv::Mat dst = cv::Mat(idx.size(), src.type());
if(isIDXContinous) {
// In this case you can copy data very efficient, using cv::Range
// I'm not sure, if all types are supported.
int nRows = dst.rows;
dst = dst.reshape(0, 1);
dst = src( cv::Range(idx.at<int>(0), idx.at<int>(idx.total()-1)) ).clone();
dst = dst.reshape(0, nRows);
return dst;
}
// Not necessary, because it should be checked outside the function to be int
// Otherwise you can cast it with (int)idx.at<T>(i)
// idx.convertTo(idx, 4);
// outsource switch from for loop
switch(src.type())
{
case 0:
for (int i = 0; i < idx.total(); i++)
dst.at<uchar>(i) = src.at<uchar>(idx.at<int>(i));
break;
case 1:
for (int i = 0; i < idx.total(); i++)
dst.at<char>(i) = src.at<char>(idx.at<int>(i));
break;
case 2:
for (int i = 0; i < idx.total(); i++)
dst.at<ushort>(i) = src.at<ushort>(idx.at<int>(i));
break;
case 3:
for (int i = 0; i < idx.total(); i++)
dst.at<short>(i) = src.at<short>(idx.at<int>(i));
break;
case 4:
for (int i = 0; i < idx.total(); i++)
dst.at<int>(i) = src.at<int>(idx.at<int>(i));
break;
case 5:
for (int i = 0; i < idx.total(); i++)
dst.at<float>(i) = src.at<float>(idx.at<int>(i));
break;
default:
for (int i = 0; i < idx.total(); i++)
dst.at<double>(i) = src.at<double>(idx.at<int>(i));
break;
}
return dst;
}
You can also use T srcArray[] = (T*)src.data; srcArray[i];
instead of src.at<T>(i);
, but this will not check limits of the array and should be handled with care.
8 | No.8 Revision |
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 exeed the array limits,...
// 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_VECTOR || IDX.kind() == _InputArray::STD_VECTOR_MAT);
// check that IDX is of type int (You should convert it outside)
cv::CV_Assert(IDX.type() == CV_32S)
// clone() will do a deep copy and costs some time.
// If data aren't changed, just pass Mat header instead to internal Mat
cv::Mat src = SRC.getMat();
cv::Mat idx = IDX.getMat();
src = src.t();
// I think this costs no time, because only the header is changed not the data
src = src.reshape(0,1);
cv::Mat dst = cv::Mat(idx.size(), src.type());
if(isIDXContinous) if(isIdxContinous) {
// In this case you can copy data very efficient, using cv::Range
// I'm not sure, if all types are supported.
int nRows = dst.rows;
dst = dst.reshape(0, 1);
dst = src( cv::Range(idx.at<int>(0), idx.at<int>(idx.total()-1)) ).clone();
dst = dst.reshape(0, nRows);
return dst;
}
// Not necessary, because it should be checked outside the function to be int
// Otherwise you can cast it with (int)idx.at<T>(i)
// idx.convertTo(idx, 4);
// outsource switch from for loop
switch(src.type())
{
case 0:
for (int i = 0; i < idx.total(); i++)
dst.at<uchar>(i) = src.at<uchar>(idx.at<int>(i));
break;
case 1:
for (int i = 0; i < idx.total(); i++)
dst.at<char>(i) = src.at<char>(idx.at<int>(i));
break;
case 2:
for (int i = 0; i < idx.total(); i++)
dst.at<ushort>(i) = src.at<ushort>(idx.at<int>(i));
break;
case 3:
for (int i = 0; i < idx.total(); i++)
dst.at<short>(i) = src.at<short>(idx.at<int>(i));
break;
case 4:
for (int i = 0; i < idx.total(); i++)
dst.at<int>(i) = src.at<int>(idx.at<int>(i));
break;
case 5:
for (int i = 0; i < idx.total(); i++)
dst.at<float>(i) = src.at<float>(idx.at<int>(i));
break;
default:
for (int i = 0; i < idx.total(); i++)
dst.at<double>(i) = src.at<double>(idx.at<int>(i));
break;
}
return dst;
}
You can also use T srcArray[] = (T*)src.data; srcArray[i];
instead of src.at<T>(i);
, but this will not check limits of the array and should be handled with care.
9 | No.9 Revision |
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 exeed the array limits,...
// 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_VECTOR _InputArray::STD_VECTOR || IDX.kind() == _InputArray::STD_VECTOR_MAT);
_InputArray::MAT);
// check that IDX is of type int (You should convert it outside)
cv::CV_Assert(IDX.type() == CV_32S)
// clone() will do a deep copy and costs some time.
// If data aren't changed, just pass Mat header instead to internal Mat
cv::Mat src = SRC.getMat();
cv::Mat idx = IDX.getMat();
src = src.t();
// I think this costs no time, because only the header is changed not the data
src = src.reshape(0,1);
cv::Mat dst = cv::Mat(idx.size(), src.type());
if(isIdxContinous) {
// In this case you can copy data very efficient, using cv::Range
// I'm not sure, if all types are supported.
int nRows = dst.rows;
dst = dst.reshape(0, 1);
dst = src( cv::Range(idx.at<int>(0), idx.at<int>(idx.total()-1)) ).clone();
dst = dst.reshape(0, nRows);
return dst;
}
// Not necessary, because it should be checked outside the function to be int
// Otherwise you can cast it with (int)idx.at<T>(i)
// idx.convertTo(idx, 4);
// outsource switch from for loop
switch(src.type())
{
case 0:
for (int i = 0; i < idx.total(); i++)
dst.at<uchar>(i) = src.at<uchar>(idx.at<int>(i));
break;
case 1:
for (int i = 0; i < idx.total(); i++)
dst.at<char>(i) = src.at<char>(idx.at<int>(i));
break;
case 2:
for (int i = 0; i < idx.total(); i++)
dst.at<ushort>(i) = src.at<ushort>(idx.at<int>(i));
break;
case 3:
for (int i = 0; i < idx.total(); i++)
dst.at<short>(i) = src.at<short>(idx.at<int>(i));
break;
case 4:
for (int i = 0; i < idx.total(); i++)
dst.at<int>(i) = src.at<int>(idx.at<int>(i));
break;
case 5:
for (int i = 0; i < idx.total(); i++)
dst.at<float>(i) = src.at<float>(idx.at<int>(i));
break;
default:
for (int i = 0; i < idx.total(); i++)
dst.at<double>(i) = src.at<double>(idx.at<int>(i));
break;
}
return dst;
}
You can also use T srcArray[] = (T*)src.data; srcArray[i];
instead of src.at<T>(i);
, but this will not check limits of the array and should be handled with care.
10 | No.10 Revision |
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 exeed exceed the array limits,...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 it outside)
cv::CV_Assert(IDX.type() == CV_32S)
// clone() will do a deep copy and costs some time.
// If data aren't changed, just pass Mat header instead to internal Mat
cv::Mat src = SRC.getMat();
cv::Mat idx = IDX.getMat();
src = src.t();
// I think this costs no time, because only the header is changed not the data
src = src.reshape(0,1);
cv::Mat dst = cv::Mat(idx.size(), src.type());
if(isIdxContinous) {
// In this case you can copy data very efficient, using cv::Range
// I'm not sure, if all types are supported.
int nRows = dst.rows;
dst = dst.reshape(0, 1);
dst = src( cv::Range(idx.at<int>(0), idx.at<int>(idx.total()-1)) ).clone();
dst = dst.reshape(0, nRows);
return dst;
}
// Not necessary, because it should be checked outside the function to be int
// Otherwise you can cast it with (int)idx.at<T>(i)
// idx.convertTo(idx, 4);
// outsource switch from for loop
switch(src.type())
{
case 0:
for (int i = 0; i < idx.total(); i++)
dst.at<uchar>(i) = src.at<uchar>(idx.at<int>(i));
break;
case 1:
for (int i = 0; i < idx.total(); i++)
dst.at<char>(i) = src.at<char>(idx.at<int>(i));
break;
case 2:
for (int i = 0; i < idx.total(); i++)
dst.at<ushort>(i) = src.at<ushort>(idx.at<int>(i));
break;
case 3:
for (int i = 0; i < idx.total(); i++)
dst.at<short>(i) = src.at<short>(idx.at<int>(i));
break;
case 4:
for (int i = 0; i < idx.total(); i++)
dst.at<int>(i) = src.at<int>(idx.at<int>(i));
break;
case 5:
for (int i = 0; i < idx.total(); i++)
dst.at<float>(i) = src.at<float>(idx.at<int>(i));
break;
default:
for (int i = 0; i < idx.total(); i++)
dst.at<double>(i) = src.at<double>(idx.at<int>(i));
break;
}
return dst;
}
You can also use T srcArray[] = (T*)src.data; srcArray[i];
instead of src.at<T>(i);
, but this will not check limits of the array and should be handled with care.
11 | No.11 Revision |
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 it outside)
cv::CV_Assert(IDX.type() == CV_32S)
// clone() will do a deep copy and costs some time.
// If data aren't changed, just pass Mat header instead to internal Mat
cv::Mat src = SRC.getMat();
cv::Mat idx = IDX.getMat();
src = src.t();
// I think this costs no time, because only the header is changed not the data
src = src.reshape(0,1);
cv::Mat dst = cv::Mat(idx.size(), src.type());
if(isIdxContinous) {
// In this case you can copy data very efficient, using cv::Range
// I'm not sure, if all types are supported.
int nRows = dst.rows;
// I think this costs no time, because only the header is changed not the data
src = src.reshape(0,1);
dst = dst.reshape(0, 1);
dst = src( cv::Range(idx.at<int>(0), idx.at<int>(idx.total()-1)) ).clone();
dst = dst.reshape(0, nRows);
return dst;
}
// Not necessary, because it should be checked outside the function to be int
// Otherwise you can cast it with (int)idx.at<T>(i)
// idx.convertTo(idx, 4);
// outsource switch from for loop
switch(src.type())
{
case 0:
for (int i = 0; i < idx.total(); i++)
dst.at<uchar>(i) = src.at<uchar>(idx.at<int>(i));
break;
case 1:
for (int i = 0; i < idx.total(); i++)
dst.at<char>(i) = src.at<char>(idx.at<int>(i));
break;
case 2:
for (int i = 0; i < idx.total(); i++)
dst.at<ushort>(i) = src.at<ushort>(idx.at<int>(i));
break;
case 3:
for (int i = 0; i < idx.total(); i++)
dst.at<short>(i) = src.at<short>(idx.at<int>(i));
break;
case 4:
for (int i = 0; i < idx.total(); i++)
dst.at<int>(i) = src.at<int>(idx.at<int>(i));
break;
case 5:
for (int i = 0; i < idx.total(); i++)
dst.at<float>(i) = src.at<float>(idx.at<int>(i));
break;
default:
for (int i = 0; i < idx.total(); i++)
dst.at<double>(i) = src.at<double>(idx.at<int>(i));
break;
}
return dst;
}
You can also use T srcArray[] = (T*)src.data; srcArray[i];
instead of src.at<T>(i);
, but this will not check limits of the array and should be handled with care.