使用 C++ 在 OpenCV 中按深度维度排序
Sort by a depth dimension in OpenCV with C++
我有一个多维矩阵,如何按三维对立方体进行排序?使用 opencv 的正确功能?
std::vector<int> sz = { 3,3,4 };
cv::Mat M(3, sz.data(), CV_32FC1, cv::Scalar(0));
文档中只有一个选项
CV_SORT_EVERY_COLUMN //dimension-1
CV_SORT_EVERY_ROW //dimension-2
cv::sort
的文档指出:
Sorts each row or each column of a matrix.
因此,您不能直接使用它对第 3 维进行排序。
不过,你可以利用in-memory layout of the data, and reshape
把它变成一个2d Mat。然后你可以对它进行排序 row-wise,并将结果重塑回原来的形状。在这种特殊情况下,您将重塑为 9 行 4 列的矩阵。
void sort3rd(cv::Mat1f const& src, cv::Mat1f& dest, int direction)
{
assert(src.size.dims() == 3);
std::vector<int> original_size(src.size.p, src.size.p + 3);
std::vector<int> new_size{ original_size[0] * original_size[1], original_size[2] };
cv::Mat1f temp(src.reshape(1, new_size));
cv::sort(temp, temp, cv::SORT_EVERY_ROW | direction);
dest = temp.reshape(1, original_size);
}
注意:重塑垫子是非常便宜的操作,只需为共享数据生成一个新的 header 即可。
演示代码:
#include <opencv2/opencv.hpp>
#include <numeric>
void dump(cv::Mat1f const& m)
{
assert(m.size.dims() == 3);
std::cout << "[ ";
for (int r(0); r < m.size[0]; ++r) {
for (int c(0); c < m.size[1]; ++c) {
for (int d(0); d < m.size[2]; ++d) {
std::cout << m.at<float>(r,c,d) << " ";
}
std::cout << "; ";
}
std::cout << "\n";
}
std::cout << " ]\n";
}
void sort3rd(cv::Mat1f const& src, cv::Mat1f& dest, int direction)
{
assert(src.size.dims() == 3);
std::vector<int> original_size(src.size.p, src.size.p + 3);
std::vector<int> new_size{ original_size[0] * original_size[1], original_size[2] };
cv::Mat1f temp(src.reshape(1, new_size));
std::cout << "Reshaped before sort\n" << temp << "\n";
cv::sort(temp, temp, cv::SORT_EVERY_ROW | direction);
std::cout << "Reshaped after sort\n" << temp << "\n";
dest = temp.reshape(1, original_size);
}
int main()
{
std::vector<int> sz{3, 3, 4};
cv::Mat1f M(static_cast<int>(sz.size()), sz.data());
std::iota(M.begin(), M.end(), 0.0f);
std::cout << "Input\n";
dump(M);
sort3rd(M, M, cv::SORT_DESCENDING);
std::cout << "Output\n";
dump(M);
return 0;
}
控制台输出:
Input
[ 0 1 2 3 ; 4 5 6 7 ; 8 9 10 11 ;
12 13 14 15 ; 16 17 18 19 ; 20 21 22 23 ;
24 25 26 27 ; 28 29 30 31 ; 32 33 34 35 ;
]
Reshaped before sort
[0, 1, 2, 3;
4, 5, 6, 7;
8, 9, 10, 11;
12, 13, 14, 15;
16, 17, 18, 19;
20, 21, 22, 23;
24, 25, 26, 27;
28, 29, 30, 31;
32, 33, 34, 35]
Reshaped after sort
[3, 2, 1, 0;
7, 6, 5, 4;
11, 10, 9, 8;
15, 14, 13, 12;
19, 18, 17, 16;
23, 22, 21, 20;
27, 26, 25, 24;
31, 30, 29, 28;
35, 34, 33, 32]
Output
[ 3 2 1 0 ; 7 6 5 4 ; 11 10 9 8 ;
15 14 13 12 ; 19 18 17 16 ; 23 22 21 20 ;
27 26 25 24 ; 31 30 29 28 ; 35 34 33 32 ;
]
我有一个多维矩阵,如何按三维对立方体进行排序?使用 opencv 的正确功能?
std::vector<int> sz = { 3,3,4 };
cv::Mat M(3, sz.data(), CV_32FC1, cv::Scalar(0));
文档中只有一个选项
CV_SORT_EVERY_COLUMN //dimension-1
CV_SORT_EVERY_ROW //dimension-2
cv::sort
的文档指出:
Sorts each row or each column of a matrix.
因此,您不能直接使用它对第 3 维进行排序。
不过,你可以利用in-memory layout of the data, and reshape
把它变成一个2d Mat。然后你可以对它进行排序 row-wise,并将结果重塑回原来的形状。在这种特殊情况下,您将重塑为 9 行 4 列的矩阵。
void sort3rd(cv::Mat1f const& src, cv::Mat1f& dest, int direction)
{
assert(src.size.dims() == 3);
std::vector<int> original_size(src.size.p, src.size.p + 3);
std::vector<int> new_size{ original_size[0] * original_size[1], original_size[2] };
cv::Mat1f temp(src.reshape(1, new_size));
cv::sort(temp, temp, cv::SORT_EVERY_ROW | direction);
dest = temp.reshape(1, original_size);
}
注意:重塑垫子是非常便宜的操作,只需为共享数据生成一个新的 header 即可。
演示代码:
#include <opencv2/opencv.hpp>
#include <numeric>
void dump(cv::Mat1f const& m)
{
assert(m.size.dims() == 3);
std::cout << "[ ";
for (int r(0); r < m.size[0]; ++r) {
for (int c(0); c < m.size[1]; ++c) {
for (int d(0); d < m.size[2]; ++d) {
std::cout << m.at<float>(r,c,d) << " ";
}
std::cout << "; ";
}
std::cout << "\n";
}
std::cout << " ]\n";
}
void sort3rd(cv::Mat1f const& src, cv::Mat1f& dest, int direction)
{
assert(src.size.dims() == 3);
std::vector<int> original_size(src.size.p, src.size.p + 3);
std::vector<int> new_size{ original_size[0] * original_size[1], original_size[2] };
cv::Mat1f temp(src.reshape(1, new_size));
std::cout << "Reshaped before sort\n" << temp << "\n";
cv::sort(temp, temp, cv::SORT_EVERY_ROW | direction);
std::cout << "Reshaped after sort\n" << temp << "\n";
dest = temp.reshape(1, original_size);
}
int main()
{
std::vector<int> sz{3, 3, 4};
cv::Mat1f M(static_cast<int>(sz.size()), sz.data());
std::iota(M.begin(), M.end(), 0.0f);
std::cout << "Input\n";
dump(M);
sort3rd(M, M, cv::SORT_DESCENDING);
std::cout << "Output\n";
dump(M);
return 0;
}
控制台输出:
Input
[ 0 1 2 3 ; 4 5 6 7 ; 8 9 10 11 ;
12 13 14 15 ; 16 17 18 19 ; 20 21 22 23 ;
24 25 26 27 ; 28 29 30 31 ; 32 33 34 35 ;
]
Reshaped before sort
[0, 1, 2, 3;
4, 5, 6, 7;
8, 9, 10, 11;
12, 13, 14, 15;
16, 17, 18, 19;
20, 21, 22, 23;
24, 25, 26, 27;
28, 29, 30, 31;
32, 33, 34, 35]
Reshaped after sort
[3, 2, 1, 0;
7, 6, 5, 4;
11, 10, 9, 8;
15, 14, 13, 12;
19, 18, 17, 16;
23, 22, 21, 20;
27, 26, 25, 24;
31, 30, 29, 28;
35, 34, 33, 32]
Output
[ 3 2 1 0 ; 7 6 5 4 ; 11 10 9 8 ;
15 14 13 12 ; 19 18 17 16 ; 23 22 21 20 ;
27 26 25 24 ; 31 30 29 28 ; 35 34 33 32 ;
]