OpenCV - C++实战(05) — 颜色检测

这篇具有很好参考价值的文章主要介绍了OpenCV - C++实战(05) — 颜色检测。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

第5章  颜色检测

5.1 实现原理

5.2 Lab颜色模型

5.3 cv :: threshold() 阈值函数 

5.4 计算图像之间的距离

5.4.1 公式计算

5.4.2 cv::absdiff()

5.4.3 cv::floodFill() 

 5.5 完整代码


Github代码地址:GitHub - Qinong/OpenCV

第5章  颜色检测

        颜色检测用来识别图像中所有像素的某种颜色。这个算法必领输人一幅图像和一个颜色,并且返回一个二值图像,显示具有指定颜色的像素。在运行算法前,还要指定一个阈值,即能接受的颜色的公差。

5.1 实现原理

         算法的核心对每个像素进行循环扫描,把像素颜色和目标颜色做比较。可以这样写这个循环:

cv::Mat ColorDetector::process(const cv::Mat &image) {

	  result.create(image.size(),CV_8U);

	  // 转换成Lab色彩空间
	  if (useLab)
		  cv::cvtColor(image, converted, CV_BGR2Lab);

	  // 获取迭代器
	  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>();

	  // 获取转换图像的迭代器
	  if (useLab) {
		  it = converted.begin<cv::Vec3b>();
		  itend = converted.end<cv::Vec3b>();
	  }

	  // 遍历每个像素
	  for ( ; it!= itend; ++it, ++itout) {
          // 通过像素与阈值比较 
          // getDistanceToTargetColor()见完整代码
		  if (getDistanceToTargetColor(*it)<maxDist) {
			  *itout= 255;
		  } 
		  else {
			  *itout= 0;
		  }
	  }

	  return result;
}

        要先创建迭代器实现扫描循环,在每个迭代步骤中计算当前像素的颜色与目标颜色的距离,检查它是否在公差(maxDist )范围之内。如果是,就在输出图像中赋值 255( 白色),否则就赋值 0( 黑色)。

5.2 Lab颜色模型

        Lab颜色模型弥补了RGB和CMYK两种色彩模式的不足。它是一种设备无关的颜色模型,也是一种基于生理特征的颜色模型。 Lab颜色模型由三个要素组成,一个要素是亮度(L),a 和b是两个颜色通道。a包括的颜色是从深绿色(低亮度值)到灰色(中亮度值)再到亮粉红色(高亮度值);b是从亮蓝色(低亮度值)到灰色(中亮度值)再到黄色(高亮度值)。因此,这种颜色混合后将产生具有明亮效果的色彩。

        Lab模式既不依赖光线,也不依赖于颜料,它是CIE组织确定的一个理论上包括了人眼可以看见的所有色彩的色彩模式。Lab模式弥补了RGB和CMYK两种色彩模式的不足。同RGB颜色空间相比,Lab是一种不常用的色彩空间。它是在1931年国际照明委员会(CIE)制定的颜色度量国际标准的基础上建立起来的。

        Lab颜色空间中的取值范围:

  • L分量用于表示像素的亮度,取值范围是[0,100],表示从纯黑到纯白;
  • a表示从红色到绿色的范围,取值范围是[127,-128];
  • b表示从黄色到蓝色的范围,取值范围是[127,-128]。

        下图所示为Lab颜色空间的图示:

OpenCV - C++实战(05) — 颜色检测

5.3 cv :: threshold() 阈值函数 

        cv::threshold()函数创建一个二值图像。这个函数通常用于将所有像素与某个阈值(第三个参数)进行比较,在常规阈值化模式 (CV::THRESH_BINARY)下,将所有大于指定阈值的像素赋值为预定的最大值(第四个参数),将其他像素赋值为 0。

double cv::threshold(  
    cv::InputArray src, 
    cv::OutputArray dst, 
    double thresh,  
    double maxValue,  
    int thresholdType 
);  
  • src: 多通道的输入图像,8bits或者32bits float 
  • dst: 与src的同尺寸、类型、通道数的输出图像
  • thresh: 阈值(介于最大值和最小值之间的一个值)
  • maxval: 与两种阈值类型(THRESH_BINARY & THRESH_BINARY_INV)结合使用,用于指定最大的值
  • type: 阈值的类型

阈值的类型

作用
THRESH_BINARY  最常见的作法,设置一个阈值,大于的时候取最大值(maxval是threshold的参数),否则取0。
 THRESH_BINARY_INV 
 
与THRESH_BINARY相反,大于阈值取0,否则取最大值,maxval对于THRESH_BINARY和THRESH_BINARY_INV有意义。
THRESH_TRUNC 
 
截断型,大于阈值的统一将为阈值,其余不变。
THRESH_TOZERO 
 
