我正在嘗試實作一個函式,該函式使用 Alpha 混合 Crgb565 = (1-a)Argb565 a*Brgb565 混合用 RGB565 編碼的兩種顏色
其中 a 是 alpha 引數,0.0-1.0 的 alpha 混合值映射到 0-32 范圍內的 unsigned char 值。我們可以選擇對 a 使用五位表示,從而將其限制在 0-31 的范圍內(有效地映射到 0.0-0.96875 的 alpha 混合值)。
以下我正在嘗試實作的代碼,您能否建議更好的方法,減少臨時變數,記憶體優化(乘法次數和所需的記憶體訪問),我的 alpha 彎曲邏輯是否正確?我沒有得到正確的結果/預期的輸出,好像我遺漏了一些東西,請查看代碼,感謝每個建議,對 alpha 引數有一些疑問。我已將我的疑問放在代碼注釋部分。有什么方法可以縮短 alpha 混合方程(除法運算)?
==================================================== ===
unsigned short blend_rgb565(unsigned short A, unsigned short B, unsigned char Alpha)
{
unsigned short res = 0;
// Alpha converted from [0..255] to [0..31] (8 bit to 5 bit)
/* I want the alpha parameter (0-32), do i need to add something in Alpha before right shift?? */
Alpha = Alpha >> 3;
// Split Image A into R, G, B components
/*Do I need to take it as unsigned short or uint8_t also work fine ??*/
unsigned short A_r = A >> 11;
unsigned short A_g = (A >> 5) & ((1u << 6) - 1); // ((1u << 6) - 1) --> 00000000 00111111
unsigned short A_b = A & ((1u << 5) - 1); // ((1u << 5) - 1) --> 00000000 00011111
// Split Image B into R, G, B components
unsigned short B_r = B >> 11;
unsigned short B_g = (B >> 5) & ((1u << 6) - 1);
unsigned short B_b = B & ((1u << 5) - 1);
// Alpha blend components
/*Do I need to use 255(8 bit) instead of 32(5 bit), Why we are dividing by it , I have taken the ref from internet , but need little bit more clarification ??*/
unsigned short uiC_r = (A_r * Alpha B_r * (32 - Alpha)) / 32;
unsigned short uiC_g = (A_g * Alpha B_g * (32 - Alpha)) / 32;
unsigned short uiC_b = (A_b * Alpha B_b * (32 - Alpha)) / 32;
// Pack result
res= (unsigned short) ((uiC_r << 11) | (uiC_g << 5) | uiC_b);
return res;
}
===================== 編輯:添加方法2,這種方法是否正確?方法二:
// rrrrrggggggbbbbb
#define RB_MASK 63519 // 0b1111100000011111 --> hex :F81F
#define G_MASK 2016 // 0b0000011111100000 --> hex :07E0
#define RB_MUL_MASK 2032608 // 0b111110000001111100000 --> hex :1F03E0
#define G_MUL_MASK 64512 // 0b000001111110000000000 --> hex :FC00
unsigned short blend_rgb565(unsigned short A,unsigned short B,unsigned char Alpha) {
// Alpha converted from [0..255] to [0..31]
Alpha = Alpha >> 3
uint8_t beta = 32 - Alpha;
// so (0..32)*Alpha (0..32)*beta always in 0..32
return (unsigned short)
(
(
( ( Alpha * (uint32_t)( A & RB_MASK ) beta * (uint32_t)( B & RB_MASK )) & RB_MUL_MASK )
|
( ( Alpha * ( A & G_MASK ) beta * ( B & G_MASK )) & G_MUL_MASK )
)
>> 5 // removing the alpha component 5 bit
);
}
uj5u.com熱心網友回復:
如果在相乘之前將 RGB 值分隔為 2 個 32 位整數,則可以將乘數從 6 減少到 2:
unsigned short blend_rgb565(unsigned short A, unsigned short B, unsigned char Alpha)
{
unsigned short res = 0;
// Alpha converted from [0..255] to [0..31] (8 bit to 5 bit)
Alpha = Alpha >> 3;
// Alpha = (Alpha (Alpha >> 5)) >> 3; // map from 0-255 to 0-32 (if Alpha is unsigned short or larger)
// Space out A and B from RRRRRGGGGGGBBBBB to 00000RRRRR00000GGGGGG00000BBBBB
// 31 = 11111 binary
// 63 = 111111 binary
unsigned int A32 = (unsigned int)A;
unsigned int A_spaced = A32 & 31; // B
A_spaced |= (A32 & (63 << 5)) << 5; // G
A_spaced |= (A32 & (31 << 11)) << 11; // R
unsigned int B32 = (unsigned int)B;
unsigned int B_spaced = B32 & 31; // B
B_spaced |= (B32 & (63 << 5)) << 5; // G
B_spaced |= (B32 & (31 << 11)) << 11; // R
// multiply and add the alpha to give a result RRRRRrrrrrGGGGGGgggggBBBBBbbbbb,
// where RGB are the most significant bits we want to keep
unsigned int C_spaced = (A_spaced * Alpha) (B_spaced * (32 - Alpha));
// remap back to RRRRRGGGGGBBBBB
res = (unsigned short)(((C_spaced >> 5) & 31) ((C_spaced >> 10) & (63 << 5)) ((C_spaced >> 16) & (31 << 11)));
return res;
}
您需要對此進行分析以查看它是否更快,它假定您保存的乘法比您替換它們的額外位操作要慢。
uj5u.com熱心網友回復:
與@samgak 的回答相同,您可以通過“后掩碼”在 64 位架構上更有效地實作,如下所示:
rrrrrggggggbbbbb
復制到 long long(通過將 long long 移動或映射到四個 shorts)
---------------- rrrrrggggggbbbbb rrrrrggggggbbbbb rrrrrggggggbbbbb
屏蔽掉無用的部分
---------------- rrrrr----------- -----gggggg----- -----------bbbbb
乘以α
-----------rrrrr rrrrr----------- ggggggggggg----- ------bbbbbbbbbb
屏蔽低位
-----------rrrrr ---------------- gggggg---------- ------bbbbb-----
盒
rrrrrgggggbbbbb
通過重寫可以節省另一種成本
(1 - α) X α Y
作為
X α (Y - X)
(或X - α (X - Y)避免負面影響)。這節省了乘法(以比較為代價)。
uj5u.com熱心網友回復:
你能建議更好的方法來減少臨時變數嗎
從實作中洗掉臨時變數沒有任何好處。當您在打開優化(例如-O2或/O2)的情況下進行編譯時,這些臨時變數將被優化掉。
我將對您的代碼進行兩項調整:
使用
uint16_t代替無符號短。對于大多數平臺來說,這無關緊要sizeof(uint16_t)==sizeof(unsigned short),但它有助于確定。將 alpha 從 8 位值轉換為 5 位值沒有意義。如果您讓 alpha 具有完整范圍,您將獲得更好的混合精度
你的一些位移看起來很奇怪。它可能會起作用。但我使用更簡單的方法。
這是對您的實施的調整:
#include <stdint.h>
#define MAKE_RGB565(r, g, b) ((r << 11) | (g << 5) | (b))
uint16_t blend_rgb565(uint16_t a, uint16_t b, uint8_t Alpha)
{
const uint8_t invAlpha = 255 - Alpha;
uint16_t A_r = a >> 11;
uint16_t A_g = (a >> 5) & 0x3f;
uint16_t A_b = a & 0x1f;
uint16_t B_r = b >> 11;
uint16_t B_g = (b >> 5) & 0x3f;
uint16_t B_b = b & 0x1f;
uint32_t C_r = (A_r * invAlpha B_r * Alpha) / 255;
uint32_t C_g = (A_g * invAlpha B_g * Alpha) / 255;
uint32_t C_b = (A_b * invAlpha B_b * Alpha) / 255;
return MAKE_RGB565(C_r, C_g, C_b);
}
但更大的問題是這個函式只適用于一對像素顏色。如果您在整個影像或一對影像上呼叫此函式,則使用函式呼叫的開銷將是一個主要的性能問題——即使編譯器優化和行內也是如此。因此,如果您row x col多次呼叫此函式,您可能應該手動將代碼行內到回圈中,該回圈列舉影像(或影像對)上的每個像素。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/484809.html
