本节我们实现这样一个算法,我们指定某种颜色和一个阈值,根据输入图片生成一张掩码,标记符合的像素。
源代码如下,我们使用一个class完成这个目标,其指定了两种构建函数,并通过逐像素扫描的形式生成掩码(process成员函数)。另外,本class做了仿函数处理(operator成员函数),类似于python中的__call__方法,可以直接调用实例像函数一样进行处理。
class ColorDetector { private: int maxDist; // 允许的最小差距 cv::Vec3b target; // 目标颜色 cv::Mat result; // 结果Mask图像 public: // 空构造函数 ColorDetector() :maxDist(100), target(0, 0, 0) {}; ColorDetector(uchar blue, uchar green, uchar red, int maxDist) : maxDist(maxDist) { setTargetColor(blue, green, red); }; // 设置颜色差距阈值 void setColorDistanceThreshold(int distance) { if (distance < 0) distance = 0; maxDist = distance; }; // 获取颜色差距阈值 int getColorDistanceThreshold() { return maxDist; }; // 设置待检测颜色 void setTargetColor(uchar blue, uchar green, uchar red) { target = cv::Vec3b(blue, green, red); }; void setTargetColor(cv::Vec3b color) { target = color; }; // 计算与目标颜色的差距 int getDistanceToTargetColor(const cv::Vec3b& color) const { return getColorDistance(color, target); }; // 计算两个颜色之间的距离 int getColorDistance(const cv::Vec3b& color1, const cv::Vec3b& color2) const { return abs(color1[0] - color2[0]) + abs(color1[0] - color2[0]) + abs(color1[0] - color2[0]); }; cv::Mat process(const cv::Mat &image); // operator()使类像函数一样工作 cv::Mat operator()(const cv::Mat &image) { return process(image); }; }; cv::Mat ColorDetector::process(const cv::Mat &image) { // 为Mask结果申请空间 result.create(image.size(), CV_8U); cv::Mat_<cv::Vec3b>::const_iterator it = image.begin<cv::Vec3b>(); cv::Mat_<cv::Vec3b>::const_iterator itend = image.end<cv::Vec3b>(); cv::Mat_<uchar>::iterator itout = result.begin<uchar>(); for (; it != itend; ++it, ++itout) { if (getDistanceToTargetColor(*it) < maxDist) { *itout = 255; } else { *itout = 0; }; }; return result; };
两种调用方法都列举了出来:
void code_3() { // 创建色彩检测器对象
ColorDetector cdetect;
cdetect.setTargetColor(10, 50, 10);
// 读取图片
cv::Mat image = cv::imread("test.jpg");
// 处理图片
cv::Mat result = cdetect.process(image);
cv::imshow("色彩检测", result);
// 仿函数
ColorDetector colordetector(230, 190, 130, 100);
result = colordetector(image);
cv::imshow("仿函数色彩检测", result); };
输出图像展示: