VC的旋轉雙線性插值演算法源碼

來源:互聯網
上載者:User
VC的旋轉雙線性插值演算法源碼

C/C++ code
/*************************************************************************
* 函數名稱:
* RotateDIB2()
* 參數:
* LPSTR lpDIB – 指向源DIB的指標
* int iRotateAngle – 旋轉的角度(0-360度)
* 傳回值:
* HGLOBAL – 旋轉成功返回新DIB控制代碼,否則返回NULL。
* 說明:
* 該函數用來以映像中心為中心旋轉DIB映像,返回新產生DIB的控制代碼。
* 調用該函數會自動擴大映像以顯示所有的象素。函數中採用雙線性插
* 值演算法進行插值。
************************************************************************/
HGLOBAL CDibImage::RotateDIB2(LPSTR lpDIB, int iRotateAngle)
{
LONG lWidth; // 源映像的寬度
LONG lHeight; // 源映像的高度
LONG lNewWidth; // 旋轉後映像的寬度
LONG lNewHeight; // 旋轉後映像的高度
LONG lNewLineBytes; // 旋轉後映像的寬度(lNewWidth’,必須是4的倍數)
LPSTR lpDIBBits; // 指向源映像的指標
HDIB hDIB; // 旋轉後新DIB控制代碼
LPSTR lpDst; // 指向旋轉映像對應象素的指標
LPSTR lpNewDIB; // 指向旋轉映像的指標
LPSTR lpNewDIBBits;
LPBITMAPINFOHEADER lpbmi; // 指向BITMAPINFO結構的指標(Win3.0)
LPBITMAPCOREHEADER lpbmc; // 指向BITMAPCOREINFO結構的指標

LONG i; // 迴圈變數(象素在新DIB中的座標)
LONG j;
FLOAT i0; // 象素在源DIB中的座標
FLOAT j0;

float fRotateAngle; // 旋轉角度(弧度)
float fSina, fCosa; // 旋轉角度的正弦和餘弦
// 源圖四個角的座標(以映像中心為座標系原點)
float fSrcX1,fSrcY1,fSrcX2,fSrcY2,fSrcX3,fSrcY3,fSrcX4,fSrcY4;
// 旋轉後四個角的座標(以映像中心為座標系原點)
float fDstX1,fDstY1,fDstX2,fDstY2,fDstX3,fDstY3,fDstX4,fDstY4;
float f1,f2;

lpDIBBits = FindDIBBits(lpDIB); // 找到源DIB映像象素起始位置
lWidth = DIBWidth(lpDIB); // 擷取映像的寬度
lHeight = DIBHeight(lpDIB); // 擷取映像的高度

// 將旋轉角度從度轉換到弧度
fRotateAngle = (float) RADIAN(iRotateAngle);

fSina = (float) sin((double)fRotateAngle); // 計算旋轉角度的正弦
fCosa = (float) cos((double)fRotateAngle); // 計算旋轉角度的餘弦

// 計算原圖的四個角的座標(以映像中心為座標系原點)
fSrcX1 = (float) (- (lWidth – 1) / 2);
fSrcY1 = (float) ( (lHeight – 1) / 2);
fSrcX2 = (float) ( (lWidth – 1) / 2);
fSrcY2 = (float) ( (lHeight – 1) / 2);
fSrcX3 = (float) (- (lWidth – 1) / 2);
fSrcY3 = (float) (- (lHeight – 1) / 2);
fSrcX4 = (float) ( (lWidth – 1) / 2);
fSrcY4 = (float) (- (lHeight – 1) / 2);

// 計算新圖四個角的座標(以映像中心為座標系原點)
fDstX1 = fCosa * fSrcX1 + fSina * fSrcY1;
fDstY1 = -fSina * fSrcX1 + fCosa * fSrcY1;
fDstX2 = fCosa * fSrcX2 + fSina * fSrcY2;
fDstY2 = -fSina * fSrcX2 + fCosa * fSrcY2;
fDstX3 = fCosa * fSrcX3 + fSina * fSrcY3;
fDstY3 = -fSina * fSrcX3 + fCosa * fSrcY3;
fDstX4 = fCosa * fSrcX4 + fSina * fSrcY4;
fDstY4 = -fSina * fSrcX4 + fCosa * fSrcY4;

// 計算旋轉後的映像實際寬度
lNewWidth = (LONG)(max(fabs(fDstX4 – fDstX1), fabs(fDstX3 – fDstX2)) + 0.5);
lNewLineBytes = WIDTHBYTES(lNewWidth * 8);

// 計算旋轉後的映像高度
lNewHeight = (LONG)(max(fabs(fDstY4 – fDstY1), fabs(fDstY3 – fDstY2)) + 0.5);

f1 = (float) (-0.5 * (lNewWidth – 1) * fCosa – 0.5 * (lNewHeight – 1) * fSina
+ 0.5 * (lWidth – 1));
f2 = (float) ( 0.5 * (lNewWidth – 1) * fSina – 0.5 * (lNewHeight – 1) * fCosa
+ 0.5 * (lHeight – 1));

// 分配記憶體,以儲存新DIB
hDIB = (HDIB) ::GlobalAlloc(GHND, lNewLineBytes * lNewHeight +
*(LPDWORD)lpDIB + PaletteSize(lpDIB));
if (hDIB == NULL)
{
return NULL;
}

lpNewDIB = (char * )::GlobalLock((HGLOBAL) hDIB);

// 複製DIB資訊頭和調色盤
memcpy(lpNewDIB, lpDIB, *(LPDWORD)lpDIB + PaletteSize(lpDIB));

// 找到新DIB象素起始位置
lpNewDIBBits = FindDIBBits(lpNewDIB);
lpbmi = (LPBITMAPINFOHEADER)lpNewDIB;
lpbmc = (LPBITMAPCOREHEADER)lpNewDIB;

// 更新DIB中映像的高度和寬度
if (IS_WIN30_DIB(lpNewDIB))
{
// 對於Windows 3.0 DIB
lpbmi->biWidth = lNewWidth;
lpbmi->biHeight = lNewHeight;
}
else
{
// 對於其它格式的DIB
lpbmc->bcWidth = (unsigned short) lNewWidth;
lpbmc->bcHeight = (unsigned short) lNewHeight;
}

for(i = 0; i < lNewHeight; i++) // 針對映像每行進行操作
{
for(j = 0; j < lNewWidth; j++) // 針對映像每列進行操作
{
// 指向新DIB第i行,第j個象素的指標
// 注意此處寬度和高度是新DIB的寬度和高度
lpDst = (char *)lpNewDIBBits + lNewLineBytes * (lNewHeight – 1 – i) + j;

// 計算該象素在源DIB中的座標
i0 = -((float) j) * fSina + ((float) i) * fCosa + f2;
j0 = ((float) j) * fCosa + ((float) i) * fSina + f1;

// 利用雙線性插值演算法來估算象素值
*lpDst = Interpolation (lpDIBBits, lWidth, lHeight, j0, i0);
}
}

return hDIB;
}

