頻率:
對于聲音,頻率實(shí)際上是指聲波振蕩的速度
高低頻率
高頻圖像是強(qiáng)度變化很大的圖像不跟。并且亮度級別從一個(gè)像素到下一個(gè)像素快速變化爷贫。低頻圖像可以是亮度相對均勻或變化非常慢的圖像想虎。這是一個(gè)例子中最容易看到的房匆。
大多數(shù)圖像都有高頻和低頻成分耸成。在上圖中,在圍巾和條紋襯衫上浴鸿,我們有一個(gè)高頻圖像模式; 這部分從一個(gè)亮度變化到另一個(gè)亮度井氢。在同一圖像中,我們看到天空和背景的部分變化非常緩慢岳链,這被認(rèn)為是平滑的低頻模式花竞。
高頻分量也對應(yīng)于圖像中對象的邊緣,這可以幫助我們對這些對象進(jìn)行分類宠页。
傅里葉變換
傅里葉變換(FT)是一種重要的圖像處理工具左胞,用于將圖像分解為其頻率分量寇仓。FT的輸出表示頻域中的圖像举户,而輸入圖像是空間域(x,y)等效物遍烦。在頻域圖像中俭嘁,每個(gè)點(diǎn)表示包含在空間域圖像中的特定頻率。因此服猪,對于具有大量高頻分量(邊緣供填,角落和條紋)的圖像,頻域中將存在高頻率值的多個(gè)點(diǎn)罢猪。
足球運(yùn)動員的圖像和相應(yīng)的頻域圖像(右)近她。頻域圖像中心的集中點(diǎn)意味著該圖像具有許多低頻(平滑背景)分量
在這里,看看如何使用OpenCV完成FT 膳帕。
傅里葉變化練習(xí)
原圖如左下所示粘捎,經(jīng)過傅里葉變換后薇缅,圖像更加接近D
高通濾波器
在圖像處理中,我們用過濾器來過濾掉圖像中不需要或無關(guān)的信息攒磨,也用過濾器來放大某些特征泳桦,比如物體邊界或其他顯著特征。
高通濾波器用于銳化圖像以及強(qiáng)化圖像的高頻區(qū)域娩缰,也就是相鄰像素發(fā)生突變的區(qū)域灸撰,比如從極暗過度到極亮的那些區(qū)域,由于我們觀察的是強(qiáng)度模式拼坎,所以用過濾器來處理灰度圖像(灰度圖像會以簡單的格式將明暗情況展示出來浮毯,從而體現(xiàn)強(qiáng)度)
以熊貓圖片為例:原圖那些強(qiáng)度沒有變化或變化不大的區(qū)域,原圖那些強(qiáng)度沒有變化或變化不大的區(qū)域泰鸡,會被高通過濾器過濾掉 而且像素顏色會變?yōu)楹谏坠欤坏谶@些區(qū)域里 由于像素比鄰近像素明亮許多,但在這些區(qū)域里 由于像素比鄰近像素明亮許多鸟顺,結(jié)果就是把邊緣強(qiáng)化了惦蚊。(所謂邊緣 就是指圖像里強(qiáng)度發(fā)生突變的區(qū)域,通常暗示著物體邊界的存在)
這類過濾器的具體原理讯嫂,過濾器是以矩陣形式存在的蹦锋,通常稱為卷積核。
以檢測邊緣的高通過濾器為例欧芽,這是個(gè)三乘三的核 其元素總和為 0莉掂,邊緣檢測時(shí) 所有元素總和為 0 是很重要的。因?yàn)檫@類過濾器要計(jì)算的是相鄰像素的差異 或者說變化千扔,要計(jì)算差異 就需要將像素值相減憎妙。在這個(gè)例子中 我們要將中間像素與周圍像素的值相減,如果這些核值加起來不等于 0曲楚,那就意味著計(jì)算出來的差厘唾,權(quán)重會有正負(fù),結(jié)果就是濾波后的圖像亮度會相應(yīng)地提高或或降低
該內(nèi)核找到圍繞給定像素的頂部邊緣和底部邊緣之間的差異
這里我們使用opencv filter2D來創(chuàng)建
Sobel濾波器
Sobel濾波器非常常用于邊緣檢測和在圖像中查找強(qiáng)度模式
創(chuàng)建過濾器
低通濾波
噪聲通常就是圖像的斑點(diǎn)或變色部分不含任何有用信息甚至?xí)绊懱幚聿僮髁埽热缭谶吘墮z測時(shí) 如果沒有先解決噪聲 高通過濾器就會把噪聲強(qiáng)化抚垃。
低通過濾器是噪聲最常見的解決方式,這類過濾器能阻擋特定高頻部分趟大,有效模糊圖像或使圖像平滑起來鹤树,從而減少高頻噪聲,這種過濾器的實(shí)用性在醫(yī)學(xué)影像里淋漓盡致地體現(xiàn)了出來
要降噪 我們可以取相鄰像素的均值逊朽,從而避免強(qiáng)度突變 特別是小范圍突變罕伯,而這種取空間像素均值的做法,同應(yīng)用低通過濾器來過濾高頻噪聲是一樣的叽讳。
我們來看一個(gè)例子 用普通核來降噪:第一個(gè)也是最簡單的一個(gè) 均值過濾器追他,會賦予中心像素及其相鄰像素一樣的權(quán)重熊昌,低通過濾器通常會取均值 不像高通過濾器取的是差值,因此低通過濾器的元素加起來應(yīng)該為 1湿酸。這就能保留圖像的亮度井赌,但我們可以看到 這個(gè)核的元素加起來等于 9切厘,所以我們需要進(jìn)行歸一化處理 也就是將核值總和除以 9
如果對整張圖像的所有像素進(jìn)行同樣的均值處理剩胁,我們就能使圖像變得平滑 圖像里的強(qiáng)度突變也會變少缚陷,這有利于減少噪聲,或使處于一定強(qiáng)度范圍的背景區(qū)域看起來更加平滑铁坎。實(shí)際上 這類過濾器在 Photoshop 里也有應(yīng)用蜂奸,可對圖像的某一部分進(jìn)行柔化或模糊處理。
高斯模糊
除了全均值過濾器硬萍,有時(shí)我們會想要個(gè)既能模糊圖像 又能更好地保存圖像邊緣的過濾器扩所,為此 我們可用高斯模糊。這或許是計(jì)算機(jī)視覺應(yīng)用中最常用的低通過濾器了朴乖。低通過濾.器其實(shí)就是加權(quán)平均法 賦予中心像素最大的權(quán)重.
在進(jìn)行濾波處理之前,首先要將圖像轉(zhuǎn)換為灰度圖.
Import resources and display image
import numpy as np
import matplotlib.pyplot as plt
import cv2
%matplotlib inline
# Read in the image
image = cv2.imread('images/brain_MR.jpg')
# Make a copy of the image
image_copy = np.copy(image)
# Change color to RGB (from BGR)
image_copy = cv2.cvtColor(image_copy, cv2.COLOR_BGR2RGB)
plt.imshow(image_copy)
#### 怎么確定濾波器低通或者高通
# Convert to grayscale for filtering
gray = cv2.cvtColor(image_copy, cv2.COLOR_RGB2GRAY)
# Create a Gaussian blurred image
gray_blur = cv2.GaussianBlur(gray, (9, 9), 0) ### 0 表示標(biāo)準(zhǔn)差為0
f, (ax1, ax2) = plt.subplots(1, 2, figsize=(20,10))
ax1.set_title('original gray')
ax1.imshow(gray, cmap='gray')
ax2.set_title('blurred image')
ax2.imshow(gray_blur, cmap='gray')
Test performance with a high-pass filter
# High-pass filter
# 3x3 sobel filters for edge detection
sobel_x = np.array([[ -1, 0, 1],
[ -2, 0, 2],
[ -1, 0, 1]])
sobel_y = np.array([[ -1, -2, -1],
[ 0, 0, 0],
[ 1, 2, 1]])
# Filter the orginal and blurred grayscale images using filter2D
filtered = cv2.filter2D(gray, -1, sobel_x)
filtered_blurred = cv2.filter2D(gray_blur, -1, sobel_x)
filtered_blurred_y = cv2.filter2D(gray_blur, -1, sobel_y)
f, (ax1, ax2,ax3) = plt.subplots(1, 3, figsize=(20,10))
ax1.set_title('original gray')
ax1.imshow(filtered, cmap='gray')
ax2.set_title('blurred image_x')
ax2.imshow(filtered_blurred, cmap='gray')
ax3.set_title('blurred image_y')
ax3.imshow(filtered_blurred_y, cmap='gray')
# Create threshold that sets all the filtered pixels to white
# Above a certain threshold
retval, binary_image = cv2.threshold(filtered_blurred, 50, 255, cv2.THRESH_BINARY)
plt.imshow(binary_image, cmap='gray')
import numpy as np
import matplotlib.pyplot as plt
import cv2
%matplotlib inline
# Define gaussian, sobel, and laplacian (edge) filters
gaussian = (1/9)*np.array([[1, 1, 1],
[1, 1, 1],
[1, 1, 1]])
sobel_x= np.array([[-1, 0, 1],
[-2, 0, 2],
[-1, 0, 1]])
sobel_y= np.array([[-1,-2,-1],
[0, 0, 0],
[1, 2, 1]])
# laplacian, edge filter
laplacian=np.array([[0, 1, 0],
[1,-4, 1],
[0, 1, 0]])
filters = [gaussian, sobel_x, sobel_y, laplacian]
filter_name = ['gaussian','sobel_x', \
'sobel_y', 'laplacian']
# perform a fast fourier transform on each filter
# and create a scaled, frequency transform image
f_filters = [np.fft.fft2(x) for x in filters]
fshift = [np.fft.fftshift(y) for y in f_filters] # 1祖屏、在matlab中,經(jīng)過fft變換后买羞,數(shù)據(jù)的頻率范圍是從[0,fs]排列的袁勺。
#2、而一般畜普,我們在畫圖或者討論的時(shí)候期丰,是從[-fs/2,fs/2]的范圍進(jìn)行分析。
#3吃挑、因此钝荡,需要將經(jīng)過fft變換后的圖像的[fs/2,fs]部分移動到[-fs/2,0]這個(gè)范圍內(nèi)。
frequency_tx = [np.log(np.abs(z)+1) for z in fshift]
# display 4 filters
for i in range(len(filters)):
plt.subplot(2,2,i+1),plt.imshow(frequency_tx[i],cmap = 'gray')
plt.title(filter_name[i]), plt.xticks([]), plt.yticks([])
plt.show()
白色或淺灰色的區(qū)域舶衬,允許那部分頻譜通過!黑色區(qū)域意味著部分光譜被遮擋在圖像之外埠通。
頻譜中的低頻在頻變換圖像的中心,高頻在邊緣约炎。你應(yīng)該看到高斯濾波器只允許低通頻率通過植阴,這是頻率變換圖像的中心蟹瘾。sobel濾波器會屏蔽某個(gè)方向的頻率圾浅,而拉普拉斯濾波器(所有邊緣,不管方向如何)會屏蔽低頻!
Canny 邊緣檢測器
要有準(zhǔn)確的邊緣檢測效果 結(jié)合使用低通和高通過濾器有多重要憾朴。
CANNY是最好用也是最常用的邊緣檢測器之一狸捕,因?yàn)樵摍z測器會借助一系列操作 不斷生成精準(zhǔn)的檢測邊緣。
- 首先 檢測器用高斯模糊過濾掉噪聲
2.然后用 Sobel 過濾器確定圖像邊緣的強(qiáng)度和方向
3.接著 借助 Sobel 過濾器的輸出,Canny 會用非極大抑制,來觀察每個(gè)檢測邊緣的強(qiáng)度和方向,選出局部最大像素,從而把最強(qiáng)的邊緣繪制成連續(xù)的众雷、一個(gè)像素寬的細(xì)線
4.最后 用滯后閥值來分離最佳邊緣,滯后閥值是雙閥值化操作,以某圖一像素寬的橫切面為例:這里的曲線代表邊緣強(qiáng)度,峰值指的是十分強(qiáng)的邊緣,使用滯后閥值時(shí)我們要確定一個(gè)高閥值以便允許這些強(qiáng)邊緣通過;再設(shè)置一個(gè)低閥值,何低于該閥值的邊緣即為弱邊緣會被舍棄,但位于高低閥值之間的邊緣,只有當(dāng)其與另一個(gè)強(qiáng)邊緣相連時(shí) 才會得到保留.
由于 Canny 著重強(qiáng)調(diào)重要邊緣,所以它特別適合檢測邊界和形狀灸拍。
例子 canny
import numpy as np
import matplotlib.pyplot as plt
import cv2
%matplotlib inline
# Read in the image
image = cv2.imread('images/brain_MR.jpg')
# Change color to RGB (from BGR)
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
plt.imshow(image)
將圖片轉(zhuǎn)為灰度圖片
# Convert the image to grayscale for processing
gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
plt.imshow(gray, cmap='gray')
實(shí)現(xiàn)canny邊緣檢測
# Try Canny using "wide" and "tight" thresholds
wide = cv2.Canny(gray, 30, 100)#該函數(shù)需要輸入的參數(shù)有 灰度圖像以及剛才定義的閥值上下限
tight = cv2.Canny(gray, 200, 240)
# Display the images
f, (ax1, ax2) = plt.subplots(1, 2, figsize=(20,10))
ax1.set_title('wide')
ax1.imshow(wide, cmap='gray')
ax2.set_title('tight')
ax2.imshow(tight, cmap='gray')
# Read in the image
image = cv2.imread('images/sunflower.jpg')
# Change color to RGB (from BGR)
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
plt.imshow(image)
# Convert the image to grayscale
gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
## TODO: Define lower and upper thresholds for hysteresis
# right now the threshold is so small and low that it will pick up a lot of noise
lower = 100
upper =200
edges = cv2.Canny(gray, lower, upper)
plt.figure(figsize=(20,10))
plt.imshow(edges, cmap='gray')
形狀檢測
我們知道如何檢測圖像中對象的邊緣做祝,但是我們?nèi)绾尾拍荛_始在對象周圍找到統(tǒng)一的邊界?
我們希望能夠在給定圖像中分離和定位多個(gè)對象鸡岗。接下來混槐,我們將討論霍夫變換,它將圖像數(shù)據(jù)從xy坐標(biāo)系轉(zhuǎn)換為霍夫空間轩性,在那里可以輕松識別簡單的邊界声登,如直線和圓。
霍夫變換
一條直線可由兩個(gè)點(diǎn)A=(X1,Y1)和B=(X2,Y2)確定(笛卡爾坐標(biāo))
也可以寫成關(guān)于(k,q)的函數(shù)表達(dá)式(霍夫空間):
對應(yīng)的變換可以通過圖形直觀表示:
變換后的空間成為霍夫空間悯嗓。即:笛卡爾坐標(biāo)系中一條直線,對應(yīng)霍夫空間的一個(gè)點(diǎn)卸察。
反過來同樣成立(霍夫空間的一條直線脯厨,對應(yīng)笛卡爾坐標(biāo)系的一個(gè)點(diǎn)):
再來看看A、B兩個(gè)點(diǎn)坑质,對應(yīng)霍夫空間的情形:
一步步來合武,再看一下三個(gè)點(diǎn)共線的情況:
可以看出如果笛卡爾坐標(biāo)系的點(diǎn)共線,這些點(diǎn)在霍夫空間對應(yīng)的直線交于一點(diǎn):這也是必然涡扼,共線只有一種取值可能眯杏。
如果不止一條直線呢?再看看多個(gè)點(diǎn)的情況(有兩條直線):
其實(shí)(3壳澳,2)與(4岂贩,1)也可以組成直線,只不過它有兩個(gè)點(diǎn)確定巷波,而圖中A萎津、B兩點(diǎn)是由三條直線匯成,這也是霍夫變換的后處理的基本方式:選擇由盡可能多直線匯成的點(diǎn)抹镊。
看看锉屈,霍夫空間:選擇由三條交匯直線確定的點(diǎn)(中間圖),對應(yīng)的笛卡爾坐標(biāo)系的直線(右圖)垮耳。
到這里問題似乎解決了颈渊,已經(jīng)完成了霍夫變換的求解,但是如果像下圖這種情況呢终佛?
k=∞是不方便表示的俊嗽,而且q怎么取值呢,這樣不是辦法铃彰。因此考慮將笛卡爾坐標(biāo)系換為:極坐標(biāo)表示绍豁。
ρ表示原點(diǎn)到直線的距離
θ 表示的是直線與橫軸所成的角
在極坐標(biāo)系下,其實(shí)是一樣的:極坐標(biāo)的點(diǎn)→霍夫空間的直線牙捉,只不過霍夫空間不再是[k,q]的參數(shù)竹揍,而是[ρ,θ ]的參數(shù)敬飒,給出對比圖:
霍夫線檢測
# Import resources and display the image
import numpy as np
import matplotlib.pyplot as plt
import cv2
%matplotlib inline
# Read in the image
image = cv2.imread('images/phone.jpg')
# Change color to RGB (from BGR)
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
plt.imshow(image)
# Perform edge detection
# Convert image to grayscale
gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
# Define our parameters for Canny
low_threshold = 50
high_threshold = 100
edges = cv2.Canny(gray, low_threshold, high_threshold)
plt.imshow(edges, cmap='gray')
#Find lines using a Hough transform
# Define the Hough transform parameters
# Make a blank the same size as our image to draw on
rho = 1
theta = np.pi/180 #其中 ρ 和 θ 就是我們的霍夫變量了,兩者定義了檢測的分辨率芬位,我把它們分別設(shè)為 1 個(gè)像素和 1 度
threshold = 60 #然后是直線檢測的最低閥值无拗,這個(gè)閥值就是霍夫空間要找到一根直線所需的最少相交數(shù)
min_line_length = 100 #最小線條長度
max_line_gap = 5 # 線條分段之間的距離
line_image = np.copy(image) #creating an image copy to draw lines on
# Run Hough on the edge-detected image
lines = cv2.HoughLinesP(edges, rho, theta, threshold, np.array([]),
min_line_length, max_line_gap)
#這個(gè)函數(shù)會返回其檢測到的所有霍夫直線,每根直線實(shí)際上是一個(gè)包含著四個(gè)點(diǎn)的數(shù)組昧碉,四個(gè)點(diǎn)即 x1蓝纲、y1 和 x2、y2晌纫,也就是每根直線兩端的終點(diǎn)税迷。
# Iterate over the output "lines" and draw lines on the image copy
for line in lines:
for x1,y1,x2,y2 in line:
cv2.line(line_image,(x1,y1),(x2,y2),(255,0,0),5)
plt.imshow(line_image)
霍夫圓檢測
import numpy as np
import matplotlib.pyplot as plt
import cv2
%matplotlib inline
# Read in the image
image = cv2.imread('images/round_farms.jpg')
# Change color to RGB (from BGR)
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
plt.imshow(image)
# Gray and blur
gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
gray_blur = cv2.GaussianBlur(gray, (3, 3), 0)
plt.imshow(gray_blur, cmap='gray')
HoughCircles
函數(shù)
- an input image, detection method (Hough gradient), resolution factor between the detection and image (1),
- minDist - the minimum distance between circles
- param1 - the higher value for performing Canny edge detection
- param2 - threshold for circle detection, a smaller value --> more circles will be detected
- min/max radius for detected circles
# for drawing circles on
circles_im = np.copy(image)
## TODO: use HoughCircles to detect circles
# right now there are too many, large circles being detected
# try changing the value of maxRadius, minRadius, and minDist
circles = cv2.HoughCircles(gray_blur, cv2.HOUGH_GRADIENT, 1,
minDist=45,
param1=70,
param2=11,
minRadius=20,
maxRadius=40)
# convert circles into expected type
circles = np.uint16(np.around(circles))
# draw each one
for i in circles[0,:]:
# draw the outer circle
cv2.circle(circles_im,(i[0],i[1]),i[2],(0,255,0),2)
# draw the center of the circle
cv2.circle(circles_im,(i[0],i[1]),2,(0,0,255),3)
plt.imshow(circles_im)
print('Circles shape: ', circles.shape)
Haar Cascades (Haar 級聯(lián))
Face detection using OpenCV
One older (from around 2001), but still popular scheme for face detection is a Haar cascade classifier; these classifiers in the OpenCV library and use feature-based classification cascades that learn to isolate and detect faces in an image. You can read the original paper proposing this approach here.
# import required libraries for this section
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
import cv2
# load in color image for face detection
image = cv2.imread('images/multi_faces.jpg')
# convert to RBG
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
plt.figure(figsize=(20,10))
plt.imshow(image)
# convert to grayscale
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
plt.figure(figsize=(20,10))
plt.imshow(gray, cmap='gray')
Next we load in the fully trained architecture of the face detector, found in the file detector_architectures/ haarcascade_frontalface_default.xml,and use it on our image to find faces!
# load in cascade classifier
face_cascade = cv2.CascadeClassifier('detector_architectures/haarcascade_frontalface_default.xml')
# run the detector on the grayscale image
faces = face_cascade.detectMultiScale(gray, 4, 6)
How many faces are detected is determined by the function, detectMultiScale which aims to detect faces of varying sizes. The inputs to this function are: (image, scaleFactor, minNeighbors); you will often detect more faces with a smaller scaleFactor, and lower value for minNeighbors, but raising these values often produces better matches. Modify these values depending on your input image.
# print out the detections found
print ('We found ' + str(len(faces)) + ' faces in this image')
print ("Their coordinates and lengths/widths are as follows")
print ('=============================')
print (faces)
The output of the classifier is an array of detections; coordinates that define the dimensions of a bounding box around each face. Note that this always outputs a bounding box that is square in dimension.
img_with_detections = np.copy(image) # make a copy of the original image to plot rectangle detections ontop of
##### Let's plot the corresponding detection boxes on our original image to see how well we've done.
# loop over our detections and draw their corresponding boxes on top of our original image
for (x,y,w,h) in faces:
# draw next detection as a red rectangle on top of the original image.
# Note: the fourth element (255,0,0) determines the color of the rectangle,
# and the final argument (here set to 5) determines the width of the drawn rectangle
cv2.rectangle(img_with_detections,(x,y),(x+w,y+h),(255,0,0),5)
# display the result
plt.figure(figsize=(20,10))
plt.imshow(img_with_detections)