connectedComponentsWithStats()函数原理是检测像素的连通区域(连通图应该不用介绍-.-),上图中每个白色斑点区域都属于一个个连通区域,当然文字部分也是,通过这个函数检测到每个连通区域后,再对不同区域的面积进行筛选(孤立点的面积肯定远远小于文字的面积),就可以去掉这些孤立点,函数用法如下:
num_labels, labels, stats, centroids = cv.connectedComponentsWithStats(src, connectivity=8, ltype=None)
函数参数:
src:传入需要处理的图片,要求为二值图像,上面用例的图像已经是二值图像了,如果不是的话需要加一步二值化
connectivity:可选值为4或8,也就是使用4连通还是8连通,就是这个区别,简单易懂
ltype:这个参数跟输出有关,可以先默认,不用管
返回值:
num_labels:所有连通域的数目
labels:这个返回值很关键,主要就用到这个,ltype参数默认为none的情况下,输出的labels是一个和原图一样大小的矩阵,原图中检测到的连通图的位置,对应的labels矩阵值为1,其余值为0,算是一种特殊的标记
stats:记录了每个连通区域的信息,是一个5列的矩阵,每一行对应一个连通区域,分别为连通区域外接矩形的x、y、width、height和面积,例如stats[0][4]就是第一个连通区域的面积
centroids:连通域的中心点,没什么大用
这样就可以通过stats对连通域进行筛选,再通过labels确定筛选出的区域坐标,在进行各种想进行操作,比如这个去除孤立点,直接让该区域像素值置为背景颜色0,就去掉了
再说findContours()函数
contours, hierarch = cv.findContours(img, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_NONE)
这个相对简单一点,是检测输入图像的轮廓,最后同样通过面积进行筛选
函数参数:
img: 输入图像,最好也是二值图像;
第二个: 表示轮廓的检索模式,有四种(有兴趣的朋友可以自己搜一下区别,这里不多做赘述了-.-)
第三个:轮廓的近似办法,有三种(同上)
返回值:
coutours:一个list,list中每个元素都是图像中的一个轮廓信息,用numpy中的ndarray表示,配合cv.contourArea() 函数可以直接得到轮廓面积,配合cv.drawContours()函数可以对某个区域进行操作,比如上述的直接让该区域像素值置为背景颜色0(这俩函数也不多做赘述了,一搜一大堆)
hierarchy:轮廓间的层次关系,为三维数组,形状为(1,n,4),用不上的参数统统简略
两个方法,个人更推荐第一个,连通区域的检测比轮廓检测要精准很多,就是慢点,毕竟有for循环
这是代码,Img1()和Img2()分别对应两个方法:
import cv2.cv2 as cv
import numpy as np
def Img1(src):
num_labels, labels, stats, centroids = cv.connectedComponentsWithStats(src, connectivity=8, ltype=None)
img = np.zeros((src.shape[0], src.shape[1]), np.uint8) #创建个全0的黑背景
for i in range(1, num_labels):
mask = labels == i #这一步是通过labels确定区域位置,让labels信息赋给mask数组,再用mask数组做img数组的索引
if stats[i][4] > 300: #300是面积 可以随便调
img[mask] = 255
img[mask] = 255
img[mask] = 255 #面积大于300的区域涂白留下,小于300的涂0抹去
else:
img[mask] = 0
img[mask] = 0
img[mask] = 0
return img
def Img2(img):
contours, hierarch = cv.findContours(img, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_NONE)
area = []
for i in range(len(contours)):
area.append(cv.contourArea(contours[i])) #计算轮廓所占面积
if area[i] < 300: #轮廓面积,可以自己随便调
cv.drawContours(img,[contours[i]],0,0,-1) #该轮廓区域填0
continue
return img
src = cv.imread('01.png',0)
cv.imshow('input',src)
cv.waitKey(0)
src = Img1(src)
cv.imshow('output', src)
cv.waitKey()