【发布时间】:2014-09-03 05:06:01
【问题描述】:
对于 OpenCV Mat,是否有 np.unique() 或 bincount() 的等价物?我正在使用 C++,所以不能只转换为 numpy 数组。
【问题讨论】:
标签: c++ arrays opencv matrix computer-vision
对于 OpenCV Mat,是否有 np.unique() 或 bincount() 的等价物?我正在使用 C++,所以不能只转换为 numpy 数组。
【问题讨论】:
标签: c++ arrays opencv matrix computer-vision
这是使用标准库实现的另一个建议。
opencv-unique.cpp
#include <opencv2/opencv.hpp>
#include <vector>
#include <iostream>
#include <algorithm>
#include <cstdint>
/**
* @brief Find unique elements of an OpenCV image
*
* @tparam type is the C++ type to access the image elements.
* @param in is the OpenCV single-channel image to find the unique values. Note: This
* modifies the image. Make a copy with .clone(), if you need the image afterwards.
*
* @returns vector of unique elements
*/
template<typename type>
std::vector<type> unique(cv::Mat in) {
assert(in.channels() == 1 && "This implementation is only for single-channel images");
auto begin = in.begin<type>(), end = in.end<type>();
auto last = std::unique(begin, end); // remove adjacent duplicates to reduce size
std::sort(begin, last); // sort remaining elements
last = std::unique(begin, last); // remove duplicates
return std::vector<type>(begin, last);
}
int main() {
cv::Mat img = (cv::Mat_<uint16_t>(3, 4) << 1, 5, 3, 4, 3, 1, 5, 5, 1, 3, 4, 3);
std::cout << "unique values: ";
auto u = unique<uint16_t>(img);
for (auto v : u)
std::cout << v << " ";
std::cout << std::endl;
return 0;
}
编译并执行产量:
$ g++ -Wall opencv-unique.cpp -o unique -lopencv_core -I /usr/include/opencv4 && ./unique
unique values: 1 3 4 5
以上版本适用于单通道图像。您可以将其扩展到多通道图像(以获得独特的颜色),例如 this。
【讨论】:
您可以尝试构建一个直方图,其中 bin 的数量等于可能的像素值的数量。
【讨论】:
不,没有!您可以自己编写代码:
std::vector<float> unique(const cv::Mat& input, bool sort = false)
查找单通道 cv::Mat 的独特元素。
参数:
输入:将被视为一维。
sort:对唯一值进行排序(可选)。
这种功能的实现非常简单,但是,以下仅适用于单通道 CV_32F:
#include <algorithm>
#include <vector>
std::vector<float> unique(const cv::Mat& input, bool sort = false)
{
if (input.channels() > 1 || input.type() != CV_32F)
{
std::cerr << "unique !!! Only works with CV_32F 1-channel Mat" << std::endl;
return std::vector<float>();
}
std::vector<float> out;
for (int y = 0; y < input.rows; ++y)
{
const float* row_ptr = input.ptr<float>(y);
for (int x = 0; x < input.cols; ++x)
{
float value = row_ptr[x];
if ( std::find(out.begin(), out.end(), value) == out.end() )
out.push_back(value);
}
}
if (sort)
std::sort(out.begin(), out.end());
return out;
}
示例:
float data[][3] = {
{ 9.0, 3.0, 7.0 },
{ 3.0, 9.0, 3.0 },
{ 1.0, 3.0, 5.0 },
{ 90.0, 30.0, 70.0 },
{ 30.0, 90.0, 50.0 }
};
cv::Mat mat(3, 5, CV_32F, &data);
std::vector<float> unik = unique(mat, true);
for (unsigned int i = 0; i < unik.size(); i++)
std::cout << unik[i] << " ";
std::cout << std::endl;
输出:
1 3 5 7 9 30 50 70 90
【讨论】:
std::set?
std::find() 变得无用,如果您的cv::Mat 是单通道并且您需要存储一个整数,它会很棒。 然而,如果您需要存储cv::Vec3b(一个像素)或其他复杂的数据类型,std::vector 可能更适合这项工作。 std::set 以特定顺序存储值,并且可能希望以不同的方式重新组织这些值,因此答案为 std::vector。
std::set 可能就足够了,而且可能是一个更快的解决方案。我并不太担心这些答案的表现,因为它是一个与问题无关的主题。一开始我尽量不讲太多细节。