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 ; }
图片效果: