canny边缘检测C\C++实现

来源:互联网 发布:液晶电视怎样连接网络 编辑:程序博客网 时间:2024/06/08 06:18

这个是主函数

#define PI              3.1415926#define EDGE_VALUE      235#define NON_EDGE_VALUE  16typedef unsigned char uint8;enum {HOR = 0, VER, POS45, NEG45};const int row_table[4] = {0, 1, 1, 1};const int col_table[4] = {1, 0, 1, -1};void CannyEdge(const uint8* img, int width, int height, int pitch, int low_thr, int high_thr, uint8 *edge){uint8 *lpf_img = new uint8[pitch * height];int *grad = new int[pitch * height];int *max_grad = new int[pitch * height];GaussianFilter(img, width, height, pitch, lpf_img);CalcGrad(lpf_img, width, height, pitch, grad);SuppressNonMax(grad, width, height, pitch, max_grad);GetEdge(max_grad, width, height, pitch, low_thr, high_thr, edge);delete [] lpf_img;delete [] grad;delete [] max_grad;}
对图像做高斯低通滤波,这里用一个7tap的滤波器,滤波器尺寸可以根据需要做调整

二维高斯滤波可以分解成两个一维的高斯滤波,先做水平滤波,再做垂直滤波

void GaussianFilter(const uint8* srcp, int width, int height, int pitch, uint8 *dstp){int filter[7] = {1, 6, 19, 27, 19, 6, 1};int weight_sum = 79;int *fltp = filter + 3;uint8 *midp = new uint8[pitch * height];memcpy(dstp, srcp, pitch * height);memcpy(midp, srcp, pitch * height);// hor filterfor(int ver = 0; ver < height; ++ver) {for(int hor = radius; hor < width - radius; ++hor) {int sum = 0;for(int x = -radius; x <= radius; ++x) {sum += srcp[ver * pitch + hor + x] * fltp[x];}midp[ver * pitch + hor] = sum / weight_sum;}}// ver filterfor(int ver = radius; ver < height - radius; ++ver) {for(int hor = 0; hor < width; ++hor) {int sum = 0;for(int y = -radius; y <= radius; ++y) {sum += midp[(ver + y) * pitch + hor] * fltp[y];}dstp[ver * pitch + hor] = sum / weight_sum;}}delete [] midp;}

计算梯度值和法线方向

void CalcGrad(uint8 *img, int width, int height, int pitch, int *grad){const double tan225 = tan(PI / 8);const double tan675 = tan(PI * 3 / 8);memset((void*)grad, 0, pitch * height * sizeof(int));for(int ver = 0; ver < height - 1; ++ver) {for(int hor = 0; hor < width - 1; ++hor) {int offset = ver * pitch + hor;int diff_x = img[offset + 1] - img[offset];int diff_y = img[offset + pitch] - img[offset];int dir;double tanv = diff_y / (diff_x + 0.0001);if(tanv < tan225 && tanv >= -tan225) dir = HOR;else if(tanv < tan675 && tanv >= tan225)  dir = POS45;else if(tanv < -tan675 || tanv >= tan675) dir = VER;else dir = NEG45;int gradient = (int)sqrt(double(diff_x * diff_x + diff_y * diff_y) );grad[offset] = (gradient << 2) + dir; // 低2位放方向,高位放梯度值}}}
非最大值抑制

void SuppressNonMax(int *grad, int width, int height, int pitch, int *max_grad){memset((void*)max_grad, 0, pitch * height * sizeof(int));for(int ver = 1; ver < height - 1; ++ver) {for(int hor = 1; hor < width - 1; ++hor) {int offset = ver * pitch + hor;int dir = grad[offset] & 0x3;int row = row_table[dir];int col = col_table[dir];int offset1 = (ver + row) * pitch + hor + col;int offset2 = (ver - row) * pitch + hor - col;int grad0 = grad[offset] >> 2;int grad1 = grad[offset1] >> 2;int grad2 = grad[offset2] >> 2;if(grad0 >= grad1 && grad0 >= grad2) {max_grad[offset] = grad0;}}}}
利用双阈值得到边缘,连接线

阈值可以根据需要进行设置,这里设置low_thr = 7,high_thr = 14

void GetEdge(int *max_grad, int width, int height, int pitch, int low_thres, int high_thres, uint8 *edge){memset(edge, NON_EDGE_VALUE, pitch * height);for(int ver = 1; ver < height-1; ++ver) {for(int hor = 1; hor < width-1; ++hor) {int offset = ver * pitch + hor;if(max_grad[offset] >= high_thres) { edge[offset] = EDGE_VALUE;}else if(max_grad[offset] >= low_thres) {for(int row = -1; row <= 1; ++row) {for(int col = -1; col <= 1; ++col) {if(max_grad[(ver + row) * pitch + hor + col] >= high_thres) {edge[offset] = EDGE_VALUE;break;}}}}}}}


左边是原图,右边是得到的边缘


0 2
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 华师附小不搬了怎么办 健康证快到期了怎么办 老公想去日本打工怎么办 学生没有资产证明怎么办日本签证 在读证明学校不按模版怎么办 办日本签证没有户口本怎么办 日本大学留级续签失败怎么办 法国签证递交时间太晚怎么办 日本留学生签证更新拒签怎么办 永驻拒签了我该怎么办 越南签证拒签了怎么办 l1签证续签被拒怎么办 去日本跟团签证怎么办 手表里指针掉了怎么办 北京居住证过期半年了怎么办 居住证明居委会不盖章怎么办 小孩感冒鼻子不通气怎么办 1岁宝宝喉咙痰多怎么办 两个月喉咙有痰怎么办 10个月咳嗽有痰怎么办 昆山初级会计审核没有居住证怎么办 初级会计审核没有居住证怎么办 哈尔滨原房主户口不牵走怎么办 在亲戚家住怎么办居住证 按揭车押金不退怎么办 护照到期韩国签证没到期怎么办 日本签证银行流水不够怎么办 想去日本cm签证怎么办 护照在签让那里怎么办 泰国出境单丢了怎么办 居住证到期了忘记续签了怎么办 贵州交警app忘记密码怎么办 科一第一次没过怎么办 社保转移时学历信息不符怎么办 天津摇号密码忘了怎么办 摇号账号密码忘了怎么办 京牌车去外地没有保险标怎么办 车子被扣12分怎么办 不在北京工作了社保怎么办 5年身份证到期了怎么办 c1驾照剩1分怎么办