过滤型,大于阈值的保持不变,其余设置为0。
THRESH_TOZERO_INV 
 
大于阈值0,其他不变。
THRESH_MASK 
 
THRESH_OTSU 
 
大津阈值
 THRESH_TRIANGLE  矩形阈值

5.4 计算图像之间的距离

5.4.1 公式计算

        要计算两个颜色向量间的距离,可使用这个简单的公式:

return abs (color [0]-target [0])+
            abs (color [1]-target [1])+
            abs (color [2]-target [2]);

 (1)公式计算颜色检测

// 计算两个颜色之间的城区距离
int 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]);
	  }

OpenCV - C++实战(05) — 颜色检测

5.4.2 cv::absdiff()

        计算两个数组(图像)差的绝对值: dst(I)c = abs(src1(I) - src2(I)c),所有数组(图像)必须有相同的数据类型、相同的大小(或ROI大小)。

void cv::absdiff( const CvArr* src1, const CvArr* src2, CvArr* dst );  
  • src1:第一个原数组  
  • src2:第二个原数组  
  • dst:输出数组 

5.4.3 cv::floodFill() 

        cv::floodFill()在判断一个像素时,要检查附近像素的状态,这是为了识别某种颜色的相关区域。用户只需指定一起始位置和允许的误差,就可以找出颜色接近的连续区域。

// 构造函数1
int floodFill(InputArray image, 
              Point seedPoint, 
              Scalar newVal, 
              Rect* rect=0,
              Scalar ioDiff=Scalar(), 
              Scalar upDiff=Scalar(), 
              int flags=4)
// 构造函数2
int floodFill(InputArray image, 
              InputArray mask, 
              Point seedPoint, 
              Scalar newVal, 
              Rect* rect=0,
              Scalar ioDiff=Scalar(), 
              Scalar upDiff=Scalar(), 
              int flags=4)
  • image:输入图像,1个或3个通道的8位或浮点图像。
  • mask:只有第二个版本才有该参数,表示作为掩膜。它应该是单通道,8位,长和宽都比输入图像大两个点的图像。因为漫水填充需要使用以及更细掩膜,所以对这个mask参数,我们一定要将其准本好并填在此处。需要注意的是,漫水填充不会填充mask的非零像素区域。例如,一个边缘检测算子的输出可以用来作为掩膜,以防止填充到边缘。同样的,也可以在多次的函数调用中使用同一个掩膜,以保证填充的区域不会重叠。需要注意的是,mask会比需填充的图像大,所以mask与输入图像(x, y)像素点对应的坐标为(x,+1 y+1)。
  • seedPoint:漫水填充算法的起始点。
  • newVal:像素被染色的值。
  • rect:默认值是0,可选参数,用于设置floodFill函数将要重绘区域的最小边界矩形区域。
  • loDiff:默认值是Scalar(),表示当前观察像素值与其部件邻域像素值或者待加入该部件的种子像素之间的亮度或颜色之负差的最大值。
  • upDiff:默认值是Scalar(),表示当前观察像素值与其部件邻域像素值或者待加入该部件的种子像素之间的亮度或颜色之正差的最大值。
  • flags:操作标志符。

(1) cv::absdiff()检测颜色

	// 使用cv::floodFill函数
    ColorDetector colordetector(230, 190, 130, 45, true);  // 第3个构造函数
	cv::floodFill(image,            // 输入/输出图像
		cv::Point(100, 50),         // 起始点
		cv::Scalar(255, 255, 255),  // 填充颜色
		(cv::Rect*)0,               // 填充颜色的边界距离
		cv::Scalar(35, 35, 35),     // 偏差的最小/最大阈值
		cv::Scalar(35, 35, 35),     // 正差阈值,两个阈值通常相等
		cv::FLOODFILL_FIXED_RANGE); // 与起始点像素比较
	cv::namedWindow("Image2");
	cv::Mat image2 = colordetector(image);
	cv::imshow("Image2", image2);
	cv::waitKey();

OpenCV - C++实战(05) — 颜色检测文章来源地址https://www.toymoban.com/news/detail-494562.html

 5.5 完整代码

/*
    colordetector.h头文件
*/
#if !defined COLORDETECT
#define COLORDETECT

#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>

class ColorDetector {

  private:
	  int maxDist;     // 允许的最小差距
	  cv::Vec3b target;    // 目标颜色
	  cv::Mat converted;   // 转换的图像
	  bool useLab;         // 是否使用Lab色彩空间
	  cv::Mat result;  // 存储二值映射结果的图像

  public:
	  // 不同的构造函数
	  // 在此初始化默认参数
	  ColorDetector() : maxDist(100), target(0,0,0), useLab(false) {}
	  ColorDetector(bool useLab) : maxDist(100), target(0,0,0), useLab(useLab) {}
	  ColorDetector(uchar blue, uchar green, uchar red, int mxDist=100, bool useLab=false): maxDist(mxDist), useLab(useLab) { 
		  // 设置需要检测的颜色
		  setTargetColor(blue, green, red);
	  }

	  // 计算与目标颜色的距离
	  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[1]-color2[1])+
					abs(color1[2]-color2[2]);
	  }

	  cv::Mat process(const cv::Mat &image);
      
	  cv::Mat operator()(const cv::Mat &image) {
		  cv::Mat input;
		 
		  if (useLab) { 
			  cv::cvtColor(image, input, CV_BGR2Lab);    // 转换成Lab色彩空间
		  }
		  else {
			  input = image;
		  }

		  cv::Mat output;
		  cv::absdiff(input,cv::Scalar(target),output);   // 计算目标图像的绝对距离
	      std::vector<cv::Mat> images;
	      cv::split(output,images);    // 分割图像的通道
	      output= images[0]+images[1]+images[2];   // 合并3个通道
	      
		  // 设定阈值
          cv::threshold(output,  // 输入图像
                        output,  // 输出图像
                        maxDist, // 阈值
                        255,     // 最大值
                        cv::THRESH_BINARY_INV); // 阈值类型
	
	      return output;
	  }


	  //设置颜色距离的阈值
	  void setColorDistanceThreshold(int distance) {
		  if (distance<0)
			  distance=0;
		  maxDist= distance;
	  }

	  // 获取颜色距离的阈值
	  int getColorDistanceThreshold() const {
		  return maxDist;
	  }
	  
	  // 设置需要检测的颜色
	  void setTargetColor(uchar blue, uchar green, uchar red) {
		  // BGR的次序
		  target = cv::Vec3b(blue, green, red);

		  if (useLab) {
			  // 创建临时的单像素图像
			  cv::Mat tmp(1, 1, CV_8UC3);
			  tmp.at<cv::Vec3b>(0, 0) = cv::Vec3b(blue, green, red);

			  // 转换成Lab色彩空间
			  cv::cvtColor(tmp, tmp, CV_BGR2Lab);
			  target = tmp.at<cv::Vec3b>(0, 0);
		  }
	  }

	  // 设置需要检测的颜色
	  void setTargetColor(cv::Vec3b color) {
		  target= color;
	  }

	  // 获取需要检测的颜色
	  cv::Vec3b getTargetColor() const {
		  return target;
	  }
};


#endif
/*
    颜色检测处理函数
*/
#include "colordetector.h"
#include <vector>
	
cv::Mat ColorDetector::process(const cv::Mat &image) {

	  result.create(image.size(),CV_8U);

	  // 转换成Lab色彩空间
	  if (useLab)
		  cv::cvtColor(image, converted, CV_BGR2Lab);

	  // 获取迭代器
	  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>();

	  // 获取转换图像的迭代器
	  if (useLab) {
		  it = converted.begin<cv::Vec3b>();
		  itend = converted.end<cv::Vec3b>();
	  }

	  // 遍历每个像素
	  for ( ; it!= itend; ++it, ++itout) {
          // 通过像素与阈值比较 
		  if (getDistanceToTargetColor(*it)<maxDist) {
			  *itout= 255;
		  } 
		  else {
			  *itout= 0;
		  }
	  }

	  return result;
}
/*
    主函数
*/
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include "colordetector.h"

int main()
{
    // step1
    // 创建检测图像的对象
	ColorDetector cdetect;

    // step2
    // 读取原图像
	cv::Mat image= cv::imread("Ferrar_F8.png");
	if (image.empty())
		return 0; 
	cv::namedWindow("Image");
	cv::imshow("Image", image);

    // step3
    // 设置输入参数与输出图像处理效果
	cdetect.setTargetColor(230,190,130);
	cv::namedWindow("Image1");
	cv::Mat image1 = cdetect.process(image);
	cv::imshow("Image1",image1);
    

	// 使用cv::floodFill函数
    ColorDetector colordetector(230, 190, 130, 45, true);  // 第3个构造函数
	cv::floodFill(image,            // 输入/输出图像
		cv::Point(100, 50),         // 起始点
		cv::Scalar(255, 255, 255),  // 填充颜色
		(cv::Rect*)0,               // 填充颜色的边界距离
		cv::Scalar(35, 35, 35),     // 偏差的最小/最大阈值
		cv::Scalar(35, 35, 35),     // 正差阈值,两个阈值通常相等
		cv::FLOODFILL_FIXED_RANGE); // 与起始点像素比较
	cv::namedWindow("Image2");
	cv::Mat image2 = colordetector(image);
	cv::imshow("Image2", image2);
	cv::waitKey();

	return 0;
}

