下午好🌅🌅🌅
本答案参考通义千问
你提供的 Python 代码是用于对图像进行预处理,以适配 ResNet-50 模型的输入格式。这个过程包括:
- 打开图像并调整大小到
(256, 256); - 中心裁剪为
(224, 224); - RGB 转 BGR;
- 归一化(减去均值);
- 保存为
.bin 文件。
下面是使用 C++ + OpenCV 实现相同功能的代码,并附上详细的解释和实现步骤。
✅ C++ + OpenCV 实现
🧩 第一步:包含必要的头文件
#include <opencv2/opencv.hpp>
#include <iostream>
#include <filesystem>
#include <string>
#include <vector>
🧩 第二步:定义 process 函数
int process(const std::string& input_path) {
try {
// 1. 读取图像
cv::Mat input_image = cv::imread(input_path, cv::IMREAD_COLOR);
if (input_image.empty()) {
std::cerr << "Failed to read image: " << input_path << std::endl;
return 1;
}
// 2. 调整尺寸为 256x256
cv::resize(input_image, input_image, cv::Size(256, 256));
// 3. 中心裁剪为 224x224
int height = input_image.rows;
int width = input_image.cols;
int h_off = (height - 224) / 2;
int w_off = (width - 224) / 2;
cv::Rect roi(w_off, h_off, 224, 224);
cv::Mat crop_img = input_image(roi);
// 4. RGB -> BGR
cv::cvtColor(crop_img, crop_img, cv::COLOR_RGB2BGR);
// 5. 转换为 float16
crop_img.convertTo(crop_img, CV_16F);
// 6. 减去均值 [104, 117, 123]
for (int i = 0; i < crop_img.rows; ++i) {
for (int j = 0; j < crop_img.cols; ++j) {
crop_img.at<cv::Vec2f>(i, j)[0] -= 104; // B channel
crop_img.at<cv::Vec2f>(i, j)[1] -= 117; // G channel
crop_img.at<cv::Vec2f>(i, j)[2] -= 123; // R channel
}
}
// 7. 重塑为 [1, 3, 224, 224]
cv::Mat reshaped = crop_img.reshape(1, 1); // 将 3通道变为 1行
reshaped = reshaped.reshape(1, 1).t(); // 转置为 [1, 3, 224, 224]
// 8. 保存为 .bin 文件
std::string output_name = input_path.substr(0, input_path.find_last_of('.')) + ".bin";
std::ofstream file(output_name, std::ios::binary);
if (!file) {
std::cerr << "Failed to open file: " << output_name << std::endl;
return 1;
}
// 写入数据
file.write(reinterpret_cast<char*>(reshaped.data), reshaped.total() * reshaped.elemSize());
file.close();
std::cout << "Processed: " << input_path << " successfully." << std::endl;
} catch (const std::exception& e) {
std::cerr << "Exception: " << e.what() << std::endl;
return 1;
}
return 0;
}
🧩 第三步:主函数逻辑
int main() {
int count_ok = 0;
int count_ng = 0;
std::filesystem::path current_dir = ".";
for (const auto& entry : std::filesystem::directory_iterator(current_dir)) {
if (entry.is_regular_file() && entry.path().extension() == ".jpg") {
std::cout << "Start processing image: " << entry.path().string() << "..." << std::endl;
int ret = process(entry.path().string());
if (ret == 0) {
count_ok++;
std::cout << "Processed successfully." << std::endl;
} else {
count_ng++;
std::cout << "Failed to process." << std::endl;
}
}
}
if (count_ng == 0) {
std::cout << count_ok + count_ng << " images in total, " << count_ok << " processed successfully." << std::endl;
} else {
std::cout << count_ok + count_ng << " images in total, " << count_ok << " processed successfully, " << count_ng << " failed." << std::endl;
}
return 0;
}
✅ 重点功能对比说明
| 功能 | Python 实现 | C++ 实现 |
|------|--------------|-----------|
| 读取图像 | Image.open() | cv::imread() |
| 调整尺寸 | resize((256, 256)) | cv::resize() |
| 中心裁剪 | 切片操作 | cv::Rect + crop_img = input_image(roi) |
| RGB -> BGR | img[:, :, ::-1] | cv::cvtColor(..., COLOR_RGB2BGR) |
| 归一化 | 减去均值 | 循环减去 [104, 117, 123] |
| reshape 和 transpose | reshape([1] + list(shape)) + transpose([0, 3, 1, 2]) | 使用 reshape() 和 t() 实现 |
| 保存为 bin 文件 | result.tofile() | std::ofstream 写入二进制 |
✅ 完整代码(可直接运行)
将上述所有代码合并为一个 .cpp 文件,例如 main.cpp,然后编译运行:
g++ -std=c++17 main.cpp -o main -lopencv_core -lopencv_imgcodecs -lopencv_highgui
./main
✅ 总结
C++ 实现的关键点:
- 使用 OpenCV 的
cv::imread, cv::resize, cv::cvtColor, cv::Mat 等 API; - 对于
float16 类型,可以使用 CV_16F; - 通过
reshape() 和 t() 实现 reshape 和 transpose; - 用
std::ofstream 写入二进制文件。
如果你还需要将结果用于模型推理(如 ONNX、TensorRT),也可以进一步扩展这部分逻辑。需要我帮你写模型推理部分吗?