/*************************************************************************
* 函數名稱:
* Interpolation()
* 參數:
* LPSTR lpDIBBits – 指向源DIB映像指標
* LONG lWidth – 源映像寬度(象素數)
* LONG lHeight – 源映像高度(象素數)
* FLOAT x – 插值元素的x座標
* FLOAT y – 插值元素的y座標
* 傳回值:
* unsigned char – 返回插值計算結果。
* 說明:
* 該函數利用雙線性插值演算法來估算象素值。對於超出映像範圍的象素,
* 直接返回255。
************************************************************************/
unsigned char CDibImage::Interpolation (LPSTR lpDIBBits, LONG lWidth,
LONG lHeight, FLOAT x, FLOAT y)
{
// 四個最臨近象素的座標(i1, j1), (i2, j1), (i1, j2), (i2, j2)
LONG i1, i2;
LONG j1, j2;

unsigned char f1, f2, f3, f4; // 四個最臨近象素值
unsigned char f12, f34; // 二個插值中間值

// 定義一個值,當象素座標相差小於改值時認為座標相同
FLOAT EXP;

LONG lLineBytes; // 映像每行的位元組數
lLineBytes = WIDTHBYTES(lWidth * 8);

EXP = (FLOAT) 0.0001;

// 計算四個最臨近象素的座標
i1 = (LONG) x;
i2 = i1 + 1;
j1 = (LONG) y;
j2 = j1 + 1;

// 根據不同情況分別處理
if( (x < 0) || (x > lWidth – 1) || (y < 0) || (y > lHeight – 1))
{
return 255; // 要計算的點不在源圖範圍內,直接返回255。
}
else
{
if (fabs(x – lWidth + 1) <= EXP)
{
// 要計算的點在映像右邊緣上
if (fabs(y – lHeight + 1) <= EXP)
{
// 要計算的點正好是映像最右下角那一個象素,直接返回該點象素值
f1 = *((unsigned char *)lpDIBBits + lLineBytes *
(lHeight – 1 – j1) + i1);
return f1;
}
else
{
// 在映像右邊緣上且不是最後一點,直接一次插值即可
f1 = *((unsigned char *)lpDIBBits + lLineBytes *
(lHeight – 1 – j1) + i1);
f3 = *((unsigned char *)lpDIBBits + lLineBytes *
(lHeight – 1 – j1) + i2);

// 返回插值結果
return ((unsigned char) (f1 + (y -j1) * (f3 – f1)));
}
}
else if (fabs(y – lHeight + 1) <= EXP)
{
// 要計算的點在映像下邊緣上且不是最後一點,直接一次插值即可
f1 = *((unsigned char*)lpDIBBits + lLineBytes * (lHeight – 1 – j1) + i1);
f2 = *((unsigned char*)lpDIBBits + lLineBytes * (lHeight – 1 – j2) + i1);

// 返回插值結果
return ((unsigned char) (f1 + (x -i1) * (f2 – f1)));
}
else
{
// 計算四個最臨近象素值
f1 = *((unsigned char*)lpDIBBits + lLineBytes * (lHeight – 1 – j1) + i1);
f2 = *((unsigned char*)lpDIBBits + lLineBytes * (lHeight – 1 – j2) + i1);
f3 = *((unsigned char*)lpDIBBits + lLineBytes * (lHeight – 1 – j1) + i2);
f4 = *((unsigned char*)lpDIBBits + lLineBytes * (lHeight – 1 – j2) + i2);

// 插值1
f12 = (unsigned char) (f1 + (x – i1) * (f2 – f1));
// 插值2
f34 = (unsigned char) (f3 + (x – i1) * (f4 – f3));
// 插值3
return ((unsigned char) (f12 + (y -j1) * (f34 – f12)));
}
}
}

上面這段代碼是VC的旋轉雙線性插值演算法

可參見我的文章:
縮放
http://blog.csdn.net/maozefa/archive/2009/10/28/4737584.aspx

旋轉:
http://blog.csdn.net/maozefa/archive/2009/11/03/4764338.aspx

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.