Obtaining list of unique pixel values in OpenCV Mat Obtaining list of unique pixel values in OpenCV Mat arrays arrays

Obtaining list of unique pixel values in OpenCV Mat


No, there is not! You can code your own, though:

std::vector<float> unique(const cv::Mat& input, bool sort = false)

Find the unique elements of a single channel cv::Mat.

Parameters:

input: It will be treated as if it was 1-D.

sort: Sorts the unique values (optional).

The implementation of such function is pretty straight forward, however, the following only works with single channel 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;}

Example:

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;

Outputs:

1 3 5 7 9 30 50 70 90 


You could try to build a histogram with number of bins equal to number of possible pixel values.


Here is another suggestion for an implementation using the standard library.

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;}

Compile and execute yields:

$ g++ -Wall opencv-unique.cpp -o unique -lopencv_core -I /usr/include/opencv4 && ./uniqueunique values: 1 3 4 5

The version above is for single-channel images. You can extend this to multi-channel images (to get unique colors), like this.