OpenCV粘连对象计数

随着机器视觉和图像处理技术的发展,在工业和生活中都应用广泛。传统的计数方法常依赖于人眼目视计数,不仅计数效率低,且容易计数错误。通常现实中的对象不会完美地分开,需要通过进一步的图像处理将对象分开,学习了***贾志刚老师***的OpenCV对象提取与计数课程,现复盘整理如下。
1、方案思路

  1. 图像预处理,二值化分割;
  2. 使用形态学操作,初步将粘连对象分开;
  3. 距离变换,分离粘连对象;
  4. 连通区域计数。

2、重要函数
全局二值化分割:

double threshold(InputArray src, OutputArray dst, double thresh, double maxval, int type)

第一个参数,InputArray类型的src,输入数组,填单通道 , 8或32位浮点类型的Mat即可。

第二个参数,OutputArray类型的dst,函数调用后的运算结果存在这里,即这个参数用于存放输出结果,且和第一个参数中的Mat变量有一样的尺寸和类型。

第三个参数,double类型的thresh,阈值的具体值。

第四个参数,double类型的maxval,当第五个参数阈值类型,可取如下值:
THRESH_BINARY=0,THRESH_BINARY_INV,THRESH_TRUNC,THRESH_TOZERO,THRESH_TOZERO_INV,THRESH_OTSU,THRESH_TRIANGLE,THRESH_MASK
其中THRESH_OTSU方法在图像灰度中具有明显双峰时,分割效果非常好,自动计算阈值。THRESH_TRIANGLE方法在两个峰值不明显情况下,使用三角形计算方法,本例程使用该种方法,示意图如下:
在这里插入图片描述
局部二值化分割:

void adaptiveThreshold(InputArray src, OutputArray dst, double maxValue, int adaptiveMethod, int thresholdType, int blockSize, double C)

参数如下:
InputArray src:源图像

OutputArray dst:输出图像,与源图像大小一致

int adaptiveMethod:在一个邻域内计算阈值所采用的算法,有两个取值,分别为 ADAPTIVE_THRESH_MEAN_C 和 ADAPTIVE_THRESH_GAUSSIAN_C 。

ADAPTIVE_THRESH_MEAN_C的计算方法是计算出领域的平均值再减去第七个参数double C的值

ADAPTIVE_THRESH_GAUSSIAN_C的计算方法是计算出领域的高斯均值再减去第七个参数double C的值

int thresholdType:这是阈值类型,只有两个取值,分别为 THRESH_BINARY 和THRESH_BINARY_INV

int blockSize:adaptiveThreshold的计算单位是像素的邻域块,邻域块取多大,就由这个值作决定

double C:这个参数实际上是一个偏移值调整量

从上面的说明中可以看出,使用函数adaptiveThreshold的关键是确定blockSize和C的值,明白了这两个值的意义之后,在实际项目中,应该可以根据试验法选出较为合适的值!
距离变换:
Opencv中distanceTransform方法用于计算图像中每一个非零点距离离自己最近的零点的距离,distanceTransform的第二个Mat矩阵参数dst保存了每一个点与最近的零点的距离信息,图像上越亮的点,代表了离零点的距离越远。

void distanceTransform(InputArray src, OutputArray dst,int distanceType,int maskSize);

参数介绍:
src:8位单通道二值图像;
dst:输出距离图像;
distanType:距离类型,取值如下:
在这里插入图片描述
maskSize:距离变换掩模大小,通常为3,5。
3、代码实现

threshold(gray, binary, 0, 255, THRESH_BINARY | THRESH_TRIANGLE);

Mat kernel = getStructuringElement(MORPH_RECT, Size(5, 5), Point(-1, -1));
dilate(binary, binary, kernel,Point(-1,-1),3);

//距离变换
Mat dist;
bitwise_not(binary, binary);
distanceTransform(binary, dist, DIST_L2, 3);
normalize(dist, dist, 0, 1.0, NORM_MINMAX);

//阈值分割
Mat dist_8u;
dist.convertTo(dist_8u, CV_8U);
	
adaptiveThreshold(dist_8u, dist_8u, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY, 69, 0.0);
kernel = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
dilate(dist_8u, dist_8u, kernel, Point(-1, -1),2);

//连通区域计数

vector<vector<Point>>contours;
findContours(dist_8u, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);

//标记
Mat markers = Mat::zeros(src.size(), CV_8UC3);
RNG rng(12345);
for (size_t t = 0; t < contours.size(); t++) {
drawContours(markers, contours, t, Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)), -1, 8, Mat());
}
cout << "numbers = " << contours.size() << endl;

4、结果实现
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值