📄 ximadsp.cpp
字号:
long nx,ny;
CxImage tmp(*this,pSelection!=0,true,true);
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
{
nx=x+(long)((rand()/(float)RAND_MAX - 0.5)*(radius*2));
ny=y+(long)((rand()/(float)RAND_MAX - 0.5)*(radius*2));
if (!IsInside(nx,ny)) {
nx=x;
ny=y;
}
if (head.biClrUsed==0){
tmp.SetPixelColor(x,y,GetPixelColor(nx,ny));
} else {
tmp.SetPixelIndex(x,y,GetPixelIndex(nx,ny));
}
#if CXIMAGE_SUPPORT_ALPHA
tmp.AlphaSet(x,y,AlphaGet(nx,ny));
#endif //CXIMAGE_SUPPORT_ALPHA
}
}
}
Transfer(tmp);
return true;
}
////////////////////////////////////////////////////////////////////////////////
/* <nipper> generates a 1-D convolution matrix to be used for each pass of
* a two-pass gaussian blur. Returns the length of the matrix.
*/
int CxImage::gen_convolve_matrix (float radius, float **cmatrix_p)
{
int matrix_length;
int matrix_midpoint;
float* cmatrix;
int i,j;
float std_dev;
float sum;
/* we want to generate a matrix that goes out a certain radius
* from the center, so we have to go out ceil(rad-0.5) pixels,
* inlcuding the center pixel. Of course, that's only in one direction,
* so we have to go the same amount in the other direction, but not count
* the center pixel again. So we double the previous result and subtract
* one.
* The radius parameter that is passed to this function is used as
* the standard deviation, and the radius of effect is the
* standard deviation * 2. It's a little confusing.
*/
radius = (float)fabs(radius) + 1.0f;
std_dev = radius;
radius = std_dev * 2;
/* go out 'radius' in each direction */
matrix_length = int (2 * ceil(radius-0.5) + 1);
if (matrix_length <= 0) matrix_length = 1;
matrix_midpoint = matrix_length/2 + 1;
*cmatrix_p = new float[matrix_length];
cmatrix = *cmatrix_p;
/* Now we fill the matrix by doing a numeric integration approximation
* from -2*std_dev to 2*std_dev, sampling 50 points per pixel.
* We do the bottom half, mirror it to the top half, then compute the
* center point. Otherwise asymmetric quantization errors will occur.
* The formula to integrate is e^-(x^2/2s^2).
*/
/* first we do the top (right) half of matrix */
for (i = matrix_length/2 + 1; i < matrix_length; i++)
{
float base_x = i - (float)floor((float)(matrix_length/2)) - 0.5f;
sum = 0;
for (j = 1; j <= 50; j++)
{
if ( base_x+0.02*j <= radius )
sum += (float)exp (-(base_x+0.02*j)*(base_x+0.02*j) /
(2*std_dev*std_dev));
}
cmatrix[i] = sum/50;
}
/* mirror the thing to the bottom half */
for (i=0; i<=matrix_length/2; i++) {
cmatrix[i] = cmatrix[matrix_length-1-i];
}
/* find center val -- calculate an odd number of quanta to make it symmetric,
* even if the center point is weighted slightly higher than others. */
sum = 0;
for (j=0; j<=50; j++)
{
sum += (float)exp (-(0.5+0.02*j)*(0.5+0.02*j) /
(2*std_dev*std_dev));
}
cmatrix[matrix_length/2] = sum/51;
/* normalize the distribution by scaling the total sum to one */
sum=0;
for (i=0; i<matrix_length; i++) sum += cmatrix[i];
for (i=0; i<matrix_length; i++) cmatrix[i] = cmatrix[i] / sum;
return matrix_length;
}
////////////////////////////////////////////////////////////////////////////////
/* ----------------------- gen_lookup_table ----------------------- */
/* <nipper> generates a lookup table for every possible product of 0-255 and
each value in the convolution matrix. The returned array is
indexed first by matrix position, then by input multiplicand (?)
value.
*/
float* CxImage::gen_lookup_table (float *cmatrix, int cmatrix_length)
{
float* lookup_table = new float[cmatrix_length * 256];
float* lookup_table_p = lookup_table;
float* cmatrix_p = cmatrix;
for (int i=0; i<cmatrix_length; i++)
{
for (int j=0; j<256; j++)
{
*(lookup_table_p++) = *cmatrix_p * (float)j;
}
cmatrix_p++;
}
return lookup_table;
}
////////////////////////////////////////////////////////////////////////////////
/* <nipper> this function is written as if it is blurring a column at a time,
even though it can operate on rows, too. There is no difference
in the processing of the lines, at least to the blur_line function. */
void CxImage::blur_line (float *ctable, float *cmatrix, int cmatrix_length, BYTE* cur_col, BYTE* dest_col, int y, long bytes)
{
float scale;
float sum;
int i=0, j=0;
int row;
int cmatrix_middle = cmatrix_length/2;
float *cmatrix_p;
BYTE *cur_col_p;
BYTE *cur_col_p1;
BYTE *dest_col_p;
float *ctable_p;
/* this first block is the same as the non-optimized version --
* it is only used for very small pictures, so speed isn't a
* big concern.
*/
if (cmatrix_length > y)
{
for (row = 0; row < y ; row++)
{
scale=0;
/* find the scale factor */
for (j = 0; j < y ; j++)
{
/* if the index is in bounds, add it to the scale counter */
if ((j + cmatrix_length/2 - row >= 0) &&
(j + cmatrix_length/2 - row < cmatrix_length))
scale += cmatrix[j + cmatrix_length/2 - row];
}
for (i = 0; i<bytes; i++)
{
sum = 0;
for (j = 0; j < y; j++)
{
if ((j >= row - cmatrix_length/2) &&
(j <= row + cmatrix_length/2))
sum += cur_col[j*bytes + i] * cmatrix[j];
}
dest_col[row*bytes + i] = (BYTE)(0.5f + sum / scale);
}
}
}
else
{
/* for the edge condition, we only use available info and scale to one */
for (row = 0; row < cmatrix_middle; row++)
{
/* find scale factor */
scale=0;
for (j = cmatrix_middle - row; j<cmatrix_length; j++)
scale += cmatrix[j];
for (i = 0; i<bytes; i++)
{
sum = 0;
for (j = cmatrix_middle - row; j<cmatrix_length; j++)
{
sum += cur_col[(row + j-cmatrix_middle)*bytes + i] * cmatrix[j];
}
dest_col[row*bytes + i] = (BYTE)(0.5f + sum / scale);
}
}
/* go through each pixel in each col */
dest_col_p = dest_col + row*bytes;
for (; row < y-cmatrix_middle; row++)
{
cur_col_p = (row - cmatrix_middle) * bytes + cur_col;
for (i = 0; i<bytes; i++)
{
sum = 0;
cmatrix_p = cmatrix;
cur_col_p1 = cur_col_p;
ctable_p = ctable;
for (j = cmatrix_length; j>0; j--)
{
sum += *(ctable_p + *cur_col_p1);
cur_col_p1 += bytes;
ctable_p += 256;
}
cur_col_p++;
*(dest_col_p++) = (BYTE)(0.5f + sum);
}
}
/* for the edge condition , we only use available info, and scale to one */
for (; row < y; row++)
{
/* find scale factor */
scale=0;
for (j = 0; j< y-row + cmatrix_middle; j++)
scale += cmatrix[j];
for (i = 0; i<bytes; i++)
{
sum = 0;
for (j = 0; j<y-row + cmatrix_middle; j++)
{
sum += cur_col[(row + j-cmatrix_middle)*bytes + i] * cmatrix[j];
}
dest_col[row*bytes + i] = (BYTE) (0.5f + sum / scale);
}
}
}
}
////////////////////////////////////////////////////////////////////////////////
/* <nipper> */
bool CxImage::UnsharpMask(float radius /*= 5.0*/, float amount /*= 0.5*/, int threshold /*= 0*/)
{
if (!pDib) return false;
if (!(head.biBitCount == 24 || IsGrayScale()))
return false;
CxImage tmp(*this);
CImageIterator itSrc(this);
CImageIterator itDst(&tmp);
// generate convolution matrix and make sure it's smaller than each dimension
float *cmatrix = NULL;
int cmatrix_length = gen_convolve_matrix(radius, &cmatrix);
// generate lookup table
float *ctable = gen_lookup_table(cmatrix, cmatrix_length);
double dbScaler = 33.3/head.biHeight;
// blur the rows
for (int y=0;y<head.biHeight;y++)
{
if (info.nEscape) break;
info.nProgress = (long)(y*dbScaler);
blur_line(ctable, cmatrix, cmatrix_length, itSrc.GetRow(y), itDst.GetRow(y), head.biWidth, 3);
}
// blur the cols
BYTE* cur_col = new BYTE[head.biHeight*3];
BYTE* dest_col = new BYTE[head.biHeight*3];
dbScaler = 33.3/head.biWidth;
for (int x=0;x<head.biWidth;x++)
{
if (info.nEscape) break;
info.nProgress = (long)(33.3+x*dbScaler);
itSrc.GetCol(cur_col, x);
itDst.GetCol(dest_col, x);
blur_line(ctable, cmatrix, cmatrix_length, cur_col, dest_col, head.biHeight, 3);
itSrc.SetCol(cur_col, x);
itDst.SetCol(dest_col, x);
}
delete [] cur_col;
delete [] dest_col;
delete [] cmatrix;
delete [] ctable;
// these are used for the merging step
int diff;
int value;
dbScaler = 33.3/head.biHeight;
// merge the source and destination (which currently contains
// the blurred version) images
for (y=0;y<head.biHeight;y++)
{
if (info.nEscape) break;
info.nProgress = (long)(66.6+y*dbScaler);
value = 0;
// get source row
BYTE* cur_row = itSrc.GetRow(y);
// get dest row
BYTE* dest_row = itDst.GetRow(y);
// combine the two
for (int u = 0; u < x; u++)
{
for (int v = 0; v < 3; v++)
{
diff = (cur_row[u*3+v] - dest_row[u*3+v]);
// do tresholding
if (abs (2 * diff) < threshold)
diff = 0;
value = int(cur_row[u*3+v] + amount * diff);
if (value < 0) dest_row[u*3+v] =0;
else if (value > 255) dest_row[u*3+v] = 255;
else dest_row[u*3+v] = value;
}
}
}
Transfer(tmp);
return TRUE;
}
////////////////////////////////////////////////////////////////////////////////
bool CxImage::Lut(BYTE* pLut)
{
if (!pDib || !pLut) return false;
RGBQUAD color;
double dbScaler;
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 {
// faster loop for full image
BYTE *iSrc=info.pImage;
for(unsigned long i=0; i < head.biSizeImage ; i++){
*iSrc++ = pLut[*iSrc];
}
return true;
}
dbScaler = 100.0/ymax;
for(long y=ymin; y<ymax; y++){
info.nProgress = (long)(y*dbScaler); //<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);
color.rgbRed = pLut[color.rgbRed];
color.rgbGreen = pLut[color.rgbGreen];
color.rgbBlue = pLut[color.rgbBlue];
SetPixelColor(x,y,color);
}
}
}
#if CXIMAGE_SUPPORT_SELECTION
} else if (pSelection && (head.biBitCount==8) && IsGrayScale()){
long xmin,xmax,ymin,ymax;
xmin = info.rSelectionBox.left; xmax = info.rSelectionBox.right;
ymin = info.rSelectionBox.bottom; ymax = info.rSelectionBox.top;
dbScaler = 100.0/ymax;
for(long y=ymin; y<ymax; y++){
info.nProgress = (long)(y*dbScaler);
for(long x=xmin; x<xmax; x++){
if (SelectionIsInside(x,y))
{
SetPixelIndex(x,y,pLut[GetPixelIndex(x,y)]);
}
}
}
#endif //CXIMAGE_SUPPORT_SELECTION
} else {
for(DWORD j=0; j<head.biClrUsed; j++){
color = GetPaletteColor((BYTE)j);
color.rgbRed = pLut[color.rgbRed];
color.rgbGreen = pLut[color.rgbGreen];
color.rgbBlue = pLut[color.rgbBlue];
SetPaletteColor((BYTE)j,color);
}
}
return true;
}
////////////////////////////////////////////////////////////////////////////////
bool CxImage::Lut(BYTE* pLutR, BYTE* pLutG, BYTE* pLutB, BYTE* pLutA)
{
if (!pDib || !pLutR || !pLutG || !pLutB) return false;
RGBQUAD color;
double dbScaler;
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;
}
dbScaler = 100.0/ymax;
for(long y=ymin; y<ymax; y++){
info.nProgress = (long)(y*dbScaler);
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 = pLutR[color.rgbRed];
color.rgbGreen = pLutG[color.rgbGreen];
color.rgbBlue = pLutB[color.rgbBlue];
if (pLutA) color.rgbReserved=pLutA[color.rgbReserved];
SetPixelColor(x,y,color,true);
}
}
}
} else {
for(DWORD j=0; j<head.biClrUsed; j++){
color = GetPaletteColor((BYTE)j);
color.rgbRed = pLutR[color.rgbRed];
color.rgbGreen = pLutG[color.rgbGreen];
color.rgbBlue = pLutB[color.rgbBlue];
SetPaletteColor((BYTE)j,color);
}
}
return true;
}
////////////////////////////////////////////////////////////////////////////////
/*bool CxImage::FloodFill(int x, int y, RGBQUAD FillColor)
{
//<JDL>
if (!pDib) return false;
FloodFill2(x,y,GetPixelColor(x,y),FillColor);
return true;
}
////////////////////////////////////////////////////////////////////////////////
void CxImage::FloodFill2(int x, int y, RGBQUAD old_color, RGBQUAD new_color)
{
// Fill in the actual pixels.
// Function steps recursively until it finds borders (color that is not old_color)
if (!IsInside(x,y)) return;
RGBQUAD r = GetPixelColor(x,y);
COLORREF cr = RGB(r.rgbRed,r.rgbGreen,r.rgbBlue);
if(cr == RGB(old_color.rgbRed,old_color.rgbGreen,old_color.rgbBlue)
&& cr != RGB(new_color.rgbRed,new_color.rgbGreen,new_color.rgbBlue) ) {
// the above if statement, after && is there to prevent
// stack overflows. The program will continue to find
// colors if you flood-fill an entire region (entire picture)
SetPixelColor(x,y,new_color);
FloodFill2((x+1),y,old_color,new_color);
FloodFill2((x-1),y,old_color,new_color);
FloodFill2(x,(y+1),old_color,new_color);
FloodFill2(x,(y-1),old_color,new_color);
}
}*/
///////////////////////////////////////////////////////////////////////////////
#endif //CXIMAGE_SUPPORT_DSP
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -