opencv學習筆記之cvSobel 函數解析

来源:http://www.cnblogs.com/feifanrensheng/archive/2017/12/16/8047420.html
-Advertisement-
Play Games

首先,我們來開一下電腦是如何檢測邊緣的。以灰度圖像為例,它的理論基礎是這樣的,如果出現一個邊緣,那麼圖像的灰度就會有一定的變化,為了方便假設由黑漸變為白代表一個邊界,那麼對其灰度分析,在邊緣的灰度函數就是一個一次函數y=kx,對其求一階導數就是其斜率k,就是說邊緣的一階導數是一個常數,而由於非邊緣 ...


首先,我們來開一下電腦是如何檢測邊緣的。以灰度圖像為例,它的理論基礎是這樣的,如果出現一個邊緣,那麼圖像的灰度就會有一定的變化,為了方便假設由黑漸變為白代表一個邊界,那麼對其灰度分析,在邊緣的灰度函數就是一個一次函數y=kx,對其求一階導數就是其斜率k,就是說邊緣的一階導數是一個常數,而由於非邊緣的一階導數為零,這樣通過求一階導數就能初步判斷圖像的邊緣了。通常是X方向和Y方向的導數,也就是梯度。理論上電腦就是通過這種方式來獲得圖像的邊緣。

    但是,具體應用到圖像中你會發現這個導數是求不了的,因為沒一個準確的函數讓你去求導,而且電腦在求解析解要比求數值解麻煩得多,所以就想到了一種替代的方式來求導數。就是用一個3×3的視窗來對圖像進行近似求導。拿對X方向求導為例,某一點的導數為第三列的元素之和減去第一列元素之和,這樣就求得了某一點的近似導數。其實也很好理解為什麼它就近似代表導數,導數就代表一個變化率,從第一列變為第三列,灰度值相減,當然就是一個變化率了。這就是所謂的Prewitt運算元。這樣近似X方嚮導數就求出來了。Y方嚮導數與X方嚮導數求法相似,只不過是用第三行元素之和減去第一行元素之和。X方向和Y方嚮導數有了,那麼梯度也就出來了。這樣就可以找出一幅圖中的邊緣了。

還有一個問題,由於求的是3×3中心點的導數,所以給第二列加了一個權重,它的權重為2,第一列和第三列的權重為1,好了,這就是Sobel運算元了。相比Prewitt運算元,Sobel的抗噪能力更強。如圖所示:

這樣,中心點的Y方嚮導數就求出來了。

舉個例子吧。X點以Sobel方式求導數ΔX=1×50+2×30+1×50-(1×50+2×30+1×50)=0。這樣可以看出這個點不是邊界。

好了,瞭解了基本理論之後,我們看看OpenCv下的Sobel函數吧,void cvSobel( const CvArr* src, CvArr* dst, int xorder, int yorder, int aperture_size=3 );src:輸入圖像;dst:輸出圖像;xorder:x 方向上的差分階數;yorder:y 方向上的差分階數;aperture_size 擴展 Sobel 核的大小(既視窗階數),必須是 1(註意這是一個3×1或1×3向量而不是一個方陣), 3, 5 或 7。

其實,這裡是問題的,因為以Sobel方式求完導數後會有負值,還有會大於255的值而你建的Sobel的圖像是 IPL_DEPTH_8U,也就是8位無符號數,所以Sobel建立的圖像位數不夠,要16位有符號的,也就是 IPL_DEPTH_16S。把建立圖像這句改為

sobel=cvCreateImage(cvGetSize(frame),IPL_DEPTH_16S,1);運行,發現不報錯了,但是Sobel圖像顯示不出來,這是什麼原因呢?原來圖像顯示是以8位無符號顯示的,現在是16位有符號,當然顯示會出問題了。所以還要將Sobel轉為8位無符號。OpenCv里提供了一個函數,就是cvConvertScaleAbs( const CvArr* src, CvArr* dst, double scale=1, double shift=0 );src:源圖像;dst:目標圖像;scale:轉化前乘的繫數;shift轉化前加的繫數。這樣新建一個無符號圖像再轉換就可以實現了。

IplImage *sobel8u=cvCreateImage(cvGetSize(sobel),IPL_DEPTH_8U,1);

再在顯示圖像前加上cvConvertScaleAbs(sobel,sobel8u,1,0);這樣就可以看到cvSobel的效果了。可以看X方向或Y方向求導是什麼效果。

