canny演算法程式碼實現
#include "core/core.hpp"
#include "highgui/highgui.hpp"
#include "imgproc/imgproc.hpp"
#include "iostream"
#include "math.h"
using namespace std;
using namespace cv;
//******************灰度轉換函式*************************
//第一個引數image輸入的彩色RGB影象;
//第二個引數imageGray是轉換後輸出的灰度影象;
//*************************************************************
void ConvertRGB2GRAY(const Mat &image,Mat &imageGray);
//******************高斯卷積核生成函式*************************
//第一個引數gaus是一個指向含有N個double型別陣列的指標;
//第二個引數size是高斯卷積核的尺寸大小;
//第三個引數sigma是卷積核的標準差
//*************************************************************
void GetGaussianKernel(double **gaus, const int size,const double sigma);
//******************高斯濾波*************************
//第一個引數imageSource是待濾波原始影象;
//第二個引數imageGaussian是濾波後輸出影象;
//第三個引數gaus是一個指向含有N個double型別陣列的指標;
//第四個引數size是濾波核的尺寸
//*************************************************************
void GaussianFilter(const Mat imageSource,Mat &imageGaussian,double **gaus,int size);
//******************Sobel運算元計算梯度和方向********************
//第一個引數imageSourc原始灰度影象;
//第二個引數imageSobelX是X方向梯度影象;
//第三個引數imageSobelY是Y方向梯度影象;
//第四個引數pointDrection是梯度方向陣列指標
//*************************************************************
void SobelGradDirction(const Mat imageSource,Mat &imageSobelX,Mat &imageSobelY,double *&pointDrection);
//******************計算Sobel的X和Y方向梯度幅值*************************
//第一個引數imageGradX是X方向梯度影象;
//第二個引數imageGradY是Y方向梯度影象;
//第三個引數SobelAmpXY是輸出的X、Y方向梯度影象幅值
//*************************************************************
void SobelAmplitude(const Mat imageGradX,const Mat imageGradY,Mat &SobelAmpXY);
//******************區域性極大值抑制*************************
//第一個引數imageInput輸入的Sobel梯度影象;
//第二個引數imageOutPut是輸出的區域性極大值抑制影象;
//第三個引數pointDrection是影象上每個點的梯度方向陣列指標
//*************************************************************
void LocalMaxValue(const Mat imageInput,Mat &imageOutput,double *pointDrection);
//******************雙閾值處理*************************
//第一個引數imageInput輸入和輸出的的Sobel梯度幅值影象;
//第二個引數lowThreshold是低閾值
//第三個引數highThreshold是高閾值
//******************************************************
void DoubleThreshold(Mat &imageIput,double lowThreshold,double highThreshold);
//******************雙閾值中間畫素連線處理*********************
//第一個引數imageInput輸入和輸出的的Sobel梯度幅值影象;
//第二個引數lowThreshold是低閾值
//第三個引數highThreshold是高閾值
//*************************************************************
void DoubleThresholdLink(Mat &imageInput,double lowThreshold,double highThreshold);
Mat imageSource;
Mat imageGray;
Mat imageGaussian;
int main(int argc,char *argv[])
{
imageSource=imread(argv[1]); //讀入RGB影象
imshow("RGB Image",imageSource);
ConvertRGB2GRAY(imageSource,imageGray); //RGB轉換為灰度圖
imshow("Gray Image",imageGray);
int size=5; //定義卷積核大小
double **gaus=new double *[size]; //卷積核數組
for(int i=0;i<size;i++)
{
gaus[i]=new double[size]; //動態生成矩陣
}
GetGaussianKernel(gaus,5,1); //生成5*5 大小高斯卷積核,Sigma=1;
imageGaussian=Mat::zeros(imageGray.size(),CV_8UC1);
GaussianFilter(imageGray,imageGaussian,gaus,5); //高斯濾波
imshow("Gaussian Image",imageGaussian);
Mat imageSobelY;
Mat imageSobelX;
double *pointDirection=new double[(imageSobelX.cols-1)*(imageSobelX.rows-1)]; //定義梯度方向角陣列
SobelGradDirction(imageGaussian,imageSobelX,imageSobelY,pointDirection); //計算X、Y方向梯度和方向角
imshow("Sobel Y",imageSobelY);
imshow("Sobel X",imageSobelX);
Mat SobelGradAmpl;
SobelAmplitude(imageSobelX,imageSobelY,SobelGradAmpl); //計算X、Y方向梯度融合幅值
imshow("Soble XYRange",SobelGradAmpl);
Mat imageLocalMax;
LocalMaxValue(SobelGradAmpl,imageLocalMax,pointDirection); //區域性非極大值抑制
imshow("Non-Maximum Image",imageLocalMax);
Mat cannyImage;
cannyImage=Mat::zeros(imageLocalMax.size(),CV_8UC1);
DoubleThreshold(imageLocalMax,90,160); //雙閾值處理
imshow("Double Threshold Image",imageLocalMax);
DoubleThresholdLink(imageLocalMax,90,160); //雙閾值中間閾值濾除及連線
imshow("Canny Image",imageLocalMax);
waitKey();
system("pause");
return 0;
}
//******************高斯卷積核生成函式*************************
//第一個引數gaus是一個指向含有N個double型別陣列的指標;
//第二個引數size是高斯卷積核的尺寸大小;
//第三個引數sigma是卷積核的標準差
//*************************************************************
void GetGaussianKernel(double **gaus, const int size,const double sigma)
{
const double PI=4.0*atan(1.0); //圓周率π賦值
int center=size/2;
double sum=0;
for(int i=0;i<size;i++)
{
for(int j=0;j<size;j++)
{
gaus[i][j]=(1/(2*PI*sigma*sigma))*exp(-((i-center)*(i-center)+(j-center)*(j-center))/(2*sigma*sigma));
sum+=gaus[i][j];
}
}
for(int i=0;i<size;i++)
{
for(int j=0;j<size;j++)
{
gaus[i][j]/=sum;
cout<<gaus[i][j]<<" ";
}
cout<<endl<<endl;
}
return ;
}
//******************灰度轉換函式*************************
//第一個引數image輸入的彩色RGB影象;
//第二個引數imageGray是轉換後輸出的灰度影象;
//*************************************************************
void ConvertRGB2GRAY(const Mat &image,Mat &imageGray)
{
if(!image.data||image.channels()!=3)
{
return ;
}
imageGray=Mat::zeros(image.size(),CV_8UC1);
uchar *pointImage=image.data;
uchar *pointImageGray=imageGray.data;
int stepImage=image.step;
int stepImageGray=imageGray.step;
for(int i=0;i<imageGray.rows;i++)
{
for(int j=0;j<imageGray.cols;j++)
{
pointImageGray[i*stepImageGray+j]=0.114*pointImage[i*stepImage+3*j]+0.587*pointImage[i*stepImage+3*j+1]+0.299*pointImage[i*stepImage+3*j+2];
}
}
}
//******************高斯濾波*************************
//第一個引數imageSource是待濾波原始影象;
//第二個引數imageGaussian是濾波後輸出影象;
//第三個引數gaus是一個指向含有N個double型別陣列的指標;
//第四個引數size是濾波核的尺寸
//*************************************************************
void GaussianFilter(const Mat imageSource,Mat &imageGaussian,double **gaus,int size)
{
imageGaussian=Mat::zeros(imageSource.size(),CV_8UC1);
if(!imageSource.data||imageSource.channels()!=1)
{
return ;
}
double gausArray[100];
for(int i=0;i<size*size;i++)
{
gausArray[i]=0; //賦初值,空間分配
}
int array=0;
for(int i=0;i<size;i++)
{
for(int j=0;j<size;j++)
{
gausArray[array]=gaus[i][j];//二維陣列到一維 方便計算
array++;
}
}
//濾波
for(int i=0;i<imageSource.rows;i++)
{
for(int j=0;j<imageSource.cols;j++)
{
int k=0;
for(int l=-size/2;l<=size/2;l++)
{
for(int g=-size/2;g<=size/2;g++)
{
//以下處理針對濾波後圖像邊界處理,為超出邊界的值賦值為邊界值
int row=i+l;
int col=j+g;
row=row<0?0:row;
row=row>=imageSource.rows?imageSource.rows-1:row;
col=col<0?0:col;
col=col>=imageSource.cols?imageSource.cols-1:col;
//卷積和
imageGaussian.at<uchar>(i,j)+=gausArray[k]*imageSource.at<uchar>(row,col);
k++;
}
}
}
}
}
//******************Sobel運算元計算X、Y方向梯度和梯度方向角********************
//第一個引數imageSourc原始灰度影象;
//第二個引數imageSobelX是X方向梯度影象;
//第三個引數imageSobelY是Y方向梯度影象;
//第四個引數pointDrection是梯度方向角陣列指標
//*************************************************************
void SobelGradDirction(const Mat imageSource,Mat &imageSobelX,Mat &imageSobelY,double *&pointDrection)
{
pointDrection=new double[(imageSource.rows-1)*(imageSource.cols-1)];
for(int i=0;i<(imageSource.rows-1)*(imageSource.cols-1);i++)
{
pointDrection[i]=0;
}
imageSobelX=Mat::zeros(imageSource.size(),CV_32SC1);
imageSobelY=Mat::zeros(imageSource.size(),CV_32SC1);
uchar *P=imageSource.data;
uchar *PX=imageSobelX.data;
uchar *PY=imageSobelY.data;
int step=imageSource.step;
int stepXY=imageSobelX.step;
int k=0;
int m=0;
int n=0;
for(int i=1;i<(imageSource.rows-1);i++)
{
for(int j=1;j<(imageSource.cols-1);j++)
{
//通過指標遍歷影象上每一個畫素
double gradY=P[(i-1)*step+j+1]+P[i*step+j+1]*2+P[(i+1)*step+j+1]-P[(i-1)*step+j-1]-P[i*step+j-1]*2-P[(i+1)*step+j-1];
PY[i*stepXY+j*(stepXY/step)]=abs(gradY);
double gradX=P[(i+1)*step+j-1]+P[(i+1)*step+j]*2+P[(i+1)*step+j+1]-P[(i-1)*step+j-1]-P[(i-1)*step+j]*2-P[(i-1)*step+j+1];
PX[i*stepXY+j*(stepXY/step)]=abs(gradX);
if(gradX==0)
{
gradX=0.00000000000000001; //防止除數為0異常
}
pointDrection[k]=atan(gradY/gradX)*57.3;//弧度轉換為度
pointDrection[k]+=90;
k++;
}
}
convertScaleAbs(imageSobelX,imageSobelX);
convertScaleAbs(imageSobelY,imageSobelY);
}
//******************計算Sobel的X和Y方向梯度幅值*************************
//第一個引數imageGradX是X方向梯度影象;
//第二個引數imageGradY是Y方向梯度影象;
//第三個引數SobelAmpXY是輸出的X、Y方向梯度影象幅值
//*************************************************************
void SobelAmplitude(const Mat imageGradX,const Mat imageGradY,Mat &SobelAmpXY)
{
SobelAmpXY=Mat::zeros(imageGradX.size(),CV_32FC1);
for(int i=0;i<SobelAmpXY.rows;i++)
{
for(int j=0;j<SobelAmpXY.cols;j++)
{
SobelAmpXY.at<float>(i,j)=sqrt(imageGradX.at<uchar>(i,j)*imageGradX.at<uchar>(i,j)+imageGradY.at<uchar>(i,j)*imageGradY.at<uchar>(i,j));
}
}
convertScaleAbs(SobelAmpXY,SobelAmpXY);
}
//******************區域性極大值抑制*************************
//第一個引數imageInput輸入的Sobel梯度影象;
//第二個引數imageOutPut是輸出的區域性極大值抑制影象;
//第三個引數pointDrection是影象上每個點的梯度方向陣列指標
//*************************************************************
void LocalMaxValue(const Mat imageInput,Mat &imageOutput,double *pointDrection)
{
//imageInput.copyTo(imageOutput);
imageOutput=imageInput.clone();
int k=0;
for(int i=1;i<imageInput.rows-1;i++)
{
for(int j=1;j<imageInput.cols-1;j++)
{
int value00=imageInput.at<uchar>((i-1),j-1);
int value01=imageInput.at<uchar>((i-1),j);
int value02=imageInput.at<uchar>((i-1),j+1);
int value10=imageInput.at<uchar>((i),j-1);
int value11=imageInput.at<uchar>((i),j);
int value12=imageInput.at<uchar>((i),j+1);
int value20=imageInput.at<uchar>((i+1),j-1);
int value21=imageInput.at<uchar>((i+1),j);
int value22=imageInput.at<uchar>((i+1),j+1);
if(pointDrection[k]>0&&pointDrection[k]<=45)
{
if(value11<=(value12+(value02-value12)*tan(pointDrection[i*imageOutput.rows+j]))||(value11<=(value10+(value20-value10)*tan(pointDrection[i*imageOutput.rows+j]))))
{
imageOutput.at<uchar>(i,j)=0;
}
}
if(pointDrection[k]>45&&pointDrection[k]<=90)
{
if(value11<=(value01+(value02-value01)/tan(pointDrection[i*imageOutput.cols+j]))||value11<=(value21+(value20-value21)/tan(pointDrection[i*imageOutput.cols+j])))
{
imageOutput.at<uchar>(i,j)=0;
}
}
if(pointDrection[k]>90&&pointDrection[k]<=135)
{
if(value11<=(value01+(value00-value01)/tan(180-pointDrection[i*imageOutput.cols+j]))||value11<=(value21+(value22-value21)/tan(180-pointDrection[i*imageOutput.cols+j])))
{
imageOutput.at<uchar>(i,j)=0;
}
}
if(pointDrection[k]>135&&pointDrection[k]<=180)
{
if(value11<=(value10+(value00-value10)*tan(180-pointDrection[i*imageOutput.cols+j]))||value11<=(value12+(value22-value11)*tan(180-pointDrection[i*imageOutput.cols+j])))
{
imageOutput.at<uchar>(i,j)=0;
}
}
k++;
}
}
}
//******************雙閾值處理*************************
//第一個引數imageInput輸入和輸出的的Sobel梯度幅值影象;
//第二個引數lowThreshold是低閾值
//第三個引數highThreshold是高閾值
//******************************************************
void DoubleThreshold(Mat &imageIput,double lowThreshold,double highThreshold)
{
for(int i=0;i<imageIput.rows;i++)
{
for(int j=0;j<imageIput.cols;j++)
{
if(imageIput.at<uchar>(i,j)>highThreshold)
{
imageIput.at<uchar>(i,j)=255;
}
if(imageIput.at<uchar>(i,j)<lowThreshold)
{
imageIput.at<uchar>(i,j)=0;
}
}
}
}
//******************雙閾值中間畫素連線處理*********************
//第一個引數imageInput輸入和輸出的的Sobel梯度幅值影象;
//第二個引數lowThreshold是低閾值
//第三個引數highThreshold是高閾值
//*************************************************************
void DoubleThresholdLink(Mat &imageInput,double lowThreshold,double highThreshold)
{
for(int i=1;i<imageInput.rows-1;i++)
{
for(int j=1;j<imageInput.cols-1;j++)
{
if(imageInput.at<uchar>(i,j)>lowThreshold&&imageInput.at<uchar>(i,j)<255)
{
if(imageInput.at<uchar>(i-1,j-1)==255||imageInput.at<uchar>(i-1,j)==255||imageInput.at<uchar>(i-1,j+1)==255||
imageInput.at<uchar>(i,j-1)==255||imageInput.at<uchar>(i,j)==255||imageInput.at<uchar>(i,j+1)==255||
imageInput.at<uchar>(i+1,j-1)==255||imageInput.at<uchar>(i+1,j)==255||imageInput.at<uchar>(i+1,j+1)==255)
{
imageInput.at<uchar>(i,j)=255;
DoubleThresholdLink(imageInput,lowThreshold,highThreshold); //遞迴呼叫
}
else
{
imageInput.at<uchar>(i,j)=0;
}
}
}
}
}
相關推薦
canny演算法程式碼實現
#include "core/core.hpp" #include "highgui/highgui.hpp" #include "imgproc/imgproc.hpp" #include "iostream" #include "math.h
數獨問題的一種簡單演算法程式碼實現
五一期間無聊時想起去年考研複試有一道上機題目當時沒作出來,於是一時興起想重新拾起看看是當時太緊張,還是自己能力不足。然後發現這道題目還真稍微有些難度,相當於一道數獨問題(sudoku)的簡化版。自己想來想去也只能想到兩種演算法,一種是拿剩餘元素做全排列測試,一種是回溯法測試。最後只實現了一個全排
MD4 演算法程式碼實現
介紹 MD4是一種資訊摘要演算法,由麻省理工學院教Ronald Rivest於1990年開發完成,演算法根據輸入的數值計算128位的摘要資訊,用於檢測資訊的完整性。該演算法影響了後來其他的密碼演算法的設計,如MD5、sha-1和RIPEMD演算法。 安全性 1991年
Spark Word2Vec演算法程式碼實現
1 import com.hankcs.hanlp.tokenizer.NLPTokenizer 2 import org.apache.hadoop.io.{LongWritable, Text} 3 import org.apache.hadoop.mapred.TextInputFormat
一致性hash演算法程式碼實現
什麼是一致性hash 一致性雜湊演算法(Consistent Hashing Algorithm)是一種分散式演算法,常用於負載均衡。Memcached client也選擇這種演算法,解決將key-value均勻分配到眾多Memcached server上的問題。它可以取代傳統的取模操作
特徵選擇mRMR演算法程式碼實現及安裝下載
演算法程式碼實現連線可以直接下載解壓執行,在mac或者Linux系統下:https://github.com/csuldw/MachineLearning/tree/master/mRMR 要看懂result.out檔案結果中,有兩個關鍵字:*** MaxRel fea
邊緣檢測之Canny演算法_Qt實現(C++)
邊緣檢測之Canny演算法_Qt實現(C++) Canny邊緣檢測演算法的簡單介紹 Canny的目標是找到一個最優的邊緣檢測演算法,最優邊緣檢測的含義是: 好的檢測 - 演算法能夠儘可能多地標識出影象中的實際邊緣。 好的定位 - 標識出的
資料結構——————排序演算法程式碼實現(未完待續......)
排序演算法 插入排序 折半插入排序 希爾排序 氣泡排序 快速排序 簡單選擇排序 堆排序 歸併排序(未完成) 基數排序(未完成) #include<bits/stdc++.h> using namespace
資料結構演算法程式碼實現——棧和佇列(一)
棧和佇列 棧和佇列是一種特殊的線性表。 從資料結構角度看:棧和佇列也是線性表,其特點性在於棧和佇列的基本操作是線性表操作的子集。它們是操作受限的線性表。 從資料型別角度看:它們是和線性表不相同的兩類重要的抽象資料型別。 棧的定義 棧(Stack)是限
機器學習(K近鄰演算法程式碼實現 迴歸)
K近鄰演算法進行迴歸預測一般步驟 1 資料的匯入與預處理 2 資料的標準化與歸一化 3 生成訓練集和測試集 4 利用訓練集進行訓練,匯入測試集得出預測值 5 真實值與與測試值進行比較評價 import csv import numpy as np import p
蟻群演算法程式碼實現
旅行商問題大都是用遺傳演算法求解,不過蟻群演算法比它高效得多,在百度的蟻群演算法吧裡有人發了個註釋清晰的程式碼,有興趣的可以去研究一下蟻群演算法和模擬退火演算法,這兩者都可以解決旅行商問題。而關於遺傳演算法和模擬退火演算法,部落格園裡的某位牛人很清楚地介紹了,發個連結吧
廣度演算法 dijskstra演算法 程式碼實現
理論:從起點開始,一次遍歷相鄰距離為1的點,把這些點儲存在佇列中一次取出,就這樣把沒遍歷的點依次放入佇列儲存。 實現:建立一張圖關係的表格 下標 dv(到起點的權重) 該點的父結點 0 0 0 1 ......... 詳細資料可以檢視《Data Structur
K-means和K-means++演算法程式碼實現(Python)
K-means和K-means++主要區別在於,K-means++演算法選擇初始類中心時,儘可能選擇相距較遠的類中心,而K-means僅僅是隨機初始化類中心。 #K-means演算法 from pylab import * from numpy import * impo
雜湊表及其常用演算法(程式碼實現)
轉載自—>http://blog.csdn.net/wangxu_zju_2010/article/details/7489548 整理了一下Hash表相關內容,如下: Hash 表是使用 O(1) 時間進行資料的插入刪除和查詢,但是 hash 表不保證表中資料的有序性,這樣在 hash 表中
快速排序演算法程式碼實現
1 演算法介紹 快速排序是一個“交換類”的排序,以軍訓排隊為例,教官說:“第一個同學出列,其他人以他為中心,比他矮的全排到他的左邊,比他高的全排他右邊。”這就是一趟快速排序。可以看出,一趟快速排序是以一個“樞軸”為中心,將序列分成兩部分,樞軸的一邊全是比它小(
基於行塊分佈函式的網頁正文抽取演算法程式碼實現
最近在在做一個與資訊相關的APP,資訊是通過爬取獲得,但是獲取只有簡單的資訊,正文沒有獲取。所以在顯示的時候很麻煩,一個<a>標籤鏈到到別人的網頁,滿屏的廣告 ,還有各種彈窗,雖然頁面確實做得很漂亮,但是不得不放棄這種簡單的方式了,所以接下來自己動手了
[MLReview] Ensemble Learning 整合學習演算法程式碼實現
把整合學習放在第二個寫是因為ensemble learning雖然有learning,但是在演算法中並未顯式表現出learning,並且也含有“投票表決”的部分內容,跟knn分類的思想比較像。(GBDT和Random Forest同屬整合學習 屬於比較重要的演算法 之後會單獨
漫畫:三種 “奇葩” 的排序演算法程式碼實現
1: 睡眠排序 public class Main2 { public static void sleepSort(int[] array) { for (int i : array) { new Thread(()->{
Java常用的八種排序演算法與程式碼實現(三):桶排序、計數排序、基數排序
三種線性排序演算法:桶排序、計數排序、基數排序 線性排序演算法(Linear Sort):這些排序演算法的時間複雜度是線性的O(n),是非比較的排序演算法 桶排序(Bucket Sort) 將要排序的資料分到幾個有序的桶裡,每個桶裡的資料再單獨進行排序,桶內排完序之後,再把桶裡的
Java常用的八種排序演算法與程式碼實現(二):歸併排序法、快速排序法
注:這裡給出的程式碼方案都是通過遞迴完成的 --- 歸併排序(Merge Sort): 分而治之,遞迴實現 如果需要排序一個數組,我們先把陣列從中間分成前後兩部分,然後對前後兩部分進行分別排序,再將排好序的數組合並在一起,這樣整個陣列就有序了 歸併排序是穩定的排序演算法,時間