📄 ximadsp.cpp
字号:
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++){
for(long x=xmin; x<xmax; x++){
#if CXIMAGE_SUPPORT_SELECTION
if (SelectionIsInside(x,y))
#endif //CXIMAGE_SUPPORT_SELECTION
{
if (bFullBlend){
color = RGBtoHSL(GetPixelColor(x,y));
color.rgbRed=hue;
color.rgbGreen=sat;
SetPixelColor(x,y,HSLtoRGB(color));
} else {
color = GetPixelColor(x,y);
hsl = RGBtoHSL(color);
hsl.rgbRed=hue;
hsl.rgbGreen=sat;
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);
SetPixelColor(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 = RGBtoHSL(color);
hsl.rgbRed=hue;
hsl.rgbGreen=sat;
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)));
}
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()) 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/ymax); //<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;
RGBQUAD c;
CxImage tmp(*this,pSelection!=0,true,true);
if (!tmp.IsValid()) 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;
}
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;
if (Kfactor==0) Kfactor = 1;
for(long y=ymin; y<ymax; y++){
info.nProgress = (long)(100*y/head.biHeight);
if (info.nEscape) break;
for(long x=xmin; x<xmax; x++){
iY1 = y*info.dwEffWidth+x;
#if CXIMAGE_SUPPORT_SELECTION
if (SelectionIsInside(x,y))
#endif //CXIMAGE_SUPPORT_SELECTION
{
if (y-k2 > 0 && (y+kmax-1) < head.biHeight && x-k2 > 0 && (x+kmax-1) < head.biWidth)
{
b=0;
iCount = 0;
iY2 = ((y-k2)*info.dwEffWidth);
for(long j=-k2;j<kmax;j++)
{
iY = iY2+x;
for(long k=-k2;k<kmax;k++)
{
i=kernel[iCount];
b += cPtr[iY+k] * i;
iCount++;
}
iY2 += info.dwEffWidth;
}
cPtr2[iY1] = (BYTE)min(255, max(0,(int)(b/Kfactor + Koffset)));
}
else
cPtr2[iY1] = cPtr[iY1];
}
}
}
}
else
{
for(long y=ymin; y<ymax; y++){
info.nProgress = (long)(100*y/head.biHeight);
if (info.nEscape) break;
for(long x=xmin; x<xmax; x++){
#if CXIMAGE_SUPPORT_SELECTION
if (SelectionIsInside(x,y))
#endif //CXIMAGE_SUPPORT_SELECTION
{
r=b=g=0;
for(long j=-k2;j<kmax;j++){
for(long k=-k2;k<kmax;k++){
c=GetPixelColor(x+j,y+k);
i=kernel[(j+k2)+Ksize*(k+k2)];
r += c.rgbRed * i;
g += c.rgbGreen * i;
b += c.rgbBlue * i;
}
}
if (Kfactor==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 {
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)));
}
tmp.SetPixelColor(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;
long kmax= Ksize-k2;
BYTE r,g,b;
RGBQUAD c;
CxImage tmp(*this,pSelection!=0,true,true);
if (!tmp.IsValid()) 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;
}
for(long y=ymin; y<ymax; y++){
info.nProgress = (long)(100*y/head.biHeight);
if (info.nEscape) break;
for(long x=xmin; x<xmax; x++){
#if CXIMAGE_SUPPORT_SELECTION
if (SelectionIsInside(x,y))
#endif //CXIMAGE_SUPPORT_SELECTION
{
r=b=g=255;
for(long j=-k2;j<kmax;j++){
for(long k=-k2;k<kmax;k++){
c=GetPixelColor(x+j,y+k);
if (c.rgbRed < r) r=c.rgbRed;
if (c.rgbGreen < g) g=c.rgbGreen;
if (c.rgbBlue < b) b=c.rgbBlue;
}
}
c.rgbRed = r;
c.rgbGreen = g;
c.rgbBlue = b;
tmp.SetPixelColor(x,y,c);
}
}
}
Transfer(tmp);
return true;
}
////////////////////////////////////////////////////////////////////////////////
/**
* Enhance the light areas of the image
* \param Ksize: size of the kernel.
* \return true if everything is ok
*/
bool CxImage::Dilate(long Ksize)
{
if (!pDib) return false;
long k2 = Ksize/2;
long kmax= Ksize-k2;
BYTE r,g,b;
RGBQUAD c;
CxImage tmp(*this,pSelection!=0,true,true);
if (!tmp.IsValid()) 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;
}
for(long y=ymin; y<ymax; y++){
info.nProgress = (long)(100*y/head.biHeight);
if (info.nEscape) break;
for(long x=xmin; x<xmax; x++){
#if CXIMAGE_SUPPORT_SELECTION
if (SelectionIsInside(x,y))
#endif //CXIMAGE_SUPPORT_SELECTION
{
r=b=g=0;
for(long j=-k2;j<kmax;j++){
for(long k=-k2;k<kmax;k++){
c=GetPixelColor(x+j,y+k);
if (c.rgbRed > r) r=c.rgbRed;
if (c.rgbGreen > g) g=c.rgbGreen;
if (c.rgbBlue > b) b=c.rgbBlue;
}
}
c.rgbRed = r;
c.rgbGreen = g;
c.rgbBlue = b;
tmp.SetPixelColor(x,y,c);
}
}
}
Transfer(tmp);
return true;
}
////////////////////////////////////////////////////////////////////////////////
/**
* Enhance the variations between adjacent pixels.
* Similar results can be achieved using Filter(),
* but the algorithms are different both in Edge() and in Contour().
* \param Ksize: size of the kernel.
* \return true if everything is ok
*/
bool CxImage::Edge(long Ksize)
{
if (!pDib) return false;
long k2 = Ksize/2;
long kmax= Ksize-k2;
BYTE r,g,b,rr,gg,bb;
RGBQUAD c;
CxImage tmp(*this,pSelection!=0,true,true);
if (!tmp.IsValid()) 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;
}
for(long y=ymin; y<ymax; y++){
info.nProgress = (long)(100*y/head.biHeight);
if (info.nEscape) break;
for(long x=xmin; x<xmax; x++){
#if CXIMAGE_SUPPORT_SELECTION
if (SelectionIsInside(x,y))
#endif //CXIMAGE_SUPPORT_SELECTION
{
r=b=g=0;
rr=bb=gg=255;
for(long j=-k2;j<kmax;j++){
for(long k=-k2;k<kmax;k++){
c=GetPixelColor(x+j,y+k);
if (c.rgbRed > r) r=c.rgbRed;
if (c.rgbGreen > g) g=c.rgbGreen;
if (c.rgbBlue > b) b=c.rgbBlue;
if (c.rgbRed < rr) rr=c.rgbRed;
if (c.rgbGreen < gg) gg=c.rgbGreen;
if (c.rgbBlue < bb) bb=c.rgbBlue;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -