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颜色空间的图示:
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]);}
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:操作标志符。
// 使用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();
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) — 颜色检测相关推荐
- 基于OpenCV的实战:轮廓检测(附代码解析)
点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 利用轮廓检测物体可以看到物体的各种颜色,在这种情况下放置在静态和动 ...
- 使用 OpenCV 进行实时对象颜色检测
在本文中,我们将讨论如何使用 python 和 OpenCV 检测单色对象.单色是指单一波长的光.我们将使用使用网络摄像头捕获的视频作为输入,并尝试检测单一颜色的对象,尤其是蓝色.但是,如果您正确设置 ...
- 3h精通OpenCV(七)-颜色检测
0.准备工作 右击新建的项目,选择Python File,新建一个Python文件,然后在开头import cv2导入cv2库,import numpy并且重命名为np. import cv2 imp ...
- opencv项目实战信用卡的检测
第一步先梳理一下我们的项目逻辑: 一. 找素材 (数字模板,银行卡照片等) 二. 识别数字则需要我们对数字模板进行处理.因此下面我们开始处理数字模板. 1.将数字模板处理成灰度图,再进行二值处理.这样 ...
- 【Opencv图像处理】BGB转HSV与颜色检测
BGB转HSV与颜色检测 什么是HSV色彩空间? Opencv代码 静态图片颜色检测 结果展示 视频颜色检测 结果展示 什么是HSV色彩空间? HSV(色相.饱和度.值,也称为 HSB [色相.饱和度 ...
- python颜色识别原理_python+opencv实现颜色检测、轮廓检测、颜色追踪
准备工作 python配置numpy和openCv库 读取图像和视频图像cv2.imread(路径) cv2.imshow(窗口名称,输出对象) cv2.waitkey(等待时间)import cv2 ...
- 《OpenCv视觉之眼》Python图像处理十六:Opencv图像处理实战一之图像中的硬币检测
本专栏主要介绍如果通过OpenCv-Python进行图像处理,通过原理理解OpenCv-Python的函数处理原型,在具体情况中,针对不同的图像进行不同等级的.不同方法的处理,以达到对图像进行去噪.锐 ...
- 《OpenCv视觉之眼》Python图像处理十九:Opencv图像处理实战四之通过OpenCV进行人脸口罩模型训练并进行口罩检测
本专栏主要介绍如果通过OpenCv-Python进行图像处理,通过原理理解OpenCv-Python的函数处理原型,在具体情况中,针对不同的图像进行不同等级的.不同方法的处理,以达到对图像进行去噪.锐 ...
- OpenCV 颜色检测| color detection
OpenCV 颜色检测 1.导入必要的包并初始化相机 import cv2 import numpy as np# Reading the image img = cv2.imread('test.j ...
最新文章
- C++的集成开发环境(IDE)
- Spring注解方式实现定时器
- 233 Matrix HDU - 5015
- Elasticsearch 5.2.x 使用 Head 插件连接不上集群
- python flv转mp4_ffmpeg将多个flv文件合成为mp4(python版)
- 进程通信方法的特点以及使用场景
- python格式化输出作业_Python格式化输出
- Android 跳转权限设置界面的终极方案
- 【数学建模】基于matlab模糊二元决策树【含Matlab源码 038期】
- Nodejs的各种数据库驱动地址汇总
- DoDAF示例图绘制
- 【资讯】时间的朋友2017跨年演讲全回顾
- 深入了解Spark SQL的Catalyst Optimizer
- jbpm支持xpdl的标准了吗?
- python 根据word生成ppt_python操作word、ppt的详解
- Linux驱动学习笔记之触摸屏驱动
- 在带头结点单链表中查找最大值,将其与最后一个元素交换(交换值)
- 【实验】实验课总结3 实验二
- 大疆精灵4与双目视觉智能导航系统
- 光纤收发器的选择与维护!
热门文章
- 不经一番寒彻骨,怎得梅花扑鼻香,android开发艺术探索电子
- caffe-ristretto:定点方案
- 解析Activity中的onCreate方法
- snat与dnat的区别
- 控制BLDC资料汇总
- Java 11已经不再完全免费,不要陷入Oracle的Java 11陷阱
- MFC 加载gif动态图片的方法
- 电脑蓝牙耳机连接不稳定_一个困扰我半年的 macOS 蓝牙有时断连的问题终于解决了!...
- python list[list] or list[list, list, list]
- MySQL简介,什么是数据库?