- 操作系统:ubuntu22.04
- OpenCV版本:OpenCV4.9
- IDE:Visual Studio Code
- 编程语言:C++11
1.功能描述
当你从摄像头读取实时视频时,如果想在视频的画面中画一个方框,或者是画一个圆,是很简单的事情,可是当我在一张图上画了一个人形站立的轮廓,要求你把这个轮廓显示在实时的视频画面中,你该怎么做呢?简单的说,第一步:把第一张图的轮廓找出来,保存好,第二部,打开实时视频,每一帧图像上画上这个保存好的轮廓,说起来容易做起来难,直接代码开撕。
2.函数findContours
参考本人文章 OpenCV图像发现轮廓函数findContours()的使用
3.drawContours函数
该函数在图像中绘制轮廓线,如果线宽(thickness)≥0,则绘制轮廓边缘;如果线宽<0,则填充轮廓所围成的区域
3.1原型
void cv::drawContours (
InputOutputArray image,
InputArrayOfArrays contours,
int contourIdx,
const Scalar & color,
int thickness = 1,
int lineType = LINE_8,
InputArray hierarchy = noArray(),
int maxLevel = INT_MAX,
Point offset = Point()
)
3.2参数
- 参数image 目标图像.
- 参数contours 所有输入的轮廓。每条轮廓都以点向量的形式存储。
- 参数contourIdx 表示要绘制的轮廓的参数。如果该值为负数,则绘制所有轮廓.
- 参数color 轮廓的颜色.
- 参数thickness 轮廓线的宽度。如果为负值(例如,thickness=FILLED),则绘制轮廓的内部区域.
- 参数lineType 线连通性. 参见 LineTypes
- 参数hierarchy 关于层次结构的可选信息。只有在您希望只绘制某些轮廓(参见maxLevel)时,才需要此信息.
- 参数 maxLevel 最大绘制轮廓的层级。如果该值为0,仅绘制指定的轮廓。如果为1,则函数会绘制轮廓及其所有嵌套的轮廓。如果为2,则函数会绘制轮廓、所有嵌套的轮廓、所有嵌套到嵌套的轮廓,依此类推。此参数仅在有层次结构可用时才被考虑
- 参数offset 可选的轮廓偏移参数。通过指定的偏移量=(dx,dy)来移动所有绘制的轮廓。
注意事项:
当厚度(thickness)设置为FILLED时,该函数被设计成即使没有提供层次结构数据,也能正确处理含有孔洞的连接组件。这是通过使用“偶数-奇数规则”共同分析所有轮廓边缘来实现的。然而,如果你拥有一组分别获取后联合在一起的轮廓,这可能会给出不正确的结果。
为了解决这个问题,你需要为每组子轮廓单独调用drawContours函数,或者在迭代轮廓集合时使用contourIdx参数。这意味着,如果你有一系列轮廓,它们内部可能相互重叠或嵌套形成孔洞,你应该确保这些相互关联的轮廓作为一组被一起处理,而不是将所有轮廓视为一个整体处理。这样可以确保填充操作能够正确区分哪些区域应当被视为内部孔洞,哪些应当被完全填充。
4.示例代码
#include <iostream>
#include <opencv2/opencv.hpp>
#include <vector>
using namespace cv;
using namespace std;
int main()
{
std::vector< std::vector< cv::Point > > contours;
std::vector< cv::Vec4i > hierarchy;
cv::Mat image3 = cv::imread( "/media/dingxin/data/projects/ir/bin/shape.png", cv::IMREAD_GRAYSCALE );
// 二值化图像
cv::Mat binary;
cv::threshold( image3, binary, 28, 255, cv::THRESH_BINARY );
cv::findContours( binary, contours, hierarchy, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE );
VideoCapture cap;
Mat frame;
if ( !cap.open( 0 ) )
{
cout << "打开摄像头失败" << endl;
return -1;
}
for ( ;; )
{
cap >> frame;
if ( frame.empty() )
break;
// frame.resize(384,100);
cv::resize(frame, frame, cv::Size(288, 384), 0, 0, cv::INTER_NEAREST);
for ( size_t i = 0; i < contours.size(); i++ )
{
// 蓝色颜色
cv::Scalar color( 255, 0, 0 );
// 只绘制第一层的轮廓
cv::drawContours( frame, contours, static_cast< int >( i ), color, 2, cv::LINE_8, hierarchy, 0 );
}
imshow( "画轮廓", frame );
char c = ( char )waitKey( 10 );
if ( c == 27 )
break;
}
waitKey( 10 );
return 0;
}
4.运行结果
第一张图:
第二张加上轮廓的视频截图:
这个小功能,为你以后说不定的需求提供了解决思路,希望能帮助到你