使用CImg實現canny邊緣檢測和跟蹤
第一步,函式toGrayScale 將彩色影象轉換為灰度影象,根據RGB值和公式計算出灰度值即可,比較簡單。
CImg<uchar> canny::toGrayScale()
{
grayscaled = CImg<uchar>(img.width(), img.height(), 1, 1);
cimg_forXY(grayscaled, x, y) {
int r = img(x, y, 0);
int g = img(x, y, 1);
int b = img(x, y, 2);
double newValue = (r * 0.2126 + g * 0.7152 + b * 0.0722);
for (int i = 0; i < 3; ++i)
grayscaled(x, y) = newValue;
}
return grayscaled;
}
第二步,函式createFilter 建立一個高斯濾波器,目的是為了降噪。使用正態分佈計算權重矩陣,然後正規化。計算公式
vector<vector<double>> canny::createFilter(int row, int column, double sigmaIn)
{
vector<vector<double>> filter;
for (int i = 0; i < row; i++)
{
vector<double> col;
for (int j = 0; j < column; j++)
{
col.push_back(-1);
}
filter.push_back(col);
}
float coordSum = 0;
float constant = 2.0 * sigmaIn * sigmaIn;
// Sum is for normalization
float sum = 0.0;
for (int x = -row / 2; x <= row / 2; x++)
{
for (int y = -column / 2; y <= column / 2; y++)
{
coordSum = (x*x + y * y);
filter[x + row / 2][y + column / 2] = (exp(-(coordSum) / constant)) / (M_PI * constant);
sum += filter[x + row / 2][y + column / 2];
}
}
// Normalize the Filter
for (int i = 0; i < row; i++)
for (int j = 0; j < column; j++)
filter[i][j] /= sum;
return filter;
}
第三步,函式 useFilter 使用第二步建立的濾波器,建立一個3*3的權重矩陣。
任何邊緣檢測演算法都不可能在未經處理的原始資料上很好地處理,對原始資料與高斯平滑模板作卷積,得到的影象與原始影象相比有些輕微的模糊。這樣,單獨的一個畫素噪聲在經過高斯平滑的影象上變得幾乎沒有影響。
CImg<uchar> canny::useFilter(CImg<uchar> img_in, vector<vector<double>> filterIn)
{
int size = (int)filterIn.size() / 2;
CImg<uchar> filteredImg(img_in.width() - 2 * size, img_in.height() - 2 * size, 1, 1);
for (int i = size; i < img_in.width() - size; i++)
{
for (int j = size; j < img_in.height() - size; j++)
{
double sum = 0;
for (int x = 0; x < filterIn.size(); x++)
for (int y = 0; y < filterIn.size(); y++)
{
sum += filterIn[x][y] * (double)(img_in(i + x - size, j + y - size));
}
filteredImg(i - size, j - size) = sum;
}
}
return filteredImg;
}
第四步,函式 sobel 使用索伯運算元處理影象,用來尋找影象中的亮度梯度。
計算公式:
分別對橫向和縱向進行處理。影象的每一個畫素的橫向及縱向梯度近似值可用以下的公式
結合: ,梯度方向: 。
這裡注意因為CImg(x,y)是以左上角為原點,橫向為x,縱向為y訪問畫素,而opencv的at(x,y)訪問的是第x行第y列的畫素,所以這裡計算sumx和sumy的模板交換。
在後面的操作中,都要注意這個問題。
CImg<uchar> canny::sobel()
{
//Sobel X Filter
double x1[] = { 1.0, 0, -1.0 };
double x2[] = { 2.0, 0, -2.0 };
double x3[] = { 1.0, 0, -1.0 };
vector<vector<double>> xFilter(3);
xFilter[0].assign(x1, x1 + 3);
xFilter[1].assign(x2, x2 + 3);
xFilter[2].assign(x3, x3 + 3);
//Sobel Y Filter
double y1[] = { -1.0, -2.0, -1.0 };
double y2[] = { 0, 0, 0 };
double y3[] = { 1.0, 2.0, 1.0 };
vector<vector<double>> yFilter(3);
yFilter[0].assign(y1, y1 + 3);
yFilter[1].assign(y2, y2 + 3);
yFilter[2].assign(y3, y3 + 3);
//Limit Size
int size = (int)xFilter.size() / 2;
CImg<uchar> filteredImg(gFiltered.width() - 2 * size, gFiltered.height() - 2 * size, 1, 1);
angles = CImg<float>(gFiltered.width() - 2 * size, gFiltered.height() - 2 * size, 1, 1); //AngleMap
for (int i = size; i < gFiltered.width() - size; i++)
{
for (int j = size; j < gFiltered.height() - size; j++)
{
double sumx = 0;
double sumy = 0;
for (int x = 0; x < xFilter.size(); x++)
for (int y = 0; y < yFilter.size(); y++)
{
sumx += yFilter[x][y] * (double)(gFiltered(i + x - size, j + y - size)); //Sobel_X Filter Value
sumy += xFilter[x][y] * (double)(gFiltered(i + x - size, j + y - size)); //Sobel_Y Filter Value
}
double sumxsq = sumx * sumx;
double sumysq = sumy * sumy;
double sq2 = sqrt(sumxsq + sumysq);
if (sq2 > 255) //Unsigned Char Fix
sq2 = 255;
filteredImg(i - size, j - size) = sq2;
if (sumx == 0) //Arctan Fix
angles(i - size, j - size) = 90;
else
angles(i - size, j - size) = atan(sumy / sumx)*(180.0 / M_PI);
}
}
return filteredImg;
}
第五步,函式 nonMaxSupp 執行非極大值抑制,在8鄰域內尋找畫素點區域性最大值,將非極大值點所對應的灰度值置為0,這樣可以剔除掉一大部分非邊緣的點。
CImg<uchar> canny::nonMaxSupp()
{
CImg<uchar> nonMaxSupped(sFiltered.width() - 2, sFiltered.height() - 2, 1, 1);
for (int i = 1; i < sFiltered.width() - 1; i++) {
for (int j = 1; j < sFiltered.height() - 1; j++) {
float Tangent = angles(i, j);
//cout << Tangent << " ";
nonMaxSupped(i - 1, j - 1) = sFiltered(i, j);
//Horizontal Edge
if (((-22.5 < Tangent) && (Tangent <= 22.5)) || ((157.5 < Tangent) && (Tangent <= -157.5)))
{
if ((sFiltered(i, j) < sFiltered(i+1, j )) || (sFiltered(i, j) < sFiltered(i-1, j )))
nonMaxSupped(i - 1, j - 1) = 0;
}
//Vertical Edge
if (((-112.5 < Tangent) && (Tangent <= -67.5)) || ((67.5 < Tangent) && (Tangent <= 112.5)))
{
if ((sFiltered(i, j) < sFiltered(i , j+1)) || (sFiltered(i, j) < sFiltered(i , j-1)))
nonMaxSupped(i - 1, j - 1) = 0;
}
//-45 Degree Edge
if (((-67.5 < Tangent) && (Tangent <= -22.5)) || ((112.5 < Tangent) && (Tangent <= 157.5)))
{
//if ((sFiltered(i, j) < sFiltered(i - 1, j + 1)) || (sFiltered(i, j) < sFiltered(i + 1, j - 1)))
if ((sFiltered(i, j) < sFiltered(i + 1, j + 1)) || (sFiltered(i, j) < sFiltered(i - 1, j - 1)))
nonMaxSupped(i - 1, j - 1) = 0;
}
//45 Degree Edge
if (((-157.5 < Tangent) && (Tangent <= -112.5)) || ((22.5 < Tangent) && (Tangent <= 67.5)))
{
//if ((sFiltered(i, j) < sFiltered(i + 1, j + 1)) || (sFiltered(i, j) < sFiltered(i - 1, j - 1)))
if ((sFiltered(i, j) < sFiltered(i - 1, j + 1)) || (sFiltered(i, j) < sFiltered(i + 1, j - 1)))
nonMaxSupped(i - 1, j - 1) = 0;
}
}
}
return nonMaxSupped;
}
第六步,函式 threshold 執行滯後閾值化,由於噪聲的影響,經常會在本應該連續的邊緣出現斷裂的問題。滯後閾值化設定兩個閾值:一個為高閾值,一個為低閾值。如果任何畫素邊緣運算元的影響超過高閾值,將這些畫素標記為邊緣;響應超過低閾值(高低閾值之間)的畫素,如果與已經標記為邊緣的畫素8-鄰接,則將這些畫素也標記為邊緣。
CImg<uchar> canny::threshold(CImg<uchar> imgin, int low, int high)
{
if (low > 255)
low = 255;
if (high > 255)
high = 255;
CImg<uchar> EdgeMat(imgin.width(), imgin.height(), 1, 1);
for (int i = 0; i < imgin.width(); i++)
{
for (int j = 0; j < imgin.height(); j++)
{
EdgeMat(i, j) = imgin(i, j);
if (EdgeMat(i, j) > high)
EdgeMat(i, j) = 255;
else if (EdgeMat(i, j) < low)
EdgeMat(i, j) = 0;
else
{
bool anyHigh = false;
bool anyBetween = false;
for (int x = i - 1; x < i + 2; x++)
{
for (int y = j - 1; y < j + 2; y++)
{
if (x <= 0 || y <= 0 || x >= EdgeMat.width() || y >= EdgeMat.height()) //Out of bounds
continue;
else
{
if (EdgeMat(x, y) > high)
{
EdgeMat(i, j) = 255;
anyHigh = true;
break;
}
else if (EdgeMat(x, y) <= high && EdgeMat(x, y) >= low)
anyBetween = true;
}
}
if (anyHigh)
break;
}
if (!anyHigh && anyBetween)
for (int x = i - 2; x < i + 3; x++)
{
for (int y = j - 1; y < j + 3; y++)
{
if (x < 0
相關推薦
使用CImg實現canny邊緣檢測和跟蹤
第一步,函式toGrayScale 將彩色影象轉換為灰度影象,根據RGB值和公式計算出灰度值即可,比較簡單。
CImg<uchar> canny::toGrayScale()
{
grayscaled = CImg<uchar>(img
OpenCV 實現canny邊緣檢測
近期,整理了一些之前做過的影象處理內容,算是複習下基礎吧;
涉及canny邊緣檢測的OpenCV實現;
影象邊緣資訊主要集中在高頻段,通常說影象銳化或檢測邊緣,實質就是高頻濾波。Canny是常用的邊緣檢測方法,其特點是試圖將獨立邊的候選畫素拼裝成輪廓。
canny邊緣檢
opencv讀影象C語言實現canny邊緣檢測
1 ////////第四步:非極大值抑制
2 //注意事項 權重的選取,也就是離得近權重大
3 /////////////////////////////////////////////////////////////////
4 IplImage * N;//非極大值抑制結果
5
【OpenCV學習筆記 004】 影象的縮放、Canny邊緣檢測和影象的二值化
一、影象的縮放
本篇將介紹使用OpenCV來縮放圖片。首先介紹幾個關鍵函式——cvResize和cvCreateImage
1.主要函式介紹
1.1 cvResize
函式功能:影象大小變換
函式原型:
voidcvResize(
const CvArr* src,
【算法隨記】Canny邊緣檢測算法實現和優化分析。
輸入 放置 位圖 code 計算 並且 比較 lan 開篇 以前的博文大部分都寫的非常詳細,有很多分析過程,不過寫起來確實很累人,一般一篇好的文章要整理個三四天,但是,時間越來越緊張,後續的一些算法可能就以隨記的方式,把實現過程的一些比較容易出錯和有價值的細節部分加以描
Canny邊緣檢測算法原理及其VC實現詳解(一)
常用 差分 實現圖 還需要 鏈接 傳感器 出了 關系 位置 轉自:http://blog.csdn.net/likezhaobin/article/details/6892176
圖象的邊緣是指圖象局部區域亮度變化顯著的部分,該區域的灰度剖面一般可以看作是一個階躍,既從
Shader特效——“Canny邊緣檢測”的實現 【GLSL】
演算法參考自:
http://blog.sina.com.cn/s/blog_676b40ec0100z2pt.html
http://blog.csdn.net/xiajun07061225/article/details/6926108
在寫這篇文章的時候,發現網上關於ca
Canny邊緣檢測演算法原理及C語言實現詳解
Canny運算元是John Canny在1986年提出的,那年老大爺才28歲,該文章發表在PAMI頂級期刊上的(1986. A computational approach to edge detection. IEEE Transactions on Pattern Analy
基於Sobel和Canny邊緣檢測
影象邊緣是由灰度突變產的,屬於一種影象的特徵,是目標探測、識別的重要手段之一。
檢測邊緣通常為求原影象的梯度或二階導數,有如下結論:
(1)一階導數通常在影象中產生較粗的邊緣
(2)二階導數對精細細
Canny邊緣檢測演算法的實現
影象邊緣資訊主要集中在高頻段,通常說影象銳化或檢測邊緣,實質就是高頻濾波。我們知道微分運算是求訊號的變化率,具有加強高頻分量的作用。在空域運算中來說,對影象的銳化就是計算微分。由於數字影象的離散訊號,微分運算就變成計算差分或梯度。影象處理中有多種邊緣檢測(梯度)運算元,常用的
利用Canny邊緣檢測運算元進行邊緣檢測的原理及OpenCV程式碼實現
Canny運算元是John Canny在1986年發表的論文中首次提出的邊緣檢測運算元,該運算元檢測效能比較好,應用廣泛。
Canny運算元進行邊緣檢測的原理和步驟如下:
⑴消除噪聲。邊緣檢測的演算法主要是基於影象強度的一階和二階微分操作,但導數通常對噪聲很敏感,邊緣檢測
OpenCV使用Canny邊緣檢測器實現影象邊緣檢測
效果圖
原始碼
Canny邊緣檢測器是一種被廣泛使用的演算法,並被認為是邊緣檢測最優的演算法,該方法使用了比高斯差分演算法更復雜的技巧,如多向灰度梯度和滯後閾值化。
Canny
Canny邊緣檢測原理及C++實現
從11.21開始寫部落格,到今天一個多月了,寫了20多篇了,希望自己能堅持下去吧!
在這裡祝大家聖誕節快樂!
Canny邊緣檢測演算法是澳大利亞科學家John F. Canny在1986年提出來的,不得不提一下的是當年John Canny本人才28歲!到今天已經30年過
邊緣檢測︱基於 HED網路TensorFlow 和 OpenCV 實現圖片邊緣檢測
.
一、邊緣檢測
1、傳統邊緣檢測
Google 搜尋 opencv scan document,是可以找到好幾篇相關的教程的,這些教程裡面的技術手段,也都大同小異,關鍵步驟就是呼叫 OpenCV 裡面的兩個函式,cv2.Canny() 和 c
Canny邊緣檢測演算法(基於OpenCV的Java實現)
目錄
Canny邊緣檢測演算法(基於OpenCV的Java實現)
緒論
Canny邊緣檢測演算法的發展歷史
Canny邊緣檢測演算法的處理流程
用高斯濾波器平滑影象
彩色RGB
canny邊緣檢測 demo
filename channels rfi 作用 namespace str named names amp
#include <iostream>
#include <string>
#include <sstream>
六 OpenCV圖像處理4 Canny 邊緣檢測
alt left 最大的 max plt src 分享 body 邊界 1.Canny 邊緣檢測原理
步驟:
·1噪聲去除: 由於邊緣檢測很容易受到噪聲影響,所以第一步是使用 5x5 的高斯濾波器 去除噪聲
·2計算圖像梯度:
OpenCV學習代碼記錄——canny邊緣檢測
scalar pos down 輸入 canny emp 函數 color 什麽 很久之前學習過一段時間的OpenCV,當時沒有做什麽筆記,但是代碼都還在,這裏把它貼出來做個記錄。
代碼放在碼雲上,地址在這裏https://gitee.com/solym/OpenCVTes
基於opencv下對視頻的灰度變換,高斯濾波,canny邊緣檢測處理,同窗體顯示並保存
rmi 其他 AS info ali 利用 測試結果 14. 中間 如題:使用opencv打開攝像頭或視頻文件,實時顯示原始視頻,將視頻每一幀依次做灰度轉換、高斯濾波、canny邊緣檢測處理(原始視頻和這3個中間步驟處理結果分別在一個窗口顯示),最後將邊緣檢測結果保存為一個
OpenCV學習筆記(11)——Canny邊緣檢測
bubuko nal die pan 一個 變化 我們 大小 ima
了解Canny邊緣檢測的概念
1.原理
Canny邊緣檢測是一種非常流行的邊緣檢測算法,是 John F。Canny在1986年提出的。它是一個有很多步構成的算法
1)噪聲去除
使用5*5的高