頻率:
對于聲音,頻率實際上是指聲波振蕩的速度

高低頻率
高頻圖像是強度變化很大的圖像。并且亮度級別從一個像素到下一個像素快速變化。低頻圖像可以是亮度相對均勻或變化非常慢的圖像。這是一個例子中最容易看到的。

大多數(shù)圖像都有高頻和低頻成分。在上圖中,在圍巾和條紋襯衫上,我們有一個高頻圖像模式; 這部分從一個亮度變化到另一個亮度。在同一圖像中,我們看到天空和背景的部分變化非常緩慢,這被認為是平滑的低頻模式。
高頻分量也對應于圖像中對象的邊緣,這可以幫助我們對這些對象進行分類。
傅里葉變換
傅里葉變換(FT)是一種重要的圖像處理工具,用于將圖像分解為其頻率分量。FT的輸出表示頻域中的圖像,而輸入圖像是空間域(x,y)等效物。在頻域圖像中,每個點表示包含在空間域圖像中的特定頻率。因此,對于具有大量高頻分量(邊緣,角落和條紋)的圖像,頻域中將存在高頻率值的多個點。

足球運動員的圖像和相應的頻域圖像(右)。頻域圖像中心的集中點意味著該圖像具有許多低頻(平滑背景)分量
在這里,看看如何使用OpenCV完成FT 。
傅里葉變化練習
原圖如左下所示,經(jīng)過傅里葉變換后,圖像更加接近D

高通濾波器
在圖像處理中,我們用過濾器來過濾掉圖像中不需要或無關的信息,也用過濾器來放大某些特征,比如物體邊界或其他顯著特征。
高通濾波器用于銳化圖像以及強化圖像的高頻區(qū)域,也就是相鄰像素發(fā)生突變的區(qū)域,比如從極暗過度到極亮的那些區(qū)域,由于我們觀察的是強度模式,所以用過濾器來處理灰度圖像(灰度圖像會以簡單的格式將明暗情況展示出來,從而體現(xiàn)強度)
以熊貓圖片為例:原圖那些強度沒有變化或變化不大的區(qū)域,原圖那些強度沒有變化或變化不大的區(qū)域,會被高通過濾器過濾掉 而且像素顏色會變?yōu)楹谏?;但在這些區(qū)域里 由于像素比鄰近像素明亮許多,但在這些區(qū)域里 由于像素比鄰近像素明亮許多,結(jié)果就是把邊緣強化了。(所謂邊緣 就是指圖像里強度發(fā)生突變的區(qū)域,通常暗示著物體邊界的存在)

這類過濾器的具體原理,過濾器是以矩陣形式存在的,通常稱為卷積核。
以檢測邊緣的高通過濾器為例,這是個三乘三的核 其元素總和為 0,邊緣檢測時 所有元素總和為 0 是很重要的。因為這類過濾器要計算的是相鄰像素的差異 或者說變化,要計算差異 就需要將像素值相減。在這個例子中 我們要將中間像素與周圍像素的值相減,如果這些核值加起來不等于 0,那就意味著計算出來的差,權重會有正負,結(jié)果就是濾波后的圖像亮度會相應地提高或或降低





該內(nèi)核找到圍繞給定像素的頂部邊緣和底部邊緣之間的差異
這里我們使用opencv filter2D來創(chuàng)建
Sobel濾波器
Sobel濾波器非常常用于邊緣檢測和在圖像中查找強度模式


創(chuàng)建過濾器
低通濾波
噪聲通常就是圖像的斑點或變色部分不含任何有用信息甚至會影響處理操作,比如在邊緣檢測時 如果沒有先解決噪聲 高通過濾器就會把噪聲強化。
低通過濾器是噪聲最常見的解決方式,這類過濾器能阻擋特定高頻部分,有效模糊圖像或使圖像平滑起來,從而減少高頻噪聲,這種過濾器的實用性在醫(yī)學影像里淋漓盡致地體現(xiàn)了出來


要降噪 我們可以取相鄰像素的均值,從而避免強度突變 特別是小范圍突變,而這種取空間像素均值的做法,同應用低通過濾器來過濾高頻噪聲是一樣的。
我們來看一個例子 用普通核來降噪:第一個也是最簡單的一個 均值過濾器,會賦予中心像素及其相鄰像素一樣的權重,低通過濾器通常會取均值 不像高通過濾器取的是差值,因此低通過濾器的元素加起來應該為 1。這就能保留圖像的亮度,但我們可以看到 這個核的元素加起來等于 9,所以我們需要進行歸一化處理 也就是將核值總和除以 9

