美文网首页
32.色彩分割(inRange/cvtColor/iostrea

32.色彩分割(inRange/cvtColor/iostrea

作者: 小嗷_a2e2 | 来源:发表于2018-07-03 12:20 被阅读130次

    本文作者:小嗷

    微信公众号:aoxiaoji

    吹比QQ群:736854977

    本文链接:https://mp.weixin.qq.com/s?__biz=MzU1MTgxNjQyMg==&mid=2247483895&idx=1&sn=b20bb19349fb1db991a2111e215777e8&chksm=fb8adc7eccfd556855625ba36b072c1ba6bb36f925db7f69cf58dde654830b4219b1b809915a#rd


    image image image

    第5篇阈值threshold函数和第29篇用到adaptiveThreshold二值化

    这应该是阈值的最后一篇

    在本篇中,您将学习:

    • 使用OpenCV cv::inRange函数执行基本阈值操作。()

    • 根据HSV颜色空间中像素值的范围检测一个对象。


    本文你会找到以下问题的答案:

    1. inRange()

    2. cvtColor()

    3. iostream()

    4. max()与min()


    2.1 原理

    • 在前几篇中,我们学习了如何使用cv::阈值函数来执行阈值。(第5篇和第29篇)

    • 在本篇中,我们将学习如何使用cv::inRange函数。

    • 这个概念仍然是一样的(和第5篇),但是现在我们添加了我们需要的一系列像素值。

    2.2 HSV 彩色空间

    HSV(色相、饱和度、值)色彩空间是一种代表色彩空间的模型,类似于RGB颜色模型。由于色彩通道为颜色类型建模,所以它在图像处理任务中非常有用,因为它需要根据颜色来分割对象。饱和度的变化从不饱和到表示灰色和完全饱和(没有白色成分)。Value channel描述颜色的亮度或强度。下一个图像显示HSV圆柱。

    image.gif

    通过sharkd派生作品:SharkD CC By sa 3.0或GFDL,通过维基共享(图源维基百科)

    (说明一下Hue是色彩的意思,Saturation是饱和度,Value代表是亮度)

    由于RGB颜色空间中的颜色是使用三个通道进行编码的,所以在图像中根据其颜色对一个对象进行分段是比较困难的。

    image

    由SharkD GFDL或CC By sa 4.0,来自维基共享(图源维基百科)

    用于从一个颜色空间转换到另一个颜色空间的公式是:cv::cvtColor函数

    HSL and HSV来自维基百科详解

    https://en.wikipedia.org/wiki/HSLandHSV

    image

    3.1 inRange()

    检查数组元素是否位于两个其他数组的元素之间。

    1void cv::inRange  ( InputArray  src,  2  InputArray  lowerb,  3  InputArray  upperb,  4  OutputArray  dst  5 ) 
    

    这个函数检查范围如下:

    对于单通道输入阵列的每一个元素:

    image

    双通道数组:

    image

    等等

    也就是说,如果src(I)在指定的1D、2D、3D中,那么dst(I)被设置为255(所有1位)。其余都是0。

    当下界和/或上界参数为标量(固定不变的数值)时,在上面的公式中,下标(I)和上b的索引应该被省略。

    参数详解:

    • src:输入图像,CV2常用Mat类型;

    • lowerb:具有包容性的下界数组或标量。

    • upperb:包含上边界数组或标量。

    • dst:与src和cv8u类型相同大小的输出阵列。(CV8U忘了是什么的小伙伴请回到第21篇,即图像深度0-255,0-255就是)

    inRange()好处及用法:可以同时针对多通道进行操作,每个通道的像素值都必须在规定的阈值范围内!

    (什么操作?这个像素值不得超过最低值lowerb,和最大值upperb,超过就黑色,没有就白色。小学数学题,忘了小嗷也没办法)

    阈值就是单纯的大于小于,inrange则是既要小于它又要大于他

    3.2 cvtColor()

    将图像从一个颜色空间转换为另一个颜色空间。

    1void cv::cvtColor  ( InputArray  src,  2  OutputArray  dst,  3  int  code,  4  int  dstCn = 0  5 )  
    

    该函数将输入图像从一个颜色空间转换为另一个颜色空间。如果转换到RGB颜色空间,通道的顺序应该显式地指定(RGB或BGR)。注意,OpenCV中的默认颜色格式通常被称为RGB,但它实际上是BGR(字节被颠倒了)。因此,标准(24位)颜色图像中的第一个字节将是一个8位的蓝色组件,第二个字节将是绿色的,第三个字节将是红色的。(8位就是2的8次方等于255,这里说的专业点)

    R、G和B通道值的常规范围是:

    • cv8u图像的0到255

    • 对于cv16u图像,0到65535

    • cv32f图像的0到1

    在线性变换的情况下,这个范围并不重要。但是,在非线性转换的情况下,输入RGB图像应该被规范化为适当的值范围,以获得正确的结果,例如,

    RGB到Luv变换。例如,如果您有一个32位的浮点图像直接从8位图像转换而没有任何缩放,那么它就会有0。255的值范围而不是0。由函数承担。因此,在调用cvtColor之前,您首先需要将图像缩小:

    img *= 1./255;
    cvtColor(img, img, COLOR_BGR2Luv);
    

    如果您使用带有8位图像的cvtColor,那么转换将会丢失一些信息。对于许多应用程序来说,这是不明显的,但是建议在应用程序中使用32位图像,这些应用程序需要全部的颜色,或者在操作之前转换图像,然后再转换回来。

    如果转换增加了alpha通道,它的值将被设置为对应的通道范围的最大值:cv8u的255,cv16u的65535,cv32f的1。

    参数详解:

    • src:输入图像为8位无符号,16位无符号(cv16uc。)或单精度浮点。

    • dst:与src相同大小和深度的输出图像。

    • code:彩色空间转换代码(参见colorconversioncode)。

    • dstCn:目标图像中的通道数;如果参数为0,则通道的数量将自动从src和代码中派生出来。(原来深度)

    其中,最后一个参数dstCn用于指定目标图像的通道数,如果指定的值是默认值0,那么通道数将由输入图像和颜色转换码决定。 cv::cvtColor()支持多种颜色空间之间的转换,其支持的转换类型和转换码如下:

    1、RGB和BGR(opencv默认的彩色图像的颜色空间是BGR)颜色空间的转换

    cv::COLORBGR2RGB cv::COLORRGB2BGR cv::COLORRGBA2BGRA cv::COLORBGRA2RGBA

    2、向RGB和BGR图像中增添alpha通道

    cv::COLORRGB2RGBA cv::COLORBGR2BGRA

    3、从RGB和BGR图像中去除alpha通道

    cv::COLORRGBA2RGB cv::COLORBGRA2BGR

    4、从RBG和BGR颜色空间转换到灰度空间

    cv::COLORRGB2GRAY cv::COLORBGR2GRAY

    cv::COLORRGBA2GRAY cv::COLORBGRA2GRAY

    5、从灰度空间转换到RGB和BGR颜色空间

    cv::COLORGRAY2RGB cv::COLORGRAY2BGR

    cv::COLORGRAY2RGBA cv::COLORGRAY2BGRA

    6、RGB和BGR颜色空间与BGR565颜色空间之间的转换

    cv::COLORRGB2BGR565 cv::COLORBGR2BGR565 cv::COLORBGR5652RGB cv::COLORBGR5652BGR cv::COLORRGBA2BGR565 cv::COLORBGRA2BGR565 cv::COLORBGR5652RGBA cv::COLORBGR5652BGRA

    7、灰度空间域BGR565之间的转换

    cv::COLORGRAY2BGR555 cv::COLORBGR5552GRAY

    8、RGB和BGR颜色空间与CIE XYZ之间的转换

    cv::COLORRGB2XYZ cv::COLORBGR2XYZ cv::COLORXYZ2RGB cv::COLORXYZ2BGR

    9、RGB和BGR颜色空间与uma色度(YCrCb空间)之间的转换

    cv::COLORRGB2YCrCb cv::COLORBGR2YCrCb cv::COLORYCrCb2RGB cv::COLORYCrCb2BGR

    10、RGB和BGR颜色空间与HSV颜色空间之间的相互转换

    cv::COLORRGB2HSV cv::COLORBGR2HSV cv::COLORHSV2RGB cv::COLORHSV2BGR

    11、RGB和BGR颜色空间与HLS颜色空间之间的相互转换

    cv::COLORRGB2HLS cv::COLORBGR2HLS cv::COLORHLS2RGB cv::COLORHLS2BGR

    12、RGB和BGR颜色空间与CIE Lab颜色空间之间的相互转换

    cv::COLORRGB2Lab cv::COLORBGR2Lab cv::COLORLab2RGB cv::COLORLab2BGR

    13、RGB和BGR颜色空间与CIE Luv颜色空间之间的相互转换

    cv::COLORRGB2Luv cv::COLORBGR2Luv cv::COLORLuv2RGB cv::COLORLuv2BGR

    14、Bayer格式(raw data)向RGB或BGR颜色空间的转换

    cv::COLORBayerBG2RGB cv::COLORBayerGB2RGB cv::COLORBayerRG2RGB cv::COLORBayerGR2RGB cv::COLORBayerBG2BGR cv::COLORBayerGB2BGR cv::COLORBayerRG2BGR cv::COLORBayerGR2BGR

    线性变换也成为线性映射( linear mapping),是从一个向量空间V到另一个向量空间W的映射且保持加法运算和数量乘法运算,而线性变换(linear transformation)是线性空间V到其自身的线性映射。(小嗷以后抽点时间写写,这里简单说说)

    LUV色彩空间全称CIE 1976(L,u,v) (也作CIELUV)色彩空间,L表示物体亮度,u和v是色度。于1976年由国际照明委员会CIE 提出,由CIE XYZ空间经简单变换得到,具视觉统一性。类似的色彩空间有CIELAB。对于一般的图像,u和v的取值范围为-100到+100,亮度为0到100。

    image

    3.3 iostream

    iostream是指iostream库

    3.4 min()与max()

    1softfloat cv::min(max)  ( const softfloat &  a,  2  const softfloat &  b  3 )  
    

    max(a, b) 表示a,b中较大的数 当a>b时,值为a。 当a<b时,值为b。

    min()则相反,不懂的话.QQ叫小嗷。

    image

    本篇文章的代码如下所示。

    1//首先是包含的包(类),1包含.图像处理,那么一定是imgproc.hpp 2//然后,需要图行界面那么就是:highgui 3//基本的输入输出流 4 5#include "opencv2/imgproc.hpp" 6#include "opencv2/highgui.hpp" 7#include <iostream> 8 9//命名控件10using namespace cv;11//色彩18012const int max_value_H = 360 / 2;13const int max_value = 255;14const String window_capture_name = "Video Capture";//打开摄像头的窗口名字15const String window_detection_name = "Object Detection";//侦察窗口名字16int low_H = 0, low_S = 0, low_V = 0;17int high_H = max_value_H, high_S = max_value, high_V = max_value;181920//定义回调函数,轨迹条21static void on_low_H_thresh_trackbar(int, void *)22{23    low_H = min(high_H - 1, low_H);24    setTrackbarPos("Low H", window_detection_name, low_H);25}2627static void on_high_H_thresh_trackbar(int, void *)28{29    high_H = max(high_H, low_H + 1);30    setTrackbarPos("High H", window_detection_name, high_H);31}3233static void on_low_S_thresh_trackbar(int, void *)34{35    low_S = min(high_S - 1, low_S);36    setTrackbarPos("Low S", window_detection_name, low_S);37}3839static void on_high_S_thresh_trackbar(int, void *)40{41    high_S = max(high_S, low_S + 1);42    setTrackbarPos("High S", window_detection_name, high_S);43}4445static void on_low_V_thresh_trackbar(int, void *)46{47    low_V = min(high_V - 1, low_V);48    setTrackbarPos("Low V", window_detection_name, low_V);49}5051static void on_high_V_thresh_trackbar(int, void *)52{53    high_V = max(high_V, low_V + 1);54    setTrackbarPos("High V", window_detection_name, high_V);55}5657int main(int argc, char* argv[])58{59    VideoCapture cap(argc > 1 ? atoi(argv[1]) : 0);6061    namedWindow(window_capture_name);62    namedWindow(window_detection_name);6364    // Trackbars to set thresholds for HSV values65    createTrackbar("Low H", window_detection_name, &low_H, max_value_H, on_low_H_thresh_trackbar);66    createTrackbar("High H", window_detection_name, &high_H, max_value_H, on_high_H_thresh_trackbar);67    createTrackbar("Low S", window_detection_name, &low_S, max_value, on_low_S_thresh_trackbar);68    createTrackbar("High S", window_detection_name, &high_S, max_value, on_high_S_thresh_trackbar);69    createTrackbar("Low V", window_detection_name, &low_V, max_value, on_low_V_thresh_trackbar);70    createTrackbar("High V", window_detection_name, &high_V, max_value, on_high_V_thresh_trackbar);7172    Mat frame, frame_HSV, frame_threshold;73    while (true) {74        cap >> frame;75        if (frame.empty())76        {77            break;78        }7980        // Convert from BGR to HSV colorspace81        cvtColor(frame, frame_HSV, COLOR_BGR2HSV);82        // Detect the object based on HSV Range Values83        inRange(frame_HSV, Scalar(low_H, low_S, low_V), Scalar(high_H, high_S, high_V), frame_threshold);8485        // Show the frames86        imshow(window_capture_name, frame);87        imshow(window_detection_name, frame_threshold);8889        char key = (char)waitKey(30);90        if (key == 'q' || key == 27)91        {92            break;93        }94    }95    return 0;96}
    

    结果:

    在编译完这个程序之后,运行它。这个程序将打开两个窗口

    当您从trackbar中设定范围值时,得到的帧将在另一个窗口中可见。

    image

    即:同时设置多个通道范围范围大小(Hue是色彩的意思,Saturation是饱和度,Value代表是亮度)

    色调H

    用角度度量,取值范围为0°~360°,从红色开始按逆时针方向计算,红色为0°,绿色为120°,蓝色为240°。它们的补色是:黄色为60°,青色为180°,品红为300°;

    饱和度S

    饱和度S表示颜色接近光谱色的程度。一种颜色,可以看成是某种光谱色与白色混合的结果。其中光谱色所占的比例愈大,颜色接近光谱色的程度就愈高,颜色的饱和度也就愈高。饱和度高,颜色则深而艳。光谱色的白光成分为0,饱和度达到最高。通常取值范围为0%~100%,值越大,颜色越饱和。

    明度V

    明度表示颜色明亮的程度,对于光源色,明度值与发光体的光亮度有关;对于物体色,此值和物体的透射比或反射比有关。通常取值范围为0%(黑)到100%(白)。

    小嗷的米黄色衣服

    image image

    因为光线的影响,所以得到的效果不满意

    解释一下:

    让我们来看看这个项目的总体结构:

    • 从默认的或提供的捕获设备中捕获视频流。
    1    VideoCapture cap(argc > 1 ? atoi(argv[1]) : 0);
    
    • 创建一个窗口来显示默认框架和阈值框架。
    1    namedWindow(window_capture_name);2    namedWindow(window_detection_name);
    
    • 创建跟踪条来设置HSV值的范围
    1    // Trackbars to set thresholds for HSV values2    createTrackbar("Low H", window_detection_name, &low_H, max_value_H, on_low_H_thresh_trackbar);3    createTrackbar("High H", window_detection_name, &high_H, max_value_H, on_high_H_thresh_trackbar);4    createTrackbar("Low S", window_detection_name, &low_S, max_value, on_low_S_thresh_trackbar);5    createTrackbar("High S", window_detection_name, &high_S, max_value, on_high_S_thresh_trackbar);6    createTrackbar("Low V", window_detection_name, &low_V, max_value, on_low_V_thresh_trackbar);7    createTrackbar("High V", window_detection_name, &high_V, max_value, on_high_V_thresh_trackbar);
    
    • 在用户希望程序退出之前,执行以下操作
     1    cap >> frame; 2    if(frame.empty()) 3    { 4        break; 5    } 6 7    // Convert from BGR to HSV colorspace 8    cvtColor(frame, frame_HSV, COLOR_BGR2HSV); 9    // Detect the object based on HSV Range Values10    inRange(frame_HSV, Scalar(low_H, low_S, low_V), Scalar(high_H, high_S, high_V), frame_threshold);
    
    • 显示的图像
    1    // Show the frames2    imshow(window_capture_name, frame);3    imshow(window_detection_name, frame_threshold);
    
    • 对于一个控制较低范围的轨迹条,比如色相值:(最低不能低于)
     1    static void on_low_H_thresh_trackbar(int, void *) 2    { 3        low_H = min(high_H-1, low_H); 4        setTrackbarPos("Low H", window_detection_name, low_H); 5    } 6 7    static void on_low_H_thresh_trackbar(int, void *) 8    { 9        low_H = min(high_H-1, low_H);10        setTrackbarPos("Low H", window_detection_name, low_H);11    }
    
    • 对于一个控制上范围的轨迹条,比如色相值:(最大不能大于)
    1    static void on_high_H_thresh_trackbar(int, void *)2    {3        high_H = max(high_H, low_H+1);4        setTrackbarPos("High H", window_detection_name, high_H);5    }
    

    有必要找出最大和最小值,以避免差异,例如阈值的高值小于低值。

    image.gif
    1. 本人是抱着玩一玩的心态,学习opencv(其实深度学习没有外界说的这么高深,小嗷是白板,而且有工作在身并且于代码无关)

    2. 大家可以把我的数学水平想象成初中水平,毕竟小嗷既不是代码靠吃饭又不是靠数学吃饭,毕业N年

    3. 写文章主要是为了后人少走点弯路,多交点朋友,一起学习

    4. 如果有好的图像识别群拉我进去QQ:631821577

    5. 就我一个白板,最后还是成的,你们别怕,慢慢来吧

    image

    分享可以无数次,转载成自己文章QQ邮箱通知一下,未经授权请勿转载。

    邮箱:631821577@qq.com
    
    QQ群:736854977
    
    有什么疑问公众号提问,下班或者周六日回答,ths
    

    感言

    嗷嗷嗷~~~,喜欢就推荐一下好友

    上次的小伙伴问我怎么滤波,只留黄色部分的图像。小嗷周六日试试的效果和代码如下

    image

    在CamfhiftDemo窗口中左键长按拉到你想要的区域,松手 -> 自动获取选中区域色彩直方图 -> 移动就跟着走(实际受到环境因素的影响,效果不怎么好,不同于软件生成图。),代码在本篇百度云链接上,

    image image

    推荐文章:

    没有

    代码链接:

    https://pan.baidu.com/s/1K-d1lr9KsY9jCXAq9WvC1g

    密码:e3vf

    小嗷

    image

    相关文章

      网友评论

          本文标题:32.色彩分割(inRange/cvtColor/iostrea

          本文链接:https://www.haomeiwen.com/subject/hpmduftx.html