OpenCV小案例(四)-- 对象计数

·问题描述
有一张图片,计算图片中种子的数量
在这里插入图片描述
主要需要解决的是如何将种子粘连的部分去掉,生成一个个独立的对象

·解决方案

1.二值化
首先进行二值分割
在进行对象计数时,推荐使用Triangle的方法来寻找阈值
在这里插入图片描述

2.形态学–膨胀操作
使用形态学的膨胀操作,可以细化图像对象之间的粘连区域但是对于一些粘连较强的部分,可能难以细化,可以留到后面解决
在这里插入图片描述

3.距离变换
距离变化可以找出各个对象的中心点,并且变现为亮点,有效找出各个对象
在这里插入图片描述

4.自适应阈值算法
根据图像不同区域亮度分布,计算其部分阈值,所以对于图像不同区域,能够自适应计算不同阈值,能够很好的检测到边缘信息,分离个目标区域
在这里插入图片描述

5.轮廓寻找及绘制
至此,各个图像已被分割。开始绘制轮廓,并输出对象个数,连通区域计数
在这里插入图片描述

·完整代码

#include<opencv2/opencv.hpp>
#include<math.h>
#include<iostream>

using namespace cv;
using namespace std;

Mat src2;
Mat src,dst,gray_src,binary;
const char* output_win = "output_img";
RNG rng(12345);
int threshold_v = 100;
int threshold_max = 255;

int main(int argc, char** argv) {
	src = imread("C:/Users/18929/Desktop/博客项目/项目图片/16.jpg");
	if (src.empty()) {
		printf("could not load image");
		return -1;
	}
	imshow("input_img", src);

	namedWindow(output_win,WINDOW_AUTOSIZE);

	//首先进行二值分割
	//在进行对象计数时,推荐使用Triangle的方法来寻找阈值
	cvtColor(src, gray_src, COLOR_BGR2GRAY);
	threshold(gray_src, binary, 0, 255, THRESH_BINARY | THRESH_TRIANGLE);
	imshow("binary_img", binary);

	//形态学操作
	//使用形态学的膨胀操作,可以细化图像对象之间的粘连区域
	//但是对于一些粘连较强的部分,可能难以细化,可以留到后面解决
	Mat kernel = getStructuringElement(MORPH_RECT, Size(5, 5), Point(-1, -1));
	dilate(binary, binary, kernel, Point(-1, -1), 2);
	imshow("dilate_img", binary);

	//距离变换
	//距离变化可以找出各个对象的中心点,并且变现为亮点,有效找出各个对象
	Mat dist;
	bitwise_not(binary, binary);
	distanceTransform(binary, dist, CV_DIST_L2, 3);
	//距离变换后要进行归一化操作,否则会有区域超越边界值
	normalize(dist, dist, 0, 1.0, NORM_MINMAX);
	imshow("dist_img", dist);

	//再进行了距离变换后,便可以找到各个对象的最亮区域
	//自适应阈值法
	//根据图像不同区域亮度分布,计算其部分阈值,所以对于图像不同区域,能够自适应计算不同阈值
	//能够很好的检测到边缘信息,分离个目标区域
	Mat dist_8u;
	dist.convertTo(dist_8u, CV_8U);//自适应阈值算法图片格式要是8u格式
	adaptiveThreshold(dist_8u, dist_8u, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY, 85, 0.0);

	//完成了自适应阈值法后,可以用膨胀操补上一些黑色部分
	kernel = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));
	dilate(dist_8u, dist_8u, kernel, Point(-1, -1), 2);
	imshow("dist-binary", dist_8u);


	//至此,各个图像已被分割。开始绘制轮廓,并输出对象个数
	//连通区域计数
	//寻找轮廓
	vector<vector<Point>> contours;
	findContours(dist_8u, contours, CV_RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);

	//画出轮廓
	Mat markers = Mat::zeros(src.size(), CV_8UC3);
	RNG rng(12345);
	int count = 0;
	for (size_t i = 0; i < contours.size(); i++)
	{
		drawContours(markers, contours, static_cast<int>(i), Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)), -1, 8, Mat());
		imshow("Final result", markers);
		count++;
	}
	cout<< count;

	
	

	waitKey(0);
	return 0;
}

在这里插入图片描述

  • 3
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值