Skip to content

Instantly share code, notes, and snippets.

@JohnWayne1986
Last active May 29, 2023 19:20
Show Gist options
  • Save JohnWayne1986/e1aee3154d14aa3597ad0e69479838e8 to your computer and use it in GitHub Desktop.
Save JohnWayne1986/e1aee3154d14aa3597ad0e69479838e8 to your computer and use it in GitHub Desktop.
This demonstrates how to get the unique pixel values from OpenCV images.
#include <opencv2/opencv.hpp>
#include <vector>
#include <iostream>
#include <algorithm>
#include <cstdint>
/**
* @brief Functor to find unique elements of an OpenCV image
*
* @tparam type is the element type. For single-channel images this can be e. g. uint8_t. For
* multi-channel images this should be some kind of cv::Vec, like cv::Vec3b.
*
* @param in is the OpenCV image to find the unique values. Note: This functor
* modifies the image. Make a copy with .clone(), if you need the image afterwards.
*
* @returns vector of unique elements
*/
template<typename type>
struct UniqueFunctor {
cv::Mat in;
std::vector<type> operator()() {
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);
}
};
template<typename type, int cn>
struct UniqueFunctor<cv::Vec<type, cn>> {
cv::Mat in;
using vec_type = cv::Vec<type, cn>;
std::vector<vec_type> operator()() {
auto compare = [] (vec_type const& v1, vec_type const& v2) {
return std::lexicographical_compare(&v1[0], &v1[cn], &v2[0], &v2[cn]);
};
auto begin = in.begin<vec_type>(), end = in.end<vec_type>();
auto last = std::unique(begin, end); // remove adjacent duplicates to reduce size
std::sort(begin, last, compare); // sort remaining elements
last = std::unique(begin, last); // remove duplicates
return std::vector<vec_type>(begin, last);
}
};
template<typename full_type>
void print_unique(cv::Mat img) {
std::cout << "unique values: ";
auto unique = UniqueFunctor<full_type>{img}();
for (auto v : unique)
std::cout << v << " ";
std::cout << std::endl;
}
int main() {
cv::Mat img;
// single-channel test
img = (cv::Mat_<uint16_t>(3, 4) << 1, 5, 3, 4, 3, 1, 5, 5, 1, 3, 4, 3);
print_unique<uint16_t>(img);
// multi-channel test
img = (cv::Mat_<cv::Vec3b>(2, 3) << cv::Vec3b{0, 0, 1}, cv::Vec3b{0, 1, 1}, cv::Vec3b{0, 1, 0},
cv::Vec3b{0, 1, 0}, cv::Vec3b{0, 0, 1}, cv::Vec3b{0, 1, 1});
print_unique<cv::Vec3b>(img);
return 0;
}
@JohnWayne1986
Copy link
Author

JohnWayne1986 commented Jun 10, 2020

Compilation and output:

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment