📄 ximadsp.cpp
字号:
////////////////////////////////////////////////////////////////////////////////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; } } c.rgbRed = 255-abs(r-rr); c.rgbGreen = 255-abs(g-gg); c.rgbBlue = 255-abs(b-bb); tmp.SetPixelColor(x,y,c); } } } Transfer(tmp); return true;}/////////////////////////////////////////////////////////////////////////////////** * Blends two images * \param imgsrc2: image to be mixed with this * \param op: blending method; see ImageOpType * \param lXOffset, lYOffset: image displacement * \param bMixAlpha: if true and imgsrc2 has a valid alpha layer, it will be mixed in the destination image. * \return true if everything is ok * * thanks to Mwolski */// void CxImage::Mix(CxImage & imgsrc2, ImageOpType op, long lXOffset, long lYOffset, bool bMixAlpha){ long lWide = min(GetWidth(),imgsrc2.GetWidth()-lXOffset); long lHeight = min(GetHeight(),imgsrc2.GetHeight()-lYOffset); bool bEditAlpha = imgsrc2.AlphaIsValid() & bMixAlpha;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -