OpenCV + CPP 系列(卌六)目标检测与计数
Posted SongpingWang
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenCV + CPP 系列(卌六)目标检测与计数相关的知识,希望对你有一定的参考价值。
文章目录
本文章处理如下两张图
一、计数
图像算法的综合使用:
- 分析图像(图像目标形状,纹理,颜色)等复杂信息。
- 考虑处理方法,形态学+距离变换函数 显著化目标
- 使用自适应阈值(或者 局部峰值计数、分水岭算法等)进行目标切分
- 计数 可视化。
头文件 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与图像处理:霍夫变换技术实现直线检测