簡體   English   中英

使用 OpenCV 進行 JPEG 壓縮

[英]JPEG Compression using OpenCV

我正在嘗試使用 OpenCV 而不使用熵編碼/霍夫曼編碼來執行基本的 JPEG 壓縮(DCT + 量化 + IDCT)。 問題是我解壓壓縮后的圖片,外觀和原圖相差甚遠。

我正在關注這些教程:

基本的 JPEG 壓縮/解壓縮模擬

使用 OpenCV 的基本 JPEG 壓縮

以下是 3 張圖像(原始圖像、壓縮圖像和解壓縮圖像): 原圖

壓縮圖像

最終圖像

我使用以下矩陣來計算亮度和色度:

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);
}

有人知道為什么我會得到那個結果圖像嗎?

謝謝你。

在將其轉換回 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);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM