• OpenCV : 基于切线方向的边缘增强算法


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

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

    代码:

    		//在种子点方向上寻找合适的梯度,用于寻找边缘
    		//对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 ;
    		}


    图片效果:

                  

  • 相关阅读:
    fork 入门
    java 注解 @Retention @interface 元数据
    JAVA泛型简析
    http数据流 gzip解压方法分析
    gdb调试提示 Missing separate debuginfos
    Vue2.x响应式原理
    观察者模式
    优秀博客收集
    切换npm源的方式
    前端模块化之ES Module
  • 原文地址:https://www.cnblogs.com/wishchin/p/9200012.html
Copyright © 2020-2023  润新知