📄 ximadsp.cpp
字号:
}
////////////////////////////////////////////////////////////////////////////////
RGBQUAD CxImage::HSLtoRGB(RGBQUAD lHSLColor)
{
//<F. Livraghi> fixed implementation for HSL2RGB routine
float h,s,l;
float m1,m2;
BYTE r,g,b;
h = (float)lHSLColor.rgbRed * 360.0f/255.0f;
s = (float)lHSLColor.rgbGreen/255.0f;
l = (float)lHSLColor.rgbBlue/255.0f;
if (l <= 0.5) m2 = l * (1+s);
else m2 = l + s - l*s;
m1 = 2 * l - m2;
if (s == 0) {
r=g=b=(BYTE)(l*255.0f);
} else {
r = (BYTE)(HueToRGB(m1,m2,h+120) * 255.0f);
g = (BYTE)(HueToRGB(m1,m2,h) * 255.0f);
b = (BYTE)(HueToRGB(m1,m2,h-120) * 255.0f);
}
RGBQUAD rgb = {b,g,r,0};
return rgb;
}
////////////////////////////////////////////////////////////////////////////////
RGBQUAD CxImage::YUVtoRGB(RGBQUAD lYUVColor)
{
int U,V,R,G,B;
float Y = lYUVColor.rgbRed;
U = lYUVColor.rgbGreen - 128;
V = lYUVColor.rgbBlue - 128;
// R = (int)(1.164 * Y + 2.018 * U);
// G = (int)(1.164 * Y - 0.813 * V - 0.391 * U);
// B = (int)(1.164 * Y + 1.596 * V);
R = (int)( Y + 1.403f * V);
G = (int)( Y - 0.344f * U - 0.714f * V);
B = (int)( Y + 1.770f * U);
R= min(255,max(0,R));
G= min(255,max(0,G));
B= min(255,max(0,B));
RGBQUAD rgb={(BYTE)B,(BYTE)G,(BYTE)R,0};
return rgb;
}
////////////////////////////////////////////////////////////////////////////////
RGBQUAD CxImage::RGBtoYUV(RGBQUAD lRGBColor)
{
int Y,U,V,R,G,B;
R = lRGBColor.rgbRed;
G = lRGBColor.rgbGreen;
B = lRGBColor.rgbBlue;
// Y = (int)( 0.257 * R + 0.504 * G + 0.098 * B);
// U = (int)( 0.439 * R - 0.368 * G - 0.071 * B + 128);
// V = (int)(-0.148 * R - 0.291 * G + 0.439 * B + 128);
Y = (int)(0.299f * R + 0.587f * G + 0.114f * B);
U = (int)((B-Y) * 0.565f + 128);
V = (int)((R-Y) * 0.713f + 128);
Y= min(255,max(0,Y));
U= min(255,max(0,U));
V= min(255,max(0,V));
RGBQUAD yuv={(BYTE)V,(BYTE)U,(BYTE)Y,0};
return yuv;
}
////////////////////////////////////////////////////////////////////////////////
RGBQUAD CxImage::YIQtoRGB(RGBQUAD lYIQColor)
{
int I,Q,R,G,B;
float Y = lYIQColor.rgbRed;
I = lYIQColor.rgbGreen - 128;
Q = lYIQColor.rgbBlue - 128;
R = (int)( Y + 0.956f * I + 0.621f * Q);
G = (int)( Y - 0.273f * I - 0.647f * Q);
B = (int)( Y - 1.104f * I + 1.701f * Q);
R= min(255,max(0,R));
G= min(255,max(0,G));
B= min(255,max(0,B));
RGBQUAD rgb={(BYTE)B,(BYTE)G,(BYTE)R,0};
return rgb;
}
////////////////////////////////////////////////////////////////////////////////
RGBQUAD CxImage::RGBtoYIQ(RGBQUAD lRGBColor)
{
int Y,I,Q,R,G,B;
R = lRGBColor.rgbRed;
G = lRGBColor.rgbGreen;
B = lRGBColor.rgbBlue;
Y = (int)( 0.2992f * R + 0.5868f * G + 0.1140f * B);
I = (int)( 0.5960f * R - 0.2742f * G - 0.3219f * B + 128);
Q = (int)( 0.2109f * R - 0.5229f * G + 0.3120f * B + 128);
Y= min(255,max(0,Y));
I= min(255,max(0,I));
Q= min(255,max(0,Q));
RGBQUAD yiq={(BYTE)Q,(BYTE)I,(BYTE)Y,0};
return yiq;
}
////////////////////////////////////////////////////////////////////////////////
RGBQUAD CxImage::XYZtoRGB(RGBQUAD lXYZColor)
{
int X,Y,Z,R,G,B;
X = lXYZColor.rgbRed;
Y = lXYZColor.rgbGreen;
Z = lXYZColor.rgbBlue;
double k=1.088751;
R = (int)( 3.240479f * X - 1.537150f * Y - 0.498535f * Z * k);
G = (int)( -0.969256f * X + 1.875992f * Y + 0.041556f * Z * k);
B = (int)( 0.055648f * X - 0.204043f * Y + 1.057311f * Z * k);
R= min(255,max(0,R));
G= min(255,max(0,G));
B= min(255,max(0,B));
RGBQUAD rgb={(BYTE)B,(BYTE)G,(BYTE)R,0};
return rgb;
}
////////////////////////////////////////////////////////////////////////////////
RGBQUAD CxImage::RGBtoXYZ(RGBQUAD lRGBColor)
{
int X,Y,Z,R,G,B;
R = lRGBColor.rgbRed;
G = lRGBColor.rgbGreen;
B = lRGBColor.rgbBlue;
X = (int)( 0.412453f * R + 0.357580f * G + 0.180423f * B);
Y = (int)( 0.212671f * R + 0.715160f * G + 0.072169f * B);
Z = (int)((0.019334f * R + 0.119193f * G + 0.950227f * B)*0.918483657f);
//X= min(255,max(0,X));
//Y= min(255,max(0,Y));
//Z= min(255,max(0,Z));
RGBQUAD xyz={(BYTE)Z,(BYTE)Y,(BYTE)X,0};
return xyz;
}
////////////////////////////////////////////////////////////////////////////////
/**
* Generates a "rainbow" palette with saturated colors
* \param correction: 1 generates a single hue spectrum. 0.75 is nice for scientific applications.
*/
void CxImage::HuePalette(float correction)
{
if (head.biClrUsed==0) return;
for(DWORD j=0; j<head.biClrUsed; j++){
BYTE i=(BYTE)(j*correction*(255/(head.biClrUsed-1)));
RGBQUAD hsl={120,240,i,0};
SetPaletteColor((BYTE)j,HSLtoRGB(hsl));
}
}
////////////////////////////////////////////////////////////////////////////////
/**
* Replaces the original hue and saturation values.
* \param hue: hue
* \param sat: saturation
* \param blend: can be from 0 (no effect) to 1 (full effect)
* \return true if everything is ok
*/
bool CxImage::Colorize(BYTE hue, BYTE sat, float blend)
{
if (!pDib) return false;
if (blend < 0.0f) blend = 0.0f;
if (blend > 1.0f) blend = 1.0f;
int a0 = (int)(256*blend);
int a1 = 256 - a0;
bool bFullBlend = false;
if (blend > 0.999f) bFullBlend = true;
RGBQUAD color,hsl;
if (head.biClrUsed==0){
long xmin,xmax,ymin,ymax;
if (pSelection){
xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right;
ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top;
} else {
xmin = ymin = 0;
xmax = head.biWidth; ymax=head.biHeight;
}
for(long y=ymin; y<ymax; y++){
info.nProgress = (long)(100*(y-ymin)/(ymax-ymin));
if (info.nEscape) break;
for(long x=xmin; x<xmax; x++){
#if CXIMAGE_SUPPORT_SELECTION
if (BlindSelectionIsInside(x,y))
#endif //CXIMAGE_SUPPORT_SELECTION
{
if (bFullBlend){
color = RGBtoHSL(BlindGetPixelColor(x,y));
color.rgbRed=hue;
color.rgbGreen=sat;
BlindSetPixelColor(x,y,HSLtoRGB(color));
} else {
color = BlindGetPixelColor(x,y);
hsl.rgbRed=hue;
hsl.rgbGreen=sat;
hsl.rgbBlue = (BYTE)RGB2GRAY(color.rgbRed,color.rgbGreen,color.rgbBlue);
hsl = HSLtoRGB(hsl);
//BlendPixelColor(x,y,hsl,blend);
//color.rgbRed = (BYTE)(hsl.rgbRed * blend + color.rgbRed * (1.0f - blend));
//color.rgbBlue = (BYTE)(hsl.rgbBlue * blend + color.rgbBlue * (1.0f - blend));
//color.rgbGreen = (BYTE)(hsl.rgbGreen * blend + color.rgbGreen * (1.0f - blend));
color.rgbRed = (BYTE)((hsl.rgbRed * a0 + color.rgbRed * a1)>>8);
color.rgbBlue = (BYTE)((hsl.rgbBlue * a0 + color.rgbBlue * a1)>>8);
color.rgbGreen = (BYTE)((hsl.rgbGreen * a0 + color.rgbGreen * a1)>>8);
BlindSetPixelColor(x,y,color);
}
}
}
}
} else {
for(DWORD j=0; j<head.biClrUsed; j++){
if (bFullBlend){
color = RGBtoHSL(GetPaletteColor((BYTE)j));
color.rgbRed=hue;
color.rgbGreen=sat;
SetPaletteColor((BYTE)j,HSLtoRGB(color));
} else {
color = GetPaletteColor((BYTE)j);
hsl.rgbRed=hue;
hsl.rgbGreen=sat;
hsl.rgbBlue = (BYTE)RGB2GRAY(color.rgbRed,color.rgbGreen,color.rgbBlue);
hsl = HSLtoRGB(hsl);
color.rgbRed = (BYTE)(hsl.rgbRed * blend + color.rgbRed * (1.0f - blend));
color.rgbBlue = (BYTE)(hsl.rgbBlue * blend + color.rgbBlue * (1.0f - blend));
color.rgbGreen = (BYTE)(hsl.rgbGreen * blend + color.rgbGreen * (1.0f - blend));
SetPaletteColor((BYTE)j,color);
}
}
}
return true;
}
////////////////////////////////////////////////////////////////////////////////
/**
* Changes the brightness and the contrast of the image.
* \param brightness: can be from -255 to 255, if brightness is negative, the image becomes dark.
* \param contrast: can be from -100 to 100, the neutral value is 0.
* \return true if everything is ok
*/
bool CxImage::Light(long brightness, long contrast)
{
if (!pDib) return false;
float c=(100 + contrast)/100.0f;
brightness+=128;
BYTE cTable[256]; //<nipper>
for (int i=0;i<256;i++) {
cTable[i] = (BYTE)max(0,min(255,(int)((i-128)*c + brightness + 0.5f)));
}
return Lut(cTable);
}
////////////////////////////////////////////////////////////////////////////////
/**
* \return mean lightness of the image. Useful with Threshold() and Light()
*/
float CxImage::Mean()
{
if (!pDib) return 0;
CxImage tmp(*this,true);
if (!tmp.IsValid()){
strcpy(info.szLastError,tmp.GetLastError());
return false;
}
tmp.GrayScale();
float sum=0;
long xmin,xmax,ymin,ymax;
if (pSelection){
xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right;
ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top;
} else {
xmin = ymin = 0;
xmax = head.biWidth; ymax=head.biHeight;
}
if (xmin==xmax || ymin==ymax) return (float)0.0;
BYTE *iSrc=tmp.info.pImage;
iSrc += tmp.info.dwEffWidth*ymin; // necessary for selections <Admir Hodzic>
for(long y=ymin; y<ymax; y++){
info.nProgress = (long)(100*(y-ymin)/(ymax-ymin)); //<zhanghk><Anatoly Ivasyuk>
for(long x=xmin; x<xmax; x++){
sum+=iSrc[x];
}
iSrc+=tmp.info.dwEffWidth;
}
return sum/(xmax-xmin)/(ymax-ymin);
}
////////////////////////////////////////////////////////////////////////////////
/**
* 2D linear filter
* \param kernel: convolving matrix, in row format.
* \param Ksize: size of the kernel.
* \param Kfactor: normalization constant.
* \param Koffset: bias.
* \verbatim Example: the "soften" filter uses this kernel:
1 1 1
1 8 1
1 1 1
the function needs: kernel={1,1,1,1,8,1,1,1,1}; Ksize=3; Kfactor=16; Koffset=0; \endverbatim
* \return true if everything is ok
*/
bool CxImage::Filter(long* kernel, long Ksize, long Kfactor, long Koffset)
{
if (!pDib) return false;
long k2 = Ksize/2;
long kmax= Ksize-k2;
long r,g,b,i;
long ksumcur,ksumtot;
RGBQUAD c;
CxImage tmp(*this);
if (!tmp.IsValid()){
strcpy(info.szLastError,tmp.GetLastError());
return false;
}
long xmin,xmax,ymin,ymax;
if (pSelection){
xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right;
ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top;
} else {
xmin = ymin = 0;
xmax = head.biWidth; ymax=head.biHeight;
}
ksumtot = 0;
for(long j=-k2;j<kmax;j++){
for(long k=-k2;k<kmax;k++){
ksumtot += kernel[(j+k2)+Ksize*(k+k2)];
}
}
if ((head.biBitCount==8) && IsGrayScale())
{
unsigned char* cPtr;
unsigned char* cPtr2;
int iCount;
int iY, iY2, iY1;
cPtr = info.pImage;
cPtr2 = (unsigned char *)tmp.info.pImage;
for(long y=ymin; y<ymax; y++){
info.nProgress = (long)(100*(y-ymin)/(ymax-ymin));
if (info.nEscape) break;
iY1 = y*info.dwEffWidth+xmin;
for(long x=xmin; x<xmax; x++, iY1++){
#if CXIMAGE_SUPPORT_SELECTION
if (BlindSelectionIsInside(x,y))
#endif //CXIMAGE_SUPPORT_SELECTION
{
b=ksumcur=0;
iCount = 0;
iY2 = ((y-k2)*info.dwEffWidth);
for(long j=-k2;j<kmax;j++, iY2+=info.dwEffWidth)
{
if (0>(y+j) || (y+j)>=head.biHeight) continue;
iY = iY2+x;
for(long k=-k2;k<kmax;k++, iCount++)
{
if (0>(x+k) || (x+k)>=head.biWidth) continue;
i=kernel[iCount];
b += cPtr[iY+k] * i;
ksumcur += i;
}
}
if (Kfactor==0 || ksumcur==0){
cPtr2[iY1] = (BYTE)min(255, max(0,(int)(b + Koffset)));
} else if (ksumtot == ksumcur) {
cPtr2[iY1] = (BYTE)min(255, max(0,(int)(b/Kfactor + Koffset)));
} else {
cPtr2[iY1] = (BYTE)min(255, max(0,(int)((b*ksumtot)/(ksumcur*Kfactor) + Koffset)));
}
}
}
}
}
else
{
for(long y=ymin; y<ymax; y++){
info.nProgress = (long)(100*(y-ymin)/(ymax-ymin));
if (info.nEscape) break;
for(long x=xmin; x<xmax; x++){
#if CXIMAGE_SUPPORT_SELECTION
if (BlindSelectionIsInside(x,y))
#endif //CXIMAGE_SUPPORT_SELECTION
{
r=b=g=ksumcur=0;
for(long j=-k2;j<kmax;j++){
for(long k=-k2;k<kmax;k++){
if (!IsInside(x+j,y+k)) continue;
c = BlindGetPixelColor(x+j,y+k);
i = kernel[(j+k2)+Ksize*(k+k2)];
r += c.rgbRed * i;
g += c.rgbGreen * i;
b += c.rgbBlue * i;
ksumcur += i;
}
}
if (Kfactor==0 || ksumcur==0){
c.rgbRed = (BYTE)min(255, max(0,(int)(r + Koffset)));
c.rgbGreen = (BYTE)min(255, max(0,(int)(g + Koffset)));
c.rgbBlue = (BYTE)min(255, max(0,(int)(b + Koffset)));
} else if (ksumtot == ksumcur) {
c.rgbRed = (BYTE)min(255, max(0,(int)(r/Kfactor + Koffset)));
c.rgbGreen = (BYTE)min(255, max(0,(int)(g/Kfactor + Koffset)));
c.rgbBlue = (BYTE)min(255, max(0,(int)(b/Kfactor + Koffset)));
} else {
c.rgbRed = (BYTE)min(255, max(0,(int)((r*ksumtot)/(ksumcur*Kfactor) + Koffset)));
c.rgbGreen = (BYTE)min(255, max(0,(int)((g*ksumtot)/(ksumcur*Kfactor) + Koffset)));
c.rgbBlue = (BYTE)min(255, max(0,(int)((b*ksumtot)/(ksumcur*Kfactor) + Koffset)));
}
tmp.BlindSetPixelColor(x,y,c);
}
}
}
}
Transfer(tmp);
return true;
}
////////////////////////////////////////////////////////////////////////////////
/**
* Enhance the dark areas of the image
* \param Ksize: size of the kernel.
* \return true if everything is ok
*/
bool CxImage::Erode(long Ksize)
{
if (!pDib) return false;
long k2 = Ksize/2;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -