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

Posted SongpingWang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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);
}
可视化


以上是关于OpenCV + CPP 系列(卌六)目标检测与计数的主要内容,如果未能解决你的问题,请参考以下文章

深度学习和目标检测系列教程 15-300:在 Python 中使用 OpenCV 执行 YOLOv3 对象检测

深度学习和目标检测系列教程 15-300:在 Python 中使用 OpenCV 执行 YOLOv3 对象检测

深度学习和目标检测系列教程 20-300:OpenCV与图像处理:霍夫变换技术实现直线检测

深度学习和目标检测系列教程 20-300:OpenCV与图像处理:霍夫变换技术实现直线检测

OpenCV + CPP 系列(三十)基于距离变换与分水岭的图像分割

opencv 矩形检测与计数