高斯模糊函数的升级版本,带剪裁区域。
函数check_rect()是处理剪裁区域矩形。如果不打算剪裁,只需要设置left, top, right, bottom都为0就可以了;另外位图的存储格式是上下反转的,如果正常剪裁的话,只需要设置bottom为 -bottom即可。
bool check_rect(int width, int height, int& left, int& top, int& right, int& bottom)
{
if(!left && !top && !right && !bottom)
{//不进行剪裁
left = 0;
top = 0;
right = width;
bottom = height;
return true;
}
if(!(right-left) || !(bottom-top))
{//0面积矩形
return false;
}
if(bottom <= 0)
{//反转上下
int h = -bottom - top;
bottom = height - top;
top = bottom - h;
}
if(right <= 0)
{//反转左右
int w = -right - left;
right = width - left;
left = right - w;
}
left = max(left, 0);
top = max(top, 0);
right = min(right, width);
bottom = min(bottom, height);
return true;
}
//快速高斯模糊函数,by sdragonx 2014-08-01
int gauss_blur(
byte_t* image, //位图数据
int linebytes, //位图行字节数,BMP数据在windows中是4字节对齐的。否则在处理非二次幂的图像时会有偏差
int width, //位图宽度
int height, //位图高度
int cbyte, //颜色通道数量
int left, //滤镜剪裁区域,都为0是不剪裁
int top,
int right,
int bottom,
float sigma //高斯系数
)
{
int x = 0, y = 0, n = 0;
int channel = 0;
int srcline = 0, dstline = 0;
int channelsize = 0;
int bufsize = 0;
float *w1 = NULL, *w2 = NULL, *imgbuf = NULL;
int time = 0;
#if defined(_INC_WINDOWS)
time = GetTickCount();
#elif defined(_CLOCK_T)
time = clock();
#endif
if(!check_rect(width, height, left, top, right, bottom))
{
return -1;
}
//剪裁宽度和高度
int rc_width = right - left;
int rc_height = bottom - top;
channelsize = rc_width*rc_height;
bufsize = rc_width > rc_height ? rc_width + 4 : rc_height + 4;
w1 = (float*)malloc(bufsize * sizeof(float));
if(!w1)
{
return -1;
}
w2 = (float*)malloc(bufsize * sizeof(float));
if(!w2)
{
free(w1);
return -1;
}
imgbuf = (float*)malloc(channelsize * sizeof(float));
if(!imgbuf)
{
free(w1);
free(w2);
return -1;
}
//----------------计算高斯核---------------------------------------//
float q = 0;
float q2 = 0, q3 = 0;
float b0 = 0, b1 = 0, b2 = 0, b3 = 0;
float B = 0;
if (sigma >= 2.5f)
{
q = 0.98711f * sigma - 0.96330f;
}
else if ((sigma >= 0.5f) && (sigma < 2.5f))
{
q = 3.97156f - 4.14554f * (float) sqrt (1.0f - 0.26891f * sigma);
}
else
{
q = 0.1147705018520355224609375f;
}
q2 = q * q;
q3 = q * q2;
b0 = (1.57825f+ (2.44413f*q)+(1.4281f *q2)+(0.422205f*q3));
b1 = ( (2.44413f*q)+(2.85619f*q2)+(1.26661f* q3));
b2 = ( -((1.4281f*q2)+(1.26661f* q3)));
b3 = ( (0.422205f*q3));
B = 1.0f-((b1+b2+b3)/b0);
b1 /= b0;
b2 /= b0;
b3 /= b0;
//----------------计算高斯核结束---------------------------------------//
// 处理图像的多个通道
for (channel = 0; channel < cbyte; ++channel)
{
// 获取一个通道的所有像素值,并预处理
srcline = top*linebytes + left*cbyte + channel;
dstline = 0;
for(y=0; y<rc_height; ++y, srcline+=linebytes, dstline+=rc_width)
{
for(x=0, n=0; x<rc_width; ++x, n+=cbyte)
{
(imgbuf+dstline)[x] = float((image+srcline)[n]);
}
}
for (int x=0; x<rc_width; ++x)
{//横向处理
w1[0] = (imgbuf + x)[0];
w1[1] = (imgbuf + x)[0];
w1[2] = (imgbuf + x)[0];
for (y=0, n=0; y<rc_height; ++y, n+=rc_width)
{
w1[y+3] = B*(imgbuf + x)[n] + (b1*w1[y+2] + b2*w1[y+1] + b3*w1[y+0]);
}
w2[rc_height+0]= w1[rc_height+2];
w2[rc_height+1]= w1[rc_height+1];
w2[rc_height+2]= w1[rc_height+0];
for (int y=rc_height-1, n=y*rc_width; y>=0; --y, n-=rc_width)
{
(imgbuf + x)[n] = w2[y] = B*w1[y+3] + (b1*w2[y+1] + b2*w2[y+2] + b3*w2[y+3]);
}
}//横向处理
srcline = 0;
dstline = top*linebytes + left*cbyte + channel;
for (y=0; y<rc_height; ++y, srcline+=rc_width, dstline+=linebytes)
{//纵向处理
//取当前行数据
w1[0] = (imgbuf + srcline)[0];
w1[1] = (imgbuf + srcline)[0];
w1[2] = (imgbuf + srcline)[0];
//正方向横向处理3个点的数据
for (x=0; x<rc_width; ++x)
{
w1[x+3] = B*(imgbuf + srcline)[x] + (b1*w1[x+2] + b2*w1[x+1] + b3*w1[x+0]);
}
w2[rc_width+0]= w1[rc_width+2];
w2[rc_width+1]= w1[rc_width+1];
w2[rc_width+2]= w1[rc_width+0];
//反方向处理
for (x=rc_width-1, n=x*cbyte; x>=0; --x, n-=cbyte)
{
//(imgbuf + srcline)[x] = w2[x] = B*w1[x+3] + (b1*w2[x+1] + b2*w2[x+2] + b3*w2[x+3]);
(image + dstline)[n] = w2[x] = B*w1[x+3] + (b1*w2[x+1] + b2*w2[x+2] + b3*w2[x+3]);
}
}//纵向处理
/*
//存储处理完毕的通道
for(int y=0; y<rc_height; ++y)
{
int dstline = (y+top)*linebytes + left*cbyte;
int srcline = y*rc_width;
for (int x=0, n=channel; x<rc_width; ++x, n+=cbyte)
{
(image + dstline)[n] = (imgbuf + srcline)[x];
//byte_edge((imgbuf + srcline)[x]);
}
}//存储循环
//*/
}//通道循环
free (w1);
w1 = NULL;
free (w2);
w2 = NULL;
free(imgbuf);
imgbuf = NULL;
#if defined(_INC_WINDOWS)
return GetTickCount() - time;
#elif defined(_CLOCK_T)
return clock() - time;
#else
return 0;
#endif
}
int gauss_blur(
byte_t* image, //位图数据
int linebytes, //位图行字节数,BMP数据在windows中是4字节对齐的。否则在处理非二次幂的图像时会有偏差
int width, //位图宽度
int height, //位图高度
int cbyte, //颜色通道数量
float sigma //高斯系数
)
{
return gauss_blur(image, linebytes, width, height, cbyte, 0, 0, 0, 0, sigma);
}
一下是剪裁效果图: