在OpenCV Mat中获取唯一像素值列表

12

是否有一个OpenCV Mat的等价物,类似于 np.unique()bincount()?我使用的是C++,因此不能简单地转换为numpy数组。

3个回答

16

没有,不存在! 不过你可以自己编写:

std::vector<float> unique(const cv::Mat& input, bool sort = false)
查找单通道cv::Mat的唯一元素。 参数: input:将被视为1-D。 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 

1
为什么不使用std::set - Shai
2
@Shai,一开始看起来这是个好主意,从性能角度来看可能更快,因为它保证了存储唯一值。它使我在代码中放置的std::find()变得无用,并且如果您需要存储一个整数并且cv::Mat是单通道的话,那么这将非常好。然而,如果您需要存储cv::Vec3b(像素)或其他复杂数据类型,则std::vector可能更适合此工作。std::set按特定顺序存储值,有人可能希望以不同方式重新组织这些值,因此答案是std::vector - karlphillip
2
我对std::vector没有太多的热情。根据您在存储/排序方面需要多少灵活性,std::set可能已经足够,并且可能是更快的解决方案。在这些答案中,我并不太担心性能,因为这不是问题相关的主题。我尽可能地讲解清楚,但首先不会涉及太多细节。 - karlphillip

4

您可以尝试使用与可能像素值数量相等的条形图。


0

这里有另一个使用标准库实现的建议。

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接