當(dāng)前位置:
首頁(yè) >
Sobel算子取代:基于特定点方向的canny边缘检测
發(fā)布時(shí)間:2023/12/31
26
豆豆
生活随笔
收集整理的這篇文章主要介紹了
Sobel算子取代:基于特定点方向的canny边缘检测
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
前言:
?????? Canny邊緣檢測(cè)使用了Sobel算子,計(jì)算dx和dy兩個(gè)方向,對(duì)于特定方向的邊緣檢測(cè),可以作少量修改。
代碼:
計(jì)算特定方向上的邊緣
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;//使用特定種子方向上的點(diǎn)尋找方向梯度FindBestGradient( _src, _dst,seed,aperture_size, L2gradient );//二值化,生成邊緣圖像//計(jì)算直方圖,尋找極大極小邊緣點(diǎn),根據(jù)波峰和波谷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;}尋找特定邊緣: //在種子點(diǎn)方向上尋找合適的梯度,用于尋找邊緣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();//目標(biāo)圖像 uchar型cv::Mat dd = _src.clone();//1.根據(jù)角度計(jì)算梯度//得到梯度矩陣//使用N*1的算子int n = aperture_size;//必須為奇數(shù)//對(duì)每個(gè)柱進(jìn)行初始化//搜索柱:在射線方向上搜索l_Search 個(gè)像素;寬度為 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);}//初始化柱//設(shè)定系數(shù)//生成模板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.生成角度圖像//在射線方向上尋找//方法不是太好,但是沒(méi)有尋找到簡(jiǎn)單有效的方法for ( int y=0 ;y< ds.rows;++y ){float* ptr = (float*)( df.data + y * df.step);for ( int x=0; x< ds.cols; ++x ){//計(jì)算角度//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;}}//計(jì)算差值-導(dǎo)數(shù)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 ){//計(jì)算角度//cvWish::BeamInit(l_Search,w_Search,cv::Point2f( x,y ),df.at<float >(y,x),beam,0);//0表示從中部開(kāi)始搜索cvWish::BeamInit(l_Search,w_Search,cv::Point2f( x,y ), *pf ,beam,0);//0表示從中部開(kāi)始搜索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;}
輔助代碼: //功能: 初始化任意角度的一個(gè)方柱,大小已經(jīng)確定:l_Search*w_Search//沿射線方向 尋找 一個(gè)柱//默認(rèn) 參數(shù) 0 從中部開(kāi)始//參數(shù) 1代表 從底部開(kāi)始;參數(shù) 2代表從top開(kāi)始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);//確定是奇數(shù)assert (w_Search%2 >0);assert ( beam.size() == l_Search);//不改變大小assert ( beam[0].size() == w_Search);//往角度方向延長(zhǎng)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://往底部移動(dòng)ps.y = pc.y-(0- sin(angle)*l_Search/2);ps.x = pc.x-(0- cos(angle)*l_Search/2);//往左邊移動(dòng)ps.y -= 0- sin(angleVert)*w_Search/2;ps.x -= 0- cos(angleVert)*w_Search/2;//對(duì)每個(gè)點(diǎn)計(jì)算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://往底部移動(dòng)//默認(rèn)底部,因此不需要移動(dòng)ps.y = pc.y;//-(0- sin(angle)*l_Search/2);ps.x = pc.x;//-(0- cos(angle)*l_Search/2);//往左邊移動(dòng)ps.y -= 0- sin(angleVert)*w_Search/2;ps.x -= 0- cos(angleVert)*w_Search/2;//對(duì)每個(gè)點(diǎn)計(jì)算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://往底部移動(dòng)//默認(rèn)頂部,因此需要移動(dòng)到底ps.y = pc.y -(0- sin(angle)*l_Search);ps.x = pc.x -(0- cos(angle)*l_Search);//往左邊移動(dòng)ps.y -= 0- sin(angleVert)*w_Search/2;ps.x -= 0- cos(angleVert)*w_Search/2;//對(duì)每個(gè)點(diǎn)計(jì)算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 相同,默認(rèn)設(shè)定為中間位置//往底部移動(dòng)ps.y = pc.y-(0- sin(angle)*l_Search/2);ps.x = pc.x-(0- cos(angle)*l_Search/2);//往左邊移動(dòng)ps.y -= 0- sin(angleVert)*w_Search/2;ps.x -= 0- cos(angleVert)*w_Search/2;//對(duì)每個(gè)點(diǎn)計(jì)算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;}
//對(duì)柱規(guī)整,使其不超出邊界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;//對(duì)每個(gè)點(diǎn) 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;}
代碼效果:
?? ? ? ? ? ? ? ? ? ? ? ? ?? ?????? ? ? ? ? ? ? ??
總結(jié)
以上是生活随笔為你收集整理的Sobel算子取代:基于特定点方向的canny边缘检测的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 夏普2658n代码ta是什么 夏普打印机
- 下一篇: win7打印机提示错误0x0000000