https://my.oschina.net/u/4611954/blog/4680845
OpenCVを使用して、画像内のオブジェクト間の距離を測定します
私たちの目標は、0.25セントを見つけ、0.25セントのサイズを使用して、0.25セントのコインと他のすべてのオブジェクトとの間の距離を測定することです。
参照オブジェクトを定義し、距離を計算します
新しいファイルを開き、distance_between.pyという名前を付けて、次のコードを挿入します。
# import the necessary packages
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)
# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True,
help="path to the input image")
ap.add_argument("-w", "--width", type=float, required=True,
help="width of the left-most object in the image (in inches)")
args = vars(ap.parse_args())
ここでのコードは先週のコードとほぼ同じです。2〜8行目に必要なPythonパッケージをインポートすることから始めます。
12〜17行目は、コマンドラインパラメータを解析します。ここでは、2つのパラメータが必要です。-測定するオブジェクトを含む入力画像のパスであるimage、および-参照オブジェクトの幅(インチ単位)。
次に、画像を前処理する必要があります。
# load the image, convert it to grayscale, and blur it slightly
image = cv2.imread(args["image"])
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (7, 7), 0)
# perform edge detection, then perform a dilation + erosion to
# close gaps in between object edges
edged = cv2.Canny(gray, 50, 100)
edged = cv2.dilate(edged, None, iterations=1)
edged = cv2.erode(edged, None, iterations=1)
# find contours in the edge map
cnts = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
# sort the contours from left-to-right and, then initialize the
# distance colors and reference object
(cnts, _) = contours.sort_contours(cnts)
colors = ((0, 0, 255), (240, 0, 159), (0, 165, 255), (255, 255, 0),
(255, 0, 255))
refObj = None
2〜4行目では、ディスクから画像を読み込み、グレースケール画像に変換してから、7 x 7カーネルのガウスフィルターを使用して画像をぼかし、ノイズを低減します。
画像がぼやけている場合は、キャニーエッジ検出器を適用して画像のエッジを検出し、拡張+侵食を実行してエッジマップのギャップを減らします(7〜9行目)。
cv2.findContoursを呼び出して、エッジマップ内のオブジェクトの等高線を検出し(11〜13行目)、16行目で等高線を左から右に並べ替えます。0.25セント(つまり参照オブジェクト)が常に画像の左端になることがわかっているため、輪郭を左から右に並べ替えると、参照オブジェクトに対応する輪郭が常にcntsリストの最初になります。
次に、距離を描画するために使用される色リストとrefObj変数を初期化します。これにより、参照オブジェクトの境界ボックス、重心、およびメートル単位のピクセル値が格納されます(ピクセル単位の具体的な定義については、前の記事を参照してください)。メートル法、実際には、参照オブジェクトの実際のサイズ(インチ単位)と画像の幅(ピクセル単位)の比率です。
# loop over the contours individually
for c in cnts:
# if the contour is not sufficiently large, ignore it
if cv2.contourArea(c) < 100:
continue
# compute the rotated bounding box of the contour
box = cv2.minAreaRect(c)
box = cv2.cv.BoxPoints(box) if imutils.is_cv2() else cv2.boxPoints(box)
box = np.array(box, dtype="int")
# order the points in the contour such that they appear
# in top-left, top-right, bottom-right, and bottom-left
# order, then draw the outline of the rotated bounding
# box
box = perspective.order_points(box)
# compute the center of the bounding box
cX = np.average(box[:, 0])
cY = np.average(box[:, 1])
2行目では、cntsリストの各輪郭のループを開始します。輪郭が比較的小さい場合(4行目と5行目)、それをノイズと見なし、無視します。
次に、7〜9行目で、現在のオブジェクトの最小回転境界ボックスを計算します。
order_points関数(このシリーズの最初の記事で定義された関数)が14行目で呼び出され、長方形のボックスの4つの頂点が左上隅、右上隅、右下隅、下隅の順に配置されます。左隅。計算オブジェクト間距離が非常に重要であることがわかります。
16行目と17行目は、x方向とy方向の境界ボックスの平均をとることにより、回転した境界ボックスの中心(x、y)座標を計算します。
次のステップは、refObjを調整することです。
# if this is the first contour we are examining (i.e.,
# the left-most contour), we presume this is the
# reference object
if refObj is None:
# unpack the ordered bounding box, then compute the
# midpoint between the top-left and top-right points,
# followed by the midpoint between the top-right and
# bottom-right
(tl, tr, br, bl) = box
(tlblX, tlblY) = midpoint(tl, bl)
(trbrX, trbrY) = midpoint(tr, br)
# compute the Euclidean distance between the midpoints,
# then construct the reference object
D = dist.euclidean((tlblX, tlblY), (trbrX, trbrY))
refObj = (box, (cX, cY), D / args["width"])
continue
refObjがNoneの場合(4行目)、初期化する必要があります。
最初に、最小回転境界ボックス(ソート済み)の座標を取得し、4つの頂点の間の中点を計算します(10〜15行目)。
次に、中点間のユークリッド距離を計算し、「ピクセル/サイズ」の比率を指定して、1インチに含まれるピクセル数を決定します。
最後に、refObjを次のような3タプルとしてインスタンス化します。
-
オブジェクトオブジェクトの最小回転長方形オブジェクトボックス
-
参照オブジェクトの図心。
-
ピクセル/幅の比率。これを使用して、オブジェクト間のピクセル距離と組み合わせて、オブジェクト間の実際の距離を決定します。
次のコードブロックは、参照オブジェクトと現在の検査オブジェクトの輪郭を描画し、変数refCoordsとobjCoordsを定義して、(1)最小の囲み行列の座標と(2)重心の座標を定義します。 (x、y)は同じ配列に含まれています:
# draw the contours on the image
orig = image.copy()
cv2.drawContours(orig, [box.astype("int")], -1, (0, 255, 0), 2)
cv2.drawContours(orig, [refObj[0].astype("int")], -1, (0, 255, 0), 2)
# stack the reference coordinates and the object coordinates
# to include the object center
refCoords = np.vstack([refObj[0], refObj[1]])
objCoords = np.vstack([box, (cX, cY)])
これで、画像内の各オブジェクトの図心と図心の間の距離の計算を開始できます。
# loop over the original points
for ((xA, yA), (xB, yB), color) in zip(refCoords, objCoords, colors):
# draw circles corresponding to the current points and
# connect them with a line
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)
# compute the Euclidean distance between the coordinates,
# and then convert the distance in pixels to distance in
# units
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)
# show the output image
cv2.imshow("Image", orig)
cv2.waitKey(0)
2行目では、画像内のオブジェクトの頂点(x、y)の座標をループし始めます。
次に、距離を計算している現在のポイントの座標を示す円を描き、これらのポイントを結ぶ線を描きます(線5〜7)。
次に、12行目で、参照位置とオブジェクト位置の間のユークリッド距離を計算し、それを「ピクセル/メートル法」で割って、2つのオブジェクト間の実際の距離(インチ単位)を取得します。次に、計算された距離を画像にマークします(13〜15行目)。
輪郭セット間の最小距離:
https://www.cnpython.com/qa/201678
import cv2
import numpy as np
def contours(layer):
gray = cv2.cvtColor(layer, cv2.COLOR_BGR2GRAY)
ret,binary = cv2.threshold(gray, 1,255,cv2.THRESH_BINARY)
image, contours, hierarchy = cv2.findContours(binary,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
drawn = cv2.drawContours(image,contours,-1,(150,150,150),3)
return contours, drawn
def minDistance(contour, contourOther):
distanceMin = 99999999
for xA, yA in contour[0]:
for xB, yB in contourOther[0]:
distance = ((xB-xA)**2+(yB-yA)**2)**(1/2) # distance formula
if (distance < distanceMin):
distanceMin = distance
return distanceMin
def cntDistanceCompare(contoursA, contoursB):
cumMinDistList = []
for contourA in contoursA:
indMinDistList = []
for contourB in contoursB:
minDist = minDistance(contourA,contourB)
indMinDistList.append(minDist)
cumMinDistList.append(indMinDistList)
l = cumMinDistList
return sum(l)/len(l) #returns mean distance
def maskBuilder(bgr,hl,hh,sl,sh,vl,vh):
hsv = cv2.cvtColor(bgr, cv2.COLOR_BGR2HSV)
lower_bound = np.array([hl,sl,vl],dtype=np.uint8)
upper_bound = np.array([hh,sh,vh],dtype=np.uint8)
return cv2.inRange(hsv, lower_bound,upper_bound)
img = cv2.imread("sample.jpg")
maskA=maskBuilder(img, 150,185, 40,220, 65,240)
maskB=maskBuilder(img, 3,20, 50,180, 20,250)
layerA = cv2.bitwise_and(img, img, mask = maskA)
layerB = cv2.bitwise_and(img, img, mask = maskB)
contoursA = contours(layerA)[0]
contoursB = contours(layerA)[1]
print cntDistanceCompare(contoursA, contoursB)
2つの等高線間の距離:
import cv2
def get_contours(img):
"""获取连通域
:param img: 输入图片
:return: 最大连通域
"""
# 灰度化, 二值化, 连通域分析
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, img_bin = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY)
img_contour, contours, hierarchy = cv2.findContours(img_bin, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
return contours[0]
def main():
# 1.导入图片
img_cs1 = cv2.imread("cs1.jpg")
img_cs2 = cv2.imread("cs2.jpg")
img_hand = cv2.imread("hand.jpg")
# 2.获取图片连通域
cnt_cs1 = get_contours(img_cs1)
cnt_cs2 = get_contours(img_cs2)
cnt_hand = get_contours(img_hand)
# 3.创建计算距离对象
hausdorff_sd = cv2.createHausdorffDistanceExtractor()
# 4.计算轮廓之间的距离
d1 = hausdorff_sd.computeDistance(cnt_cs1, cnt_cs1)
print("与自身的距离hausdorff\t d1=", d1)
d2 = hausdorff_sd.computeDistance(cnt_cs1, cnt_cs2)
print("与相似图片的距离hausdorff\t d2=", d2)
d3 = hausdorff_sd.computeDistance(cnt_cs1, cnt_hand)
print("与不同图片的距离hausdorff\t d3=", d3)
# 5.显示图片
cv2.imshow("img_cs1", img_cs1)
cv2.imshow("img_cs2", img_cs2)
cv2.imshow("img_hand", img_hand)
cv2.waitKey()
cv2.destroyAllWindows()
if __name__ == '__main__':
main()
ポイントから輪郭までの距離を測定します
import cv2
def point_contour_dist(img, hull, point, text, measure_dist=True):
"""点与轮廓hull的距离
:param img: 绘制结果图片
:param hull: 轮廓hull
:param point: 计算的点
:param text: 文本距离
:param measure_dist: 计算结果方式
:return: 距离
"""
dist = cv2.pointPolygonTest(hull, point, measure_dist)
font = cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(img, text, point, font, 1, (0, 255, 0), 3)
print("dist%s=" % text, dist)
return dist
def main():
# 1.导入图片
img_src = cv2.imread("cs1.jpg")
# 2.灰度化,二值化
img_gray = cv2.cvtColor(img_src, cv2.COLOR_BGR2GRAY)
ret, img_bin = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY)
# 3.连通域分析
img_bin, contours, hierarchy = cv2.findContours(img_bin,
cv2.RETR_LIST,
cv2.CHAIN_APPROX_SIMPLE)
# 4.计算hull并且显示
hull = cv2.convexHull(contours[0])
img_result = cv2.cvtColor(img_bin, cv2.COLOR_GRAY2BGR)
cv2.polylines(img_result, [hull], True, (0, 255, 0), 2)
# 5.计算点与轮廓hull之间的距离
point_contour_dist(img_result, hull, (300, 150), "A")
point_contour_dist(img_result, hull, (300, 250), "B")
point_contour_dist(img_result, hull, (464, 122), "C")
# 6.显示结果图片
cv2.imshow("img_src", img_src)
cv2.imshow("img_result", img_result)
cv2.imwrite("img_result.jpg", img_result)
cv2.waitKey()
cv2.destroyAllWindows()
if __name__ == '__main__':
main()
————————————————
版权声明:本文为CSDN博主「廷益--飞鸟」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_45875105/article/details/103934244