用 Opencv 和 Python 對汪星人做模糊檢測
(點擊
上方公眾號
,可快速關注)
編譯:伯樂在線 - NoneLand,英文:Adrian Rosebrock
http://python.jobbole.com/83702/
Jemma,一隻超級甜美,極其活潑可愛的家養米格魯獵犬,可能是家裡有史以來照片最多的狗狗了。從我在她
八周大
的時候遇到她開始,三年以來,我已經累積了6000 多張她的照片。過度了吧?
或許是吧。但是我喜歡狗狗。非常喜歡。尤其是米格魯獵犬。所以應該不足為奇,作為狗狗主人的我,會花很多時間用 Jemma 最喜歡的玩具和她玩拔河遊戲,或者和她在廚房地板上滾來滾去相互打鬧。當然,我會用我的 iphone 拍攝大量她的照片。
在剛剛過去的這個周末,我坐下來想在 iphoto 中整理這些海量的照片。這不僅僅意味著巨大的工作量,因為我很快注意到一個現象——其中充斥著大量模糊的照片。
主要因為我的攝影技術比較low,Jemma又特別活潑,跑來跑去,有時候看到我拍照,它又嚇得縮起來發抖,所以我抓拍的效果不是很好,導致有多照片都是模糊的
作為一個普通人,我可能會想軟體設計者們會開發出新功能來檢測出這些模糊的照片(或者至少把他們移到一個單獨的文件夾)。但是作為一個計算機視覺科學家,我是不會這樣想的。
相反,我打開編輯器很快就編寫了一個 Python 腳本,用 OpenCV 來執行模糊檢測。
在這篇文章剩下的部分里,我將會展示如何用 OpenCV、Python 和拉普拉斯運算元來計算圖片中的模糊量。到文章結束,讀者就能應用
拉普拉斯方差演算法
來檢測圖片中的模糊量。
拉普拉斯方差演算法(Variance of the Laplacian)
圖1,用拉普拉斯運算元與輸入圖像做卷積
我檢測圖片模糊量的第一步就是去拜讀這篇優秀的綜述文獻——《Analysis of focus measure operators for shape-from-focus》[2013 Pertuz et al.]。在這篇文獻中,Pertuz 等人論述了近 36 種不同的圖片清晰度評價(focus measure)方法。
如果讀者了解信號處理,就會知道最直接的方法就是計算圖片的快速傅里葉變換,然後查看高低頻的分布。如果圖片有少量的高頻成分,那麼該圖片就可以被認為是模糊的。然而,區分高頻量多少的具體閾值卻是十分困難的,不恰當的閾值將會導致極差的結果。
相反,如果我們能用計算出的一個具體浮點數值來表徵圖片的模糊程度,豈不是十分優雅?
Pertuz 等人討論了很多種方法來計算「模糊度」。其中的一些方法簡單明了,僅僅使用了像素灰度值的統計數據,其他的一些相比更加先進並且是基於特徵的,使用了局部二值模式。
在快速瀏覽論文之後,我開始著手實現我找到的拉普拉斯方差演算法——出自 Pech-Pacheco 等人 2000 年模式識別國際會議論文:《Diatom autofocusing in brightfield microscopy: a comparative study》
這種方法簡潔明了,論證翔實,並且可以通過僅僅一行代碼來實現:
cv2.Laplacian(image, cv2.CV_64F).var()
只需要將圖片中的某一通道(但一般用灰度值)用下面的拉普拉斯掩模做卷積運算:
圖2,拉普拉斯掩模
然後計算方差(即標準差的平方)。
如果某圖片方差低於預先定義的閾值,那麼該圖片就可以被認為是模糊的。高於閾值,就不是模糊的。
這種方法湊效的原因就在於拉普拉斯運算元定義本身。它被用來測量圖片的二階導數,突出圖片中強度快速變化的區域,和 Sobel 以及 Scharr 運算元十分相似。並且,和以上運算元一樣,拉普拉斯運算元也經常用於邊緣檢測。此外,此演算法基於以下假設:如果圖片具有較高方差,那麼它就有較廣的頻響範圍,代表著正常,聚焦準確的圖片。但是如果圖片具有有較小方差,那麼它就有較窄的頻響範圍,意味著圖片中的邊緣數量很少。正如我們所知道的,圖片越模糊,其邊緣就越少。
很顯然,此演算法的技巧在於設置合適的閾值。然而,閾值卻十分依賴於所應用的領域。閾值太低會導致正常圖片被誤斷為模糊圖片,閾值太高會導致模糊圖片被誤判為正常圖片。這種方法在能計算出可接受清晰度評價值的範圍的環境中趨於發揮作用,能檢測出異常照片。
檢測圖片中的模糊量
到目前為止,本文已經介紹完了計算給定圖片模糊度的方法。下面這十二張圖片組成的數據集將會在下文用到:
圖3,圖像數據集
在這些圖片中,有些是模糊的,有些是正常的,而要完成目標就是把它們區分開來。
如前文所述,新建文件並命名為」detect_blur.py」,開始碼代碼吧:
# import the necessary packages
from
imutils
import
paths
import
argparse
import
cv2
def
variance_of_laplacian
(
image
)
:
# compute the Laplacian of the image and then return the focus
# measure, which is simply the variance of the Laplacian
return
cv2
.
Laplacian
(
image
,
cv2
.
CV_64F
).
var
()
# construct the argument parse and parse the arguments
ap
=
argparse
.
ArgumentParser
()
ap
.
add_argument
(
"-i"
,
"--images"
,
required
=
True
,
help
=
"path to input directory of images"
)
ap
.
add_argument
(
"-t"
,
"--threshold"
,
type
=
float
,
default
=
100.0
,
help
=
"focus measures that fall below this value will be considered "blurry""
)
args
=
vars
(
ap
.
parse_args
())
在代碼開始的2-4行,導入了必需的模塊。如果讀者還沒有安裝我開發的 imutils 模塊,請先安裝該模塊:
$ pip intall imutils
在代碼第六行中,定義了 variance_of_laplacian 函數。此函數只接收一個待計算清晰度評價的 image 參數(假設是單通道圖像,例如灰度圖)。第九行對 image 用3×3拉普拉斯運算元做卷積,然後返回方差。
12-17行處理命令行參數解析。第一個需要的參數是 –image,包含進行模糊度檢測的圖片數據集路徑。
代碼中還定義了一個可選參數 –thresh, 是用於模糊檢測的閾值。如果給定圖片的清晰度評價值低於該閾值,該圖片就會被判定為模糊。如果讀者使用其他的數據集,調整該閾值是很重要的。閾值 100 對於本文所使用的數據集效果良好,但是閾值受具體圖片內容影響較大,因此為了獲得最優結果,讀者需要審慎地確定閾值。
不管你信不信,最艱苦的部分已經完成了。剩下的就只需要寫點代碼來從磁碟中讀入圖片,計算拉普拉斯方差然後標記圖片為模糊或者正常:
# import the necessary packages
from
imutils
import
paths
import
argparse
import
cv2
def
variance_of_laplacian
(
image
)
:
# compute the Laplacian of the image and then return the focus
# measure, which is simply the variance of the Laplacian
return
cv2
.
Laplacian
(
image
,
cv2
.
CV_64F
).
var
()
# construct the argument parse and parse the arguments
ap
=
argparse
.
ArgumentParser
()
ap
.
add_argument
(
"-i"
,
"--images"
,
required
=
True
,
help
=
"path to input directory of images"
)
ap
.
add_argument
(
"-t"
,
"--threshold"
,
type
=
float
,
default
=
100.0
,
help
=
"focus measures that fall below this value will be considered "blurry""
)
args
=
vars
(
ap
.
parse_args
())
# loop over the input images
for
imagePath
in
paths
.
list_images
(
args
[
"images"
])
:
# load the image, convert it to grayscale, and compute the
# focus measure of the image using the Variance of Laplacian
# method
image
=
cv2
.
imread
(
imagePath
)
gray
=
cv2
.
cvtColor
(
image
,
cv2
.
COLOR_BGR2GRAY
)
fm
=
variance_of_laplacian
(
gray
)
text
=
"Not Blurry"
# if the focus measure is less than the supplied threshold,
# then the image should be considered "blurry"
if
fm
&
lt
;
args
[
"threshold"
]
:
text
=
"Blurry"
# show the image
cv2
.
putText
(
image
,
"{}: {:.2f}"
.
format
(
text
,
fm
),
(
10
,
30
),
cv2
.
FONT_HERSHEY_SIMPLEX
,
0.8
,
(
0
,
0
,
255
),
3
)
cv2
.
imshow
(
"Image"
,
image
)
key
=
cv2
.
waitKey
(
0
)
代碼第二十行遍歷給定目錄中的所有圖片。對每一幅從磁碟載入的圖像,先將它們轉化為灰度圖,然後用OpenCV執行模糊檢測(代碼24-27行)。
如果圖像的清晰度低於命令行提供的預置參數,該圖像將被標記為「模糊」。
在代碼最後,第35-38行將 text 和計算出的清晰度評價值寫入圖像中並將圖像展示在屏幕上。
用OpenCV執行模糊檢測
至此,detect_blur.py 腳本已經編寫完畢,來練練手吧。打開命令行,敲入以下命令:
$ python detect_blur.py --images images
圖4,準確標記為「模糊」
這張圖象的清晰度評價值為 83.17,低於閾值 100,因此標記其為「模糊」。
此圖像清晰度評價值為64.25,同樣標記其為「模糊」。
圖6,標記為「正常」
圖像6的清晰度評價值高達 1004.14,比前兩張圖像高出兩個數量級。毫無疑問,此圖不模糊,十分清晰。
此圖唯一模糊的地方在 Jemma 搖動的尾巴上。
雖然此圖的清晰度評價值低於圖7,但是我們還是可以把它準確歸入「正常」。
我們可以清除看見上圖的模糊。
如此高的清晰度評價值意味著此圖「正常」。
此圖中包含有大量的模糊。
圖12,標記為「模糊」
圖13,和圖12相比,模糊量大大減少
圖14,準確標記為「正常」
圖15,標記為「模糊」
總結
在此文中,我們學習了用 OpenCV 和 Python 來執行模糊檢測。
我們實現了拉普拉斯方差演算法,該演算法提供給我們一個浮點數來代表具體圖像的「模糊度」。該演算法快速,簡單且易於使用——用拉普拉斯運算元與輸入圖像做卷積然後計算方差即可。如果方差低於預定義閾值,圖像就被標記為「模糊」。
讀者必須明白閾值是一個很重要的待調整參數,針對每一個數據集都需要重新設定,閾值太低會導致正常圖片被誤斷為模糊圖片,閾值太高會導致模糊圖片被誤判為正常圖片。
下載代碼,然後嘗試一下吧!
鏈接:http://pan.baidu.com/s/1o7x909c
看完本文有收穫?請轉
發分享給更多人
關注「P
ython開發者」,提升Python技能
TAG:Python開發者 |