OpenCV计算机视觉开发入门与实践<四十>:自动识别物体数量

摘要 :本文介绍基于 OpenCV 的物体计数实现方法。首先讲解物体计数的基本原理------基于形态学与距离变换的分水岭算法,并给出整体实现思路;随后详细说明如何在图像上绘制文字,包括 cv2.putText 函数的基本用法、在定义画布上绘制文字,以及解决灰度图无法直接显示彩色文本的方法;最后通过一个完整的药片计数示例,演示从图像读取、形态学处理、二值化、轮廓提取到计数标注的完整流程。

  在机器视觉中,有时需要对产品进行检测和计数。物体计数在生活中的应用非常广泛,例如每天都要吃维生素片,但有时候忘了今天有没有吃过,就想对瓶子里的药片计

数。本章就来介绍一下机器视觉检测和计数的实现。

1.物体计数基本原理

  本章所说的物体计数是基于形态学的物体检测和计数,是在形态学的基础上衍生出的基于距离变换的分水岭算法,效果更具普遍性。至于什么是形态学,这里不再赘述,因为本章是应用章节,不会讲很多理论。物体计数的整体实现思路如下:

(1)读取图片。

(2)形态学处理(在二值化前进行适度形态学处理,效果俱佳)。

(3)二值化。

(4)提取轮廓(进行药片分割)

(5)获取轮廓索引,并筛选所需要的轮廓。

(6)画出轮廓,显示计数。

2.在图像上绘制文字

  为了方便统计物品,我们在物品计数的结果上通常要写上该物品的序号,这就需要在图像上绘制字符文字。在OpenCV中,调用cv2.putText函数可添加文字到指定位置。它对于需要在图片中加入文字的场景,提供了一种比较直接、方便的方式。注意:OpenCV不支持显示中文字符,使用cv2.putText添加的文本字符串不能包含中文字符(包括中文标点

符号)。

【例16.1】在现成图片上绘制英文字符

cpp 复制代码
#include "opencv2/opencv.hpp"
using namespace cv;
int main()
{
	Mat img = imread("lena.png"); //读取彩色图像(BGR)
	putText(img, "lena", Size(100, 40), FONT_HERSHEY_COMPLEX, 1, (0, 255, 0), 2, LINE_AA);
	imshow("test", img); //显示叠加图像
	waitKey();  //等待按键命令

	return 0;
}

【例16.2】在定义画布上画文字

cpp 复制代码
#include "opencv2/opencv.hpp"
using namespace cv;
int main()
{
	// 创建一个空的8位单通道灰度图像,大小为100x300
	Mat txtImage(100, 300, CV_8UC1, Scalar(0));
	txtImage.setTo(Scalar(128)); //这句可以设置其它颜色,现在设置灰色
	putText(txtImage, "hello world", Size(20, 30), FONT_HERSHEY_COMPLEX, 1, (255, 255, 255), 2);  //在画布上画字符串hello world
	imshow("result", txtImage);//显示图像
	waitKey();  // 等待按键命令

	return 0;
}

OpenCV的putText函数需要一个颜色参数,如果直接传递一个灰度图作为背景图像,

文本可能不会显示任何颜色。这是因为OpenCV中的颜色通常以BGR格式表示,而不是常

见的RGB格式。在灰度图中,每个像素只有一个灰度值,没有色彩信息。解决方法是在

绘制文本之前,将灰度图转换为BGR图像。我们可以先调用cvtColor函数将灰度图转换为

BGR图像,再使用putText函数。看下面的例子。

【例16.3】在灰度图上使用putText函数

cpp 复制代码
#include "opencv2/opencv.hpp"
using namespace cv;
#include <opencv2/opencv.hpp>

int main() {
	// 创建一个空白的黑色背景图像
	Mat img(100, 300, CV_8UC1, Scalar(0, 0, 0));
	// 设置文本内容
	std::string text = "Hello, OpenCV!";
	Mat bgr_image;
	// 将灰度图转换为BGR图像
	cvtColor(img, bgr_image, COLOR_GRAY2BGR);
	// 设置文本起始坐标(左下角点)
	Point textOrg(10, 50);
	// 设置文本字体
	int fontFace = FONT_HERSHEY_SIMPLEX;
	// 设置字体缩放比例
	double fontScale = 1;
	// 设置文本颜色,使用BGR格式
	Scalar color(255, 0, 255); // 白色文本
	// 设置文本线条类型和粗细
	int thickness = 2;
	// 绘制文本
	putText(bgr_image, text, textOrg, fontFace, fontScale, color, thickness);
	// 显示图像
	imshow("Image with Text", bgr_image);
	waitKey(0);
	return 0;
}

3.代码实现药片计数

【例16.4】实现药片计数

cpp 复制代码
#include "opencv2/opencv.hpp"
using namespace cv;
#include <iostream>
using namespace std;

int main(int argc, char** argv)
{
	Mat src, src_binary, dst, src_distance;
	src = imread("med.png");//读取药片图像文件,第二个参数省略,则表示返回彩色图像
	imshow("src", src);//显示源图像
	Mat kernel = getStructuringElement(MORPH_RECT, Size(22, 22), Point(-1, -1));
	morphologyEx(src, dst, MORPH_OPEN, kernel);//执行形态学开运算操作
	imshow("morphology", dst);//显示形态学开运算后的图像
	cvtColor(dst, dst, COLOR_RGB2GRAY); //将RGB格式的图像转换为灰度图像
	threshold(dst, src_binary, 100, 255, THRESH_OTSU);//进行图像阈值分割
	imshow("binary", src_binary);//显示二值化后图像
	vector<vector<Point>> contours;
	findContours(src_binary, contours, RETR_EXTERNAL, CHAIN_APPROX_NONE, Point(0, 0));
	RNG rng(12345);//为了后续使用随机函数,这里先设置随机数种子
	double area;
	Point2i PL;
	for (size_t i = 0; i < contours.size(); i++)
	{
		area = contourArea(contours[i]);//用于计算图像轮廓的面积,参数是图像的轮廓点
		if (area < 500)continue;  //如果面积小于500
		PL = contours[i].front();
		Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));//得到一个随机颜色值
		drawContours(src, contours, i, color, 2, 8);
		putText(src, to_string(i), PL, FONT_HERSHEY_COMPLEX, 1, color, 2);
	}
	imshow("number of drugs", src);
	waitKey(0);
	return 0;
}
相关推荐
世岩清上1 小时前
展厅不同分区播放差异化视频,怎样做到内容串联不割裂整体叙事?
运维·人工智能·音视频·展厅改造
Dawson Zhu1 小时前
Agent 记忆调用的上下文感知:从“能召回“到“敢开口“的决策框架
人工智能·语言模型·架构·aigc·agi
来让爷抱一个1 小时前
2026 姿态控制实战:八个姿势钉死动作,百智云精灵图把骨骼契约写进素材包
人工智能·机器学习
wuminyu1 小时前
Kafka利用sendfile与Page Cache实现高性能传输剖析
java·linux·c语言·jvm·c++
hansang_IR1 小时前
【题解】P4456 [CQOI2018] 交错序列(数学递推)
c++·算法
流浪0011 小时前
大厂 C/C++ 2023–2025 面试答案题汇总
开发语言·c++
青少儿编程课堂1 小时前
贪心算法进阶:区间调度与最少资源整合解析
c++·python·算法·贪心·信息学竞赛·区间调度
龙亘川1 小时前
数字化建设案例|构建议案履职一体化闭环,解决议案建议办理多主体协同难题
大数据·人工智能·科技·信息可视化·智慧城市
CyberVein1 小时前
Dell暴涨之后,更加需要关注算力服务了
人工智能