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

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 Inverted
char* 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机器人摄像头获取图像时,白平衡及曝光等参数的设定也至关重要,如果用滑动条的方式去寻找合适的参数,也不失为一种高效的方法!

时间: 2024-08-11 03:27:53

OpenCV中通过滑动条阈值分割多通道图像的相关文章

python opencv:使用滑动条做调色板

cv2.getTrackbarPos() 函数的 一个参数是滑动条的名字, 第二个参数是滑动条被放置窗口的名字, 第三个参数是滑动条的默认位置. 第四个参数是滑动条的最大值, 第五个函数是回调函数,每次滑动条的滑动都会调用回调函数. 回调函数通常都会含有一个默认参数,就是滑动条的位置. 在本例中这个函数不用做任何事情,我们只需要 pass 就可以了 滑动条的另外一个重要应用就是用作转换按钮. 默认情况下 OpenCV 本身不带有按钮函数. 所以我们使用滑动条来代替. 在我们的程序中,我们要创建一

管窥Android中的滑动条SeekBar的父类AbsSeekBar的源码

Android中的控件中有一类是ProgressBar,其子类中有一个是AbsSeekBar.相信有不少童鞋对这个拖动条的父类比较感兴趣吧!尤其是看到网易云音乐的进度条上面是可以处理播放与暂停事件,是不是很羡慕的哈~  俺在这里告诉大家,不用羡慕,看了我下面的代码分析,你也是可以做出那样的效果的哦.Let's go. 下面先给大家列表一下AbsSeekBar的成员变量有哪些. //当前的矩形 private final Rect mTempRect = new Rect(); //可以拖动的滑块

第十四节,OpenCV学习(三)图像的阈值分割

图像的阈值处理 图像的阈值分割:图像的二值化(Binarization) 阈值分割法的特点是:适用于目标与背景灰度有较强对比的情况,重要的是背景或物体的灰度比较单一,而且总可以得到封闭且连通区域的边界. 一.简单阈值 选取一个全局阈值,然后把图像分成非黑即白的二值图像. cv2.threshold()[源图像矩阵,进行分类的阈值,高于(低于)阈值时赋予的新值,方法选择参数] 返回两个值:阈值,阈值处理后的图像矩阵. cv2.THRESH_BINARY(黑白二值) cv2.THRESH_BINAR

创建一个程序读入和显示视频文件,并可以使用滑动条控制视频文件的播放。一个滑动条用来控制视频播放位置,以10为步长跳进。另一个滑动条用来控制停止/播放

/* 创建一个程序读入和显示视频文件,并可以使用滑动条控制视频文件的播放. 一个滑动条用来控制视频播放位置,以10为步长跳进.另一个滑动条用来控制 停止/播放 */ #include <cv.h> #include <highgui.h> int g_slider_position = 0; CvCapture* g_capture = NULL; int index = 0; bool flag = true; int g_slider_position1 = 0; void o

使用OpenCV滑动条写成的简单调色器,实时输出RGB值

好久没有写博客了,最近在看OpenCV,于是动手写了个简单的RGB调色器,在终端实时输出RGB的值.通过这个程序学习滑动条的使用.程序中主要用到cvCreateTrackbar ,其用法如下: cvCreateTrackbar 创建trackbar并将它添加到指定的窗口. CV_EXTERN_C_FUNCPTR( void (*CvTrackbarCallback)(int pos) ); int cvCreateTrackbar( const char* trackbar_name, cons

滑动条 Trackbar[OpenCV 笔记9]

OpenCV中没有实现按钮的功能,我们可以利用滑动条来实现按钮功能. int createTrackerbar(const string& trackerbarname, const string winame, int* value, int count, TrackbarCallback onChange=0, void* userdata=0); trackbarname 轨迹条的名字. winname 窗口的名字,轨迹条会依附在这个窗口上. value 一个指向整型的指针,表示滑块的位置

python+opencv实现阈值分割

最近老师留了几个作业,虽然用opencv很简单一句话就出来了,但是还没用python写过.在官方文档中的tutorial中的threshold里,看到可以创建两个滑动条来选择type和value,决定用python实现一下 注意python中的全局变量,用global声明 开始出现了一些问题,因为毁掉函数每次只能传回一个值,所以每次只能更新value,后来就弄了两个毁掉函数,这个时候,又出现了滑动其中一个,另一个的值就会变为默认值的情况,这个时候猜想是全局变量的问题,根据猜想改动之后果然是. 感

Lua中调用 cocos2d-x 的滑动条/滚动条 ScrollView

 ScrollView 我想玩儿过手机的朋友对滑动条都不陌生吧,(旁边: 这不是废话么???? )   那好吧,废话不多说直接开始ScrollView吧 local m_BaseNode  -- 主场景 local CreateScroll    -- 房间分级滑动视图 local CreateStageNode   -- 创建节点 local m_ScrollView              -- 滑动层变量 local m_Inner     -- 内容器 local addScrol

opencv学习之路(5)、鼠标和滑动条操作

一.鼠标事件 1 #include<opencv2/opencv.hpp> 2 #include<iostream> 3 using namespace cv; 4 using namespace std; 5 6 Mat img(500,500,CV_8UC3,Scalar(255,255,255));//定义成全局变量 7 8 void OnMouse(int event,int x,int y,int flags,void* param){ 9 if(event==CV_EV