图像分割并转为bgr格式

代码简介

这个代码主要是项目需要,因为海康的超脑给的demo是处理bg文件格式,且由于为了迎合原本yolov5模型的极小目标检测场景。海康摄像头采集的大图resize检测效果太差,只能考虑把大图裁剪成多个小图做推理提升效果。代码有C++和opencv两个版本。其他的都是基于基本库实现的。

代码结构

整体上,该程序主要包括以下几个功能模块:

  1. 文件遍历模块:使用listAllFiles函数对指定目录进行递归遍历,获取所有图片文件的路径列表。

  2. 文件夹创建模块:使用createDirectory函数创建输出文件夹,用于存储裁剪后的图片。

  3. 图像裁剪与保存模块:使用cropAndSave函数对每张图片进行裁剪,并将裁剪后的图像数据以二进制格式保存到指定的文件中。

  4. 主函数模块:在main函数中调用以上模块,实现整体的功能流程。

函数详解

头文件

#include <iostream>
#include <fstream>
#include <opencv2/opencv.hpp>
#include <dirent.h>
#include <sys/stat.h>

listAllFiles函数

  • 功能:遍历指定目录下的所有文件,并返回所有图片文件的路径列表。
  • 参数:
    • rootdir:根目录路径。
  • 返回值:包含所有图片文件路径的字符串向量。
  • 实现原理:使用opendirreaddir函数遍历指定目录下的所有文件和子目录。对于每一个文件和子目录,使用stat函数获取其文件信息,判断是否是文件夹或者图片文件。对于文件夹,递归调用listAllFiles函数;对于图片文件,将其路径添加到结果列表中。
    std::vector<std::string> listAllFiles(const std::string& rootdir) {
        std::vector<std::string> files;
        DIR* dir = opendir(rootdir.c_str());
        if (dir == nullptr) {
            return files;
        }
        dirent* entry;
        while ((entry = readdir(dir)) != nullptr) {
            std::string path = rootdir + "/" + entry->d_name;
            struct stat statbuf;
            if (stat(path.c_str(), &statbuf) == -1) {
                continue;
            }
            if (S_ISDIR(statbuf.st_mode)) {
                if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
                    continue;
                }
                std::vector<std::string> subFiles = listAllFiles(path);
                files.insert(files.end(), subFiles.begin(), subFiles.end());
            } else if (S_ISREG(statbuf.st_mode)) {
                std::string extension = path.substr(path.find_last_of(".") + 1);
                std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
                if (extension == "jpg" || extension == "png" || extension == "jpeg" || extension == "bmp") {
                    files.push_back(path);
                }
            }
        }
        closedir(dir);
        return files;
    }

