使用 OpenCV 进行轮廓处理和图像保存
使用 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;}