到了这里,关于OpenCV - C++实战(05) — 颜色检测的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Python-opencv实现目标检测定位:判断固定颜色物体是否在规定区域内

    主要实现实时检测视频或者摄像头中出现的固定颜色(本例中使用绿色)是否在规定的区域范围内,并将结果反馈到原视频上。 实现的效果如下图所示: 1、当绿色物体出现在屏幕中的黑框中时,在视频左上角反馈一个“True”的信息。 2、当绿色物体出现在屏幕中但没有完全

    2024年01月17日
    浏览(47)
  • OpenCV C++案例实战三十三《缺陷检测》

    本案例将使用OpenCV C++ 进行PCB印刷缺陷检测。目前缺陷检测算法可分为两大类: 一:基于模板匹配的缺陷检测 二:基于深度学习的缺陷检测,主要利用目标检测去识别缺陷部分。 本文算法主要是基于模板匹配算法进行缺陷检测,参考《基于差异模型的印刷标签缺陷检测算法

    2024年02月08日
    浏览(46)
  • 人脸检测实战:使用opencv加载深度学习模型实现人脸检测(1)

    import argparse import cv2 ap = argparse.ArgumentParser() ap.add_argument(“-i”, “–image”, required=True, help=“path to input image”) ap.add_argument(“-p”, “–prototxt”, required=True, help=“path to Caffe ‘deploy’ prototxt file”) ap.add_argument(“-m”, “–model”, required=True, help=“path to Caffe pre-trained model”)

    2024年04月16日
    浏览(58)
  • 【OpenCV实战】3.OpenCV颜色空间实战

    OpenCV imread()方法不同的flags差异性 获取单色通道【R通道、G通道、B通道】 HSV、YUV、RGB 常用的有三种 a. -1 IMREAD_UNCHANGED:忽视alpha通道 b. 0 IMREAD_GRAYSCALE:灰度图 c. 1 IMREAD_COLOR 不填默认值,且格式为BGR assign_2.cpp 输出结果: 输出结果 输出结果 RGB:视频监视器,彩色摄像机 HSV

    2024年02月09日
    浏览(42)
  • VC++中使用OpenCV进行颜色检测

    在VC++中使用OpenCV进行颜色检测非常简单,首选读取一张彩色图像,并调用函数 cvtColor(img, imgHSV, COLOR_BGR2HSV); 函数将原图img转换成HSV图像imgHSV,再设置好HSV三个分量的上限和下限值,调用 inRange 函数 inRange(imgHSV, lower, upper, mask); 将HSV色彩图像转换成掩码图,掩码图中只有黑白二

    2024年01月21日
    浏览(41)
  • 霍夫变换直线检测算法实现OpenCV(C++)

    一、原理 对于霍夫变换的原理这里就不进行描述啦,感兴趣的可以自行搜索。也可以看知乎上面的这篇贴文通俗易懂理解——霍夫变换原理。 二、算法代码 三、效果测试 测试代码 上述代码中的drawLine()函数是《OpenCV4快速入门》一书的代码清单 7-2中的原函数,只用于画线。

    2024年02月05日
    浏览(46)
  • 使用opencv和dlib库(C++代码)实现人脸活体检测(眨眼、张嘴、摇头检测)

    本文章使用opencv和dlib库,使用C++代码实现了人脸活体检测,包括眨眼检测、张嘴检测以及摇头检测,可以对静态图片和活体进行有效区分。 dlib是一个开源的C++机器学习库,它提供了一系列用于图像处理、人脸检测、人脸识别、物体检测、图像标注等功能的算法和工具。dli

    2024年04月14日
    浏览(60)
  • opencv 案例05-基于二值图像分析(简单缺陷检测)

    缺陷检测,分为两个部分,一个部分是提取指定的轮廓,第二个部分通过对比实现划痕检测与缺角检测。本次主要搞定第一部分,学会观察图像与提取图像ROI对象轮廓外接矩形与轮廓。 下面是基于二值图像分析的大致流程 读取图像 将图像转换为灰度图,并对其进行二值化处

    2024年02月10日
    浏览(46)
  • 【OpenCV DNN】Flask 视频监控目标检测教程 05

    欢迎关注『OpenCV DNN @ Youcans』系列,持续更新中 本系列从零开始,详细讲解使用 Flask 框架构建 OpenCV DNN 模型的 Web 应用程序。 本节介绍用 Flask 构建流媒体服务器,向服务器发送请求可以播放本地视频文件。 本例程使用Flask框架构建一个视频流服务器,通过OpenCV读取本地视频

    2024年02月07日
    浏览(120)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包