createDirectory函数

  • 功能:创建指定路径的文件夹。
  • 参数:
    • path:要创建的文件夹路径。
  • 返回值:创建成功返回true,否则返回false。
  • 实现原理:使用mkdir函数创建指定路径的文件夹,并设置权限。
    bool createDirectory(const std::string& path) {
        int ret = mkdir(path.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
        if (ret == -1) {
            return false;
        }
        return true;
    }
    

cropAndSave函数

  • 功能:对输入的图像进行裁剪并保存为二进制文件。
  • 参数:
    • img:输入的图像。
    • output_path:保存输出文件的路径。
    • crop_size:裁剪的尺寸。
  • 返回值:无。
  • 实现原理:首先计算图像的高度和宽度,然后计算裁剪时需要添加的底部和右侧填充大小。使用copyMakeBorder函数对图像进行填充,然后根据裁剪尺寸和填充后的图像大小计算裁剪的行数和列数。使用循环对图像进行裁剪,并将每个通道的数据分别保存到二进制文件中。
    void cropAndSave(const cv::Mat& img, const std::string& output_path, const cv::Size& crop_size) {
        int height = img.rows;
        int width = img.cols;
    
        // Calculate the padding size
        int pad_bottom = crop_size.height - (height % crop_size.height);
        if (pad_bottom == crop_size.height) {
            pad_bottom = 0;
        }
        int pad_right = crop_size.width - (width % crop_size.width);
        if (pad_right == crop_size.width) {
            pad_right = 0;
        }
    
    
        cv::Mat padded_img;
        cv::copyMakeBorder(img, padded_img, 0, pad_bottom, 0, pad_right, cv::BORDER_CONSTANT, cv::Scalar(0, 0, 0));
    
    
        int num_cols = padded_img.cols / crop_size.width;
        int num_rows = padded_img.rows / crop_size.height;
        int count = 0;
        for (int row = 0; row < num_rows; ++row) {
            for (int col = 0; col < num_cols; ++col) {
                int y1 = row * crop_size.height;
                int y2 = y1 + crop_size.height;
                int x1 = col * crop_size.width;
                int x2 = x1 + crop_size.width;
                cv::Mat crop_img = padded_img(cv::Rect(x1, y1, crop_size.width, crop_size.height));
    
                std::string output_file = output_path + "/" + std::to_string(count) + ".bgr";
    
                cv::Mat channels[3];
                cv::split(crop_img, channels);
    
                std::ofstream outfile(output_file, std::ios::binary);
                outfile.write(reinterpret_cast<char*>(channels[0].data), crop_size.width * crop_size.height);
                outfile.write(reinterpret_cast<char*>(channels[1].data), crop_size.width * crop_size.height);
                outfile.write(reinterpret_cast<char*>(channels[2].data), crop_size.width * crop_size.height);
                outfile.close();
    
                ++count;
            }
        }
    }

主函数(main函数)

  • 功能:代码的入口函数。
  • 参数:无。
  • 返回值:整型,程序运行结果。
  • 实现原理:定义输入和输出的根目录路径、裁剪尺寸等变量。调用listAllFiles函数获取所有图片文件的路径列表。遍历每个图片文件,提取文件名并创建对应的输出文件夹。读取图像并调用cropAndSave函数进行裁剪和保存。同时将裁剪后的文件路径写入到输出文件中。最后关闭输出文件,返回0表示程序正常结束。
    int main() {
        std::string input_root = "./image_input";
        std::string output_root = "./bgr";
        std::string txt_path = "./txt文本"; 
        cv::Size crop_size(512, 512); // 切割小图的大小
    
        std::vector<std::string> img_list = listAllFiles(input_root);
        
        int count = 0; 
    
        std::ofstream outfile(txt_path); 
    
        for (const std::string& img_name : img_list) {
            // std::string dir_name = img_name.substr(img_name.find_last_of("/") + 1);
            std::string file_name = img_name.substr(img_name.find_last_of("/") + 1);
            size_t pos = file_name.find_last_of(".");
            if (pos != std::string::npos) {
                file_name = file_name.substr(0, pos);
            }
            std::string dir_name = file_name;
            std::string output_dir = output_root + "/" + dir_name;
            createDirectory(output_dir);
    
            cv::Mat img = cv::imread(img_name);
            if (!img.empty()) {
                cropAndSave(img, output_dir, crop_size);
                
                std::string relative_output_dir = output_dir.substr(output_root.length() - 7); // 计算相对路径
    
                std::string file_name = std::to_string(count) + ".bgr";
                outfile << "." << relative_output_dir << "/" << file_name << std::endl;
    
                count++; // 递增计数器变量
            }
        }
    
        outfile.close(); // 关闭txt文件
    
        return 0;
    }
    

总体

#include <iostream>
#include <fstream>
#include <opencv2/opencv.hpp>
#include <dirent.h>
#include <sys/stat.h>

std::vector<std::string> listAllFiles(const std::string& rootdir) {
    std::vector<std::string> files;
    DIR* dir = opendir(rootdir.c_str());
    if (dir == nullptr) {
        return files;
    }
    dirent* entry;
    while ((entry = readdir(dir)) != nullptr) {
        std::string path = rootdir + "/" + entry->d_name;
        struct stat statbuf;
        if (stat(path.c_str(), &statbuf) == -1) {
            continue;
        }
        if (S_ISDIR(statbuf.st_mode)) {
            if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
                continue;
            }
            std::vector<std::string> subFiles = listAllFiles(path);
            files.insert(files.end(), subFiles.begin(), subFiles.end());
        } else if (S_ISREG(statbuf.st_mode)) {
            std::string extension = path.substr(path.find_last_of(".") + 1);
            std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
            if (extension == "jpg" || extension == "png" || extension == "jpeg" || extension == "bmp") {
                files.push_back(path);
            }
        }
    }
    closedir(dir);
    return files;
}

bool createDirectory(const std::string& path) {
    int ret = mkdir(path.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
    if (ret == -1) {
        return false;
    }
    return true;
}

void cropAndSave(const cv::Mat& img, const std::string& output_path, const cv::Size& crop_size) {
    int height = img.rows;
    int width = img.cols;

    // Calculate the padding size
    int pad_bottom = crop_size.height - (height % crop_size.height);
    if (pad_bottom == crop_size.height) {
        pad_bottom = 0;
    }
    int pad_right = crop_size.width - (width % crop_size.width);
    if (pad_right == crop_size.width) {
        pad_right = 0;
    }


    cv::Mat padded_img;
    cv::copyMakeBorder(img, padded_img, 0, pad_bottom, 0, pad_right, cv::BORDER_CONSTANT, cv::Scalar(0, 0, 0));


    int num_cols = padded_img.cols / crop_size.width;
    int num_rows = padded_img.rows / crop_size.height;
    int count = 0;
    for (int row = 0; row < num_rows; ++row) {
        for (int col = 0; col < num_cols; ++col) {
            int y1 = row * crop_size.height;
            int y2 = y1 + crop_size.height;
            int x1 = col * crop_size.width;
            int x2 = x1 + crop_size.width;
            cv::Mat crop_img = padded_img(cv::Rect(x1, y1, crop_size.width, crop_size.height));

            std::string output_file = output_path + "/" + std::to_string(count) + ".bgr";

            cv::Mat channels[3];
            cv::split(crop_img, channels);

            std::ofstream outfile(output_file, std::ios::binary);
            outfile.write(reinterpret_cast<char*>(channels[0].data), crop_size.width * crop_size.height);
            outfile.write(reinterpret_cast<char*>(channels[1].data), crop_size.width * crop_size.height);
            outfile.write(reinterpret_cast<char*>(channels[2].data), crop_size.width * crop_size.height);
            outfile.close();

            ++count;
        }
    }
}

int main() {
    std::string input_root = "./image_input";
    std::string output_root = "./bgr";
    std::string txt_path = "./txt"; 
    cv::Size crop_size(512, 512);

    std::vector<std::string> img_list = listAllFiles(input_root);
    
    int count = 0; 

    std::ofstream outfile(txt_path); 

    for (const std::string& img_name : img_list) {
        // std::string dir_name = img_name.substr(img_name.find_last_of("/") + 1);
        std::string file_name = img_name.substr(img_name.find_last_of("/") + 1);
        size_t pos = file_name.find_last_of(".");
        if (pos != std::string::npos) {
            file_name = file_name.substr(0, pos);
        }
        std::string dir_name = file_name;
        std::string output_dir = output_root + "/" + dir_name;
        createDirectory(output_dir);

        cv::Mat img = cv::imread(img_name);
        if (!img.empty()) {
            cropAndSave(img, output_dir, crop_size);
            
            std::string relative_output_dir = output_dir.substr(output_root.length() - 7); // 计算相对路径

            std::string file_name = std::to_string(count) + ".bgr";
            outfile << "." << relative_output_dir << "/" << file_name << std::endl;

            count++; // 递增计数器变量
        }
    }

    outfile.close(); // 关闭txt文件

    return 0;
}

总结

代码其实不难,主要是为了迎合设备的环境所以写的时候限制很多。不得不说gpt现在真的很好用,在解决bug的过程中帮我节省了很大的时间。整体思路就是这样了,python代码就不附了。python写起来比C++简单太多了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值