You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用OpenCV C++离散余弦变换(DCT)及逆变换恢复原始图像

错误原因
  • 最核心的问题是对DCT系数的格式转换操作完全错误:OpenCV的dct接口输出的是CV_32FC1类型的矩阵,系数包含正负浮点值,且数值范围远超出0~255区间,直接调用DCT.convertTo(DCTconv, CV_8UC1)会强制截断所有小于0的值为0、大于255的值为255,几乎丢失了全部有效系数信息,逆变换自然无法还原原始图像。
  • 次要逻辑问题:Image2ByteList函数内存在冗余的k++操作,每次内循环都会重新计算k的取值,多余的自增操作无实际作用,属于不严谨的代码写法。
修正方案

如果你的需求是无损存储DCT系数用于后续逆变换,直接存储原始浮点类型的DCT系数即可,不要转成8位无符号格式,修正后的参考代码如下:

#include <iostream>
#include <fstream>
#include <vector>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/imgcodecs.hpp>

// 存储浮点型DCT系数到vector
void DCT2FloatList(const cv::Mat& dctMat, std::vector<float>& coeffList){
    coeffList.resize(dctMat.rows * dctMat.cols);
    for (int i = 0; i < dctMat.rows; i++)
    {
        for (int j = 0; j < dctMat.cols; j++)
        {
            int k = i * dctMat.cols + j;
            coeffList[k] = dctMat.at<float>(i, j);
        }
    }
    // 可选:存储系数到文本文件
    std::ofstream fout("DCTList.txt");
    for (size_t i = 0; i < coeffList.size(); i++)
    {
        fout << coeffList[i] << " ";
    }
}

// 从vector恢复DCT系数矩阵
void floatList2DCT(const std::vector<float>& coeffList, cv::Mat& dctMat, int rows, int cols)
{
    cv::Mat newMat(rows, cols, CV_32FC1);
    for (int k = 0; k < coeffList.size(); k++)
    {
        newMat.at<float>(k / cols, k % cols) = coeffList[k];
    }
    dctMat = newMat.clone();
}


void function()
{
    cv::Mat img, imgGray, imgConv, DCT, recoverDCT, recoverImg;

    img = cv::imread("jpg_44.jpg");
    cv::cvtColor(img, imgGray, cv::COLOR_BGR2GRAY);
    imgGray.convertTo(imgConv, CV_32FC1);

    // 正向DCT变换
    cv::dct(imgConv, DCT);

    // 存储DCT系数
    std::vector<float> coeffsList;
    DCT2FloatList(DCT, coeffsList);

    // 恢复DCT系数矩阵
    floatList2DCT(coeffsList, recoverDCT, DCT.rows, DCT.cols);

    // 逆DCT变换
    cv::idct(recoverDCT, recoverImg);
    // 逆变换输出是32F格式,转成8U再保存
    recoverImg.convertTo(recoverImg, CV_8UC1);
    cv::imwrite("Test.jpg", recoverImg);
 }

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

如果你确实有需求要把DCT系数压缩成字节存储,需要先对DCT系数做归一化处理,把所有值映射到0~255区间,逆变换前再映射回原始数值范围,不能直接做格式截断。

内容的提问来源于stack exchange,提问作者Popescu Daniel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 04:48:02