opencv 彩色图像分割(inrange)

时间:2022-12-09 15:31:35

  灰度图像大多通过算子寻找边缘和区域生长融合来分割图像。

  彩色图像增加了色彩信息,可以通过不同的色彩值来分割图像,常用彩色空间HSV/HSI, RGB, LAB等都可以用于分割!

  笔者主要介绍inrange() 来划分颜色区域。先看看OpenCV的文档:

  C++: void inRange(InputArray src, InputArray lowerb, InputArray upperb, OutputArray dst)

  C: void cvInRangeS(const CvArr* src, CvScalar lower, CvScalar upper, CvArr* dst) 

  • src – first input array.
  • lowerb – inclusive lower boundary array or a scalar.
  • upperb – inclusive upper boundary array or a scalar.
  • dst – output array of the same size as src and CV_8U type
  • For two-channel arrays:

    opencv 彩色图像分割(inrange)

  • and so forth.

  意思主要是:

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

  lowerb:lower boundary下限,scalar类型的像素值,单通道scalar取一个值就行,彩图3通道scalar三个值;

  upperb:上限,类型与lowerb同理;

  dst:输出图像,尺寸与src一致,类型是CV_8U,但没有指定通道数。

  对于多通道的输入,输出结果是各个通道的结果相与,当各通道结果都在上下限之内时,输出为255,否则为0。因此也有人将输出理解为掩码模板!

 

  看个例子吧:  

 1 int hmax = 360;
 2 int hmax_Max = 360;
 3 //饱和度  
 4 int smin = 0;
 5 int smin_Max = 255;
 6 int smax = 255;
 7 int smax_Max = 255;
 8 //亮度  
 9 int vmin = 106;
10 int vmin_Max = 255;
11 int vmax = 250;
12 int vmax_Max = 255;
13 //显示原图的窗口  
14 string windowName = "src";
15 //输出图像的显示窗口  
16 string dstName = "dst";
17 //输出图像  
18 Mat dst;
19 //回调函数  
20 void callBack(int, void*)
21 {
22     //输出图像分配内存  
23     dst = Mat::zeros(img.size(), CV_32FC3);
24     //掩码  
25     Mat mask;
26     inRange(hsv, Scalar(hmin, smin / float(smin_Max), vmin / float(vmin_Max)), Scalar(hmax, smax / float(smax_Max), vmax / float(vmax_Max)), mask);
27     //只保留  
28     for (int r = 0; r < bgr.rows; r++)
29     {
30         for (int c = 0; c < bgr.cols; c++)
31         {
32             if (mask.at<uchar>(r, c) == 255)
33             {
34                 dst.at<Vec3f>(r, c) = bgr.at<Vec3f>(r, c);
35             }
36         }
37     }
38     //输出图像  
39     imshow(dstName, dst);
40     //保存图像  
41     dst.convertTo(dst, CV_8UC3, 255.0, 0);
42     imwrite("HSV_inRange.jpg", dst);
43 }
44 void test_main()
45 {
46     //输入图像  
47     img = imread("E:\\素材图片\\1.png",1);
48     if (!img.data || img.channels() != 3)
49         return ;
50     imshow(windowName, img);
51     //彩色图像的灰度值归一化  
52     img.convertTo(bgr, CV_32FC3, 1.0 / 255, 0);
53     //颜色空间转换  
54     cvtColor(bgr, hsv, COLOR_BGR2HSV);
55     //定义输出图像的显示窗口  
56     namedWindow(dstName, WINDOW_NORMAL);
57     //调节色相 H  
58     createTrackbar("hmin", dstName, &hmin, hmin_Max, callBack);
59     createTrackbar("hmax", dstName, &hmax, hmax_Max, callBack);
60     //调节饱和度 S  
61     createTrackbar("smin", dstName, &smin, smin_Max, callBack);
62     createTrackbar("smax", dstName, &smax, smax_Max, callBack);
63     //调节亮度 V  
64     createTrackbar("vmin", dstName, &vmin, vmin_Max, callBack);
65     createTrackbar("vmax", dstName, &vmax, vmax_Max, callBack);
66     callBack(0, 0);
67     waitKey(0);
68     return;
69 }

  函数外的为全局变量,头文件自己加上就行。

  放两张不同的图片分割结果:

opencv 彩色图像分割(inrange)    opencv 彩色图像分割(inrange)

  第一种是通过调节H值将红色和绿色分割开,SV的值我选择保持默认。(忽略结果图右下角的输入法。。。)

  opencv 彩色图像分割(inrange)    opencv 彩色图像分割(inrange)

  第二种调节H值并没有什么改善,但是可以调节S饱和度,将车牌前景和背景对比的更加强烈。(忽略结果图右下角的输入法。。。)

  更多调节策略欢迎大家评价~~