使用 OpenCV 进行 JPEG 压缩

问题描述 投票:0回答:1

我正在尝试使用 OpenCV 执行基本的 JPEG 压缩(DCT + 量化 + IDCT),而不是使用熵编码/霍夫曼编码。问题是,当我解压压缩图像后,它的外观与原始图像并不接近。

我正在关注这些教程:

基本 JPEG 压缩/解压缩模拟

使用 OpenCV 的基本 JPEG 压缩

以下是3张图像(原始图像、压缩图像和解压缩图像): Original Image

Compressed Image

Final Image

我使用以下矩阵来计算亮度和色度:

double dataLuminance[8][8] = {
    {16, 11, 10, 16, 24, 40, 51, 61},
    {12, 12, 14, 19, 26, 58, 60, 55},
    {14, 13, 16, 24, 40, 57, 69, 56},
    {14, 17, 22, 29, 51, 87, 80, 62},
    {18, 22, 37, 56, 68, 109, 103, 77},
    {24, 35, 55, 64, 81, 104, 113, 92},
    {49, 64, 78, 87, 103, 121, 120, 101},
    {72, 92, 95, 98, 112, 100, 103, 99}
};

double dataChrominance[8][8] = {
    {17, 18, 24, 27, 99, 99, 99, 99},
    {18, 21, 26, 66, 99, 99, 99, 99},
    {24, 26, 56, 99, 99, 99, 99, 99},
    {47, 66, 99, 99, 99, 99, 99, 99},
    {99, 99, 99, 99, 99, 99, 99, 99},
    {99, 99, 99, 99, 99, 99, 99, 99},
    {99, 99, 99, 99, 99, 99, 99, 99},
    {99, 99, 99, 99, 99, 99, 99, 99}
};

// 编辑 1:@Micka 讲述了使用 imread/imwrite 的问题,因此我编辑了代码以直接从程序中使用压缩图像。

压缩方式为:

void ImageCompression::compression(){
// Getting original image size
int height = imgOriginal.size().height;
int width = imgOriginal.size().width;

// Converting image color
Mat imgColorConverted;
cvtColor(imgOriginal, imgColorConverted, CV_BGR2YCrCb);

// Transforming 2D Array in Image Matrix
Mat luminance = Mat(8,8, CV_64FC1, &dataLuminance);
Mat chrominance = Mat(8,8, CV_64FC1, &dataChrominance);

cout << "Luminance: " << luminance << endl << endl;
cout << "Chrominance" << chrominance << endl << endl;

// Splitting the image into 3 planes
vector<Mat> planes;
split(imgColorConverted, planes);

// Downsampling chrominance
// Resizing to 1/4 of original image
resize(planes[1], planes[1], Size(width/2, height/2));
resize(planes[2], planes[2], Size(width/2, height/2));

// Resizing to original image size
resize(planes[1], planes[1], Size(width, height));
resize(planes[2], planes[2], Size(width, height));

// Dividing image in blocks 8x8
for ( int i = 0; i < height; i+=8 ){
    for( int j = 0; j < width; j+=8 ){
        // For each plane
        for( int plane = 0; plane < imgColorConverted.channels(); plane++ ){

            // Creating a block
            Mat block = planes[plane](Rect(j, i, 8, 8));

            // Converting the block to float
            block.convertTo( block, CV_64FC1 );

            // Subtracting the block by 128
            subtract( block, 128.0, block );

            // DCT
            dct( block, block );

            // Applying quantization
            if( plane == 0 ){
                divide( block, luminance, block );
            }
            else {
                divide( block, chrominance, block );
            }

            // Converting it back to unsigned int
            block.convertTo( block, CV_8UC1 );

            // Copying the block to the original image
            block.copyTo( planes[plane](Rect(j, i, 8, 8)) );
        }
    }
}

merge( planes, finalImage );
}

还有我的解压方法:

ImageCompression::decompression{
// Getting the size of the image
int height = finalImage.size().height;
int width = finalImage.size().width;

// Transforming 2D Array in Image Matrix
Mat luminance = Mat(8,8, CV_64FC1, &dataLuminance);
Mat chrominance = Mat(8,8, CV_64FC1, &dataChrominance);

// Splitting the image into 3 planes
vector<Mat> planes;
split(finalImage, planes);

// Dividing the image in blocks 8x8
for ( int i = 0; i < height; i+=8 ){
    for( int j = 0; j < width; j+=8 ){
        // For each plane
        for( int plane = 0; plane < finalImage.channels(); plane++ ){

            // Creating a block
            Mat block = planes[plane](Rect(j, i, 8, 8));

            // Converting the block to float
            block.convertTo( block, CV_64FC1 );

            // Applying dequantization
            if( plane == 0 ){
                multiply( block, luminance, block );
            }
            else {
                multiply( block, chrominance, block );
            }

            // IDCT
            idct( block, block );

            // Adding 128 to the block
            add( block, 128.0, block );

            // Converting it back to unsigned int
            block.convertTo( block, CV_8UC1 );

            // Copying the block to the original image
            block.copyTo( planes[plane](Rect(j, i, 8, 8)) );
        }
    }
}

merge(planes, finalImage);
cvtColor( finalImage, finalImage, CV_YCrCb2BGR );

imshow("Decompressed image", finalImage);
waitKey(0);
imwrite(".../finalResult.jpg", finalImage);
}

有人知道为什么我会得到这样的图像吗?

谢谢你。

c++ image opencv jpeg image-compression
1个回答
0
投票

在将其转换回 unsigned int 之前,您需要将 128 添加回该块,然后在解压时再次减去它。

            add(block, 128.0, block);

            // Converting it back to unsigned int
            block.convertTo(block, CV_8UC1);

.

        // Converting the block to float
        block.convertTo(block, CV_64FC1);

        subtract(block, 128.0, block);
© www.soinside.com 2019 - 2024. All rights reserved.