代碼如下

 1 //Sobel邊緣檢測的程式
 2 #include "cv.h"
 3 #include "highgui.h"
 4 int main( int argc , char** argv)
 5 {
 6   //以灰度圖格式載入圖像或者用函數cvCvtColor(frame,gray,CV_BGR2GRAY);轉為灰度
 7   IplImage* src = cvLoadImage(argv[1],CV_LOAD_IMAGE_GRAYSCALE);
 8   //以sobel方式求完導之後會有負數,會有大於255的值,故建立圖像的數據格式
 9   //要為IPL_DEPTH_16S
10   IplImage* dst1 = cvCreateImage(cvGetSize(src),IPL_DEPTH_16S,1);
11   IplImage* dst2 = cvCreateImage(cvGetSize(src),IPL_DEPTH_16S,1);
12   IplImage* dst18u = cvCreateImage(cvGetSize(src),IPL_DEPTH_8U,1);
13   IplImage* dst28u = cvCreateImage(cvGetSize(src),IPL_DEPTH_8U,1);
14   //逼近x方向上一階微分的Sobel運算元的效果
15   cvSobel(
16           src,
17           dst1,
18           1,
19           0,
20           3);
21   //逼近y方向上一階微分的Sobel運算元的效果  
22   cvSobel(
23           src,
24           dst2,
25           0,
26           1,
27           3);
28   //圖像是以8位無符號顯示的,故要把輸出圖像的數據格式轉化為IPL_DEPTH_8U
29   cvConvertScaleAbs(dst1,dst18u,1,0);
30   cvConvertScaleAbs(dst2,dst28u,1,0);
31   cvNamedWindow("src",1);
32   cvNamedWindow("dst1",1);
33   cvNamedWindow("dst2",1);
34   cvShowImage("src",src);
35   cvShowImage("dst1",dst18u);
36   cvShowImage("dst2",dst28u);
37   cvWaitKey(0);
38   cvReleaseImage(&src);
39   cvReleaseImage(&dst1);
40   cvReleaseImage(&dst2);
41   cvReleaseImage(&dst18u);
42   cvReleaseImage(&dst28u);
43   cvDestroyWindow("src");
44   cvDestroyWindow("dst1");
45   cvDestroyWindow("dst2");
46   return 0;
47 }

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、2個概念: 1、變數可以指向函數本身 2、函數名也是變數 二、高階函數 一個函數可以接收另一個函數作為參數,這種函數就稱之為高階函數。 ...
  • 要求: 1.完成常識中的ATM存取款機功能 2.把ATM機故障考慮進去 3.不能直接輸入賬戶名和卡號等等信息,模擬出插銀行卡讓ATM機自動讀取卡信息 4.密碼驗證超過三次錯誤即鎖定賬戶 5.操作類型有:存款,取款,查詢,轉賬,列印憑條,退卡,一共六個選項,跟用戶輸入做出不同的反饋 6.當用戶正常進入 ...
  • 概述      java中的參數傳遞問題可以根據參數的類型大致可以分為三類:傳遞基本類型,傳遞String類型,傳遞引用類型,至於最終是否可以歸納為值傳遞和引用傳遞,根據每個人的理解不同,答案不同,此處不做強調。 傳遞基本類型 結果 :Before ...
  • 參考大佬博文:blog.csdn.net/jia20003/article/details/7724530 lps-683.iteye.com/blog/2254368 openCV里有兩個函數(比較常用)處理霍夫變換直線檢測,有什麼區別呢。 CvHoughLine:是用於標準的霍夫變換方法 CvH ...
  • 作為一名軟體開發者,要追求的,應該是不斷地提升自己分析問題把握事物關鍵點,實事求是地給出切實可行且能“一劍封喉”的優雅解決方案的能力,再提升一點境界,就是要不斷提升自己創新的能力(即創造新東西、提出新思路、解決新問題的能力)。 我個人認為,花費大量的時間去"精通"某種語言、某個平臺和某些工具,其實是 ...
  • 一、可迭代對象定義 可以直接作用於for迴圈的數據類型有以下幾種: 一類是集合數據類型,如list、tuple、dict、set、str、bytes、bytearray等; 一類是generator,包括表達式生成器和帶yield的函數生成器。 這些可以直接作用於for迴圈的對象統稱為可迭代對象:I ...
  • 一、生成器定義 通過列表生成表達式,我們可以直接創建一個列表。但是,受到記憶體限制,列表容量肯定是有限的。所以,如果列表元素可以按照某種演算法推算出來,那我們是否可以在迴圈的過程中不斷推算出後續的元素呢?這樣就不必創建完整的list,從而節省大量的空間。在Python中,這種一邊迴圈一邊計算的機制,稱為 ...
  • Jupyter Notebook 有兩種鍵盤輸入模式。 編輯模式,允許你往單元中鍵入代碼或文本,這時的單元框線是綠色的。 命令模式,鍵盤輸入運行程式命令;這時的單元框線是藍色。 命令模式 (按鍵 Esc 開啟) Enter : 轉入編輯模式 Shift-Enter : 運行本單元,選中下個單元 Ct ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...