EasyX繪制透明背景圖的方法詳解
三元光柵操作
根據(jù)在網(wǎng)上的搜索總結(jié)得到兩種方案,最常見(jiàn)的繪制帶有透明背景的圖像的方案都是采用如下的源圖像和掩碼圖像疊加來(lái)消去邊緣部分:
IMAGE img[2]; loadimage(&img[0], "sun1.png", 100, 100); // 掩碼圖像 loadimage(&img[1], "sun0.png", 100, 100); // 源圖像 putimage(0, 0, &img[0], NOTSRCERASE); // 掩碼圖與背景或取反 putimage(0, 0, &img[1], SRCINVERT); // 源圖像與背景異或
直觀理解:由于按位運(yùn)算是依次對(duì)某一位做運(yùn)算,因此只需要考察一位數(shù)字的變化
// 不妨假設(shè)白色為 1,黑色為 0 // 需要變成透明的部分,需要顯示最初的背景色 // 背景色為 a,~a 表示反 a,掩碼此部分是黑色 0,源圖像此部分是白色 1 ~ (a | 0); //-> ~a 或取反 (~a) ^ 1; //-> a 異或 // 結(jié)果仍為背景色 // 需要顯示源圖像的部分 // 背景色為 a,源圖像此部分為 b,掩碼此部分是白色 1 ~ (a | 1); //-> 0 或取反(可以看到第一部分與 a 無(wú)關(guān)) 0 ^ b; //-> b 異或 // 結(jié)果為源圖像
然而,上面的方案雖然足夠解決問(wèn)題,但是未免太過(guò)繁瑣,不僅需要源圖像,還需要花時(shí)間來(lái)制作掩碼圖。最糟糕的就是技術(shù)問(wèn)題導(dǎo)致掩碼圖和原圖不能完全重合,繪制出的圖像有黑邊。
于是,經(jīng)過(guò)長(zhǎng)期搜索,終于找到一種不需要掩碼圖,而是直接對(duì)圖像進(jìn)行處理的方案。
優(yōu)化方案
此方案使用了貝葉斯定理來(lái)對(duì)圖像的每個(gè)像素進(jìn)行計(jì)算,原版代碼的具體來(lái)源因?yàn)闀r(shí)間比較久,已經(jīng)找不到了。這里的方案和原版本有所不同,因?yàn)閷?shí)際需求,我根據(jù)原版本添加了透明度參數(shù) AA ,并且修改了部分代碼使得它與我的需求相契合。
函數(shù)聲明為:
void drawAlpha( IMAGE* image, // 圖像指針 int x, int y, // 輸出坐標(biāo) int width, int height, // 輸出尺寸 int pic_x, int pic_y, // 圖像中的位置 double AA = 1 // 透明度 );
也就是說(shuō)它會(huì)在 x,y
位置輸出從圖像中 pic_x,pic_y
位置開(kāi)始,寬高為 width,height
的部分,且透明度為 AA
。
函數(shù)定義部分:
// 繪圖函數(shù),補(bǔ)充透明度 AA void drawAlpha(IMAGE* image, int x, int y, int width, int height, int pic_x, int pic_y, double AA = 1) { // 變量初始化 DWORD* dst = GetImageBuffer(); // GetImageBuffer() 函數(shù),用于獲取繪圖設(shè)備的顯存指針, EasyX 自帶 DWORD* draw = GetImageBuffer(); DWORD* src = GetImageBuffer(image); // 獲取 picture 的顯存指針 int imageWidth = image->getwidth(); // 獲取圖片寬度 int imageHeight = image->getheight(); // 獲取圖片寬度 int dstX = 0; // 在 繪圖區(qū)域 顯存里像素的角標(biāo) int srcX = 0; // 在 image 顯存里像素的角標(biāo) // 實(shí)現(xiàn)透明貼圖 公式: Cp=αp*FP+(1-αp)*BP , 貝葉斯定理來(lái)進(jìn)行點(diǎn)顏色的概率計(jì)算 for (int iy = 0; iy < height; iy++) { for (int ix = 0; ix < width; ix++) { // 防止越界 if (ix + pic_x >= 0 && ix + pic_x < imageWidth && iy + pic_y >= 0 && iy + pic_y < imageHeight && ix + x >= 0 && ix + x < WindowWidth && iy + y >= 0 && iy + y < WindowHeight) { // 獲取像素角標(biāo) int srcX = (ix + pic_x) + (iy + pic_y) * imageWidth; dstX = (ix + x) + (iy + y) * WindowWidth; int sa = ((src[srcX] & 0xff000000) >> 24) * AA; // 0xAArrggbb; AA 是透明度 int sr = ((src[srcX] & 0xff0000) >> 16); // 獲取 RGB 里的 R int sg = ((src[srcX] & 0xff00) >> 8); // G int sb = src[srcX] & 0xff; // B // 設(shè)置對(duì)應(yīng)的繪圖區(qū)域像素信息 int dr = ((dst[dstX] & 0xff0000) >> 16); int dg = ((dst[dstX] & 0xff00) >> 8); int db = dst[dstX] & 0xff; draw[dstX] = ((sr * sa / 255 + dr * (255 - sa) / 255) << 16) //公式: Cp=αp*FP+(1-αp)*BP ; αp=sa/255 , FP=sr , BP=dr | ((sg * sa / 255 + dg * (255 - sa) / 255) << 8) //αp=sa/255 , FP=sg , BP=dg | (sb * sa / 255 + db * (255 - sa) / 255); //αp=sa/255 , FP=sb , BP=db } } } }
注意其中 WindowWidth 和 WindowHeight 都是預(yù)先定義的全局變量。實(shí)際應(yīng)用時(shí),先在頭文件中定義窗口尺寸,然后就可以直接使用
IMAGE img; loadimage(&img, "sun.png", 100, 100); int x = 100, y = 100; int width = 50, height = 50; int pic_x = 50, pic_y = 50; drawAlpha(img, x, y, width, height, pic_x, pic_y, 0.8);
還可以調(diào)整透明度為 0.8 ,比方案 1 更為實(shí)用。
到此這篇關(guān)于EasyX繪制透明背景圖的方法詳解的文章就介紹到這了,更多相關(guān)EasyX繪制透明背景圖內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解基于C++實(shí)現(xiàn)約瑟夫環(huán)問(wèn)題的三種解法
約瑟夫環(huán)問(wèn)題是算法中相當(dāng)經(jīng)典的一個(gè)問(wèn)題,其問(wèn)題理解是相當(dāng)容易的,并且問(wèn)題描述有非常多的版本,并且約瑟夫環(huán)問(wèn)題還有很多變形,通過(guò)這篇約瑟夫問(wèn)題的講解,一定可以帶你理解透徹2021-06-06C++中vector<vector<int>?>的基本使用方法
vector<vector<int>?>其實(shí)就是容器嵌套容器,外層容器的元素類(lèi)型是vector<int>,下面這篇文章主要給大家介紹了關(guān)于C++中vector<vector<int>?>的基本使用方法,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-07-07C++中的頭文件與Extern(外部函數(shù)調(diào)用)方式
這篇文章主要介紹了C++中的頭文件與Extern(外部函數(shù)調(diào)用)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-08-08