1. 程式人生 > >canny演算法程式碼實現

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):   分而治之,遞迴實現   如果需要排序一個數組,我們先把陣列從中間分成前後兩部分,然後對前後兩部分進行分別排序,再將排好序的數組合並在一起,這樣整個陣列就有序了   歸併排序是穩定的排序演算法,時間