8*8DCT、量化、zigzag扫描

       距上次说的DCT处理有段时间了。8*8DCT就是对图片进行划分为多个8*8块的方正进行DCT处理,然后对处理后的矩阵进行量化(这个处理对原图是有损的),由DCT处理的特征,我们对处理后的矩阵进行zigzag scan。具体原理请见:jpeg压缩原理(大牛的)

       代码附上:

// myDCT.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "cv.h"
#include "highgui.h"
#include "winsock.h"
#include <iostream>
#include <iomanip>
#include <vector>
#include <string>
using namespace std;

void dct(IplImage* img);
void zigzag(CvMat* m,int n,vector<double> &v);
vector<double> v;

int _tmain(int argc, _TCHAR* argv[])
{
    const char* img_name="image_0002.jpg";
    IplImage* img=cvLoadImage(img_name,1);
    if(!img)//载入失败
    {
        cout<<"load image fail!"<<endl;
        system("pause");
        return -1;
    }
    if(!img->imageData)//载入的图像数据是否正确
    {
            system("pause");
            return -1;
    }
    dct(img);
    cvReleaseImage(&img);
    system("pause");
    return 0;
}

/*
    对图像进行DCT处理
*/
void dct(IplImage* img)
{
    IplImage* imggray=cvCreateImage(cvSize(img->width,img->height),IPL_DEPTH_8U,1);
    cvCvtColor(img,imggray,CV_RGB2GRAY);
    //获取图像信息
    int height,width,step,channels;
    uchar *data;
    height=imggray->height;
    width=imggray->width;
    step=imggray->widthStep;
    channels=imggray->nChannels;
    data=(uchar *)imggray->imageData;
    //定义一个图像矩阵
    CvMat *img_mat= cvCreateMat(width,height, CV_64FC1);
    IplImage* dst=cvCreateImage(cvSize(width,height),IPL_DEPTH_64F,1);
    //把图像转化为矩阵
    cvConvert(imggray,img_mat);
    //矩阵分块 设置了一个8*8子矩阵遍历提取原矩阵数据,进行DCT变换,赋值给另一矩阵
    CvMat *imgmatfenkuai=cvCreateMat(width, height, CV_64FC1);
    cvSetIdentity(imgmatfenkuai);
    CvMat *imgmatquantize8;
    //量化系数
    int QS[8][8] ={1,1,1,1,1,1,1,1,
        1,1,1,1,1,1,1,1,
        1,1,1,1,1,1,1,1,
        1,1,1,1,1,1,1,1,
        1,1,1,1,1,1,1,1,
        1,1,1,1,1,1,1,1,
        1,1,1,1,1,1,1,1,
        1,1,1,1,1,1,1,1};

    /*int QS[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
    };*/

    for (int s=0;s<width/8;s++)
    {
        for(int k=0;k<height/8;k++)
        {
            //从img_mat中取出8*8子块
            CvMat *imgmatsub=cvCreateMat(8,8,CV_64FC1);
            CvRect imgmatsubrect=cvRect(8*s,8*k,8,8);
            cvGetSubArr(img_mat,imgmatsub,imgmatsubrect);
            IplImage* imgdstsub=cvCreateImage(cvSize(8,8),IPL_DEPTH_64F,1);
            //对字块进行DCT处理
            cvDCT(imgmatsub,imgdstsub,CV_DXT_FORWARD);
            CvMat *imgmatdctsub=cvCreateMat(8,8,CV_64FC1);
            //把DCT图像转化成矩阵
            cvConvert(imgdstsub,imgmatdctsub);
            imgmatquantize8=cvCreateMat(8,8,CV_64FC1);
            for (int i=0;i<8;i++)
            {
                for(int j=0;j<8;j++)
                {	
                    //往分imgmatfenkuai矩阵中添加经过DCT处理后值
                    cvmSet(imgmatfenkuai,8*s+i,8*k+j,cvmGet(imgmatdctsub,i,j));
                    //对经过DCT后字块进行量化
                    double lianghua=cvRound(cvmGet(imgmatdctsub,i,j)/QS[i][j]);//quantization *QS[i][j]
                    //另将量化后值存在imgmatquantize8中,以便之后对之进行zigzag扫描
                    cvmSet(imgmatquantize8,i,j,lianghua);
                    
                }
            }
            //对量化后矩阵进行zigzag扫描
            zigzag(imgmatquantize8,8,v);
            cvReleaseMat(&imgmatsub);
            cvReleaseMat(&imgmatdctsub);
            cvReleaseImage(&imgdstsub);
            cvReleaseMat(&imgmatquantize8);
        }
    }
    //对每个8*8矩阵zigzag扫描后的向量进行遍历输出
    vector<double>::iterator it=v.begin();
    while(it!=v.end())
    {
        cout<<(*it)<<"    ";
        it++;
    }
    v.clear();
    cvReleaseImage( &imggray );
}
/*
    对矩阵进行zigzag扫描,m表示扫描矩阵,n表示矩阵维度,v为扫描后得到的定长向量
*/
void zigzag(CvMat* m,int n,vector<double> &v)
{
    int i,j,s,dir,squa;
    i=j=0;
    dir=0;
    s=0;
    squa=n*n;
    //扫描
    while(s<squa)
    {
        switch(dir)
        {
        case 0:
            v.push_back(cvmGet(m,i,j));
            j++;
            if(0==i)
                dir=1;
            if(n-1==i)
                dir=3;
            break;
        case 1:
            v.push_back(cvmGet(m,i,j));
            i++;
            j--;
            if(n-1==i)//这里有if和else,注意这里的逻辑和上面两个if的逻辑有区别的
                dir=0;
            else if(0==j)
                dir=2;
            break;
        case 2:
            v.push_back(cvmGet(m,i,j));
            i++;
            if(0==j)
                dir=3;
            if(n-1==j)
                dir=1;
            break;
        case 3:
            v.push_back(cvmGet(m,i,j));
            i--;
            j++;
            if(n-1==j)
                dir=2;
            else if(0==i)
                dir=0;
            break;
        default:
            break;
        }
        s++;
    }
}

Reference:

8*8DCT

zigzag数组

    原文作者:Z字形编排问题
    原文地址: https://blog.csdn.net/BikeyTang/article/details/24291465
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