推理完的小图合并为大图

文章介绍了如何使用C++和OpenCV库处理大图切割后的多个小图,通过findNonBlackRegion函数找出非全黑区域边界,然后在restore_images函数中按顺序拼接小图,并移除黑色区域,最后保存为大图。
摘要由CSDN通过智能技术生成

代码简介

之前说过大图切割成小图,小图推理,但是最终呈现的结果肯定是要返还回去变成大图的。这个就是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>  

函数详解

  1. 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;
      }

  2. 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);
          }
      }
  3. 主函数(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程序可以留言,私发给你。基本上对环境没啥特别要求。因为写的时候本身就规避了很多库迎合服务器的环境。

  • 15
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值