❶ OpenCV(二)掩碼操作與平滑(均值,高斯模糊)
OpenCV知識總結來到了下一個難度高一點的,掩碼操作和模糊效果,這是圖像處理裡面常見的操作。
如果遇到問題請在這里聯系我: https://www.jianshu.com/p/67324fb69074
掩碼操作實際上思想上很簡單:根據一個掩碼矩陣(卷積核)重新計算圖像中的每一個像素。掩碼矩陣中的值表示近鄰像素的值(包括自身像素的值)對新像素的值有多大的影響,從數學上觀點看來,就是對掩碼矩陣內每一個設置好權重,然後對對應的像素領域內做一個權加平均。
卷積是什麼?用一個簡單的公式來表示:
本質上,卷積就是這種思想。卷積把萬事萬物看成一個輸入,當萬事萬物的狀態出現了變化,則會通過某種系統產生變化,變成另一種輸出狀態。而這個系統往往就在數學眼裡就叫做卷積。
而在深度學習中,往往每一個卷積核是一個奇數的矩陣,做圖像識別的時候會通過這個卷積核做一次過濾,篩選出必要的特徵信息。
那麼掩碼操作在數學上是怎麼回事?我們平常運用掩碼做什麼?在OpenCV中掩碼最常見的操作就是增加圖片對比度。對比度的概念是什麼,在上一節聊過,通俗來講就是能夠增強像素之間的細節。我們可以對對每個像素做如下操作:
可能這幅圖,理解起來比較困難。實際上流程如此:
舉個例子,就以計算出掩碼矩陣之後的E的位置,能看到此時是原圖中所有的像素都會取出和掩碼矩陣一樣大小的矩陣。也就是取出原圖的紅色那一塊的領域,分別對E周邊包括自己做了一次加權處理,最後賦值回E中。
並且進行如下的權加公式:
這樣就能對原來的矩陣進行掩碼處理。但是這么做發現沒有,如果我們要對A做掩碼處理就會發現掩碼矩陣對應到原圖的位置不存在。現在處理有兩種,一種是不對邊緣的像素做掩碼處理,另一種是為周邊的圖像做一個padding處理,這種操作在深度學習的圖像處理中很常見,通常設置0像素,或者拷貝對邊的邊緣像素。
能看到這里處理和卷積處理不太一樣,只是為了方便,把這種掩碼濾波操作稱為一種核,是自相關,並不是去計算卷積。
能看到此時這兩張圖片的對比度有很明顯的區別。經過掩碼矩陣之後,會發現原圖會更加平滑一點,而掩碼操作之後會導致整個圖片最亮和最暗之間的差距拉大。
從數學公式上來看,當前像素權重為5,周邊的點的權重是-1和0.能夠發現會對當前的節點加深,同時把周圍的像素值減掉,就增加了每一個像素點和周邊像素差值,也就是對比度。
當然在OpenCV中,有這么一個函數filter2D,處理掩碼操作。
這里創建一個3*3的核。這個核實際上就是上圖的那個。這樣傳遞一個掩碼矩陣和圖像的深度就完成了掩碼操作。
平滑也稱為模糊,是一項高頻率使用的操作。
平滑的作用有很多,其中一項就是降噪音。平滑處理和掩碼操作有點相似,也是需要一個濾波器,我們最常用的濾波器就是線性濾波器。線性濾波處理的輸出像素值 是輸出像素值 的權加和:
其中,h(k,l)成為核,它僅僅只是一個權加系數。圖形上的操作和上面的圖相似。不妨把核當成一個滑動窗口,不斷的沿著原圖像素的行列掃動,掃動的過程中,不斷的把路過像素都平滑處理。
這里先介紹均值濾波器,它的核心如下:
這里的參數意思是,src:輸入的圖像,dst:經過均值模糊之後的輸出圖像,Size:是指這個濾波器的大小,Point是指整個圖像模糊繞著哪個原點為半徑的進行處理,傳入(-1,-1)就是指圖像中心,這樣就能模糊整個圖像。
其計算原理很簡單就是,把核裡面的所有權重設置為1,最後全部相加求平均值。最後賦值到原來的像素上。
最有用的濾波器 (盡管不是最快的)。 高斯濾波是將輸入數組的每一個像素點與 高斯內核 卷積將卷積和當作輸出像素值。
高斯模糊實際上是一個二維的高斯核。回顧一下一維的高斯函數:
那麼二維實際上就是,就是在原來的x,y軸的情況下,增加一個z軸的緯度,實際上看起來就像一座山一樣。
二維的高斯函數可以表示為:
為了達到達到
其OpenCV的調用方式:
這里的參數意思是,src:輸入的圖像,dst:經過高斯模糊之後的輸出圖像,Size:是指這個濾波器的大小。sigmaX和sigmaY分別指代的是高斯模糊x軸上和y軸上的二維高斯函數的變化幅度。
換個形象的話說,用上圖舉個例子,就是確定這個高斯函數這個山的x方向的陡峭程度以及y軸方向的陡峭程度。
下面就高斯模糊,均值模糊和原圖的比對
能看到,高斯模糊比起均值模糊保留了圖像中相關的形狀信息。
為什麼會這樣呢?原因很簡單。因為在計算高斯模糊之前,會根據當前像素區域中所有的像素點進行一次,核的計算,越往中心的權重越高,權重如同小山一下,因此中心的像素權重像素一高了,雖然模糊但是還是保留了原來的形狀。
但是當高斯模糊的矩陣大小和sigmaX,sigmaY相似的時候,整個高斯函數就不像山,而是想平原一樣平坦。換句話說,整個高斯核中的權重就會,偏向一,就會導致和均值模糊類似效果。
高斯模糊計算流程:
圖像中某一段圖形的像素是如下分布,
這個時候高斯模糊需要一個核去對每一個位置做濾波。此時不同於均值模糊,沒有固定的核矩陣,而是通過上面這個矩陣,計算出高斯的核,最後再計算變化後的矩陣每一個對應的像素。
雖然原理是這樣,但是實際上OpenCV為了迅速,在原生實現的時候,內部判斷到核是小於7的大小,設置一套固定的高斯模糊矩陣。
這樣直接就結束,不是我文章的風格,作為一個程序員,還是有必要探索一下,為什麼OpenCV計算速度會比我們自己手寫的快。
為了讓源碼看的不那麼辛苦,先聊聊OpenCV底層的設計思想。首先在OpenCV中,內置了幾種計算方案,按照效率高低優先度依次的向後執行。
這種設計可以看成我們的平常開發的攔截器設計。當發現優先度高的計算模式發現可以使用的時候,OpenCV將會使用這種模式下的演算法進行運算。
一般來說,OpenCV內置如下四個層級計算方案,按照優先順序依次為:
能看到按照這個優先順序不斷的向下查找,找到當前OpenCV最快的計算環境。除了最後一個之外,其他三個都是並發計算。
記住這個流程,我們查看OpenCV的源碼就很輕鬆了。
先來看看filter2D的源碼。
果不其然,在filter2D實現的第一步,就開始調用CV_OCL_RUN宏去調用OpenCL的顯卡並發計算。
能看到,這裡面發送了一個condition和一個方法到OpenCL中運行。但是如果,OpenCV在編譯的時候,我們沒有打開這個OpenCL的選項,沒有OpenCL的環境的時候,它實際上就是一個沒什麼用處的宏:
當有了OpenCL的環境,這個宏就會替換成這個:
能清晰的看到,此時會判斷當前的OpenCL是否還在活躍,活躍的狀態,並且條件和方法符合規范,就會通過CV_IMPL_ADD,把方法添加到一個vector向量中,讓OpenCL讀取執行。
在這裡面,OpenCV想要使用OpenCL進行計算,就需要這個Mat的類型是UMat,並且是緯度小於等於2.當不符合這兩個條件將不會執行OpenCL。
UMat是專門給OpenCL規范計算而使用的矩陣。裡面有很多和Mat相似的方法。
此時可能是多線程處理,因此會添加一個智能鎖,去保證數據的正確性。
具體的思路,將不作為重點,這邊先看看OpenCV是傳入了ocl_filter2D的方法,看看這個方法在OpenCL中的執行流程。
OpenCL會把命令最後發送到顯卡處理。
實際上這一步和上面的方法有點相似。本質上都是獲取需要模糊的區域,如果是(-1,-1),則取中心點,接著判斷當前濾波對邊緣的處理(BORDER_ISOLATED 不去獲取Point為圓心設置的模糊之外的區域)。
能看到這個枚舉已經解釋很清楚了,默認的邊緣處理是復制二個和倒數第二個填充邊緣。
最後進入到hal的filter2D進一步操作。
能看到這里有四種方式:
在情況1中,一般的情況replacementFilter2D返回的是一個沒有實現的錯誤碼,第二種情況是Intel的並行計算庫,沒有任何研究,跳過。我們來看看第三種情況和第四種情況
當然這裡面判斷能夠使用dft的判斷首先要當前必須要整張圖做濾波處理,其次是不能是(0,0)的點為圓心做濾波。最後要判斷當前當前的cpu指令是否支持,支持則允許核的寬 高最高為130以內使用原生實現,否則只支持核的寬 高為50以內使用原生實現。
能看到這裡面的核心就是調用crossCorr,處理核以及原圖的矩陣(使用了快速傅立葉處理相關性計算)。最後從同add添加到目標Mat中,由於add的delta函數為0,因此就和替代的效果一致。
能看到此時,先初始化一個FilterEngine(線性濾波引擎),接著使用apply調用濾波引擎的執行方法。
我們來看看線性引擎的創建:
實際上在這個過程中通過makePtr創建一個sharedptr的指針指向FilterEngine,其原理和Android的智能指針相似。
這個引擎不是關鍵關鍵的是getLinearFilter,這個方法創建了一個線性濾波器的實際操作對象。
我們來看看這個結構體:
能看到這裡面會根據次數傳進來的目標矩陣和原始矩陣的位深創建不同的濾波操作者。
假設,我們現在原圖和目標圖都是8位位深的矩陣,我們只需要關注下面這個構造函數。
Fliter2D結構體持有著模糊中心點,核,原/目標矩陣, 可以猜測到實際上正在做操作的就是這個結構體。
在preprocess2DKernel方法中,Fliter2D把核的相關信息存儲到coords,coeffs中
可以看到此時會判斷當前的核矩陣中type是什麼,接著再把矩陣中每一個不為0的位置設置進coords,像素數值設置到_coeffs。此時相當於把核矩陣展開成一個向量。
能看到此時濾波引擎會先調用FilterEngine__start,再調用FilterEngine__proceed執行計算。
實際上在FilterEngine__start中計算的是本次循環,需要計算的邊界。
FilterEngine__proceed中才是正式計算,做dst循環,最後把具體操作丟給線性引擎生成的Fliter2D的方法中。
了解這兩個東西我們直接抽出核心看看fliter是如何運作:
❷ 怎麼用Photoshop製作easyx需要用的掩碼圖啊
在原有的圖片編碼方法基礎上,增加像素的透明度信息。圖形處理中,通常把RGB三種顏色信息稱為紅通道、綠通道和藍通道,相應的把透明度稱為Alpha通道。多數使用顏色表的點陣圖格式都支持Alpha通道。
簡單的來說,掩碼圖就是設置一個區域,使其不參加處理
❸ 用什麼軟體可以將普通圖片轉換為矢量圖
矢量圖軟體AI可以編輯矢量圖,但注意的是不是所有圖片都可以轉化為矢量圖的。