透明的频谱图选择叠加
Transparent spectrogram selection overlays
我正在尝试在频谱图上创建透明的选择叠加层,但它不太奏效。我的意思是结果不是很令人满意。相比之下,绘制在波形顶部的叠加效果很好,但我需要同时支持波形和频谱图视图(以及未来可能的其他视图)
选择覆盖在波形视图中工作正常
这是频谱图视图中的选择叠加层(选择看起来很糟糕,遮住了部分频谱图)
两个视图的代码 (VCL) 相同
void TWaveDisplayContainer::DrawSelectedRegion(){
if(selRange.selStart.x == selRange.selEnd.x){
DrawCursorPosition( selRange.selStart.x);
return;
}
Graphics::TBitmap *pWaveBmp = eContainerView == WAVEFORM ? pWaveBmpLeft : pSfftBmpLeft;
TRect selRect(selRange.selStart.x, 0, selRange.selEnd.x, pWaveLeft->Height);
TCanvas *pCanvas = pWaveLeft->Canvas;
int copyMode = pCanvas->CopyMode;
pCanvas->Draw(0,0, pWaveBmp);
pCanvas->Brush->Color = clActiveBorder;
pCanvas->CopyMode = cmSrcAnd;
pCanvas->Rectangle(selRect);
pCanvas->CopyRect(selRect, pWaveBmp->Canvas, selRect);
pCanvas->CopyMode = copyMode;
if(numChannels == 2){
TCanvas* pOtherCanvas = pWaveRight->Canvas;
pWaveBmp = eContainerView == WAVEFORM ? pWaveBmpRight :
pSfftBmpRight;
pOtherCanvas->Draw(0,0, pWaveBmp);
pOtherCanvas->Brush->Color = clActiveBorder;
pOtherCanvas->CopyMode = cmSrcAnd;
pOtherCanvas->Rectangle(selRect);
pOtherCanvas->CopyRect(selRect, pWaveBmp->Canvas, selRect);
pOtherCanvas->CopyMode = copyMode;
}
}
因此,我正在使用 cmSrcAnd
复制模式和 CopyRect
方法来执行实际的 painting/drawing(TCanvas
对应于设备上下文(HDC on Windows
)。我认为,由于频谱图与波形不同,它实际上没有单一的背景颜色,因此在大多数情况下使用简单的混合复制模式效果不佳。
请注意,我仍然可以完成我想要的,但这需要弄乱各个像素,这是我希望尽可能避免的事情)
我基本上是在寻找能够做到这一点的 API
(VCL
包装 GDI
,所以即使 WINAPI 也可以)。
非常感谢任何帮助
我要回答我自己的问题,希望这对某些人有用。因为这显然不可能实现
在普通 VCL
或使用 WINAPI
中(某些情况除外),我编写了一个简单的函数,将位图 (32bpp / 24bpp
) 与覆盖颜色(任何颜色)混合。
实际结果还取决于赋予单个像素 red, green and blue
分量的权重 (w0,w1
)。改变这些会产生
分别更倾向于频谱图颜色或叠加层颜色的叠加层。
代码
Graphics::TBitmap *TSelectionOverlay::GetSelectionOverlay(Graphics::TBitmap *pBmp, TColor selColour,
TRect &rect, EChannel eChannel){
Graphics::TBitmap *pSelOverlay = eChannel==LEFT ? pSelOverlayLeft : pSelOverlayRight;
const unsigned cGreenShift = 8;
const unsigned cBlueShift = 16;
const unsigned overlayWidth = abs(rect.right-rect.left);
const unsigned overlayHeight = abs(rect.bottom-rect.top);
pSelOverlay->Width = pBmp->Width;
pSelOverlay->Height = pBmp->Height;
const unsigned startOffset = rect.right>rect.left ? rect.left : rect.right;
pSelOverlay->Assign(pBmp);
unsigned char cRed0, cGreen0, cBlue0,cRed1, cGreen1, cBlue1, bRedColor0, bGreenColor0, bBlueColor0;
cBlue0 = selColour >> cBlueShift;
cGreen0 = selColour >> cGreenShift & 0xFF;
cRed0 = selColour & 0xFF;
unsigned *pPixel;
for(int i=0;i<overlayHeight;i++){
pPixel = (unsigned*)pSelOverlay->ScanLine[i];//provides access to the pixel array
for(int j=0;j<overlayWidth;j++){
unsigned pixel = pPixel[startOffset+j];
cBlue1 = pixel >> cBlueShift;
cGreen1 = pixel >> cGreenShift & 0xFF;
cRed1 = pixel & 0xFF;
//blend the current bitmap pixel with the overlay colour
const float w0 = 0.5f; //these weights influence the appearance of the overlay (here we use 50%)
const float w1 = 0.5f;
bRedColor0 = cRed0*w0+cRed1*w1;
bGreenColor0 = cGreen0*w0+cGreen1*w1);
bBlueColor0 = cBlue0*w0+cBlue1*w1;
pPixel[startOffset+j] = ((bBlueColor0 << cBlueShift) | (bGreenColor0 << cGreenShift)) | bRedColor0;
}
}
return pSelOverlay;
}
请注意,由于某些原因,CopyRect
与 CopyMode
值 cmSrcCopy
一起使用效果不佳,因此我改为使用 Draw
。
pCanvas->CopyMode = cmSrcCopy;
pCanvas->CopyRect(dstRect, pSelOverlay->Canvas, srcRec);//this still didn't work well--possibly a bug
所以我用了
pCanvas->Draw(0,0, pSelOverlay);
结果
我正在尝试在频谱图上创建透明的选择叠加层,但它不太奏效。我的意思是结果不是很令人满意。相比之下,绘制在波形顶部的叠加效果很好,但我需要同时支持波形和频谱图视图(以及未来可能的其他视图)
选择覆盖在波形视图中工作正常
这是频谱图视图中的选择叠加层(选择看起来很糟糕,遮住了部分频谱图)
两个视图的代码 (VCL) 相同
void TWaveDisplayContainer::DrawSelectedRegion(){
if(selRange.selStart.x == selRange.selEnd.x){
DrawCursorPosition( selRange.selStart.x);
return;
}
Graphics::TBitmap *pWaveBmp = eContainerView == WAVEFORM ? pWaveBmpLeft : pSfftBmpLeft;
TRect selRect(selRange.selStart.x, 0, selRange.selEnd.x, pWaveLeft->Height);
TCanvas *pCanvas = pWaveLeft->Canvas;
int copyMode = pCanvas->CopyMode;
pCanvas->Draw(0,0, pWaveBmp);
pCanvas->Brush->Color = clActiveBorder;
pCanvas->CopyMode = cmSrcAnd;
pCanvas->Rectangle(selRect);
pCanvas->CopyRect(selRect, pWaveBmp->Canvas, selRect);
pCanvas->CopyMode = copyMode;
if(numChannels == 2){
TCanvas* pOtherCanvas = pWaveRight->Canvas;
pWaveBmp = eContainerView == WAVEFORM ? pWaveBmpRight :
pSfftBmpRight;
pOtherCanvas->Draw(0,0, pWaveBmp);
pOtherCanvas->Brush->Color = clActiveBorder;
pOtherCanvas->CopyMode = cmSrcAnd;
pOtherCanvas->Rectangle(selRect);
pOtherCanvas->CopyRect(selRect, pWaveBmp->Canvas, selRect);
pOtherCanvas->CopyMode = copyMode;
}
}
因此,我正在使用 cmSrcAnd
复制模式和 CopyRect
方法来执行实际的 painting/drawing(TCanvas
对应于设备上下文(HDC on Windows
)。我认为,由于频谱图与波形不同,它实际上没有单一的背景颜色,因此在大多数情况下使用简单的混合复制模式效果不佳。
请注意,我仍然可以完成我想要的,但这需要弄乱各个像素,这是我希望尽可能避免的事情)
我基本上是在寻找能够做到这一点的 API
(VCL
包装 GDI
,所以即使 WINAPI 也可以)。
非常感谢任何帮助
我要回答我自己的问题,希望这对某些人有用。因为这显然不可能实现
在普通 VCL
或使用 WINAPI
中(某些情况除外),我编写了一个简单的函数,将位图 (32bpp / 24bpp
) 与覆盖颜色(任何颜色)混合。
实际结果还取决于赋予单个像素 red, green and blue
分量的权重 (w0,w1
)。改变这些会产生
分别更倾向于频谱图颜色或叠加层颜色的叠加层。
代码
Graphics::TBitmap *TSelectionOverlay::GetSelectionOverlay(Graphics::TBitmap *pBmp, TColor selColour,
TRect &rect, EChannel eChannel){
Graphics::TBitmap *pSelOverlay = eChannel==LEFT ? pSelOverlayLeft : pSelOverlayRight;
const unsigned cGreenShift = 8;
const unsigned cBlueShift = 16;
const unsigned overlayWidth = abs(rect.right-rect.left);
const unsigned overlayHeight = abs(rect.bottom-rect.top);
pSelOverlay->Width = pBmp->Width;
pSelOverlay->Height = pBmp->Height;
const unsigned startOffset = rect.right>rect.left ? rect.left : rect.right;
pSelOverlay->Assign(pBmp);
unsigned char cRed0, cGreen0, cBlue0,cRed1, cGreen1, cBlue1, bRedColor0, bGreenColor0, bBlueColor0;
cBlue0 = selColour >> cBlueShift;
cGreen0 = selColour >> cGreenShift & 0xFF;
cRed0 = selColour & 0xFF;
unsigned *pPixel;
for(int i=0;i<overlayHeight;i++){
pPixel = (unsigned*)pSelOverlay->ScanLine[i];//provides access to the pixel array
for(int j=0;j<overlayWidth;j++){
unsigned pixel = pPixel[startOffset+j];
cBlue1 = pixel >> cBlueShift;
cGreen1 = pixel >> cGreenShift & 0xFF;
cRed1 = pixel & 0xFF;
//blend the current bitmap pixel with the overlay colour
const float w0 = 0.5f; //these weights influence the appearance of the overlay (here we use 50%)
const float w1 = 0.5f;
bRedColor0 = cRed0*w0+cRed1*w1;
bGreenColor0 = cGreen0*w0+cGreen1*w1);
bBlueColor0 = cBlue0*w0+cBlue1*w1;
pPixel[startOffset+j] = ((bBlueColor0 << cBlueShift) | (bGreenColor0 << cGreenShift)) | bRedColor0;
}
}
return pSelOverlay;
}
请注意,由于某些原因,CopyRect
与 CopyMode
值 cmSrcCopy
一起使用效果不佳,因此我改为使用 Draw
。
pCanvas->CopyMode = cmSrcCopy;
pCanvas->CopyRect(dstRect, pSelOverlay->Canvas, srcRec);//this still didn't work well--possibly a bug
所以我用了
pCanvas->Draw(0,0, pSelOverlay);
结果