如果對整張圖像的所有像素進行同樣的均值處理,我們就能使圖像變得平滑 圖像里的強度突變也會變少,這有利于減少噪聲,或使處于一定強度范圍的背景區(qū)域看起來更加平滑。實際上 這類過濾器在 Photoshop 里也有應用,可對圖像的某一部分進行柔化或模糊處理。
高斯模糊
除了全均值過濾器,有時我們會想要個既能模糊圖像 又能更好地保存圖像邊緣的過濾器,為此 我們可用高斯模糊。這或許是計算機視覺應用中最常用的低通過濾器了。低通過濾.器其實就是加權平均法 賦予中心像素最大的權重.
在進行濾波處理之前,首先要將圖像轉(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 表示標準差為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、而一般,我們在畫圖或者討論的時候,是從[-fs/2,fs/2]的范圍進行分析。
#3、因此,需要將經(jīng)過fft變換后的圖像的[fs/2,fs]部分移動到[-fs/2,0]這個范圍內(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ū)域意味著部分光譜被遮擋在圖像之外。
頻譜中的低頻在頻變換圖像的中心,高頻在邊緣。你應該看到高斯濾波器只允許低通頻率通過,這是頻率變換圖像的中心。sobel濾波器會屏蔽某個方向的頻率,而拉普拉斯濾波器(所有邊緣,不管方向如何)會屏蔽低頻!
Canny 邊緣檢測器
要有準確的邊緣檢測效果 結(jié)合使用低通和高通過濾器有多重要。
CANNY是最好用也是最常用的邊緣檢測器之一,因為該檢測器會借助一系列操作 不斷生成精準的檢測邊緣。
- 首先 檢測器用高斯模糊過濾掉噪聲
2.然后用 Sobel 過濾器確定圖像邊緣的強度和方向
3.接著 借助 Sobel 過濾器的輸出,Canny 會用非極大抑制,來觀察每個檢測邊緣的強度和方向,選出局部最大像素,從而把最強的邊緣繪制成連續(xù)的、一個像素寬的細線
4.最后 用滯后閥值來分離最佳邊緣,滯后閥值是雙閥值化操作,以某圖一像素寬的橫切面為例:這里的曲線代表邊緣強度,峰值指的是十分強的邊緣,使用滯后閥值時我們要確定一個高閥值以便允許這些強邊緣通過;再設置一個低閥值,何低于該閥值的邊緣即為弱邊緣會被舍棄,但位于高低閥值之間的邊緣,只有當其與另一個強邊緣相連時 才會得到保留.


由于 Canny 著重強調(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')

實現(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)一的邊界?
我們希望能夠在給定圖像中分離和定位多個對象。接下來,我們將討論霍夫變換,它將圖像數(shù)據(jù)從xy坐標系轉(zhuǎn)換為霍夫空間,在那里可以輕松識別簡單的邊界,如直線和圓。

霍夫變換
一條直線可由兩個點A=(X1,Y1)和B=(X2,Y2)確定(笛卡爾坐標)


也可以寫成關于(k,q)的函數(shù)表達式(霍夫空間):
對應的變換可以通過圖形直觀表示:

變換后的空間成為霍夫空間。即:笛卡爾坐標系中一條直線,對應霍夫空間的一個點。
反過來同樣成立(霍夫空間的一條直線,對應笛卡爾坐標系的一個點):

再來看看A、B兩個點,對應霍夫空間的情形:

一步步來,再看一下三個點共線的情況:

可以看出如果笛卡爾坐標系的點共線,這些點在霍夫空間對應的直線交于一點:這也是必然,共線只有一種取值可能。
如果不止一條直線呢?再看看多個點的情況(有兩條直線):

其實(3,2)與(4,1)也可以組成直線,只不過它有兩個點確定,而圖中A、B兩點是由三條直線匯成,這也是霍夫變換的后處理的基本方式:選擇由盡可能多直線匯成的點。
看看,霍夫空間:選擇由三條交匯直線確定的點(中間圖),對應的笛卡爾坐標系的直線(右圖)。

到這里問題似乎解決了,已經(jīng)完成了霍夫變換的求解,但是如果像下圖這種情況呢?

k=∞是不方便表示的,而且q怎么取值呢,這樣不是辦法。因此考慮將笛卡爾坐標系換為:極坐標表示。

ρ表示原點到直線的距離
θ 表示的是直線與橫軸所成的角
在極坐標系下,其實是一樣的:極坐標的點→霍夫空間的直線,只不過霍夫空間不再是[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 #其中 ρ 和 θ 就是我們的霍夫變量了,兩者定義了檢測的分辨率,我把它們分別設為 1 個像素和 1 度
threshold = 60 #然后是直線檢測的最低閥值,這個閥值就是霍夫空間要找到一根直線所需的最少相交數(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)
#這個函數(shù)會返回其檢測到的所有霍夫直線,每根直線實際上是一個包含著四個點的數(shù)組,四個點即 x1、y1 和 x2、y2,也就是每根直線兩端的終點。
# 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)
