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.