读取图片函数
用opencv读取图片返回mat,为避免中文路径的问题,不能直接用imread
用ifstream以二进制打开图片,把文件内容读入到std::vector<uchar> 缓冲区,再用imdecode解码数据为MAT格式返回。
cpp
static cv::Mat imread_unicode(const std::wstring& filename) {
std::ifstream ifs(filename, std::ios::binary);
std::vector<uchar> buffer((std::istreambuf_iterator<char>(ifs)), {});
return cv::imdecode(buffer, cv::IMREAD_UNCHANGED);
}
裁剪图片函数
参数说明:
- input_path:输入图片路径
- output_path:输出图片路径
- x, y:裁剪区域左上角坐标
- width, height:裁剪区域宽高
- out_width, out_height:输出图片的宽高(缩放用)
- max_size:最大允许输出文件大小(未在实现中直接用到)
主要流程:
- 用 ifstream 读取 input_path 指定的图片文件内容到内存 buffer。
- 用 OpenCV 的 imdecode 解码 buffer 得到 cv::Mat 图像对象。
- 检查图像是否加载成功,失败则返回 false。
- 校正裁剪区域,确保不会越界。
- 用 OpenCV 的 Rect 和 Mat 裁剪出指定区域。
- 用 resize 将裁剪后的图片缩放到 out_width × out_height。
- 用 imencode 按输出路径的扩展名编码图片到 output_buffer。
- 用 ofstream 写入 output_path。
- 写入成功返回 true,失败返回 false。
- 捕获异常,出错时返回 false 并记录日志。
cpp
static bool cropImage(std::string_view input_path, const std::string_view output_path, int x, int y, int width,
int height, int out_width, int out_height, int max_size) {
try {
std::ifstream ifs(CommonTool::charToWchar(input_path), std::ios::binary);
std::vector<uchar> buffer((std::istreambuf_iterator<char>(ifs)), {});
cv::Mat image = cv::imdecode(buffer, cv::IMREAD_UNCHANGED);
if (image.empty()) {
spdlog::error("Failed to load image: {}", input_path);
return false;
}
// 确保裁剪区域在图像范围内
x = std::max(0, x);
y = std::max(0, y);
width = std::min(width, image.cols - x);
height = std::min(height, image.rows - y);
if (width <= 0 || height <= 0) {
spdlog::error("Invalid crop dimensions.");
return false;
}
cv::Rect crop_region(x, y, width, height);
cv::Mat cropped_image = image(crop_region);
cv::Mat img_fixed;
resize(cropped_image, img_fixed, {out_width, out_height}, 0, 0, cv::INTER_AREA);
std::vector<uchar> output_buffer;
bool success = cv::imencode(CommonTool::getExtension(output_path), img_fixed, output_buffer);
if (success) {
std::ofstream ofs(CommonTool::charToWchar(output_path), std::ios::binary);
if (ofs.is_open()) {
ofs.write(reinterpret_cast<const char*>(output_buffer.data()), output_buffer.size());
ofs.close();
} else {
spdlog::error("Failed to open file for writing: {}", output_path);
return false;
}
} else {
spdlog::error("Failed to encode image");
return false;
}
return true;
} catch (const cv::Exception& e) {
spdlog::error("OpenCV error: {}", e.what());
return false;
} catch (const std::exception& e) {
spdlog::error("Standard exception: {}", e.what());
return false;
} catch (...) {
spdlog::error("Unknown error occurred while cropping the image.");
return false;
}
}
获取图像编码器辅助函数
获取编码器数量以及编码器数组大小,遍历数组中的类型,当匹配的时候返回
cpp
static int getEncoderClsid(const WCHAR* format, CLSID* pClsid) {
UINT num = 0; // 编码器数量
UINT size = 0; // 编码器数组大小
Gdiplus::ImageCodecInfo* codec_info = nullptr;
Gdiplus::GetImageEncodersSize(&num, &size);
if (size == 0)
return -1; // 失败
auto buffer = std::make_unique<BYTE[]>(size);
codec_info = reinterpret_cast<Gdiplus::ImageCodecInfo*>(buffer.get());
if (!codec_info)
return -1; // 失败
GetImageEncoders(num, size, codec_info);
for (UINT j = 0; j < num; ++j) {
if (wcscmp(codec_info[j].MimeType, format) == 0) {
*pClsid = codec_info[j].Clsid;
return j;
}
}
return -1;
}