使用切线方法,对切线方向上的边缘进行强化:

参考连接:图像锐化和边缘检测

代码:

		//在种子点方向上寻找合适的梯度,用于寻找边缘
//对low_Gray, high_gray之间的点寻找边缘
void FindBestGradient(
cv::Mat &_src, cv::Mat &_dst,
cv::Point2f &seed,
float low_Gray,
float high_gray,
int aperture_size, bool oPenEnhence )
{
//角度矩阵
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 ;
} //2.生成角度图像
//在射线方向上寻找//方法不是太好,但是没有寻找到简单有效的方法
for ( int y=0 ;y< ds.rows;++y )
{
float* ptr = (float*)( df.data + y * df.step);
unsigned char* pS = ( unsigned char* )( ds.data + y * ds.step);
for ( int x=0; x< ds.cols; ++x )
{
//计算角度
if ( (int)(*pS) > low_Gray && (int)(*pS) <high_gray )
{
*ptr = (float)(cvWish::cosCv(seed,cv::Point2f( x,y ) ) );
}
else
{
*ptr = 0.00000000000f;
}
++ptr;
++pS;
}
} //计算差值-导数
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 )
{
//计算角度
if ( abs((float)(*pf)) > 0.00000001 )
{
//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); *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);
}
else
{
*pd = (unsigned char) (0);
} ++pf;
++pg;
++pd;
}
} cv::Mat edgeMat = dd;
cv::Mat angleMat= df;
int maskSize = 5;
if ( oPenEnhence )
{
int num = 1;
for (int i=0;i< num;++i)
{
EnhanceEdgeByTangent( edgeMat ,angleMat, maskSize);
} }
else
{
}
_dst = edgeMat.clone();
return;
}

边缘强化函数:

//使用边缘增强--沿切线方向增强
//方向性,边缘限制
void EnhanceEdgeByTangent( cv::Mat &edgeMat ,cv::Mat &angleMat, int maskSize)
{
cv::Mat ds = edgeMat;
cv::Mat dd = edgeMat.clone(); cv::Mat df = angleMat;
cv::Mat dg = angleMat.clone();//导数图,最终转化为 灰度图 dd const int l_Search = maskSize;
const 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/ ( l_Search - 1);
std::vector< double > mask(l_Search);
for (int i=0;i< mask.size();++i)
{
mask[i] =abs( 1- abs( -1 + i*gap ) );
} //强化边缘
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 )
{
//计算角度
if ( abs((float)(*pf)) > 0.00000001 )
{
float angle = *pf + PI_1_2 ;//切线方向,加 PI_1_2
angle = angle>=PI_4_2? angle - PI_4_2:angle; cvWish::BeamInit( l_Search, w_Search, cv::Point2f( x,y ), angle , beam, 0 );
cvWish::BeamNormal(dg.cols, dg.rows , beam); *pg = 0;
const int gl= ds.at<unsigned char>(y,x) ;//当前像素值
int vvv = dd.at<unsigned char>(y,x);
for ( int k =0; k< l_Search; ++k ){
vvv += gl* mask[k];
}
if ( vvv>255 )
{
vvv=255 ;
}
dd.at<unsigned char>(y,x) = vvv; //*pd = (unsigned char) (s);
}
else
{
*pd = (unsigned char) (0);
}
++pf;
++pg;
++pd;
}
} edgeMat = dd.clone();
return ;
}

图片效果:

