头文件ColorDetector.h
#pragma once
#include<iostream>
#include<opencv2/opencv.hpp>
#include<vector>
class ColorDetector
{
private:
//颜色公差
int maxDist;
//目标颜色
cv::Vec3b target;
public:
//默认构造
ColorDetector();
//有参构造1
ColorDetector(uchar blue, uchar green, uchar red, int distance);
//有参构造2
ColorDetector(cv::Vec3b color, int distance);
//设置目标颜色函数1
void setTargetColor(uchar blue, uchar green, uchar red);
//设置目标颜色函数2
void setTargetColor(cv::Vec3b color);
//设置颜色公差
void setColorDistance(int distance);
//取颜色公差
int getMaxDist() const;
//取目标颜色
cv::Vec3b getTargetColor() const;
//用城区距离计算颜色差距以供类内调用
int getColorDistance(const cv::Vec3b& color1, const cv::Vec3b& color2) const;
//计算与目标颜色差距
int getColorDistanceToTargetColor(const cv::Vec3b& color) const;
//用迭代器遍历并返回二值图像
cv::Mat process(const cv::Mat& image);
//用自带的函数生成二值图像
cv::Mat processThreshold(const cv::Mat& image);
};
源文件ColorDetector.cpp
#include"ColorDetector.h"
ColorDetector::ColorDetector()
{
this->maxDist = 100;
this->target = cv::Vec3b(0, 0, 0);
}
ColorDetector::ColorDetector(uchar blue, uchar green, uchar red, int distance)
{
this->maxDist = distance;
this->target = cv::Vec3b(blue, green, red);
}
ColorDetector::ColorDetector(cv::Vec3b color, int distance)
{
this->maxDist = distance;
this->target = color;
}
void ColorDetector::setTargetColor(uchar blue, uchar green, uchar red)
{
this->target = cv::Vec3b(blue, green, red);
}
void ColorDetector::setTargetColor(cv::Vec3b color)
{
this->target = color;
}
void ColorDetector::setColorDistance(int distance)
{
this->maxDist = distance;
}
int ColorDetector::getMaxDist() const
{
return this->maxDist;
}
cv::Vec3b ColorDetector::getTargetColor() const
{
return this->target;
}
int ColorDetector::getColorDistance(const cv::Vec3b& color1, const cv::Vec3b& color2) const
{
return abs(color1[0] - color2[0]) + abs(color1[1] - color2[1]) + abs(color1[2] - color2[2]);
}
int ColorDetector::getColorDistanceToTargetColor(const cv::Vec3b& color) const
{
return ColorDetector::getColorDistance(this->target, color);
}
实现1:使用迭代器逐个比较像素
cv::Mat ColorDetector::process(const cv::Mat& image)
{
cv::Mat result;
result.create(image.size(), CV_8UC1);
cv::Mat_<cv::Vec3b>::const_iterator it1 = image.begin<cv::Vec3b>();
cv::Mat_<cv::Vec3b>::const_iterator itend = image.end<cv::Vec3b>();
cv::Mat_<uchar>::iterator it2 = result.begin<uchar>();
for (; it1 != itend; it1++, it2++)
{
//如果颜色差距大于公差,则设为黑色
if (ColorDetector::getColorDistanceToTargetColor(*it1) > (this->maxDist))
{
(*it2) = 0;
}
//否则设为白色
else
{
(*it2) = 255;
}
}
return result;
}
实现2:使用自带absdiff
、threshold
方法直接生成
该方法使用了absdiff函数计算图像像素与标量值之间差距的绝对值,再将三通道分开并相加,最后根据内置阈值函数将低于maxDist的值变为255,其余置为0。
cv::Mat ColorDetector::processThreshold(const cv::Mat& image)
{
cv::Mat result;
//将image与标量图像作差取绝对值并存到image中
cv::absdiff(image, cv::Scalar(this->target), result);
std::vector<cv::Mat> images;
//把通道分割进三幅图像
cv::split(result, images);
//三个通道相加,自动转为CV_8UC1,且有saturate_cast函数自动取饱和
result = images[0] + images[1] + images[2];
//应用阈值函数,低于maxDist的都转为255,别的转为0
cv::threshold(result, result, this->maxDist, 255, cv::THRESH_BINARY_INV);
return result;
}
补充:cv::threshold
函数的使用
函数签名
double threshold( InputArray src, OutputArray dst,
double thresh, double maxval, int type );
其中,参数分别为:
输入图像,输出图像,阈值,预定值,模式。
模式名 | 作用 |
---|---|
cv::THRESH_BINARY | 大于阈值置为预定值,其他像素置为0 |
cv::THRESH_BINARY_INV | 小于阈值置为预定值,其他像素置为0 |
cv::THRESH_TOZERO_TRUNC | 大于阈值置为阈值,其他像素不变 |
cv::THRESH_TOZERO_INV | 小于阈值不变,其他像素置为0 |
cv::THRESH_TOZERO | 大于阈值不变,其他像素置为0 |
其中,第一幅图为原图,后面五幅图分别为五种处理类型。
效果(Processed1同Processed2)