OpenCV中通过滑动条阈值分割多通道图像

来源:互联网 发布:软件实施过程文档 编辑:程序博客网 时间:2024/06/05 16:57

1、阈值分割

阈值分割法是一种基于区域的图像分割技术。其基本原理是:通过设定不同的特征阈值,把图像象素点分为若干类。根据图像阈值化算法所依据的信息源,可将阈值化方法分为五类:1) 基于聚类的方法:数据聚类中,总的数据集被划分为属性相似的子类,例如将灰度级聚类成为两部分:前景物体部分和背景部分。2) 基于直方图的方法:在直方图的峰、谷和直方图的圆滑曲线上进行分析。3) 基于熵的方法:熵方法将区域分为背景区域和前景区域,前景区域通常是物体部分(在一些热红外图像中,背景部分是物体) 。该方法是通过最小化一个熵函数来实现的,交叉熵函数包含了介于原图和其二值图像之间的保留信息。4) 基于空间方法:使用概率密度函数模型,考虑全局范围内的像素之间的相似关系。5) 基于自适应方法:局部方法不能决定单一的阈值,自适应阈值依赖于局部图像特点。

这里,我们仅结合OpenCV中的API函数 threshold 来介绍一下阈值化。threshold函数原型如下:

double threshold(InputArray src, OutputArray dst, double thresh,                 double maxVal, int thresholdType)

Parameters:
第一个参数: 输入的灰度图像的地址。
第二个参数: 输出图像的地址。
第三个参数: 进行阈值操作时阈值的大小。
第四个参数: 设定的最大灰度值(该参数运用在二进制与反二进制阈值操作中)。
第五个参数: 阈值的类型。

最后一个参数是阈值化类型,函数一共提供了五种类型(图片来自opencv官网)。
1)二进制阈值化,参数值为0.
这里写图片描述
这里写图片描述
很好理解,像素值大于阈值设为255,反正设为0;
2)反二进制阈值化
这里写图片描述
这里写图片描述
与二进制阈值化类似,只不过大于阈值设为0,反之设为255;
3)截断阈值化
这里写图片描述
这里写图片描述
图像中大于该阈值的像素点被设定为该阈值,小于该阈值的保持不变;
4)阈值化为0
这里写图片描述
这里写图片描述
大于阈值的像素点不进行任何改变,其余灰度值全部变为0;
5)反阈值化为0
这里写图片描述
这里写图片描述
与阈值化类似,大于阈值的像素设为0,其余不做任何改变。

此外,OpenCV中应用极为广泛的阈值化API函数为adaptiveThreshold(自适应阈值化函数),详细用法参考OpenCV文档。

2、Trackbar

OpenCV提供了API函数createTrackbar,这使我们在设置参数的时候可以很方便的同程序交互。creatTrackbar函数原型如下:

int createTrackbar(const string& trackbarname,                    const string& winname, int* value,                    int count, TrackbarCallback onChange=0,                          )

第一个参数,const string&类型的trackbarname,表示轨迹条的名字,用来代表我们创建的轨迹条。
第二个参数,const string&类型的winname,填窗口的名字,表示这个轨迹条会依附到哪个窗口上,即对应namedWindow(),创建窗口时填的某一个窗口名。
第三个参数,int* 类型的value,一个指向整型的指针,表示滑块的位置。并且在创建时,滑块的初始位置就是是由该变量当前的值。
第四个参数,int类型的count,表示滑块可以达到的最大位置的值。PS:滑块最小的位置的值始终为0。
第五个参数,TrackbarCallback类型的onChange,首先注意他有默认值0。这是一个指向回调函数的指针,每次滑块位置改变时,这个函数都会进行回调。并且这个函数的原型必须为void Foo(int,void*);其中第一个参数是轨迹条的位置,第二个参数是用户数据(看下面的第六个参数)。如果回调是NULL指针,表示没有回调函数的调用,仅第三个参数value有变化。
第六个参数,void*类型的userdata,他也有默认值0。这个参数是用户传给回调函数的数据,用来处理轨迹条事件。如果使用的第三个参数value实参是全局变量的话,完全可以不去管这个userdata参数。


Demo程序如下:

