上一篇博客记录了在旭日x3派上运行opencv进行颜色识别和在图像中的定位。在处理实际问题时颜色的阈值调整时会遇到一些问题,比如要识别的颜色不一定是经典红或绿或黄,此时对于HSV色域的阈值选择则需要实时调整了。

另外这里补充下为什么要选用HSV色域而不用RGB色域,比如黄色在HSV色域中描述色彩值H为35-77,但是在RGB中便不好描述一个范围。HSV色域H代表色彩,S代表深度,V代表亮度,如下图圆锥体表示出来的色彩空间。

了解了色域问题,接下来描述下遇到的问题。

采用如上表的颜色阈值进行识别绿色和红色的模型时效果良好,但是识别黄色时就出现问题了:识别得到红色区域面积最大,因而判定为红,但是明明颜色的阈值都是按照阈值表来设定的,甚至黄色识别部分一点都识别不到。

//黄色阈值设定
Scalar lower_yellow(26,43,46); 
Scalar upper_yellow(34,255,255);

有了问题就需要解决,这种问题一般是因为理论上的阈值和实际的颜色有偏差导致的,因此需要一个工具可以让我们根据自己要识别的物体具体实时调整,来获取对应的阈值。编写这个小工具需要用到滑块控件:

滑块控件

要实现阈值的选择,我们不可能一个数值一个数值的输入再运行看效果,然后再试。所以要使用到滑块控件,在图片中实时调节并可以观察到效果。

int cv::createTrackbar(const String & trackbarname,
const String & winname,
int * value,
int count,
TrackbarCallback onChange = 0,
void * userdata = 0 
)	

opencv官方提供了以上滑块控件api。第一个输入参数滑块的名称,第二个参数是滑块显示在的窗口名称,第三个参数是滑块的值赋予的变量的地址,第四个输入参数是滑块的最大值(该api默认最小值为0),第五个输入参数回调函数名,第六输入参数会直接原样输入给回调函数。

创建工程

老样子在旭日x3派跑destop系统,需要提高速度可以试试交叉编译。在qtcreator新建一个Non-Qt Project——Plain C++ Application的项目,其余默认即可。打开 .pro文件配置参数。首先添加头文件路径:

INCLUDEPATH += /usr/include/opencv4 \
            /usr/include/opencv2 \
            /usr/include/opencv

再添加相应的库,使用旭日x3派,如果是使用apt install libopencv-dev安装编译好的opencv库,那么其库文件路径就是/usr/lib/x86_64-linux-gnu/.如果是另外编译安装的可以在终端中输入 dpkg -L libopencv-dev 查看包的安装路径。

LIBS += -L/usr/lib/x86_64-linux-gnu -lopencv_core -lopencv_highgui -lopencv_imgcodecs \
        -lopencv_calib3d -lopencv_features2d -lopencv_imgproc -lopencv_photo -lopencv_superres \
        -lopencv_stitching

说明:

  • LIBS += :表示将后面的库文件添加到已有库文件的列表中。
  • -L/usr/lib/x86_64-linux-gnu:表示告诉链接器在 /usr/lib/x86_64-linux-gnu 目录下查找库文件。
  • -lopencv_core -lopencv_highgui等:表示要链接的库文件分别是libopencv_core.a、libopencv_highgui.a等简单来说,这个指令的作用是将 OpenCV 的核心库、高级图形库等链接到你的程序中,以便你可以使用它们的函数和类。

效果

代码以无回调函数形式应用滑块控件。

#include <iostream>
#include<opencv4/opencv2/opencv.hpp>

using namespace cv;
using namespace std;

/* 定义HSV的阈值
 * lh、uh分别为色调h的低阈值和高阈值
 * ls、us分别为饱和度s的低阈值和高阈值
 * lv、uv分别为亮度v的低阈值和高阈值
 * hsv储存将RGB色域图像转为HSV色域的图像
*/
int lh,ls,lv,uh,us,uv; Mat hsv;
Mat dst;

int main()
{
    //建立窗口命名为dst
    namedWindow("dst", WINDOW_AUTOSIZE);
    Mat img = imread("/home/wch/模板/cv_1/yellow.jpg");

    //RGB转HSV色域
    cvtColor(img, hsv, COLOR_RGB2HSV);

    //创建控件
    //没有回调函数时,回调函数名那个参数设置为0
    createTrackbar("lh","dst",&lh,255,0);
    createTrackbar("ls","dst",&ls,255,0);
    createTrackbar("lv","dst",&lv,255,0);
    createTrackbar("uh","dst",&uh,255,0);
    createTrackbar("us","dst",&us,255,0);
    createTrackbar("uv","dst",&uv,255,0);

    while(1)
    {
        inRange(hsv, Scalar(lh,ls,lv), Scalar(uh,us,uv), dst);
        imshow("dst", dst);

        //延时等待,按回车退出
        if(waitKey(2) == 13)  //27==esc  13==enter
            break;
    }

    destroyAllWindows();

    return 0;
}

经过阈值调节选择后获得一个较为理想的阈值Scalar(86,62,110),Scalar(105,255,255);这个值作为识别黄色模型苗就较理论上黄色阈值Scalar(26,43,46),Scalar(34,255,255)更加优。

然后识别程序中的阈值修改为该程序调节选取获得的阈值,可以看到黄色的识别问题得到了解决。

 Scalar lower_yellow(86,62,110); 
 Scalar upper_yellow(105,255,255);

另外,这种方式的识别受光线影响大,因此要尽可能避免光线的影响。同时考虑到这是室外作业,因此通常是强光条件,所以以光亮的情景下选取阈值,同时在摄像头旁装上照明灯,哪怕室外阴天光线较弱,照明灯也可以保证获取的图像与光线充足时相近。