📄 ximadsp.cpp
字号:
}
}
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;
if (bEditAlpha && AlphaIsValid()==false){
AlphaCreate();
}
RGBQUAD rgbBackgrnd = GetTransColor();
RGBQUAD rgb1, rgb2, rgbDest;
for(long lY=0;lY<lHeight;lY++)
{
info.nProgress = (long)(100*lY/head.biHeight);
if (info.nEscape) break;
for(long lX=0;lX<lWide;lX++)
{
#if CXIMAGE_SUPPORT_SELECTION
if (SelectionIsInside(lX,lY) && imgsrc2.SelectionIsInside(lX+lXOffset,lY+lYOffset))
#endif //CXIMAGE_SUPPORT_SELECTION
{
rgb1 = GetPixelColor(lX,lY);
rgb2 = imgsrc2.GetPixelColor(lX+lXOffset,lY+lYOffset);
switch(op)
{
case OpAdd:
rgbDest.rgbBlue = (BYTE)max(0,min(255,rgb1.rgbBlue+rgb2.rgbBlue));
rgbDest.rgbGreen = (BYTE)max(0,min(255,rgb1.rgbGreen+rgb2.rgbGreen));
rgbDest.rgbRed = (BYTE)max(0,min(255,rgb1.rgbRed+rgb2.rgbRed));
if (bEditAlpha) rgbDest.rgbReserved = (BYTE)max(0,min(255,rgb1.rgbReserved+rgb2.rgbReserved));
break;
case OpSub:
rgbDest.rgbBlue = (BYTE)max(0,min(255,rgb1.rgbBlue-rgb2.rgbBlue));
rgbDest.rgbGreen = (BYTE)max(0,min(255,rgb1.rgbGreen-rgb2.rgbGreen));
rgbDest.rgbRed = (BYTE)max(0,min(255,rgb1.rgbRed-rgb2.rgbRed));
if (bEditAlpha) rgbDest.rgbReserved = (BYTE)max(0,min(255,rgb1.rgbReserved-rgb2.rgbReserved));
break;
case OpAnd:
rgbDest.rgbBlue = (BYTE)(rgb1.rgbBlue&rgb2.rgbBlue);
rgbDest.rgbGreen = (BYTE)(rgb1.rgbGreen&rgb2.rgbGreen);
rgbDest.rgbRed = (BYTE)(rgb1.rgbRed&rgb2.rgbRed);
if (bEditAlpha) rgbDest.rgbReserved = (BYTE)(rgb1.rgbReserved&rgb2.rgbReserved);
break;
case OpXor:
rgbDest.rgbBlue = (BYTE)(rgb1.rgbBlue^rgb2.rgbBlue);
rgbDest.rgbGreen = (BYTE)(rgb1.rgbGreen^rgb2.rgbGreen);
rgbDest.rgbRed = (BYTE)(rgb1.rgbRed^rgb2.rgbRed);
if (bEditAlpha) rgbDest.rgbReserved = (BYTE)(rgb1.rgbReserved^rgb2.rgbReserved);
break;
case OpOr:
rgbDest.rgbBlue = (BYTE)(rgb1.rgbBlue|rgb2.rgbBlue);
rgbDest.rgbGreen = (BYTE)(rgb1.rgbGreen|rgb2.rgbGreen);
rgbDest.rgbRed = (BYTE)(rgb1.rgbRed|rgb2.rgbRed);
if (bEditAlpha) rgbDest.rgbReserved = (BYTE)(rgb1.rgbReserved|rgb2.rgbReserved);
break;
case OpMask:
if(rgb2.rgbBlue==0 && rgb2.rgbGreen==0 && rgb2.rgbRed==0)
rgbDest = rgbBackgrnd;
else
rgbDest = rgb1;
break;
case OpSrcCopy:
if(memcmp(&rgb1,&rgbBackgrnd,sizeof(RGBQUAD))==0)
rgbDest = rgb2;
else // copy straight over
rgbDest = rgb1;
break;
case OpDstCopy:
if(memcmp(&rgb2,&rgbBackgrnd,sizeof(RGBQUAD))==0)
rgbDest = rgb1;
else // copy straight over
rgbDest = rgb2;
break;
case OpScreen:
{
BYTE a,a1;
if (imgsrc2.IsTransparent(lX+lXOffset,lY+lYOffset)){
a=0;
} else if (imgsrc2.AlphaIsValid()){
a=imgsrc2.AlphaGet(lX+lXOffset,lY+lYOffset);
a =(BYTE)((a*(1+imgsrc2.info.nAlphaMax))>>8);
} else {
a=255;
}
if (a==0){ //transparent
rgbDest = rgb1;
} else if (a==255){ //opaque
rgbDest = rgb2;
} else { //blend
a1 = (BYTE)~a;
rgbDest.rgbBlue = (BYTE)((rgb1.rgbBlue*a1+rgb2.rgbBlue*a)>>8);
rgbDest.rgbGreen = (BYTE)((rgb1.rgbGreen*a1+rgb2.rgbGreen*a)>>8);
rgbDest.rgbRed = (BYTE)((rgb1.rgbRed*a1+rgb2.rgbRed*a)>>8);
}
if (bEditAlpha) rgbDest.rgbReserved = (BYTE)(((1+rgb1.rgbReserved)*a)>>8);
}
break;
case OpSrcBlend:
if(memcmp(&rgb1,&rgbBackgrnd,sizeof(RGBQUAD))==0)
rgbDest = rgb2;
else
{
long lBDiff = abs(rgb1.rgbBlue - rgbBackgrnd.rgbBlue);
long lGDiff = abs(rgb1.rgbGreen - rgbBackgrnd.rgbGreen);
long lRDiff = abs(rgb1.rgbRed - rgbBackgrnd.rgbRed);
double lAverage = (lBDiff+lGDiff+lRDiff)/3;
double lThresh = 16;
double dLarge = lAverage/lThresh;
double dSmall = (lThresh-lAverage)/lThresh;
double dSmallAmt = dSmall*((double)rgb2.rgbBlue);
if( lAverage < lThresh+1){
rgbDest.rgbBlue = (BYTE)max(0,min(255,(int)(dLarge*((double)rgb1.rgbBlue) +
dSmallAmt)));
rgbDest.rgbGreen = (BYTE)max(0,min(255,(int)(dLarge*((double)rgb1.rgbGreen) +
dSmallAmt)));
rgbDest.rgbRed = (BYTE)max(0,min(255,(int)(dLarge*((double)rgb1.rgbRed) +
dSmallAmt)));
}
else
rgbDest = rgb1;
}
break;
default:
return;
}
SetPixelColor(lX,lY,rgbDest,bEditAlpha);
}
}
}
}
////////////////////////////////////////////////////////////////////////////////
// thanks to Kenneth Ballard
void CxImage::MixFrom(CxImage & imagesrc2, long lXOffset, long lYOffset)
{
RGBQUAD rgbBackgrnd = imagesrc2.GetTransColor();
RGBQUAD rgb1;
long width = imagesrc2.GetWidth();
long height = imagesrc2.GetHeight();
int x, y;
for(x = 0; x < width; x++)
{
for(y = 0; y < height; y++)
{
rgb1 = imagesrc2.GetPixelColor(x, y);
if(memcmp(&rgb1, &rgbBackgrnd, sizeof(RGBQUAD)) != 0)
SetPixelColor(x + lXOffset, y + lYOffset, rgb1);
}
}
}
////////////////////////////////////////////////////////////////////////////////
/**
* Adjusts separately the red, green, and blue values in the image.
* \param r, g, b: can be from -255 to +255.
* \return true if everything is ok
*/
bool CxImage::ShiftRGB(long r, long g, long b)
{
if (!pDib) return false;
RGBQUAD color;
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
{
color = GetPixelColor(x,y);
color.rgbRed = (BYTE)max(0,min(255,(int)(color.rgbRed + r)));
color.rgbGreen = (BYTE)max(0,min(255,(int)(color.rgbGreen + g)));
color.rgbBlue = (BYTE)max(0,min(255,(int)(color.rgbBlue + b)));
SetPixelColor(x,y,color);
}
}
}
} else {
for(DWORD j=0; j<head.biClrUsed; j++){
color = GetPaletteColor((BYTE)j);
color.rgbRed = (BYTE)max(0,min(255,(int)(color.rgbRed + r)));
color.rgbGreen = (BYTE)max(0,min(255,(int)(color.rgbGreen + g)));
color.rgbBlue = (BYTE)max(0,min(255,(int)(color.rgbBlue + b)));
SetPaletteColor((BYTE)j,color);
}
}
return true;
}
////////////////////////////////////////////////////////////////////////////////
/**
* Adjusts the color balance of the image
* \param gamma can be from 0.1 to 5.
* \return true if everything is ok
*/
bool CxImage::Gamma(float gamma)
{
if (!pDib) return false;
double dinvgamma = 1/gamma;
double dMax = pow(255.0, dinvgamma) / 255.0;
BYTE cTable[256]; //<nipper>
for (int i=0;i<256;i++) {
cTable[i] = (BYTE)max(0,min(255,(int)( pow((double)i, dinvgamma) / dMax)));
}
return Lut(cTable);
}
////////////////////////////////////////////////////////////////////////////////
#if CXIMAGE_SUPPORT_WINCE == 0
/**
* Adjusts the intensity of each pixel to the median intensity of its surrounding pixels.
* \param Ksize: size of the kernel.
* \return true if everything is ok
*/
bool CxImage::Median(long Ksize)
{
if (!pDib) return false;
long k2 = Ksize/2;
long kmax= Ksize-k2;
long i,j,k;
RGBQUAD* kernel = (RGBQUAD*)malloc(Ksize*Ksize*sizeof(RGBQUAD));
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
{
for(j=-k2, i=0;j<kmax;j++)
for(k=-k2;k<kmax;k++, i++)
kernel[i]=GetPixelColor(x+j,y+k);
qsort(kernel, i, sizeof(RGBQUAD), CompareColors);
tmp.SetPixelColor(x,y,kernel[i/2]);
}
}
}
free(kernel);
Transfer(tmp);
return true;
}
#endif //CXIMAGE_SUPPORT_WINCE
////////////////////////////////////////////////////////////////////////////////
/**
* Adds an uniform noise to the image
* \param level: can be from 0 (no noise) to 255 (lot of noise).
* \return true if everything is ok
*/
bool CxImage::Noise(long level)
{
if (!pDib) return false;
RGBQUAD color;
long xmin,xmax,ymin,ymax,n;
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/ymax); //<Anatoly Ivasyuk>
for(long x=xmin; x<xmax; x++){
#if CXIMAGE_SUPPORT_SELECTION
if (SelectionIsInside(x,y))
#endif //CXIMAGE_SUPPORT_SELECTION
{
color = GetPixelColor(x,y);
n=(long)((rand()/(float)RAND_MAX - 0.5)*level);
color.rgbRed = (BYTE)max(0,min(255,(int)(color.rgbRed + n)));
n=(long)((rand()/(float)RAND_MAX - 0.5)*level);
color.rgbGreen = (BYTE)max(0,min(255,(int)(color.rgbGreen + n)));
n=(long)((rand()/(float)RAND_MAX - 0.5)*level);
color.rgbBlue = (BYTE)max(0,min(255,(int)(color.rgbBlue + n)));
SetPixelColor(x,y,color);
}
}
}
return true;
}
////////////////////////////////////////////////////////////////////////////////
/**
* Computes the bidimensional FFT or DFT of the image.
* - The images are processed as grayscale
* - If the dimensions of the image are a power of, 2 the FFT is performed automatically.
* - If dstReal and/or dstImag are NULL, the resulting images replaces the original(s).
* - Note: with 8 bits there is a HUGE loss in the dynamics. The function tries
* to keep an acceptable SNR, but 8bit = 48dB...
*
* \param srcReal, srcImag: source images: One can be NULL, but not both
* \param dstReal, dstImag: destination images. Can be NULL.
* \param direction: 1 = forward, -1 = inverse.
* \param bForceFFT: if true, the images are resampled to make the dimensions a power of 2.
* \param bMagnitude: if true, the real part returns the magnitude, the imaginary part returns the phase
* \return true if everything is ok
*/
bool CxImage::FFT2(CxImage* srcReal, CxImage* srcImag, CxImage* dstReal, CxImage* dstImag,
long direction, bool bForceFFT, bool bMagnitude)
{
//check if there is something to convert
if (srcReal==NULL && srcImag==NULL) return false;
long w,h;
//get width and height
if (srcReal) {
w=srcReal->GetWidth();
h=srcReal->GetHeight();
} else {
w=srcImag->GetWidth();
h=srcImag->GetHeight();
}
bool bXpow2 = IsPowerof2(w);
bool bYpow2 = IsPowerof2(h);
//if bForceFFT, width AND height must be powers of 2
if (bForceFFT && !(bXpow2 && bYpow2)) {
long i;
i=0;
while((1<<i)<w) i++;
w=1<<i;
bXpow2=true;
i=0;
while((1<<i)<h) i++;
h=1<<i;
bYpow2=true;
}
// I/O images for FFT
CxImage *tmpReal,*tmpImag;
// select output
tmpReal = (dstReal) ? dstReal : srcReal;
tmpImag = (dstImag) ? dstImag : srcImag;
// src!=dst -> copy the image
if (srcReal && dstReal) tmpReal->Copy(*srcReal,true,false,false);
if (srcImag && dstImag) tmpImag->Copy(*srcImag,true,false,false);
// dst&&src are empty -> create new one, else turn to GrayScale
if (srcReal==0 && dstReal==0){
tmpReal = new CxImage(w,h,8);
tmpReal->Clear(0);
tmpReal->SetGrayPalette();
} else {
if (!tmpReal->IsGrayScale()) tmpReal->GrayScale();
}
if (srcImag==0 && dstImag==0){
tmpImag = new CxImage(w,h,8);
tmpImag->Clear(0);
tmpImag->SetGrayPalette();
} else {
if (!tmpImag->IsGrayScale()) tmpImag->GrayScale();
}
if (!(tmpReal->IsValid() && tmpImag->IsValid())){
if (srcReal==0 && dstReal==0) delete tmpReal;
if (srcImag==0 && dstImag==0) delete tmpImag;
return false;
}
//resample for FFT, if necessary
tmpReal->Resample(w,h,0);
tmpImag->Resample(w,h,0);
//ok, here we have 2 (w x h), grayscale images ready for a FFT
double* real;
double* imag;
long j,k,m;
_complex **grid;
//double mean = tmpReal->Mean();
/* Allocate memory for the grid */
grid = (_complex **)malloc(w * sizeof(_complex));
for (k=0;k<w;k++) {
grid[k] = (_complex *)malloc(h * sizeof(_complex));
}
for (j=0;j<h;j++) {
for (k=0;k<w;k++) {
grid[k][j].x = tmpReal->GetPixelIndex(k,j)-128;
grid[k][j].y = tmpImag->GetPixelIndex(k,j)-128;
}
}
//DFT buffers
double *real2,*imag2;
real2 = (double*)malloc(max(w,h) * sizeof(double));
imag2 = (double*)malloc(max(w,h) * sizeof(double));
/* Transform the rows */
real = (double *)malloc(w * sizeof(double));
imag = (double *)malloc(w * sizeof(double));
m=0;
while((1<<m)<w) m++;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -