前言:

Canny边缘检测使用了Sobel算子,计算dx和dy两个方向,对于特定方向的边缘检测,可以作少量修改。

代码:

计算特定方向上的边缘

     void CannyOrient( cv::Mat &_src, cv::Mat &_dst,cv::Point2f  &seed,double low_thresh, double high_thresh,int aperture_size, bool L2gradient ){low_thresh  = 0; high_thresh = 1;//使用特定种子方向上的点寻找方向梯度FindBestGradient( _src, _dst,seed,aperture_size,  L2gradient );//二值化,生成边缘图像//计算直方图,寻找极大极小边缘点,根据波峰和波谷int hh[256];memset(hh,0,256*sizeof(int ) );int minV = 255;int maxV =   0;cvWish::CalHist(_dst,1,minV,maxV,hh);cv::Mat canvas( 600 ,256*4, CV_8U, 1);for(int i=0;i< 256; ++i){int Pos = ( (int)(hh[i]) ) %( canvas.rows);canvas.at<uchar>( canvas.rows - Pos-1,i*4 ) =255;}cv::imshow("canvas",canvas);cv::waitKey(1);return;}

寻找特定边缘:

     //在种子点方向上寻找合适的梯度,用于寻找边缘void FindBestGradient( cv::Mat &_src, cv::Mat &_dst,cv::Point2f  &seed,int aperture_size, bool L2gradient ){//角度矩阵cv::Mat df = cv::Mat::zeros( _src.rows,_src.cols, CV_32FC1 );//梯度矩阵cv::Mat dg = cv::Mat::zeros( _src.rows,_src.cols, CV_32FC1 );//原始图像cv::Mat ds = _src.clone();//目标图像 uchar型cv::Mat dd = _src.clone();//1.根据角度计算梯度//得到梯度矩阵//使用N*1的算子int n = aperture_size;//必须为奇数//对每个柱进行初始化//搜索柱:在射线方向上搜索l_Search 个像素;宽度为 int l_Search = n;int w_Search = 1;std::vector<std::vector<std::pair<cv::Point ,float>  >  >  beam;beam.resize( l_Search );for (int i=0;i< beam.size();++i){beam[i].resize(w_Search);}//初始化柱//设定系数//生成模板double gap = 2.0/ (n-1);std::vector< double > mask(l_Search);for (int i=0;i< mask.size();++i){mask[i] = -1 + i*gap ;//std::cout<< "  mask[i]:" << mask[i] ;}//2.生成角度图像//在射线方向上寻找//方法不是太好,但是没有寻找到简单有效的方法for ( int y=0 ;y< ds.rows;++y ){float* ptr = (float*)( df.data + y * df.step);for ( int x=0; x< ds.cols; ++x ){//计算角度//float ag = (float)(cvWish::cosCv(seed,cv::Point2f( x,y ) ) );//df.at<float>(y ,x) = (float)(cvWish::cosCv(seed,cv::Point2f( x,y ) ) );*ptr = (float)(cvWish::cosCv(seed,cv::Point2f( x,y ) ) );++ptr;}}//计算差值-导数for (int y=0 ;y< ds.rows;++y){float* pf = (float*)( df.data + y * df.step);float* pg = (float*)( dg.data + y * dg.step);unsigned char* pd = (unsigned char*)( dd.data + y * dd.step);for (int x=0;x< ds.cols;++x ){//计算角度//cvWish::BeamInit(l_Search,w_Search,cv::Point2f( x,y ),df.at<float >(y,x),beam,0);//0表示从中部开始搜索cvWish::BeamInit(l_Search,w_Search,cv::Point2f( x,y ), *pf ,beam,0);//0表示从中部开始搜索cvWish::BeamNormal(dg.cols, dg.rows , beam);#ifdef SHOW_TEMPint ii =0;for (;ii<beam.size()  ;++ii){int j=0;for (;j<beam[ii].size()  ;++j){//canvasSrc.at<cv::Vec3b>(beam[ii][j].first.y ,beam[ii][j].first.x )[0] =255 ;//canvasSrc.at<cv::Vec3b>(beam[ii][j].first.y ,beam[ii][j].first.x )[1] =0 ;//canvasSrc.at<cv::Vec3b>(beam[ii][j].first.y ,beam[ii][j].first.x )[2] =0 ;}  }//cv::imshow("edgeEvolution",canvasSrc);//cv::waitKey(1);
#endif//dg.at<float >(y,x)= 0;//for ( int k =0; k< l_Search; ++k ){//  dg.at<float >(y,x) += (float)( mask[k]* ds.at<unsigned char>(beam[k][0].first.y,beam[k][0].first.x)  );//}//int s = abs ( ( (int)(dg.at<float >(y,x) ) )%255 ) ;//dd.at<unsigned char >( y, x ) =(unsigned char) (s);*pg = 0;for ( int k =0; k< l_Search; ++k ){*pg += (float)( mask[k]* ds.at<unsigned char>(beam[k][0].first.y,beam[k][0].first.x)  );}int s = abs ( ( (int)(*pg ) )%255 ) ;*pd = (unsigned char) (s);++pf;++pg;++pd;}}ds.copyTo(_dst);return;}

辅助代码:

 //功能: 初始化任意角度的一个方柱,大小已经确定:l_Search*w_Search//沿射线方向 寻找 一个柱//默认 参数 0 从中部开始//参数 1代表 从底部开始;参数 2代表从top开始void BeamInit( const int l_Search, const int w_Search,const cv::Point2f &pc, const float angle,std::vector<std::vector<std::pair<cv::Point ,float> >  >  &beam,const int bottomOrTop ){assert (l_Search%2 >0);//确定是奇数assert (w_Search%2 >0);assert ( beam.size() == l_Search);//不改变大小assert ( beam[0].size() == w_Search);//往角度方向延长cv::Point2f  ps(0,0);const float angleVert = angle+ PI_1_2 < PI_4_2?  ( angle+ PI_1_2): ( angle+ PI_1_2)- PI_4_2;cv::Point2f  pIdx(0,0);switch (bottomOrTop){case 0://往底部移动ps.y = pc.y-(0- sin(angle)*l_Search/2);ps.x = pc.x-(0- cos(angle)*l_Search/2);//往左边移动ps.y -= 0- sin(angleVert)*w_Search/2;ps.x -= 0- cos(angleVert)*w_Search/2;//对每个点计算for (int i=0;i< beam.size();++i ){pIdx.y = ps.y +(0- sin(angle)*i);pIdx.x = ps.x +(0- cos(angle)*i);for (int j=0;j< beam[i].size();++j ){beam[i][j].first.y = pIdx.y +(0- sin(angleVert)*j);beam[i][j].first.x = pIdx.x +(0- cos(angleVert)*j);}}//int iwCenter = w_Search>>1;//int ilCenter = l_Search>>1;先算十字中间//for ( int i=0; i< beam.size(); ++i )//{// beam[i][iwCenter].first.x = 0- cos(angle)*i;;//}break;case 1://往底部移动//默认底部,因此不需要移动ps.y = pc.y;//-(0- sin(angle)*l_Search/2);ps.x = pc.x;//-(0- cos(angle)*l_Search/2);//往左边移动ps.y -= 0- sin(angleVert)*w_Search/2;ps.x -= 0- cos(angleVert)*w_Search/2;//对每个点计算for (int i=0;i< beam.size();++i ){pIdx.y = ps.y +(0+ sin(angle)*i);pIdx.x = ps.x +(0+ cos(angle)*i);for (int j=0;j< beam[i].size();++j ){beam[i][j].first.y = pIdx.y +(0- sin(angleVert)*j);beam[i][j].first.x = pIdx.x +(0- cos(angleVert)*j);}}break;case 2://往底部移动//默认顶部,因此需要移动到底ps.y = pc.y -(0- sin(angle)*l_Search);ps.x = pc.x -(0- cos(angle)*l_Search);//往左边移动ps.y -= 0- sin(angleVert)*w_Search/2;ps.x -= 0- cos(angleVert)*w_Search/2;//对每个点计算for (int i=0;i< beam.size();++i ){pIdx.y = ps.y +(0- sin(angle)*i);pIdx.x = ps.x +(0- cos(angle)*i);for (int j=0;j< beam[i].size();++j ){beam[i][j].first.y = pIdx.y +(0- sin(angleVert)*j);beam[i][j].first.x = pIdx.x +(0- cos(angleVert)*j);}}break;default://和case 0 相同,默认设定为中间位置//往底部移动ps.y = pc.y-(0- sin(angle)*l_Search/2);ps.x = pc.x-(0- cos(angle)*l_Search/2);//往左边移动ps.y -= 0- sin(angleVert)*w_Search/2;ps.x -= 0- cos(angleVert)*w_Search/2;//对每个点计算for (int i=0;i< beam.size();++i ){pIdx.y = ps.y +(0- sin(angle)*i);pIdx.x = ps.x +(0- cos(angle)*i);for (int j=0;j< beam[i].size();++j ){beam[i][j].first.y = pIdx.y +(0- sin(angleVert)*j);beam[i][j].first.x = pIdx.x +(0- cos(angleVert)*j);}}break;}return;}
 //对柱规整,使其不超出边界void BeamNormal( const int width ,const int height ,std::vector<std::vector<std::pair<cv::Point ,float> >  >  &beam){int w = width  -1;int h = height -1;//对每个点 sfor ( int i=0;i< beam.size();++i ){for (int j=0;j< beam[i].size();++j ){if (beam[i][j].first.x < 0 ){beam[i][j].first.x = 0;}if (beam[i][j].first.y < 0 ){beam[i][j].first.y = 0;}if (beam[i][j].first.x >w ){beam[i][j].first.x = w;}if (beam[i][j].first.y > h ){beam[i][j].first.y = h;}}}return;}

代码效果:

                                        

Sobel算子取代:基于特定点方向的canny边缘检测相关推荐

  1. candy算子python_Python-计算机视觉中的Canny边缘检测方法

    今天的想法是用Canny边缘检测算法,建立一种可以勾画出图像上任何物体的边缘的算法. 首先,我们来描述一下Canny边缘检测器:Canny边缘检测算子是一种边缘检测算子,它采用多级算法检测图像中广泛的 ...

  2. OpenCV_08 边缘检测:Sobel检测算子+Laplacian算子+Canny边缘检测

    1 原理 边缘检测是图像处理和计算机视觉中的基本问题,边缘检测的目的是标识数字图像中亮度变化明显的点.图像属性中的显著变化通常反映了属性的重要事件和变化.边缘的表现形式如下图所示: 图像边缘检测大幅度 ...

  3. 差分近似图像导数算子之Sobel算子

    背景引言 图像处理中,一个最基本并且最重要的卷积就是导数的计算,一般用来表达微分最常用的操作是Sobel算子,可以包含任意阶的微分以及融合偏导.主要用作为边缘检测.在技术上,它是一离散性差分算子,用来 ...

  4. 【CV】Sobel算子简介

    引言 Sobel算子是一种常用的边缘检测算法,是一种离散性差分算子,用差分近似代替梯度.对x求1阶差分用来检测竖直边缘,同样的对y求1阶差分用来检测水平边缘. sobel算子对垂直和水平方向上的排列表 ...

  5. sobel算子_OpenCV图像处理专栏十八 | 手动构造Sobel算子完成边缘检测

    1. 前言 众所周知,在传统的图像边缘检测算法中,最常用的一种算法是利用Sobel算子完成的.Sobel算子一共有 个,一个是检测水平边缘的算子,另一个是检测垂直边缘的算子. 2. Sobel算子优缺 ...

  6. OpenCV-Python教程(6)(7)(8): Sobel算子 Laplacian算子 Canny边缘检测

    OpenCV-Python教程(6.Sobel算子) 本篇文章介绍如何用OpenCV-Python来使用Sobel算子. 提示: 转载请详细注明原作者及出处,谢谢! 本文介绍使用OpenCV-Pyth ...

  7. opencv-python图像处理 ----图像梯度、Sobel算子

    一.图像的梯度处理 1.Sobel算子 梯度可以按照x方向或者y方向求梯度,其实就是在看像素点的差异变化情况,比如黑白物体的交界,其像素值变化差异是非常大的. 求梯度计算使用的函数就叫做Sobel算子 ...

  8. OpenCV 边缘检测之Sobel算子

    文章目录 Sobel算子(索贝尔算子) Sobel算子定义: Sobel算子作用: Sobel卷积因子 Sobel卷积计算公式: 相关API Sobel() convertScaleAbs() add ...

  9. 应用sobel算子算法c语言,Canny算子与Sobel算子求图像边缘的C代码实现

    *Canny算子与Sobel算子求图像边缘笔记* 1.Canny求边缘算法原理简述 Canny检测边缘主要分为以下 四个算法步骤: A:噪声去除 canny算子是通过对每个像素点求一阶导数来找到梯度明 ...

最新文章

  1. xlrd,xlwt模塊
  2. boost::math::quadrature::tanh_sinh用法的测试程序
  3. 江苏电信:SOC建设介绍
  4. Google CVPR 2019最新成果!用神经架构搜索实现更好的目标检测
  5. java两种不同单例模式_关于Java里的两种单例模式
  6. ASP.NET前台table通过Ajax获取绑定后台查询的json数据
  7. java中输出5个数_编写一个程序,要求用户输入5个数字,并输出这些数字中最大的数字和这些数字中最小的数字...
  8. 月薪14.5K...转行测试还是考公考研?律师小哥是这样选择的...
  9. .net 怎么在控制器action中返回一个试图_ASP.NET Core MVC/WebAPI中另辟蹊径的全局统一异常处理方式...
  10. 神泣服务器维护公告,《神泣》官方网站—创天互娱
  11. Cherno OpenGL 教程
  12. java方法建议不超过多少行,Java方法不应超过15行
  13. 中职学校计算机课听课记录表,中职听课记录
  14. Kubernetes 安全容器技术 kata gvisor
  15. 2017春节~人生智慧箴言
  16. 拉链表断链、交叉链判断及处理方式
  17. 塑源码是什么_源码是什么意思啊
  18. 14款超时尚的HTML5时钟动画
  19. 转:SWOT分析法与职业生涯规划
  20. 我不敢再哭了,因为我怕自己成为职场上的杨超越

热门文章

  1. 开发者论坛一周精粹(第二十期) :晒往期云栖大会的照片或感想,赢2017杭州云栖大会门票...
  2. 去广告,原来可以如此简单——ADSafe 3.5.4.520 精简版
  3. 怎样在Ubuntu系统安装可用的QQ
  4. 2/2 pymysql:基础操作总结
  5. 用 chown 和 chmod 修改目录所属用户及权限
  6. nginx proxy_pass末尾神奇的/
  7. CNN-2: AlexNet 卷积神经网络模型
  8. 网络编程—网络基础概览、socket,TCP/UDP协议
  9. MySql 事务+异常处理+异常抛出
  10. EJS脚本中AES应用