OpenCV : 基于切线方向的边缘增强算法的更多相关文章

  1. opencv基于PCA降维算法的人脸识别

    opencv基于PCA降维算法的人脸识别(att_faces) 一.数据提取与处理 # 导入所需模块 import matplotlib.pyplot as plt import numpy as n ...

  2. JavaScript基于时间的动画算法

    转自:https://segmentfault.com/a/1190000002416071 前言 前段时间无聊或有聊地做了几个移动端的HTML5游戏.放在不同的移动端平台上进行测试后有了诡异的发现, ...

  3. 最小生成树--Prim算法,基于优先队列的Prim算法,Kruskal算法,Boruvka算法,“等价类”UnionFind

    最小支撑树树--Prim算法,基于优先队列的Prim算法,Kruskal算法,Boruvka算法,“等价类”UnionFind 最小支撑树树 前几节中介绍的算法都是针对无权图的,本节将介绍带权图的最小 ...

  4. mahout入门指南之基于mahout的itembased算法

    基于mahout的itembased算法 事实上mahout分布式上仅仅是实现了部分算法.比方推荐算法中Item-based和slopone都有hadoop实现和单机版实现,User-based没有分 ...

  5. 基于ReliefF和K-means算法的医学应用实例

    基于ReliefF和K-means算法的医学应用实例 数据挖掘方法的提出,让人们有能力最终认识数据的真正价值,即蕴藏在数据中的信息和知识.数据挖掘 (DataMiriing),指的是从大型数据库或数据 ...

  6. OpenCV学习(20) grabcut分割算法

    http://www.cnblogs.com/mikewolf2002/p/3330390.html OpenCV学习(20) grabcut分割算法 在OpenCV中,实现了grabcut分割算法, ...

  7. 大数据算法->推荐系统常用算法之基于内容的推荐系统算法

    港真,自己一直非常希望做算法工程师,所以自己现在开始对现在常用的大数据算法进行不断地学习,今天了解到的算法,就是我们生活中无处不在的推荐系统算法. 其实,向别人推荐商品是一个很常见的现象,比如我用了一 ...

  8. 基于FPGA的Cordic算法实现

    CORDIC(Coordinate Rotation Digital Computer)算法即坐标旋转数字计算方法,是J.D.Volder1于1959年首次提出,主要用于三角函数.双曲线.指数.对数的 ...

  9. 基于Twitter的Snowflake算法实现分布式高效有序ID生产黑科技(无懈可击)

    参考美团文档:https://tech.meituan.com/2017/04/21/mt-leaf.html Twitter-Snowflake算法产生的背景相当简单,为了满足Twitter每秒上万 ...

随机推荐

  1. ES6的let和var声明变量的区别

    关于let的描述 let允许你声明一个作用域被限制在块级中的变量.语句或者表达式.与var关键字不同的是,它声明的变量只能是全局或者整个函数块的. 作用域规则 let声明的变量只在其声明的块或子块中可 ...

  2. [TS-A1489][2013中国国家集训队第二次作业]抽奖[概率dp]

    概率dp第一题,开始根本没搞懂,后来看了09年汤可因论文才基本搞懂,关键就是递推的时候做差比较一下,考虑新加入的情况对期望值的贡献,然后推推公式(好像还是不太会推qaq...) #include &l ...

  3. [Poj2112][USACO2003 US OPEN] Optimal Milking [网络流,最大流][Dinic+当前弧优化]

    题意:有K个挤奶机编号1~K,有C只奶牛编号(K+1)~(C+K),每个挤奶机之多能挤M头牛,现在让奶牛走到挤奶机处,求奶牛所走的最长的一条边至少是多少. 题解:从起点向挤奶机连边,容量为M,从挤奶机 ...

  4. SQL Server 日志

    http://www.cnblogs.com/CareySon/category/354290.html http://blog.csdn.net/tjvictor/article/details/5 ...

  5. HDU 4891 The Great Pan (字符串处理)

    题目链接:HDU 4891 The Great Pan 求一串字符有多少种不同的意思,当中关心'{','}'之间的'|'. 和'$','$'之间的空格,连续N个空格算N+1种. AC代码: #incl ...

  6. array_change_key_case()

    定义和用法 array_change_key_case() 函数将指定数组的所有的键进行大小写转换. 如果数组的键(索引)为数字则不发生变化.如果未提供第二个参数,则默认转换为小写. 语法 array ...

  7. bzoj1087【SCOI2005】互不侵犯King

    1087: [SCOI2005]互不侵犯King Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 2405  Solved: 1413 [Submit ...

  8. 基于Windows Azure 搭建基于SharePoint 2010 Intranet、Extranet、Internet (4): 配置传出邮件服务: 使用 outlook.com 发送邮件通知

    前几篇文章,已经安装了SharePoint 2010,今天将演示如何配置传出邮件.由于某些原因,企业可能没有安装自己邮件服务器,此时我们可以使用公共的邮箱服务来发送邮件通知,比如outlook.com ...

  9. 【oracle 11G Grid 】Crsctl start cluster 和 crsctl start crs 有差别么?

     [oracle 11G Grid ]Crsctl start cluster 和 crsctl start crs 有差别么? q:Crsctl start cluster 是 11.2新特性和 ...

  10. Linux系统编程——特殊进程之僵尸进程

    僵尸进程(Zombie Process) 进程已执行结束,但进程的占用的资源未被回收.这种进程称为僵尸进程. 在每一个进程退出的时候,内核释放该进程全部的资源.包含打开的文件.占用的内存等. 可是仍然 ...