辨識圖片中兩物體的實際距離
Measuring distance between objects in an image

★範例所使用的圖檔下載位置

http://imgur.com/pSaQUS0

★程式範例執行


#以圖片最左矩形寬作為依據的距離測量
from scipy.spatial import distance as dist
from imutils import perspective
from imutils import contours
import numpy as np
import argparse
import imutils
import cv2

def midpoint(ptA, ptB):
    return ((ptA[0] + ptB[0]) * 0.5, (ptA[1] + ptB[1]) * 0.5)

ap = argparse.ArgumentParser()

#讓圖檔於開啟指令執行時輸入最左端的矩形寬度
#cmd進入py檔和圖檔所在資料夾後,輸入python 1117_distance.py --width 寬度(inch) 開啟
#寬度可直接輸入數字
ap.add_argument("-w", "--width", type=float, required=True)

args = vars(ap.parse_args())

#讀取圖檔→灰階→模糊
#cv2.GaussianBlur模糊程度可以用3x3, 5x5, 7x7
img = cv2.imread("gear4.png", 1)
Gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(Gray, (3, 3), 0)

#輪廓描邊→補空&侵蝕
edged = cv2.Canny(gray, 50, 100)
edged = cv2.dilate(edged, None, iterations=1)
edged = cv2.erode(edged, None, iterations=1)

#進行偵測
cnts = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL,
    cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if imutils.is_cv2() else cnts[1]

#以最左矩形四點&中心為基準到其他物品的距離標示線顏色
(cnts, _) = contours.sort_contours(cnts)
colors = ((0, 0, 255), (240, 0, 159), (0, 165, 255), (255, 255, 0),
    (255, 0, 255))
refObj = None

#進行一連串的輪廓校準
for c in cnts:
    # 忽略過小的輪廓 (限定輪廓描繪範圍)
    if cv2.contourArea(c) < 1500:
        continue

    # 計算輪廓旋轉邊界
    gear4 = cv2.minAreaRect(c)
    gear4 = cv2.cv.BoxPoints(gear4) if imutils.is_cv2() else cv2.boxPoints(gear4)
    gear4 = np.array(gear4, dtype="int")

    # 重新設定邊界角落座標的順序, 由左上 右上 右下 左下, 順時針方向繞
    gear4 = perspective.order_points(gear4)

    # 計算物體的中心
    cX = np.average(gear4[:, 0])
    cY = np.average(gear4[:, 1])

# 以左邊邊界輪廓當基準, 當參考對象
    if refObj is None:
        # 計算物品左右邊界的中點
        (tl, tr, br, bl) = gear4
        (tlblX, tlblY) = midpoint(tl, bl)
        (trbrX, trbrY) = midpoint(tr, br)

        # 用座標法計算兩物體中心距離
        D = dist.euclidean((tlblX, tlblY), (trbrX, trbrY))
        refObj = (gear4, (cX, cY), D / args["width"])
        continue

    # 輪廓描繪
    orig = img.copy()
    cv2.drawContours(orig, [gear4.astype("int")], -1, (0, 255, 0), 2) # 其餘物品的輪廓描繪
    cv2.drawContours(orig, [refObj[0].astype("int")], -1, (0, 255, 0), 2) # 最左邊物品的輪廓描繪


    # refCoords為基準物, objCoords為測量物
    refCoords = np.vstack([refObj[0], refObj[1]])
    objCoords = np.vstack([gear4, (cX, cY)])

    for ((xA, yA), (xB, yB), color) in zip(refCoords, objCoords, colors):
        # 基準物的四個角&中心點 測量物的四個角&中心點 點到點的距離
        cv2.circle(orig, (int(xA), int(yA)), 5, color, -1)
        cv2.circle(orig, (int(xB), int(yB)), 5, color, -1)
        cv2.line(orig, (int(xA), int(yA)), (int(xB), int(yB)), color, 2)

        #用座標距離法算出圖中的座標距離,並和實際的距離做比值,求出待測實際距離
        D = dist.euclidean((xA, yA), (xB, yB)) / refObj[2]
        (mX, mY) = midpoint((xA, yA), (xB, yB))
        cv2.putText(orig, "{:.1f}in".format(D), (int(mX), int(mY - 10)),
        cv2.FONT_HERSHEY_SIMPLEX, 0.55, color, 2)
        # "{:.1f}in" 取到小數點第一位

        cv2.imshow("Image", orig)
        cv2.waitKey(0)


★範例執行結果





★Numpy & Scipy 運用的主要數學計算

用numpy找出物體的中心
用scipy進行距離計算,計算的方式是用座標法:



◎計算過程
1.以一開始輸入基準物(最左的物體)的實際寬度和用座標法在圖片中算出的寬度做比值
2.分別假設基準物和待測物的座標為(X1,Y1)和(X2,Y2)帶入座標法計算出圖片中的距離
3.把第二步驟求出的距離帶入第一步驟求出的比值,算出待測物的實際距離

★細部程式介紹

【cv2.GaussianBlur】圖像模糊

◎使用格式:


◎範例程式
import cv2

img = cv2.imread('gear4.png')

# cv2.GaussianBlur模糊程度可以用3x3, 5x5, 7x7
# cv2.blur指令: blur = cv2.blur(img, (5,5))
# 相較於 cv2.blur, cv2.GaussianBlur多一個參數color σ(顏色空間的標準差),此數值越大使得模糊效果更明顯
blur = cv2.GaussianBlur(img, (5,5), 0)

cv2.imshow("Image", blur)
cv2.waitKey(0)

◎結果:



【cv2.Canny & cv2.dilate & cv2.erode】描繪輪廓→擴張輪廓→修邊侵蝕

◎使用格式:


◎範例程式
import cv2

img = cv2.imread('gear4.png',0)
edges = cv2.Canny(img,10,50)
edged = cv2.dilate(edges, None, iterations=1)
erosion = cv2.erode(edged,None,iterations = 1)

cv2.imshow("Image1", edges)
cv2.imshow("Image2", edged)
cv2.imshow("Image3", erosion)
cv2.waitKey(0)

◎結果:



Comments

comments powered by Disqus