#include <iostream>#include <cstring>#include "opencv2/core/core.hpp"#include "opencv2/imgproc/imgproc.hpp"#include "opencv2/highgui/highgui.hpp"using namespace std;using namespace cv;// 全局变量定义及赋值int threshold_type = 3;int const max_type = 4;     //阈值化类型int threshold_Bvalue = 0;   //B通道阈值设定int threshold_Gvalue = 0;   //G通道阈值设定  int threshold_Rvalue = 0;   //R通道阈值设定int const max_value = 255;  int const max_BINARY_value = 255;Mat src, dst;//创建一个图像向量vector<Mat> planes; char* window_name = "Threshold Func";char* trackbar_type = "TrackbarType";  //0: Binary 1: Binary Inverted 2: Truncate                                    //3: To Zero  4: To Zero Invertedchar* trackbar_Bvalue = "B_Value";char* trackbar_Gvalue = "G_Value";char* trackbar_Rvalue = "R_Value";/// 自定义函数声明void Threshold_Func( int, void* );int main(){  //加载一幅图片  src = imread( "test.jpg", 1 );  // 将图片转换成灰度图片  //cvtColor( src, src_gray, CV_RGB2GRAY );    //将多通道图像分割为若干单通道图像  split(src, planes);  // 创建一个窗口显示图片  namedWindow( window_name, CV_WINDOW_AUTOSIZE );     // 创建滑动条来控制阈值  createTrackbar( trackbar_type,                  window_name, &threshold_type,                  max_type, Threshold_Func );  createTrackbar( trackbar_Bvalue,                  window_name, &threshold_Bvalue,                  max_value, Threshold_Func );  createTrackbar( trackbar_Gvalue,                  window_name, &threshold_Gvalue,                  max_value, Threshold_Func );  createTrackbar( trackbar_Rvalue,                  window_name, &threshold_Rvalue,                  max_value, Threshold_Func );  // 初始化自定义的阈值函数  Threshold_Func( 0, 0 );  // 等待用户按键。如果是ESC健则退出等待过程。  while(true)  {    int c;    c = waitKey( 20 );    if( (char)c == 27 )      { break; }   }}//自定义的阈值函数void Threshold_Func( int, void* ){  /* 0: 二进制阈值     1: 反二进制阈值     2: 截断阈值     3: 0阈值     4: 反0阈值   */  dst.create(src.size(),src.type());  vector<Mat> thredplanes;  split(dst,thredplanes);  threshold( planes[0], thredplanes[0], threshold_Bvalue, max_BINARY_value,threshold_type );  threshold( planes[1], thredplanes[1], threshold_Gvalue, max_BINARY_value,threshold_type );  threshold( planes[2], thredplanes[2], threshold_Rvalue, max_BINARY_value,threshold_type );  //将三个单通道图像重新合并为一个三通道图像  merge(thredplanes,dst);  //显示dst图像  imshow( window_name, dst );}

运行结果:
这里写图片描述
程序说明:
1)先读取一副图片,如果是图片颜色类型是BGR三通道类型,则分离为三个单通道图像。

vector<Mat> planes;      //创建图像向量,用来存放src分割后的单通道图像split(src, planes);      //分割原始图像为若干单通道图像,split函数原型为                         //void split(const Mat& mtx, vector<Mat>& mv)                         //对偶运算为void merge(const vector<Mat>& mv, OutputArray dst)

2)创建一个窗口来显示该图片可以检验转换结果
3)创建滑动条。
第一个滑动条作用:选择阈值类型:二进制,反二进制,截断,0,反0。
二、三、四滑动条作用:分别选择BGR通道(分割后)阈值的大小。
4)等待用户拖动滚动条来输入阈值类型以及阈值的大小,或者是用户键入ESC健退出程序。

3、Nao红球识别

我们在Nao机器人的远程环境下进行红球识别,光照等外部环境对识别的结果有很大影响,所以一般将BGR颜色空间转换到HSV空间。无论如何选择颜色空间,进行多通道的阈值分割是保证后续识别的重要步骤。此外,用Nao机器人摄像头获取图像时,白平衡及曝光等参数的设定也至关重要,如果用滑动条的方式去寻找合适的参数,也不失为一种高效的方法!

2 0