【645】OpenCV 相关函数说明
目录:
- cv2.threshold
- cv2.distanceTransform
- cv2.cvtColor
- cv2.findContours
- cv2.subtract
- cv2.drawContours
- cv2.waterShed
- cv2.connectedComponents
1. cv2.threshold
opencv: 阈值处理(cv2.threshold) 探究(图示+源码)
API定义:OpenCV 3.2.0 中,阈值处理的 api 定义如下:
cv2.threshold (src, thresh, maxval, type)
即:
cv2.threshold (源图片, 阈值, 填充色, 阈值类型)
参数:
- src:源图片,必须是单通道
- thresh:阈值,取值范围0~255
- maxval:填充色,取值范围0~255
- type:阈值类型,具体见下表
阈值 | types | 小于阈值的像素点 | 大于阈值的像素点 |
---|---|---|---|
0 | cv2.THRESH_BINARY | 置0 | 置填充色 |
1 | cv2.THRESH_BINARY_INV | 置填充色 | 置0 |
2 | cv2.THRESH_TRUNC | 保持原色 | 置灰色,threshold |
3 | cv2.THRESH_TOZERO | 置0 | 保持原色 |
4 | cv2.THRESH_TOZERO_INV | 保持原色 | 置0 |
举个例子:
下面例子实现的功能就是提取出里面颜色最白的部分
# Finding sure foreground area # Opencv中distanceTransform方法用于计算图像中每一个非零点距离离自己最近的零点的距离, # distanceTransform的第二个Mat矩阵参数dst保存了每一个点与最近的零点的距离信息,图像上 # 越亮的点,代表了离零点的距离越远。 dist_transform = cv2.distanceTransform(opening,cv2.DIST_L2,5) # 本身不能完全显示,需要拉伸后显示 display(Image.fromarray((dist_transform*255/np.max(dist_transform)).astype('uint8'))) # 70%-100% 的大值变为 白色,255 # 0% - 70% 的小值变为 黑色,0 # sure foreground ret, sure_fg = cv2.threshold(dist_transform, 0.7*dist_transform.max(), 255, 0) display(Image.fromarray(sure_fg.astype('uint8')))
2. cv2.distanceTransform
Opencv中distanceTransform方法用于计算图像中每一个非零点距离离自己最近的零点的距离,distanceTransform的第二个Mat矩阵参数dst保存了每一个点与最近的零点的距离信息,图像上越亮的点,代表了离零点的距离越远。
该函数的参数设置挺迷的,就按照下面的例子就行,cv2.DIST_L2 为欧氏距离,实现的效果就是距离 0 点越远,值越大,从而将主体部分分离出来,如下图所示:
# Finding sure foreground area # Opencv中distanceTransform方法用于计算图像中每一个非零点距离离自己最近的零点的距离, # distanceTransform的第二个Mat矩阵参数dst保存了每一个点与最近的零点的距离信息,图像上 # 越亮的点,代表了离零点的距离越远。 dist_transform = cv2.distanceTransform(opening, cv2.DIST_L2, 5) # 本身不能完全显示,需要拉伸后显示 display(Image.fromarray((dist_transform*255/np.max(dist_transform)).astype('uint8')))
3. cv2.cvtColor
cv2.cvtColor()方法用于将图像从一种颜色空间转换为另一种颜色空间。最常用的就是彩色图片转为灰度图片。
用法:
cv2.cvtColor(src, code[, dst[, dstCn]])
参数:
- src: 它是要更改其色彩空间的图像。
- code: 它是色彩空间转换代码。
- dst: 它是与src图像大小和深度相同的输出图像。它是一个可选参数。
- dstCn: 它是目标图像中的频道数。如果参数为0,则通道数自动从src和代码得出。它是一个可选参数。
返回值:它返回一个图像。
img = cv2.imread('seg_smooth.png') # 转为灰度的图,也是二值图,针对cv2读取的图像是 BGR 三通道 thresh = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
4. cv2.findContours
用法:
cv2.findContours(image, mode, method[, contours[, hierarchy[, offset ]]])
opencv2返回两个值:contours:hierarchy。注:opencv3会返回三个值,分别是img, countours, hierarchy
参数:
第一个参数是寻找轮廓的图像;
第二个参数表示轮廓的检索模式,有四种(本文介绍的都是新的cv2接口):
- cv2.RETR_EXTERNAL 表示只检测外轮廓
- cv2.RETR_LIST 检测的轮廓不建立等级关系
- cv2.RETR_CCOMP 建立两个等级的轮廓,上面的一层为外边界,里面的一层为内孔的边界信息。如果内孔内还有一个连通物体,这个物体的边界也在顶层。
- cv2.RETR_TREE 建立一个等级树结构的轮廓。
第三个参数method为轮廓的近似办法
- cv2.CHAIN_APPROX_NONE 存储所有的轮廓点,相邻的两个点的像素位置差不超过1,即max(abs(x1-x2),abs(y2-y1))==1
- cv2.CHAIN_APPROX_SIMPLE 压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标,例如一个矩形轮廓只需4个点来保存轮廓信息
- cv2.CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS 使用teh-Chinl chain 近似算法
返回值:
cv2.findContours()函数返回两个值,一个是轮廓本身,一个list,list中每个元素都是图像中的一个轮廓,用numpy中的ndarray表示;还有一个是每条轮廓对应的属性。
举例:
# 获取 contours 列表 # 每一个 contour 是一个二维 ndarray 数组,包含 polygon 的像素坐标集合 contours, _ = cv2.findContours(opening, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) # 获取 contours 数量 n = len(contours) print("后处理之前分类个数:", n) # 将 contours 通过 polylines 显示出来 img_line = np.zeros_like(opening) cv2.polylines(img_line, contours, isClosed=True, color=(255,255,255), thickness=2) display(Image.fromarray(img_line))
效果:
5. cv2.subtract
这里不展开说,只说明下与直接 ndarray 相减的区别:图像大部分像素数据在BGR三个分量上出现了很小的变化,可能每个通道就1-2个数值的差异,有的通道增加了一点,有得减少了一点,opencv是饱和运算,小于0时被置为了0,但矩阵运算出现负数时由于类型是uint8,负数变成了256加该负数的值,导致差异很大。
参考:OpenCV-Python图像的减法运算cv2.subtract函数详解以及和矩阵减法的差异对比
6. cv2.drawContours
OpenCV中通过cv2.drawContours在图像上绘制轮廓。
语法:
cv2.drawContours(image, contours, contourIdx, color[, thickness[, lineType[, hierarchy[, maxLevel[, offset ]]]]])
参数:
- 第一个参数是指明在哪幅图像上绘制轮廓;
- 第二个参数是轮廓本身,在Python中是一个list。
- 第三个参数指定绘制轮廓list中的哪条轮廓,如果是-1,则绘制其中的所有轮廓。后面的参数很简单。其中thickness表明轮廓线的宽度,如果是-1(cv2.FILLED),则为填充模式。绘制参数将在以后独立详细介绍。
举例,实现与上面 fillPolylines 一样的效果
img_contours = np.zeros_like(opening) cv2.drawContours(img_contours, contours, -1, 255, 2) display(Image.fromarray(img_contours))
效果:
7. cv2.watershed
Image Segmentation with Watershed Algorithm
实现分水岭算法,返回分水岭的边界线。
语法:
cv2.watershed(image, markers) -> markers
参数:
- image: Input 8-bit 3-channel image.(3 通道图像)
- markers: Input/output 32-bit single-channel image (map) of markers. It should have the same size as image.(输入和输出,用 0 表示未知的边界区域,其他正数表示确定的前景和背景)
举例:
# opening 灰度图 转为 RGB img_opening = cv2.cvtColor(opening, cv2.COLOR_GRAY2RGB) # 通过分水岭处理,marker 的值发生变化,原来的 0(未知区域) 被转为 -1(分割线)和其他的分类(其他数字) # 处理前:0 未知区域,1 背景,2+ 前景 # 处理后:-1 分割线,1 背景,2+ 前景,没有未知区域了 markers = cv2.watershed(img_opening, markers)
如下图所示:未知区域被看成是山峰,通过注水在确定的前景色和确定的背景色,来识别分水岭的边界线
8. cv2.connectedComponents
OpenCV python实现连通域处理函数cv2.connectedComponentsWithStats()和cv2.connectedComponents()
总得来说,connectedComponents()仅仅创建了一个标记图(图中不同连通域使用不同的标记,和原图宽高一致),connectedComponentsWithStats()可以完成上面任务,除此之外,还可以返回每个连通区域的重要信息–bounding box, area, andcentroid。
8.1 什么是连通域
连通区域一般是指图像中具有相同像素值且位置相邻的前景像素点组成的图像区域。连通区域分析是指将图像中的各个连通区域找出并标记。
连通区域分析是一种在CVPR和图像分析处理的众多应用领域中较为常用和基本的方法。例如:OCR识别中字符分割提取(车牌识别、文本识别、字幕识别等)、视觉跟踪中的运动前景目标分割与提取(行人入侵检测、遗留物体检测、基于视觉的车辆检测与跟踪等)、医学图像处理(感兴趣目标区域提取)、等等。也就是说,在需要将前景目标提取出来以便后续进行处理的应用场景中都能够用到连通区域分析方法,通常连通区域分析处理的对象是一张二值化后的图像。
8.2 cv2.connectedComponents()
定义:
num_objects, labels = cv2.connectedComponents(image)
参数:
- image:也就是输入图像,必须是二值图,即8位单通道图像。(因此输入图像必须先进行二值化处理才能被这个函数接受)
返回值:
- num_labels:所有连通域的数目
- labels:图像上每一像素的标记,用数字1、2、3…表示(不同的数字表示不同的连通域)
表示出彼此的不同,从而可以进行分水岭算法
通过拉伸来显示不同的分类
举例:
# Marker labelling # ret 分类的数量 25 # markers 从 0 - 24 的数值 ret, markers = cv2.connectedComponents(sure_fg) # Add one to all labels so that sure background is not 0, but 1 # sure background: 1 # 其他 sure foreground: 2 以后 markers = markers+1 # Now, mark the region of unknown with zero # 像素为 0 的为 unknown 区域,也就是需要找到分水岭的区域 markers[unknown==255] = 0 # 注意西面每个白色的块的周围还有一圈深色的环 display(Image.fromarray((markers*255/(np.max(markers))).astype('uint8'))) # 转为 RGB,通过红色来显示 unknown 区域 markers_RGB = cv2.cvtColor((markers*255/(np.max(markers))).astype('uint8'), cv2.COLOR_GRAY2RGB) markers_RGB[:,:,0][unknown==255] = 100 display(Image.fromarray(markers_RGB))
显示: