高斯模糊函数的升级版本,带剪裁区域。
函数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); }
一下是剪裁效果图:
文章发布于 2014-08-01 14:53:35 CSDN,现转博客园。
sdragonx https://github.com/sdragonx