zoukankan      html  css  js  c++  java
  • 图片缩放应用(nearest / bilinear / three-order interpolate)

    typedef xPixel PIXELCOLORRGB;

    double Sinxx(double value)
    {
    if (value < 0) value = -value;

    if (value < 1.0) {
    float temp = value * value;
    return 0.5 * temp * value - temp + 2.0 / 3.0;
    }
    else if (value < 2.0) {
    value = 2.0 - value;
    value *= value * value;
    return value / 6.0;
    }
    else {
    return 0.0;
    }
    }
    int BOUND(int value, int min, int max)
    {
    chASSERT(min <= max);
    if (value <= min)
    {
    return min;
    }
    else if (value >= max)
    {
    return max;
    }
    else
    {
    return value;
    }

    }

    enum ImageQaulityE
    {
    IMAGE_GEOMETRY_NEAREST_NEIGHBOR_INTERPOLATE = 0,
    IMAGE_GEOMETRY_BILINEAR_INTERPOLATE,
    IMAGE_GEOMETRY_THREE_ORDER_INTERPOLATE
    };
    ImageQaulityE Quality = ImageQaulityE::IMAGE_GEOMETRY_BILINEAR_INTERPOLATE;
    PIXELCOLORRGB Interpolate(LPBYTE lpbySrcXY, int x, int y, float fu, float fv, int nScanWidth, int nScanHeight)
    {
    PIXELCOLORRGB rgb;

    //行字节数, 可以将dwWidthBytes作为参数传递过来
    DWORD dwWidthBytes = (DWORD)nScanWidth * 4;

    switch (Quality)
    {
    case IMAGE_GEOMETRY_NEAREST_NEIGHBOR_INTERPOLATE:
    {
    BYTE* pbySrc = lpbySrcXY;
    rgb.b = *pbySrc++;
    rgb.g = *pbySrc++;
    rgb.r = *pbySrc++;
    rgb.a = *pbySrc;
    break;
    }
    case IMAGE_GEOMETRY_BILINEAR_INTERPOLATE:
    {
    //相邻的四个像素最右下角点的x, y坐标偏移量
    int nx = 1;
    int ny = 1;
    if ((x + 1) > (nScanWidth - 1)) nx = 0;
    if ((y + 1) > (nScanHeight - 1)) ny = 0;

    //相邻四个像素的像素值
    BYTE abyRed[2][2], abyGreen[2][2], abyBlue[2][2], abyAlpha[2][2];

    //像素点(x, y)的数据位置
    BYTE* pbySrc = lpbySrcXY;
    //获取像素数值.
    //(x, y) = (x, y) + (0, 0)
    abyBlue[0][0] = *pbySrc++;
    abyGreen[0][0] = *pbySrc++;
    abyRed[0][0] = *pbySrc++;
    abyAlpha[0][0] = *pbySrc;

    //(x + 1, y) = (x, y) + (1, 0)
    pbySrc = (lpbySrcXY + nx * 4);
    abyBlue[1][0] = *pbySrc++;
    abyGreen[1][0] = *pbySrc++;
    abyRed[1][0] = *pbySrc++;
    abyAlpha[1][0] = *pbySrc;


    //指向下一行数据
    BYTE* pbySrcTemp = (lpbySrcXY + ny * dwWidthBytes);

    //(x , y + 1) = (x, y) + (0, 1)
    pbySrc = pbySrcTemp;
    abyBlue[0][1] = *pbySrc++;
    abyGreen[0][1] = *pbySrc++;
    abyRed[0][1] = *pbySrc++;
    abyAlpha[0][1] = *pbySrc;

    //(x + 1, y + 1) = (x, y) + (1, 1)
    pbySrc = pbySrcTemp + (4 * nx);
    abyBlue[1][1] = *pbySrc++;
    abyGreen[1][1] = *pbySrc++;
    abyRed[1][1] = *pbySrc++;
    abyAlpha[1][1] = *pbySrc;

    rgb.r = (BYTE)(BOUND(((1 - fu) * (1 - fv) * ((float)abyRed[0][0]) +
    (1 - fu) * fv * ((float)abyRed[0][1]) +
    fu * (1 - fv) * ((float)abyRed[1][0]) +
    fu * fv * ((float)abyRed[1][1])), 0, 255));
    rgb.g = (BYTE)(BOUND(((1 - fu) * (1 - fv) * ((float)abyGreen[0][0]) +
    (1 - fu) * fv * ((float)abyGreen[0][1]) +
    fu * (1 - fv) * ((float)abyGreen[1][0]) +
    fu * fv * ((float)abyGreen[1][1])), 0, 255));

    rgb.b = (BYTE)(BOUND(((1 - fu) * (1 - fv) * ((float)abyBlue[0][0]) +
    (1 - fu) * fv * ((float)abyBlue[0][1]) +
    fu * (1 - fv) * ((float)abyBlue[1][0]) +
    fu * fv * ((float)abyBlue[1][1])), 0, 255));
    rgb.a = (BYTE)(BOUND(((1 - fu) * (1 - fv) * ((float)abyAlpha[0][0]) +
    (1 - fu) * fv * ((float)abyAlpha[0][1]) +
    fu * (1 - fv) * ((float)abyAlpha[1][0]) +
    fu * fv * ((float)abyAlpha[1][1])), 0, 255));
    break;
    }

    case IMAGE_GEOMETRY_THREE_ORDER_INTERPOLATE:
    {
    //像素坐标
    int xx[4], yy[4];
    //相邻四个像素的像素值
    BYTE abyRed[4][4], abyGreen[4][4], abyBlue[4][4], abyAlpha[4][4];

    xx[0] = -1; xx[1] = 0; xx[2] = 1; xx[3] = 2;
    yy[0] = -1; yy[1] = 0; yy[2] = 1; yy[3] = 2;

    //保证合法
    if ((x - 1) < 0) xx[0] = 0;
    if ((x + 1) > (nScanWidth - 1)) xx[2] = 0;
    if ((x + 2) > (nScanWidth - 1)) xx[3] = ((xx[2] == 0) ? 0 : 1);

    if ((y - 1) < 0) yy[0] = 0;
    if ((y + 1) > (nScanHeight - 1)) yy[2] = 0;
    if ((y + 2) > (nScanHeight - 1)) yy[3] = ((yy[2] == 0) ? 0 : 1);

    //像素点(x, y)的数据位置
    //获取数据
    int i;
    for (i = 0; i < 4; i++)
    {
    //像素点(x, y)的数据位置
    BYTE* pbySrcBase = lpbySrcXY + yy[i] * dwWidthBytes;

    for (int j = 0; j < 4; j++)
    {
    BYTE* pbySrc = pbySrcBase + 4 * xx[j];
    abyBlue[i][j] = *pbySrc++;
    abyGreen[i][j] = *pbySrc++;
    abyRed[i][j] = *pbySrc++;
    abyAlpha[i][j] = *pbySrc++;
    }
    }

    //u, v向量
    float afu[4], afv[4];

    afu[0] = Sinxx(1.0f + fu);
    afu[1] = Sinxx(fu);
    afu[2] = Sinxx(1.0f - fu);
    afu[3] = Sinxx(2.0f - fu);

    afv[0] = Sinxx(1.0f + fv);
    afv[1] = Sinxx(fv);
    afv[2] = Sinxx(1.0f - fv);
    afv[3] = Sinxx(2.0f - fv);

    //矩阵乘向量的中间值
    float afRed[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
    float afGreen[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
    float afBlue[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
    float afAlpha[4] = { 0.0f, 0.0f, 0.0f, 0.0f };

    for (i = 0; i < 4; i++)
    {
    for (int j = 0; j < 4; j++)
    {
    afRed[i] += afv[j] * abyRed[j][i];
    afGreen[i] += afv[j] * abyGreen[j][i];
    afBlue[i] += afv[j] * abyBlue[j][i];
    afAlpha[i] += afv[j] * abyAlpha[j][i];
    }
    }
    rgb.r = (BYTE)(BOUND((afu[0] * afRed[0] + afu[1] * afRed[1] + afu[2] * afRed[2] +
    afu[3] * afRed[3]), 0, 255));
    rgb.g = (BYTE)(BOUND((afu[0] * afGreen[0] + afu[1] * afGreen[1] + afu[2] * afGreen[2] +
    afu[3] * afGreen[3]), 0, 255));
    rgb.b = (BYTE)(BOUND((afu[0] * afBlue[0] + afu[1] * afBlue[1] + afu[2] * afBlue[2] +
    afu[3] * afBlue[3]), 0, 255));
    rgb.a = (BYTE)(BOUND((afu[0] * afAlpha[0] + afu[1] * afAlpha[1] + afu[2] * afAlpha[2] +
    afu[3] * afAlpha[3]), 0, 255));
    break;
    }
    default: break;
    }//end switch

    return rgb;
    }

    bool xPixmap::load(const chConstStringA& filename)
    {
    QImage img;
    if(img.load(toQString(filename)) || img.load(QString::fromLocal8Bit(filename.c_ptr(), filename.length())))
    {
    m_bHasAlphaChannel = img.hasAlphaChannel();
    #if WINDOWS_SYSTEM
    double nPDI = getCurrentStation().m_dPDI;
    QSize sizeNew(_X(img.width()), _Y(img.height()));
    //QSize sizeNew((img.width() * nPDI), (img.height() * nPDI));
    if(filename.indexOf("-ext") != -1)
    {
    sizeNew = QSize(img.width(), img.height());
    }
    //img = img.scaled(sizeNew, Qt::IgnoreAspectRatio/*, Qt::SmoothTransformation*/);
    #endif
    int w = img.width() * nPDI;
    int h = img.height() * nPDI;
    setNull();
    data().createGraphic(w, h);
    if (-0.0001 < (nPDI - 1) && (nPDI - 1) < 0.0001)
    {
    memcpy((LPVOID)data().pixels(), img.constBits(), w * h * sizeof(xPixel));
    }
    else
    {
    xPixel* pImage = (xPixel*)img.constBits();
    xPixel* pDst = (xPixel*)data().pixels();
    for (int y = 0; y < h; ++y)
    {
    for (int x = 0; x < w; ++x)
    {
    float fX = x * 1.0 / nPDI;
    float fY = y * 1.0 / nPDI;
    xPixel* pSrc = pImage + (int)fY * img.width() + (int)fX;
    *pDst = Interpolate((LPBYTE)pSrc, int(fX), int(fY), fX - int(fX), fY - int(fY), img.width(), img.height());
    ++pDst;
    }
    }
    }
    return true;
    }
    chASSERTx(FALSE, "Faile to load:%s", filename.c_str());
    return false;
    }

  • 相关阅读:
    Android开发环境配置
    Spring API后端原理及最佳实践
    Hibernate 编程
    MySQL 远程访问
    MySQL 5.7 8.0 重置密码
    H5 流媒体
    你不知道的项目
    Promise
    Why Vuex
    Vue 技术细节
  • 原文地址:https://www.cnblogs.com/hqu-ye/p/5213516.html
Copyright © 2011-2022 走看看