在工作中常常需要将图像转化为raw数据或者yuv数据,这里将提供 cpp 版本和 python 版本的互转代码
代码链接见文档尾部。
cpp 版本
jpg2raw.cpp
#include <fstream>
#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>// Windows 和 Linux 下通用的创建目录函数
#ifdef _WIN32
#include <direct.h> // For _mkdir on Windows
#define MKDIR(dir) _mkdir(dir)
#else
#include <sys/stat.h> // For mkdir on POSIX systems
#define MKDIR(dir) mkdir(dir, 0755)
#endifbool create_directory(const std::string &dir_path)
{
#ifdef _WIN32if (_mkdir(dir_path.c_str()) != 0){return false;}
#elseif (MKDIR(dir_path.c_str()) != 0 && errno != EEXIST){return false;}
#endifreturn true;
}int main(int argc, char **argv)
{if (argc != 2){std::cerr << "Usage: ./image_to_raw input_image.jpg" << std::endl;return -1;}std::string input_image_path = argv[1];std::string base_name = input_image_path.substr(input_image_path.find_last_of('/') + 1); // Unix风格路径分隔符
#ifdef _WIN32std::replace(base_name.begin(), base_name.end(), '\\', '/'); // 对于Windows下的反斜杠,统一转换为正斜杠
#endifstd::cout <<" ----------- input_image_path: " << input_image_path << " ------------------------"<<std::endl;std::cout <<" ----------- basename: " << base_name << " ------------------------"<<std::endl;std::string raw_dir = "raws/";// std::string output_raw_path = raw_dir + base_name + ".raw";std::string file_name = input_image_path.substr(input_image_path.find_last_of("/\\") + 1);std::string file_name_without_suffix = file_name.substr(0, file_name.find_last_of("."));std::string file_name_with_suffix = file_name_without_suffix + ".raw";std::string output_raw_path = raw_dir + file_name_with_suffix;// 创建 'raw' 子目录(如果不存在)if (!create_directory(raw_dir)){std::cerr << "Failed to create directory: " << raw_dir << std::endl;//return -1;}cv::Mat img = cv::imread(input_image_path, 1);if (img.empty()){std::cerr << "Failed to load the image: " << input_image_path << std::endl;return -1;}int im_width = img.cols;int im_height = img.rows;int im_depth = img.channels();std::cout << "im_width: " << im_width << std::endl;std::cout << "im_height: " << im_height << std::endl;std::cout << "im_depth: " << im_depth << std::endl;// 写入 RAW 文件std::ofstream raw_file(output_raw_path, std::ios::binary);if (!raw_file.is_open()){std::cerr << "Failed to open file for writing: " << output_raw_path << std::endl;return -1;}raw_file.write(reinterpret_cast<const char *>(img.data), im_width * im_height * im_depth);raw_file.close();std::cout << "Converted " << input_image_path << " to " << output_raw_path << std::endl;return 0;
}
raw2jpg
#include <fstream>
#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <unordered_map>#ifdef _WIN32
#include <direct.h> // For _mkdir on Windows
#define MKDIR(dir) _mkdir(dir)
#else
#include <sys/stat.h> // For mkdir on POSIX systems
#define MKDIR(dir) mkdir(dir, 0755)
#endifstruct ImageSize
{int width;int height;
};const std::unordered_map<int, ImageSize> image_sizes = {{921600, {640, 480}},{2764800, {1280, 720}},{5858640, {1896, 1030}},{6220800, {1920, 1080}},{11059200, {2560, 1440}},{12257280, {2688, 1520}},{15116544, {2592, 1944}},{3686400, {1280, 960}}};// 跨平台创建目录函数(仅支持Linux和Windows)
bool create_directory(const std::string &path)
{
#ifdef _WIN32return (_mkdir(path.c_str()) == 0);
#elsereturn (::mkdir(path.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == 0);
#endif
}int main(int argc, char **argv)
{if (argc != 2){std::cerr << "Usage: ./raw_image_viewer raw_image.raw" << std::endl;return -1;}std::string raw_image_path = argv[1];std::cout << "raw_image_path: " << raw_image_path << std::endl;// 获取文件大小std::ifstream file(raw_image_path, std::ios::binary | std::ios::ate);size_t file_size = file.tellg();file.close();std::cout << "size: " << file_size << " bytes" << std::endl;// 查找对应的图像尺寸auto it = image_sizes.find(file_size);if (it == image_sizes.end()){std::cout << file_size << " is not supported!" << std::endl;return -1;}const ImageSize &size = it->second;int im_width = size.width;int im_height = size.height;int im_depth = 3; // 假设所有图像都是RGB三通道std::cout << "im_width: " << im_width << std::endl;std::cout << "im_height: " << im_height << std::endl;std::cout << "im_depth: " << im_depth << std::endl;cv::Mat raw_image(im_height, im_width, CV_8UC3);// 读取 RAW 文件的内容std::ifstream raw_file(raw_image_path, std::ios::binary);raw_file.read(reinterpret_cast<char *>(raw_image.data), im_width * im_height * im_depth);raw_file.close();// 提取并创建 images 文件夹(跨平台)std::string images_path = "images/";bool dir_created = create_directory(images_path);std::string file_name = raw_image_path.substr(raw_image_path.find_last_of("/\\") + 1);std::string file_name_without_suffix = file_name.substr(0, file_name.find_last_of("."));std::string file_name_with_suffix = file_name_without_suffix + ".jpg";std::string output_path = images_path + file_name_with_suffix;cv::imwrite(output_path, raw_image);std::cout << " images_path: " << images_path << std::endl;std::cout << " file_name_with_suffix: " << file_name_with_suffix << std::endl;std::cout << " file save name: " << output_path << std::endl;if (!dir_created){std::cerr << "Failed to create 'images' directory." << std::endl;}// (可选)显示图像// cv::imshow("raw_image", raw_image);// cv::waitKey(5);// cv::destroyAllWindows();// (可选)删除原始 RAW 文件// std::remove(raw_image_path.c_str());return 0;
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.10)project(convertRAW2jpg CXX)# 设置安装目录
set(CMAKE_INSTALL_PREFIX "${PROJECT_BINARY_DIR}/install")
set(CMAKE_SKIP_INSTALL_RPATH FALSE)
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")# 要求编译器支持C++11
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)# Windows 特定选项和标志
if(MSVC)add_compile_options(/utf-8)add_definitions(-D_CRT_SECURE_NO_WARNINGS)
endif()# OpenCV 手动配置部分(保留 find_package 并注释)
if(WIN32)# find_package(OpenCV REQUIRED) # 注释掉以使用自定义路径set(OpenCV_DIR "D:/opencv480vc16/build" CACHE PATH "Path to a custom OpenCV build on Windows")set(OPENCV_INCLUDE_DIRS "${OpenCV_DIR}/include")set(OPENCV_LIB_DIR "${OpenCV_DIR}/x64/vc16/lib") # 根据实际编译器版本调整include_directories(${OPENCV_INCLUDE_DIRS})link_directories(${OPENCV_LIB_DIR})list(APPEND EXTRA_LIBS opencv_world480.lib) # 根据实际OpenCV库名称调整
elseif(NOT WIN32)# Linux 下的手动 OpenCV 配置# find_package(OpenCV REQUIRED) # 注释掉以使用自定义路径set(OpenCV_DIR "~/install/opencv4.5.4" CACHE PATH "Path to a custom OpenCV build on Unix-like systems")set(OPENCV_INCLUDE_DIRS "${OpenCV_DIR}/include/opencv4")set(OPENCV_LIB_DIR "${OpenCV_DIR}/lib")include_directories(${OPENCV_INCLUDE_DIRS})link_directories(${OPENCV_LIB_DIR})list(APPEND EXTRA_LIBS opencv_world -fopenmp -lpthread -lm) # 根据实际OpenCV库名称和依赖调整
endif()include_directories(${OpenCV_INCLUDE_DIRS})# 添加源文件
add_executable(raw2jpg src/raw2jpg.cpp)
add_executable(jpg2raw src/jpg2raw.cpp)target_link_libraries(raw2jpg PRIVATE ${EXTRA_LIBS})
target_link_libraries(jpg2raw PRIVATE ${EXTRA_LIBS})# 安装目标及辅助脚本
set(TMP_TEST_DIR ${PROJECT_SOURCE_DIR}/temp_example)
install(TARGETS raw2jpgRUNTIME DESTINATION examplesRUNTIME DESTINATION ${TMP_TEST_DIR})install(TARGETS jpg2rawRUNTIME DESTINATION examplesRUNTIME DESTINATION ${TMP_TEST_DIR})# 找到 assets 目录下所有的 raw 文件,并安装到临时目录
FILE(GLOB RAWS assets/raws/*.raw)
FILE(GLOB JPGS assets/jpgs/*.jpg)install(FILES ${RAWS} DESTINATION ${TMP_TEST_DIR}/test_raws)
install(FILES ${JPGS} DESTINATION ${TMP_TEST_DIR}/test_jpgs)if (WIN32)install(FILES ${PROJECT_SOURCE_DIR}/onekey_windows_batch2jpg.batDESTINATION examplesDESTINATION ${TMP_TEST_DIR})install(FILES ${PROJECT_SOURCE_DIR}/onekey_windows_batch2raw.batDESTINATION examplesDESTINATION ${TMP_TEST_DIR})
else()install(FILES ${PROJECT_SOURCE_DIR}/onekey_ubuntu_batch2jpg.shDESTINATION examplesDESTINATION ${TMP_TEST_DIR})install(FILES ${PROJECT_SOURCE_DIR}/onekey_ubuntu_batch2raw.shDESTINATION examplesDESTINATION ${TMP_TEST_DIR})
endif(WIN32)
批量将 raw 转换为 jpg 的脚本
ubuntu
onekey_ubuntu_batch2jpg.sh
#!/bin/bash
set -eif [ $# -eq 0 ]; thenim_path=`pwd`
elseim_path=$1
fiecho "batch convert the raw image to jpg images in path: $im_path"
i=0
for im in $(ls $im_path)
do if [ "${im##*.}" = "raw" ]; thenif [ -f $im_path/$im ];thenecho "convert $file to jpg image..."./raw2jpg $im_path/$imlet i+=1fifi
done
echo "DONE: $i pictures been gennerated!"**s**
windows
onekey_windows_batch2jpg.bat
@echo off@REM 如果没有输入路径, 就使用当前路径
@if "%~1"=="" (set "im_path=%cd%"
) else (set "im_path=%~1"
)@REM 输出批处理将要转换文件的路径信息
echo Batch converting RAW images to JPG in the current directory or specified path: %im_path%@REM 遍历指定目录及其子目录下的所有.raw文件
for /R "%im_path%" %%i in (*.raw) do (@REM 获取图片名称(不包括完整路径)set "img_file=%%~ni"@REM 输出正在处理的原始图像文件名echo Processing image: %%i@REM 调用 raw2jpg.exe 进行转换,由于程序内部已经设置了输出目录和文件名规则,所以这里仅传入原始文件路径即可.\raw2jpg.exe "%%i"
)@REM 暂停脚本执行,等待用户按键继续
pause
批量将 jpg 转换为 raw 的脚本
ubuntu
onekey_ubuntu_batch2raw.sh
#!/bin/bash
set -eif [ $# -eq 0 ]; thenim_path=`pwd`
elseim_path=$1
fiecho "batch convert the jpg images to raw image in path: $im_path"
i=0
for im in $(ls $im_path)
do if [ "${im##*.}" = "jpg" ]; thenif [ -f $im_path/$im ];thenecho "convert $file to jpg image..."./jpg2raw $im_path/$imlet i+=1fifi
done
echo "DONE: $i pictures been gennerated!"s
windows
onekey_windows_batch2raw.bat
@echo off@REM 如果没有输入路径, 就使用当前路径
if "%1"=="" (set "im_path=%cd%"
) else (set "im_path=%~1"
)@REM 输出当前处理的路径
echo Batch converting image files to raw images in path: %im_path%@REM 遍历指定目录及其子目录下的所有.jpg, .jpeg, .bmp, .png文件
for /R "%im_path%" %%i in (*.jpg, *.jpeg, *.bmp, *.png) do (@REM 获取图片名称(这里保留完整路径)echo Processing image: %%i.\jpg2raw.exe "%%i"
)pause
所有代码见
raw2jpg-github