代码简介
之前说过大图切割成小图,小图推理,但是最终呈现的结果肯定是要返还回去变成大图的。这个就是jpg格式拼接回去。之前给出的demo它生成之后,就是全部都在一个文件夹内,文件名从0开始排序。所以自己就做了一个根据顺序拼接的代码。然后拼接过程中,把切割的时候增加的黑色区域剪裁掉。
代码结构
- findNonBlackRegion函数:用于找到图像中非全黑区域的边界。
- restore_images函数:对输入文件夹中的小图进行拼接,并保存为大图。
- 主函数(main函数):程序入口,调用以上函数实现小图拼接和保存。
头文件
#include <iostream>
#include <opencv2/opencv.hpp>
#include <dirent.h>
#include <cstring>
#include <vector>
#include <algorithm>
#include <regex>
#include <sys/stat.h>
#include <unistd.h>
函数详解
-
findNonBlackRegion函数
- 功能:找到图像中非全黑区域的边界。
- 参数:img(输入的图像)。
- 返回值:包含非全黑区域边界的矩形对象。
- 实现原理:将彩色图像转换为灰度图像,使用阈值操作找到非黑色区域的掩码,通过轮廓检测找到最大的非黑色区域并获取其边界矩形。
cv::Rect findNonBlackRegion(cv::Mat& img) { cv::Mat gray; cv::cvtColor(img, gray, cv::COLOR_BGR2GRAY); cv::Mat mask = gray > 0; std::vector<std::vector<cv::Point>> contours; cv::findContours(mask, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE); if (contours.empty()) { return cv::Rect(); } cv::Rect bounding_rect = cv::boundingRect(contours[0]); for (size_t i = 1; i < contours.size(); ++i) { cv::Rect rect = cv::boundingRect(contours[i]); bounding_rect |= rect; } return bounding_rect; }
-
restore_images函数
- 功能:对输入文件夹中的小图进行拼接,并保存为大图。
- 参数:input_folder(输入文件夹路径)、output_folder(输出文件夹路径)、crop_size(小图的尺寸)、num_per_row(每行小图的数量)、num_per_col(每列小图的数量)。
- 返回值:无。
- 实现原理:创建输出文件夹,获取输入文件夹中所有小图文件名并排序,计算大图的大小,逐批次拼接小图到大图上,并保存为大图文件。拼接时根据小图的位置计算在大图上的坐标。
void restore_images( const std::string& input_folder, const std::string& output_folder, const cv::Size& crop_size, int num_per_row, int num_per_col ) { // 创建输出文件夹 mkdir(output_folder.c_str(), 0777); // 获取所有小图文件名,并按照顺序排序 std::vector<std::string> file_names; DIR* dir = opendir(input_folder.c_str()); dirent* entry; while ((entry = readdir(dir)) != nullptr) { std::string file_name = entry->d_name; if (file_name == "." || file_name == "..") { continue; } file_names.push_back(file_name); } closedir(dir); std::sort(file_names.begin(), file_names.end(), [](const std::string& a, const std::string& b) { return std::stoi(std::regex_replace(a, std::regex("\\D"), "")) < std::stoi(std::regex_replace(b, std::regex("\\D"), "")); }); // 计算大图的大小 int height = num_per_col * crop_size.height; int width = num_per_row * crop_size.width; // 逐批次还原图像 for (size_t i = 0; i < file_names.size(); i += num_per_row * num_per_col) { cv::Mat merged_img(height, width, CV_8UC3, cv::Scalar(0, 0, 0)); for (int j = 0; j < num_per_row * num_per_col; ++j) { if (i + j >= file_names.size()) { break; } std::string crop_path = input_folder + "/" + file_names[i + j]; cv::Mat crop_img = cv::imread(crop_path); if (crop_img.empty()) { break; } int row = j % num_per_row; int col = j / num_per_row; int y1 = col * crop_size.height; int y2 = y1 + crop_size.height; int x1 = row * crop_size.width; int x2 = x1 + crop_size.width; cv::Mat roi = merged_img(cv::Rect(x1, y1, crop_size.width, crop_size.height)); crop_img.copyTo(roi); } // 计算非全黑区域的边界 cv::Rect boundingRect = findNonBlackRegion(merged_img); // 裁剪拼接图像 cv::Mat cropped_img = merged_img(boundingRect); // 保存拼接后的大图 std::string output_path = output_folder + "/" + std::to_string(i / (num_per_row * num_per_col)) + ".jpg"; cv::imwrite(output_path, cropped_img); } }
-
主函数(main函数)
- 功能:程序入口函数。
- 参数:无。
- 返回值:整型,程序运行结果。
- 实现原理:定义输入和输出的文件夹路径、小图的尺寸,每行和每列的小图数量,调用restore_images函数进行小图拼接和保存。
int main() { std::string input_folder = "./results"; // 小图 std::string output_folder = "./output"; // 拼接后 cv::Size crop_size(512, 512); // 小图的大小 int num_per_row = 5; // 每行小图的数量 int num_per_col = 3; // 每列小图的数量 // 创建输出文件夹 mkdir(output_folder.c_str(), 0777); restore_images(input_folder, output_folder, crop_size, num_per_row, num_per_col); return 0; }
整体
#include <iostream>
#include <opencv2/opencv.hpp>
#include <dirent.h>
#include <cstring>
#include <vector>
#include <algorithm>
#include <regex>
#include <sys/stat.h>
#include <unistd.h>
cv::Rect findNonBlackRegion(cv::Mat& img) {
cv::Mat gray;
cv::cvtColor(img, gray, cv::COLOR_BGR2GRAY);
cv::Mat mask = gray > 0;
std::vector<std::vector<cv::Point>> contours;
cv::findContours(mask, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
if (contours.empty()) {
return cv::Rect();
}
cv::Rect bounding_rect = cv::boundingRect(contours[0]);
for (size_t i = 1; i < contours.size(); ++i) {
cv::Rect rect = cv::boundingRect(contours[i]);
bounding_rect |= rect;
}
return bounding_rect;
}
void restore_images(
const std::string& input_folder, const std::string& output_folder,
const cv::Size& crop_size, int num_per_row, int num_per_col
) {
// 创建输出文件夹
mkdir(output_folder.c_str(), 0777);
// 获取所有小图文件名,并按照顺序排序
std::vector<std::string> file_names;
DIR* dir = opendir(input_folder.c_str());
dirent* entry;
while ((entry = readdir(dir)) != nullptr) {
std::string file_name = entry->d_name;
if (file_name == "." || file_name == "..") {
continue;
}
file_names.push_back(file_name);
}
closedir(dir);
std::sort(file_names.begin(), file_names.end(), [](const std::string& a, const std::string& b) {
return std::stoi(std::regex_replace(a, std::regex("\\D"), "")) < std::stoi(std::regex_replace(b, std::regex("\\D"), ""));
});
// 计算大图的大小
int height = num_per_col * crop_size.height;
int width = num_per_row * crop_size.width;
// 逐批次还原图像
for (size_t i = 0; i < file_names.size(); i += num_per_row * num_per_col) {
cv::Mat merged_img(height, width, CV_8UC3, cv::Scalar(0, 0, 0));
for (int j = 0; j < num_per_row * num_per_col; ++j) {
if (i + j >= file_names.size()) {
break;
}
std::string crop_path = input_folder + "/" + file_names[i + j];
cv::Mat crop_img = cv::imread(crop_path);
if (crop_img.empty()) {
break;
}
int row = j % num_per_row;
int col = j / num_per_row;
int y1 = col * crop_size.height;
int y2 = y1 + crop_size.height;
int x1 = row * crop_size.width;
int x2 = x1 + crop_size.width;
cv::Mat roi = merged_img(cv::Rect(x1, y1, crop_size.width, crop_size.height));
crop_img.copyTo(roi);
}
// 计算非全黑区域的边界
cv::Rect boundingRect = findNonBlackRegion(merged_img);
// 裁剪拼接图像
cv::Mat cropped_img = merged_img(boundingRect);
// 保存拼接后的大图
std::string output_path = output_folder + "/" + std::to_string(i / (num_per_row * num_per_col)) + ".jpg";
cv::imwrite(output_path, cropped_img);
}
}
int main() {
std::string input_folder = "./results";
std::string output_folder = "./output";
cv::Size crop_size(512, 512); // 小图的大小
int num_per_row = 5; // 每行小图的数量
int num_per_col = 3; // 每列小图的数量
// 创建输出文件夹
mkdir(output_folder.c_str(), 0777);
restore_images(input_folder, output_folder, crop_size, num_per_row, num_per_col);
return 0;
}
总结
因为对C++不是很熟悉,所以是先写的python理了思绪,后面在写的C++。需要python程序可以留言,私发给你。基本上对环境没啥特别要求。因为写的时候本身就规避了很多库迎合服务器的环境。