OpenCV + CPP 系列(卌六)目标检测与计数


本文章处理如下两张图
在这里插入图片描述

一、计数

图像算法的综合使用:

  1. 分析图像(图像目标形状,纹理,颜色)等复杂信息。
  2. 考虑处理方法,形态学+距离变换函数 显著化目标
  3. 使用自适应阈值(或者 局部峰值计数、分水岭算法等)进行目标切分
  4. 计数 可视化。

头文件 image_feature_all.h:声明类与公共函数

#pragma once
#include <opencv2/opencv.hpp>
#include <iostream>
#include <opencv2/xfeatures2d.hpp>  //新增引入库

using namespace cv;
using namespace std;


class ImageFeature {
public:
	void object_detect(Mat& image);
	void object_area_detect(Mat& image);

};

主函数main.cpp调用该类的公共成员函数

#include "image_feature_all.h"



int main(int argc, char** argv) {
	const char* img_path = "D:\\Desktop\\match_dst.jpg";
	Mat image = imread(img_path, IMREAD_GRAYSCALE);
	if (image.empty()) {
		cout << "图像数据为空,读取文件失败!" << endl;
	}
	ImageFeature imgfeature;
	imgfeature.object_detect(image);
	imgfeature.object_area_detect(image);

	waitKey(0);
	destroyAllWindows();
	return 0;
}
void ImageFeature::object_detect(Mat& image) {
	Mat gray_img, binary_img;
	cvtColor(image, gray_img, COLOR_BGR2GRAY);
	threshold(gray_img, binary_img, 0, 255, THRESH_BINARY_INV | THRESH_TRIANGLE);
	imshow("binary_img", binary_img);

	//形态学操作
	Mat kernel_diamond = (Mat_<uchar>(5, 5) <<
		0, 0, 1, 0, 0, 
		0, 1, 1, 1, 0, 
		1, 1, 1, 1, 1, 
		0, 1, 1, 1, 0,
		0, 0, 1, 0, 0);

	// 测试几种不同的去噪分割方式。
	//Mat morph_img, morph_img2, morph_img3;
	//Mat kernel = getStructuringElement(cv::MORPH_RECT, Size(5, 5));
	//morphologyEx(binary_img.clone(), morph_img, MORPH_OPEN, kernel_diamond, Point(-1, -1), 1);
	//morphologyEx(binary_img.clone(), morph_img2, MORPH_OPEN, kernel, Point(-1,-1), 1);

	Mat morph_img;
	Mat kernel = getStructuringElement(cv::MORPH_RECT, Size(5, 5));
	erode(binary_img, morph_img, kernel, Point(-1, -1), 1);

	//距离变换, 转成8U;
	Mat dist, dist_8u;
	distanceTransform(morph_img, dist, DIST_L2, 3);
	normalize(dist, dist, 0, 0.9, NORM_MINMAX);
	dist.convertTo(dist_8u, CV_8U);
	imshow("dist", dist);

	//自适应二值化分割
	adaptiveThreshold(dist_8u, dist_8u, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY, 95, 0.0);
	erode(dist_8u, dist_8u, kernel, Point(-1, -1), 1);
	dilate(dist_8u, dist_8u, kernel, Point(-1, -1), 3);

	// 查找轮廓-->轮廓质心-->连通域计数可视化
	vector<vector<Point>> contours;
	findContours(dist_8u, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
	vector<Moments> moments_cap(contours.size());
	vector<Point> centers(contours.size());

	for (size_t i = 0; i < contours.size(); i++){
		moments_cap[i] = moments(contours[i]);
		centers[i] = Point(
			static_cast<float>(moments_cap[i].m10 / moments_cap[i].m00),
			static_cast<float>(moments_cap[i].m01 / moments_cap[i].m00)
		);
	}

	Mat result_img = Mat::zeros(image.size(), CV_8UC3);
	RNG rng(12312);
	for (size_t i = 0; i < contours.size(); i++){
		Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
		drawContours(result_img, contours, i, color, 2, 8);
		putText(result_img, to_string(i), centers[i], 0, 1, color, 2, 8, 0);
	}
	imshow("result_img", result_img);
}
可视化

关键几步展示
在这里插入图片描述

二、目标检测(对象提取)
void ImageFeature::object_area_detect(Mat& image) {
	int height = image.rows;
	int width = image.cols;
	Mat gray_img, binary_img;
	cvtColor(image, gray_img, COLOR_BGR2GRAY);
	GaussianBlur(gray_img, gray_img, Size(5, 5), 15);
	threshold(gray_img, binary_img, 0, 255, THRESH_BINARY | THRESH_TRIANGLE);
	imshow("binary_img", binary_img);

	Mat morph_img;
	Mat kernel = getStructuringElement(cv::MORPH_RECT, Size(3, 3));
	morphologyEx(binary_img, morph_img, MORPH_CLOSE, kernel, Point(-1, -1), 2);
	imshow("morph_img", morph_img);

	vector<vector<Point>> contours;
	findContours(morph_img, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
	Mat resultImage = Mat::zeros(image.size(), CV_8UC3);
	for (size_t i = 0; i < contours.size(); i++) {
		Rect rect = boundingRect(contours[i]);
		if (rect.width > width / 2 && rect.height > height / 2) {
			double Area = contourArea(contours[i]);
			double length = arcLength(contours[i], true);
			drawContours(resultImage, contours, i, Scalar(0, 0, 255), 2, 8);
			putText(resultImage, "Area  : "+to_string(Area), Point(static_cast<int>(width / 2), height - 80), 0, 0.8, Scalar(255, 0, 0), 2, 8, 0);
			putText(resultImage, "length: "+to_string(length), Point(static_cast<int>(width / 2), height - 40), 0, 0.8, Scalar(255, 0, 0), 2, 8, 0);
		}
	}
	imshow("resultImage", resultImage);
}
可视化

在这里插入图片描述
在这里插入图片描述

  • 5
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SongpingWang

你的鼓励是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值