運行環境:python3.6.4
opencv3.4.0
# -*- coding:utf-8 -*-
"""
Note: 使用Python和OpenCV檢測圖像中的物體並將物體裁剪下來
"""
import
cv2
import
numpy as np
# step1:加載圖片,轉成灰度圖
image
=
cv2.imread(
"353.jpg"
)
gray
=
cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# step2:用Sobel算子計算x,y方向上的梯度,之後在x方向上減去y方向上的梯度,通過這個減法,我們留下具有高水平梯度和低垂直梯度的圖像區域。
gradX
=
cv2.Sobel(gray, cv2.CV_32F, dx
=
1
, dy
=
0
, ksize
=
-
1
)
gradY
=
cv2.Sobel(gray, cv2.CV_32F, dx
=
0
, dy
=
1
, ksize
=
-
1
)
# subtract the y-gradient from the x-gradient
gradient
=
cv2.subtract(gradX, gradY)
gradient
=
cv2.convertScaleAbs(gradient)
# show image
cv2.imshow(
"first"
, gradient)
cv2.waitKey()
# step3:去除圖像上的噪聲。首先使用低通濾潑器平滑圖像(9 x 9內核),這將有助於平滑圖像中的高頻噪聲。
# 低通濾波器的目標是降低圖像的變化率。如將每個像素替換爲該像素周圍像素的均值。這樣就可以平滑並替代那些強度變化明顯的區域。
# 然後,對模糊圖像二值化。梯度圖像中不大於90的任何像素都設置爲0(黑色)。 否則,像素設置爲255(白色)。
# blur and threshold the image
blurred
=
cv2.blur(gradient, (
9
,
9
))
_, thresh
=
cv2.threshold(blurred,
90
,
255
, cv2.THRESH_BINARY)
# SHOW IMAGE
cv2.imshow(
"thresh"
, thresh)
cv2.waitKey()
# step4:在上圖中我們看到蜜蜂身體區域有很多黑色的空餘,我們要用白色填充這些空餘,使得後面的程序更容易識別昆蟲區域,
# 這需要做一些形態學方面的操作。
kernel
=
cv2.getStructuringElement(cv2.MORPH_RECT, (
25
,
25
))
closed
=
cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
# show image
cv2.imshow(
"closed1"
, closed)
cv2.waitKey()
# step5:從上圖我們發現圖像上還有一些小的白色斑點,這會干擾之後的昆蟲輪廓的檢測,要把它們去掉。分別執行4次形態學腐蝕與膨脹。
# perform a series of erosions and dilations
closed
=
cv2.erode(closed,
None
, iterations
=
4
)
closed
=
cv2.dilate(closed,
None
, iterations
=
4
)
# show image
cv2.imshow(
"closed2"
, closed)
cv2.waitKey()
# step6:找出昆蟲區域的輪廓。
# cv2.findContours()函數
# 第一個參數是要檢索的圖片,必須是爲二值圖,即黑白的(不是灰度圖),
# 所以讀取的圖像要先轉成灰度的,再轉成二值圖,我們在第三步用cv2.threshold()函數已經得到了二值圖。
# 第二個參數表示輪廓的檢索模式,有四種:
# 1. cv2.RETR_EXTERNAL表示只檢測外輪廓
# 2. cv2.RETR_LIST檢測的輪廓不建立等級關係
# 3. cv2.RETR_CCOMP建立兩個等級的輪廓,上面的一層爲外邊界,裏面的一層爲內孔的邊界信息。如果內孔內還有一個連通物體,這個物體的邊界也在頂層。
# 4. cv2.RETR_TREE建立一個等級樹結構的輪廓。
# 第三個參數爲輪廓的近似方法
# cv2.CHAIN_APPROX_NONE存儲所有的輪廓點,相鄰的兩個點的像素位置差不超過1,即max(abs(x1-x2),abs(y2-y1))==1
# cv2.CHAIN_APPROX_SIMPLE壓縮水平方向,垂直方向,對角線方向的元素,只保留該方向的終點座標,例如一個矩形輪廓只需4個點來保存輪廓信息
# cv2.findContours()函數返回兩個值,一個是輪廓本身,還有一個是每條輪廓對應的屬性。
# cv2.findContours()函數返回第一個值是list,list中每個元素都是圖像中的一個輪廓,用numpy中的ndarray表示。
# 每一個ndarray裏保存的是輪廓上的各個點的座標。我們把list排序,點最多的那個輪廓就是我們要找的昆蟲的輪廓。
x
=
cv2.findContours(closed.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# import pdb
# pdb.set_trace()
_a, cnts, _b
=
x
c
=
sorted
(cnts, key
=
cv2.contourArea, reverse
=
True
)[
0
]
# OpenCV中通過cv2.drawContours在圖像上繪製輪廓。
# 第一個參數是指明在哪幅圖像上繪製輪廓
# 第二個參數是輪廓本身,在Python中是一個list
# 第三個參數指定繪製輪廓list中的哪條輪廓,如果是-1,則繪製其中的所有輪廓
# 第四個參數是輪廓線條的顏色
# 第五個參數是輪廓線條的粗細
# cv2.minAreaRect()函數:
# 主要求得包含點集最小面積的矩形,這個矩形是可以有偏轉角度的,可以與圖像的邊界不平行。
# compute the rotated bounding box of the largest contour
rect
=
cv2.minAreaRect(c)
# rect = cv2.minAreaRect(cnts[1])
box
=
np.int0(cv2.boxPoints(rect))
# draw a bounding box arounded the detected barcode and display the image
cv2.drawContours(image, [box],
-
1
, (
0
,
255
,
0
),
3
)
cv2.imshow(
"Image"
, image)
cv2.imwrite(
"contoursImage2.jpg"
, image)
cv2.waitKey(
0
)
# step7:裁剪。box裏保存的是綠色矩形區域四個頂點的座標。我將按下圖紅色矩形所示裁剪昆蟲圖像。
# 找出四個頂點的x,y座標的最大最小值。新圖像的高=maxY-minY,寬=maxX-minX。
Xs
=
[i[
0
]
for
i
in
box]
Ys
=
[i[
1
]
for
i
in
box]
x1
=
min
(Xs)
x2
=
max
(Xs)
y1
=
min
(Ys)
y2
=
max
(Ys)
hight
=
y2
-
y1
width
=
x2
-
x1
cropImg
=
image[y1:y1
+
hight, x1:x1
+
width]
# show image
cv2.imshow(
"cropImg"
, cropImg)
cv2.imwrite(
"bee.jpg"
, cropImg)
cv2.waitKey()