記錄準研一小白第一次動手實踐課題組師姐安排的任務,非常感謝CSDN前輩們所撰寫的博客對我的幫助,
一、專案背景
如圖所示,有這樣一張現場勘測的圖片,要實作繪制出圖中三個黃色標記塊的最小矩形框以及左上角的坐標點
二、研究思路
讀取圖片——>提取圖中黃色部分——>腐蝕操作剔除細小輪廓——>查找所有輪廓——>篩選并繪制出符合條件的輪廓——>繪制最小矩形框并標記出坐標
三、代碼實作
讀取圖片代碼如下:
# 1.讀取圖片
# 使用函式cv2.imread(filepath,flags)讀入一副圖片
image = cv2.imread(img_path)
print(image.shape)
# (5792,4344,3)
# 源影像:3通道影像
height, width, channel = image.shape
# 通過resize()函式進行影像縮放
# 縮小影像,比例為(0.125,0.125)
# 插值方法:基于4x4像素鄰域的3次插值法
image = cv2.resize(image, (int(0.125*width), int(0.125*height)), interpolation=cv2.INTER_CUBIC)
# 使用函式cv2.imshow(wname,img)顯示影像,第一個引數是顯示影像的視窗的名字,第二個引數是要顯示的影像(imread讀入的影像)
cv2.imshow("original", image)

提取圖片黃色區域代碼如下:
# 2.提取圖片中的黃色部分
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
low_hsv = np.array([26,43,46])
high_hsv = np.array([34,255,255])
mask = cv2.inRange(hsv,lowerb=low_hsv,upperb=high_hsv)
cv2.imshow("find_yellow",mask)
可以通過比照HSV的參考表,獲取所需要提取顏色的相應范圍

通過腐蝕操作剔除一系列細小輪廓代碼如下:
#腐蝕,消除影像邊緣小的部分,并將影像縮小,從而使其補集擴大,原型為:dst=cv2.erode(src表示原影像,kernel表示卷積核,iterations表示迭代次數)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3)) #設定kernel卷積核為 3 * 3 正方形,8位uchar型,全1結構元素
mask = cv2.erode(mask, kernel,15)
cv2.imshow("morphology", mask)
可以發現經過此操作后得到的影像明顯干凈了很多

查找所有輪廓的代碼如下:
# 4.查找輪廓,輸出找到的輪廓個數為5個
contours, hierarchy = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
print("find", len(contours), "contours")
# 繪制輪廓函式
# 自定義繪制輪廓的函式(為簡化操作)
# 輸入1:winName:視窗名
# 輸入2:image:原圖
# 輸入3:contours:輪廓
# 輸入4:draw_on_blank:繪制方式,True在白底上繪制,False:在原圖image上繪制
def drawMyContours(winName, image, contours, draw_on_blank):
# cv2.drawContours(image, contours, index, color, line_width)
# 輸入引數:
# image:與原始影像大小相同的畫布影像(也可以為原始影像)
# contours:輪廓(python串列)
# index:輪廓的索引(當設定為-1時,繪制所有輪廓)
# color:線條顏色,
# line_width:線條粗細
# 回傳繪制了輪廓的影像image
if (draw_on_blank): # 在白底上繪制輪廓
temp = np.ones(image.shape, dtype=np.uint8) * 255
cv2.drawContours(temp, contours, -1, (0, 0, 0), 2)
else:
temp = image.copy()
cv2.drawContours(temp, contours, -1, (0, 0, 255), 2)
cv2.imshow(winName, temp)
# 5.繪制原始輪廓
drawMyContours("find contours", image, contours, True)

使用輪廓長度濾波篩選出符合要求的三個輪廓代碼如下:
# 自定義函式:用于洗掉串列指定序號的輪廓
# 輸入 1:contours:原始輪廓
# 輸入 2:delete_list:待洗掉輪廓序號串列
# 回傳值:contours:篩選后輪廓
def delet_contours(contours, delete_list):
delta = 0
for i in range(len(delete_list)):
# print("i= ", i)
del contours[delete_list[i] - delta]
delta = delta + 1
return contours
# 6.篩選輪廓,計算每個輪廓長度
lengths = list()
for i in range(len(contours)):
length = cv2.arcLength(contours[i], True)
lengths.append(length)
print("輪廓%d 的周長: %d" % (i, length))
# 使用輪廓長度濾波
min_size = 20
max_size = 200
delete_list = []
for i in range(len(contours)):
if (cv2.arcLength(contours[i], True) < min_size) or (cv2.arcLength(contours[i], True) > max_size):
delete_list.append(i)
# 根據串列序號洗掉不符合要求的輪廓
contours = delet_contours(contours, delete_list)#篩選后的輪廓
print("find", len(contours), "contours left after length filter")#列印篩選后的輪廓
drawMyContours("contours after length filtering", image, contours, False)

分別繪制出所篩選出輪廓的最小覆寫矩形并標記出左上角坐標值的代碼如下:
# 7.形狀描述子
# 7.1 最小覆寫矩形
result = image.copy()
for i in range(len(contours)):
rect = cv2.minAreaRect(contours[i])
box = cv2.boxPoints(rect)
box = np.int0(box)
draw_rect = cv2.drawContours(image.copy(), [box], -1, (0, 0, 255), 2)
#左上角坐標值
pt = (box[1][0],box[1][1])
#畫紅點
cv2.circle(result, pt, 2, (0, 0, 255), 2)
text = "(" + str(pt[0]) + ", " + str(pt[1]) + ")"
cv2.putText(result, text, (pt[0] + 10, pt[1] + 10), cv2.FONT_HERSHEY_PLAIN, 1.5, (255, 255, 255), 1, 8, 0)
print("box_{}:{},左上角坐標為{}\n".format(i, box, box[1]))
image = draw_rect
cv2.imshow("draw_rect", draw_rect)
cv2.imshow("only_res", result)


將所篩選輪廓的最小覆寫矩形以及左上角坐標值繪制在同一張圖片中的代碼如下:
# 8.標記左上角坐標點(輪廓和點在同一張圖中顯示)
for i in range(len(contours)):
rect = cv2.minAreaRect(contours[i])
box = cv2.boxPoints(rect)
box = np.int0(box)
draw_rect = cv2.drawContours(image.copy(), [box], -1, (0, 0, 255), 2)
# 左上角坐標值
pt = (box[1][0], box[1][1])
# 畫綠點
circle = cv2.circle(draw_rect.copy(), pt, 2, (0, 255, 0), 2)
text = "(" + str(pt[0]) + ", " + str(pt[1]) + ")"
all = cv2.putText(circle.copy(), text, (pt[0] + 10, pt[1] + 10), cv2.FONT_HERSHEY_PLAIN, 1.5, (255, 255, 255), 1, 8, 0)
image = all
cv2.imshow("all_res", all)

最后,不能忘記
#防止視窗閃現
cv2.waitKey()
#銷毀所有視窗
cv2.destroyAllWindows()
四、資料分享
關于OpenCv輪廓操作部分的詳細講解,請參考輪廓操作
關于OpenCv不同形狀的輪廓擬合,請參考輪廓形狀擬合
以及RGB配色表
后續會不斷進行改進,希望能與大家共同進步!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/291132.html
標籤:其他


