zoukankan      html  css  js  c++  java
  • BITMAP图片压缩算法三则--bilinear、nearest、cubic

    原文:http://blog.chinaunix.net/uid-253932-id-3037805.html

    工作需要,要弄截图且缩小。截图倒是好说,WIN API可以搞定,但是缩小且尽量不失真,这个对我来说难度太大了吧。这里主要说说缩小的算法。我从网上找到两个算法分别是bilinear和nearest。但是效果看上去太差了。我先贴上处理后的三种算法效果图,然后再贴算法。

    bilinear

    JKE1VSDO[SA@J(9I6ZZ[RV4

    nearest

    TYJC3GZ~@4WZ}J0IMAY8`VK

    cubic

    T9547]O@N7VHL{%@DGS_Q}0

         当然大家可以看的出来,效果最好的自然是Cubic,提供一些该算法的资料,不过我自己是没看懂http://en.wikipedia.org/wiki/Cubic_function。cubic是我们公司多媒体方面的牛人帮我写的。

    以下是代码:

    #include "stdafx.h"
    #include <stdio.h>
    #include <string>
    #include <windows.h>
    #include <math.h>
    using namespace std;
    enum StretchMode
    {
        nearest, //最临近插值算法
        bilinear, //双线性内插值算法
        cubic
    };
    const int CUBIC_SIZE = 3;
    int getSincVec(float *pfVec, float fPos, float fScale)
    {
        int nPos = (int)fPos;
        fPos -= (float)nPos;
        memset(pfVec, 0, sizeof(float) * CUBIC_SIZE);
        float fSum = 0.f;
        for (int i=0; i<CUBIC_SIZE; i++)
        {
            float fTmp = (i - 1.f + fPos) * 3.14159265358979323846f;
            if (fTmp > 0.00001 || fTmp < -0.00001)
            {
                pfVec[i] = sinf(fTmp * fScale) / fTmp;
            }
            else
            {
                pfVec[i] = 1.f;
            }
            fSum += pfVec[i];
        }
        fSum = 1.f / fSum;
        for (int i=0; i<CUBIC_SIZE; i++)
        {
            pfVec[i] *= fSum;
        }
        return nPos;
    }
    void calcSincMat(float *pfMat, float *pfVecY, float *pfVecX)
    {
        for (int i=0; i<CUBIC_SIZE; i++)
        {
            for (int j=0; j<CUBIC_SIZE; j++)
            {
                pfMat[i * CUBIC_SIZE + j] = pfVecY[i] * pfVecX[j];
            }
        }
    }
    void Stretch(const string& srcFile,const string& desFile,int desW,int desH,StretchMode mode)
    {
        BITMAPFILEHEADER bmfHeader;
        BITMAPINFOHEADER bmiHeader;
        FILE *pFile;
        if ((pFile = fopen(srcFile.c_str(),"rb")) == NULL)
        {
            printf("open bmp file error.");
            exit(-1);
        }
        //读取文件和Bitmap头信息
        fseek(pFile,0,SEEK_SET);
        fread(&bmfHeader,sizeof(BITMAPFILEHEADER),1,pFile);
        fread(&bmiHeader,sizeof(BITMAPINFOHEADER),1,pFile);
        //先不支持小于16位的位图
        int bitCount = bmiHeader.biBitCount;
        if (bitCount < 16)
        { 
            exit(-1);
        }
        int srcW = bmiHeader.biWidth;
        int srcH = bmiHeader.biHeight;
        int lineSize = bitCount * srcW / 8;
        //偏移量,windows系统要求每个扫描行按四字节对齐
        int alignBytes = ((bmiHeader.biWidth * bitCount + 31) & ~31) / 8L
            - bmiHeader.biWidth * bitCount / 8L;
        //原图像缓存
        int srcBufSize = lineSize * srcH;
        BYTE* srcBuf = new BYTE[srcBufSize];
        int i,j;
        //读取文件中数据
        for (i = 0; i < srcH; i++)
        { 
            fread(&srcBuf[lineSize * i],lineSize,1,pFile);
            fseek(pFile,alignBytes,SEEK_CUR);
        }
        //目标图像缓存
        int desBufSize = ((desW * bitCount + 31) / 32) * 4 * desH;
        int desLineSize = ((desW * bitCount + 31) / 32) * 4; 
        BYTE *desBuf = new BYTE[desBufSize];
        double rateH = (double)srcH / desH;
        double rateW = (double)srcW / desW;
        //最临近插值算法
        if (mode == nearest)
        {
            for (i = 0; i < desH; i++)
            {
                //选取最邻近的点
                int tSrcH = (int)(rateH * i + 0.5);
                for (j = 0; j < desW; j++)
                {
                    int tSrcW = (int)(rateW * j + 0.5); 
                    memcpy(&desBuf[i * desLineSize] + j * bmiHeader.biBitCount / 8,&srcBuf[tSrcH * lineSize] + tSrcW * bmiHeader.biBitCount / 8,bmiHeader.biBitCount / 8); 
                }
            } 
        }
        //双线型内插值算法
        else if (mode == bilinear)
        {
            for (i = 0; i < desH; i++)
            {
                int tH = (int)(rateH * i);
                int tH1 = min(tH + 1,srcH - 1);
                float u = (float)(rateH * i - tH);
                for (j = 0; j < desW; j++)
                {
                    int tW = (int)(rateW * j); 
                    int tW1 = min(tW + 1,srcW - 1);
                    float v = (float)(rateW * j - tW);
                    //f(i+u,j+v) = (1-u)(1-v)f(i,j) + (1-u)vf(i,j+1) + u(1-v)f(i+1,j) + uvf(i+1,j+1) 
                    for (int k = 0; k < 3; k++)
                    {
                        desBuf[i * desLineSize + j * bitCount / 8 + k] = 
                            (1 - u)*(1 - v) * srcBuf[tH * lineSize + tW * bitCount / 8 + k] + 
                            (1 - u)*v*srcBuf[tH1 * lineSize + tW * bitCount / 8+ k] + 
                            u * (1 - v) * srcBuf[tH * lineSize + tW1 * bitCount / 8 + k] + 
                            u * v * srcBuf[tH1 * lineSize + tW1 * bitCount / 8 + k]; 
                    } 
                }
            }
        }
        else
        {
            float pfVecX[CUBIC_SIZE], pfVecY[CUBIC_SIZE], pfMat[CUBIC_SIZE][CUBIC_SIZE];
            int nPixelBytes = bitCount / 8;
            for (i=1; i<desH-1; i++)
            {
                int nSrcY = getSincVec(pfVecY, rateH * i, 1.f / rateH);
                for (j = 1; j < desW-1; j++)
                {
                    int nSrcX = getSincVec(pfVecX, rateW * j, 1.f / rateW);
                    calcSincMat(pfMat[0], pfVecY, pfVecX);
                    BYTE *pbyTmpDes = desBuf + i * desLineSize + j * nPixelBytes;
                    BYTE *pbyTmpSrc = srcBuf + nSrcY * lineSize + nSrcX * nPixelBytes;
                    for (int k = 0; k < 3; k++)
                    {
                        float fTmp = pbyTmpSrc[0] * pfMat[1][1];
                        fTmp += pbyTmpSrc[-lineSize] * pfMat[0][1];
                        fTmp += pbyTmpSrc[lineSize] * pfMat[2][1];
                        fTmp += pbyTmpSrc[-nPixelBytes] * pfMat[1][0];
                        fTmp += pbyTmpSrc[-nPixelBytes-lineSize] * pfMat[0][0];
                        fTmp += pbyTmpSrc[-nPixelBytes+lineSize] * pfMat[2][0];
                        fTmp += pbyTmpSrc[nPixelBytes] * pfMat[1][2];
                        fTmp += pbyTmpSrc[nPixelBytes-lineSize] * pfMat[0][2];
                        fTmp += pbyTmpSrc[nPixelBytes+lineSize] * pfMat[2][2];
                        if (fTmp < 0.f) fTmp = 0.f;
                        if (fTmp > 255.f) fTmp = 255.f;
                        *pbyTmpDes++ = (BYTE)fTmp;
                        pbyTmpSrc++;
                    } 
                }
            }
        }
        //创建目标文件
        HFILE hfile = _lcreat(desFile.c_str(),0); 
        //文件头信息
        BITMAPFILEHEADER nbmfHeader; 
        nbmfHeader.bfType = 0x4D42;
        nbmfHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)
            + desW * desH * bitCount / 8;
        nbmfHeader.bfReserved1 = 0;
        nbmfHeader.bfReserved2 = 0;
        nbmfHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
        //Bitmap头信息
        BITMAPINFOHEADER bmi; 
        bmi.biSize=sizeof(BITMAPINFOHEADER); 
        bmi.biWidth=desW; 
        bmi.biHeight=desH; 
        bmi.biPlanes=1; 
        bmi.biBitCount=bitCount; 
        bmi.biCompression=BI_RGB; 
        bmi.biSizeImage=0; 
        bmi.biXPelsPerMeter=0; 
        bmi.biYPelsPerMeter=0; 
        bmi.biClrUsed=0; 
        bmi.biClrImportant=0; 
        //写入文件头信息
        _lwrite(hfile,(LPCSTR)&nbmfHeader,sizeof(BITMAPFILEHEADER));
        //写入Bitmap头信息
        _lwrite(hfile,(LPCSTR)&bmi,sizeof(BITMAPINFOHEADER));
        //写入图像数据
        _lwrite(hfile,(LPCSTR)desBuf,desBufSize);
        _lclose(hfile);
    }
    int main(int argc, char* argv[])
    {
        FILE *pFile;
        if ((pFile = fopen("e://t.bmp","rb")) == NULL)
        {
            printf("open bmp file error.");
            return -1;
        }
        string srcFile("e://t.bmp");
        string desFileN("e://nearest.bmp");
        string desFileB("e://bilinear.bmp");;
        string desFileC("e://cubic.bmp");
        //Stretch(srcFile,desFileN,235,136,nearest);
        //Stretch(srcFile,desFileB,235,136,bilinear);
        Stretch(srcFile,desFileC,235,136,cubic);
        //int alignBytes = ~31;
        //printf("alignbytes : %d",alignBytes);
        return 0;
    }
    

      



  • 相关阅读:
    五、面向对象模型OOM(ObjectOriented Model)
    四、物理数据模型PDM(Physical Data Model )
    Asp.net WebForm中应用Jquery EasyUI Layout
    七、模型文档
    六、PowerDesigner 正向工程 和 逆向工程 说明
    JQuery 原理
    三、概念数据模型CDM(Conceptual Database Model )
    C#基础Func,Action
    Ioc容器应用浅析
    Discuz上面找到的不错的分页算法
  • 原文地址:https://www.cnblogs.com/hwl1023/p/5091237.html
Copyright © 2011-2022 走看看