使用 OpenCV 进行轮廓处理和图像保存
在这篇博客中,我们将展示如何使用 OpenCV 库来处理图像中的轮廓,并将处理结果保存为带有时间戳的图片。我们还将介绍如何在处理图像时应用一些条件来进行进一步的操作。
前置条件
在开始之前,请确保您已经安装了 OpenCV 库。如果尚未安装,可以通过以下命令安装:
pip install opencv-python
代码实现
包含必要的库
首先,我们需要包含必要的头文件:
#include <opencv2/opencv.hpp>
#include <iostream>
#include <vector>
#include <filesystem>
#include <ctime>
设置命名空间和常量
为了简化代码,我们将 std::filesystem
命名空间设置为 fs
。另外,我们还定义了一个常量 limitHeight
,它将用于设置某种模式:
namespace fs = std::filesystem;
struct MyThread {
int mode;
};
const int limitHeight = 1;
主处理函数
以下是处理轮廓和保存图像的主函数。该函数接受一帧图像 frame2
和缩小后的图像 ZoomOutimage
作为输入,并将结果保存到指定文件夹中:
void processContours(
const cv::Mat& frame2,
const cv::Mat& ZoomOutimage,
MyThread& mythread,
std::string& nextColor
) {
std::vector<std::vector<cv::Point>> contours;
cv::findContours(frame2, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
int Ycount = 0;
cv::Mat output_image = ZoomOutimage.clone();
double total_white_area = 0;
for (const auto& contour : contours) {
cv::RotatedRect rect = cv::minAreaRect(contour);
cv::Point2f box[4];
rect.points(box);
std::vector<cv::Point> box_points(box, box + 4);
float width = rect.size.width;
float height = rect.size.height;
if (width == 0 || height == 0) {
continue;
}
float aspect_ratio = std::max(width, height) / std::min(width, height);
double area = cv::contourArea(contour);
std::cout << "矩形大小: 宽 = " << width << ", 高 = " << height << ", 面积 = " << area << std::endl;
total_white_area += area;
if (0 <= aspect_ratio && aspect_ratio <= 20 && area > 0) {
Ycount++;
cv::polylines(output_image, box_points, true, cv::Scalar(0, 255, 0), 2);
}
}
std::cout << "满足条件的矩形个数: " << Ycount << std::endl;
std::cout << "在白色颜色范围内的总面积: " << total_white_area << std::endl;
cv::Mat combined_image;
cv::hconcat(std::vector<cv::Mat>{ZoomOutimage, frame2, output_image}, combined_image);
std::time_t now = std::time(nullptr);
char buffer[80];
std::strftime(buffer, sizeof(buffer), "%Y%m%d_%H%M%S", std::localtime(&now));
std::string current_time(buffer);
cv::putText(combined_image, current_time, cv::Point(10, combined_image.rows - 10), cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(255, 255, 255), 1);
std::string folder = "imageY";
if (!fs::exists(folder)) {
fs::create_directory(folder);
}
std::string filename = folder + "/output_image_" + current_time + ".jpg";
cv::imwrite(filename, combined_image);
if (Ycount >= 1) {
mythread.mode = limitHeight;
nextColor = "null";
std::cout << "recognize blue" << std::endl;
return;
}
}
主要步骤说明
- 查找轮廓:使用
cv::findContours
函数在二值化图像frame2
中查找所有轮廓。 - 初始化变量:定义计数器
Ycount
和结果图像output_image
,并初始化总面积total_white_area
。 - 遍历轮廓:遍历所有轮廓,计算每个轮廓的最小外接矩形的宽、高和面积,并输出这些信息。
- 绘制满足条件的矩形:根据长宽比和面积条件,筛选出符合要求的矩形,并将其绘制在结果图像
output_image
上。 - 合并图像并添加时间戳:将原图、二值化图像和结果图像横向合并,并在合并后的图像上添加当前时间戳。
- 创建保存文件夹并保存图像:检查
imageY
文件夹是否存在,不存在则创建。然后使用时间戳作为文件名的一部分,将处理后的图像保存到该文件夹中。 - 设置模式:如果找到满足条件的矩形,则设置
mythread.mode
为limitHeight
并返回。
通过这篇博客,我们展示了如何使用 OpenCV 进行图像处理、轮廓分析以及结果保存。希望这些内容对您有所帮助。欢迎在评论区留言讨论!
std::vector<std::vector<cv::Point>> contours;
cv::findContours(frame2, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
// 初始化计数器和结果图像
int Ycount = 0;
cv::Mat output_image = ZoomOutimage.clone();
double total_white_area = 0;
// 遍历所有轮廓
for (const auto& contour : contours) {
// 获取最小外接矩形
cv::RotatedRect rect = cv::minAreaRect(contour);
cv::Point2f box[4];
rect.points(box);
std::vector<cv::Point> box_points(box, box + 4);
// 计算长宽比和面积
float width = rect.size.width;
float height = rect.size.height;
// 检查是否有零值
if (width == 0 || height == 0) {
continue;
}
float aspect_ratio = std::max(width, height) / std::min(width, height);
double area = cv::contourArea(contour);
// 输出矩形的大小
std::cout << "矩形大小: 宽 = " << width << ", 高 = " << height << ", 面积 = " << area << std::endl;
// 输出总面积
total_white_area += area;
// 检查长宽比和面积条件
if (2 <= aspect_ratio && aspect_ratio <= 15 && area > 500) {
Ycount++;
cv::polylines(output_image, box_points, true, cv::Scalar(0, 255, 0), 2);
}
}
// 显示结果
std::cout << "满足条件的矩形个数: " << Ycount << std::endl;
std::cout << "在白色颜色范围内的总面积: " << total_white_area << std::endl;
// 将每一步处理的图像横向并列
cv::Mat combined_image;
cv::hconcat(std::vector<cv::Mat>{ZoomOutimage, frame2, output_image}, combined_image);
// 获取当前时间
std::time_t now = std::time(nullptr);
char buffer[80];
std::strftime(buffer, sizeof(buffer), "%Y%m%d_%H%M%S", std::localtime(&now));
std::string current_time(buffer);
// 在图像上绘制时间戳
cv::putText(combined_image, current_time, cv::Point(10, combined_image.rows - 10), cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(255, 255, 255), 1);
// 使用时间戳命名文件
std::string filename = "output_image_" + current_time + ".jpg";
// 保存结果图像
cv::imwrite(filename, combined_image);
if(Ycount>=1){
mythread.mode=limitHeight;
nextColor="null";
cout<<"recognize blue"<<endl;
return;
}