libjpeg-turbo图片解码 VS opencv

发布于:2025-07-12 ⋅ 阅读:(37) ⋅ 点赞:(0)
#include <glog/logging.h>

#include <opencv2/opencv.hpp>
#include <turbojpeg.h>

std::pair<int, int> JpegTurboDecode(const std::string& raw_jpeg_data, std::vector<unsigned char>* result_data) {
    if (nullptr == result_data) {
        LOG(INFO) << "result_data_ptr is nullptr";
        return { -1, -1 };
    }
    auto start_time = std::chrono::high_resolution_clock::now();
    // 初始化解压缩对象
    tjhandle tjInstance = tjInitDecompress();
    if (tjInstance == nullptr) {
        LOG(ERROR) << "无法初始化libjpeg-turbo解压缩对象";
        return { -1, -1 };
    }

    int width, height, jpegSubsamp;

    // 获取图像信息
    if (tjDecompressHeader2(tjInstance, reinterpret_cast<unsigned char*>(const_cast<char*>(raw_jpeg_data.data())),
        raw_jpeg_data.size(), &width, &height, &jpegSubsamp) < 0) {
        LOG(ERROR) << "无法读取JPEG头信息: " << tjGetErrorStr() << std::endl;
        tjDestroy(tjInstance);
        return { -1, -1 };
    }

    // 分配内存用于存储解压缩后的图像
    result_data->resize(width * height * 3);
    // std::vector<unsigned char> imgBuffer(width * height * 3);

    // 解压缩图像; 这里注意TJPF_BGR和TJFLAG_ACCURATEDCT可以按需设置
    if (tjDecompress2(tjInstance, reinterpret_cast<unsigned char*>(const_cast<char*>(raw_jpeg_data.data())),
        raw_jpeg_data.size(), result_data->data(), width, 0, height, TJPF_BGR, TJFLAG_ACCURATEDCT) < 0) {
        LOG(ERROR) << "解压缩失败: " << tjGetErrorStr();
        tjDestroy(tjInstance);
        return { -1, -1 };
    }
    auto end_time = std::chrono::high_resolution_clock::now();
    auto latency_us1 = std::chrono::duration_cast<std::chrono::microseconds>(end_time - start_time).count();
    LOG(INFO) << "jpeg-turbo 解码耗时:" << latency_us1 << "us";
    return { height, width };
}

void JpegTurboVSOpencv() {
    // std::ifstream fs("./1c0b187eb1f7087d.png");
    std::ifstream fs("load.jpg");
    if (!fs) {
        LOG(ERROR) << "fs_ptr is invalid!";
        return;
    }
    std::stringstream buffer;
    buffer << fs.rdbuf();  // 读取文件内容到 stringstream
    std::string str_tmp(buffer.str());

    // cv解码↓
    auto start_time1 = std::chrono::high_resolution_clock::now();
    // 零拷贝构造cv::Mat
    cv::Mat input_cvmat(1, str_tmp.size(), CV_8UC1, reinterpret_cast<char*>(str_tmp.data()));
    // 解码
    auto decode_by_cv = cv::imdecode(input_cvmat, CV_LOAD_IMAGE_COLOR);
    auto latency_us1 = std::chrono::duration_cast<std::chrono::microseconds>(
        std::chrono::high_resolution_clock::now() - start_time1).count();
    LOG(INFO) << "cv-解码耗时:" << latency_us1 << "us";
    // cv解码↑

    // jpeg-turbo解码↓
    std::vector<unsigned char> result_vec;
    const auto& h_w_pair = JpegTurboDecode(str_tmp, &result_vec);
    cv::Mat cv_mat_from_jpeg_turbo(h_w_pair.first, h_w_pair.second, CV_8UC3,
        reinterpret_cast<char*>(result_vec.data()));
    // jpeg-turbo解码↑

    int idx = 0;
    // const auto cv_decode_result_data = decode_by_cv.data();
    LOG(INFO) << "size from cv:" << decode_by_cv.total()
              << "; size from  jpeg-turbo:" << cv_mat_from_jpeg_turbo.total();
    LOG(INFO) << "type:" << decode_by_cv.type() << ";  type:" << cv_mat_from_jpeg_turbo.type();




    // 比较两者的结果↓
    // 获取矩阵的行数和列数
    int rows = decode_by_cv.rows;
    int cols = decode_by_cv.cols;

    // 获取矩阵的通道数
    int channels = decode_by_cv.channels();

    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            if (channels == 1) {
                // 单通道图像(如灰度图)
                std::cout << static_cast<int>(decode_by_cv.at<uchar>(i, j)) << std::endl;
            } else if (channels == 3) {
                // 三通道图像(如BGR彩色图)
                cv::Vec3b pixel = decode_by_cv.at<cv::Vec3b>(i, j);
                const auto& another = cv_mat_from_jpeg_turbo.at<cv::Vec3b>(i, j);
                if  (static_cast<int>(pixel[0]) - static_cast<int>(another[0]) != 0 ||
                     static_cast<int>(pixel[1]) - static_cast<int>(another[1]) != 0 ||
                     static_cast<int>(pixel[2]) - static_cast<int>(another[2]) != 0) {
                    std::cout << "位置 (" << i << "," << j << "): ";
                    std::cout << "B:" << static_cast<int>(pixel[0]) << "," << static_cast<int>(another[0])
                          << " G:" << static_cast<int>(pixel[1]) << "," << static_cast<int>(another[1])
                          << " R:" << static_cast<int>(pixel[2])  << "," << static_cast<int>(another[2])
                          << std::endl;
                }
            } else {
                std::cout << "不支持的通道数: " << channels << std::endl;
                return;
            }
        }
    }
}

int main() {
    JpegTurboVSOpencv();
    return 0;
}

运行结果

结论

  1. libjpeg-turbo 解码操作耗时优于opencv 35%+
  2. 参数(色彩通道,解码选项)一致情况下,二者的解码数据可以做到无diff

网站公告

今日签到

点亮在社区的每一天
去签到