【小さいケース:3つ】OpenCVの弧長角度測定

1.二値化+輪郭探索

img = cv2.imread('11.png')
# cv2.imshow('src',img)

gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(gray, 70, 255, cv2.THRESH_BINARY)

contours,hierarchy=cv2.findContours(thresh,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)

2. 輪郭凸包欠陥を見つけ、円弧の始点と終点の座標を決定します。

hull = cv2.convexHull(contours[0],returnPoints=False)#默认returnPoints=True

defects = cv2.convexityDefects(contours[0],hull)
start = end = (0,0)
for i in range(0,defects.shape[0]):
  s,e,f,d = defects[i,0]
  start = tuple(contours[0][s][0])
  end = tuple(contours[0][e][0])
  far = tuple(contours[0][f][0])
  if d > 5000:
    cv2.line(img,start,end,[0,255,0],2)#凸包
    #cv2.circle(img,far,5,[0,0,255],-1)#凸包缺陷点
    cv2.circle(img,end,5,[0,0,255],-1)#凸包缺陷点
    cv2.circle(img,start,5,[0,0,255],-1)#凸包缺陷点
    break
cv2.imshow('find', img)

出力
ここに画像の説明を挿入

3. 輪郭の最小外接円を求め、円の中心を求め、円弧の角度を計算します

center,radius = cv2.minEnclosingCircle(contours[0])
cv2.circle(img,(int(center[0]),int(center[1])),8,(255,0,255),-1)
cv2.circle(img,end,8,[0,255,255],-1)#凸包缺陷点
cv2.circle(img,start,8,[0,255,255],-1)#凸包缺陷点
cv2.line(img,start,(int(center[0]),int(center[1])),[0,255,0],2)#凸包
cv2.line(img,end,(int(center[0]),int(center[1])),[0,255,0],2)#凸包

angle = cal_ang(start,center,end)
print('angle = %0.2f' % angle)

出力
ここに画像の説明を挿入

4. 外接円の円周の角度比から円弧長を計算する

length = (1 - angle / 360.0) * math.pi * radius * 2
print((angle / 360.0))
print('radius = %0.2f' % radius)
strL = 'length=%0.2f' % length

cv2.putText(img,strL,(int(center[0]-40),int(center[1]+40)),0,0.8,(255,0,0),2)
cv2.imshow('result', img)

angle_1 = cal_ang(start, center, ((center[0]+100),(center[1])))
angle_2 = cal_ang(end, center, ((center[0]+100),(center[1])))
cv2.ellipse(img,(int(center[0]),int(center[1])),(int(radius),int(radius)),0,-angle_1,0,(255,0,255),2, cv2.LINE_AA)
cv2.ellipse(img,(int(center[0]),int(center[1])),(int(radius),int(radius)),0,0,angle_2,(255,0,255),2,cv2.LINE_AA)

cv2.imshow('result', img)

出力
ここに画像の説明を挿入

完全なコードは次のとおりです。

import cv2
import math

def cal_ang(start, center, end):
  point_1 = start
  point_2 = center
  point_3 = end

  """
      根据三点坐标计算夹角
      :param point_1: 点1坐标
      :param point_2: 点2坐标
      :param point_3: 点3坐标
      :return: 返回任意角的夹角值,这里只是返回点2的夹角
      """
  a = math.sqrt(
    (point_2[0] - point_3[0]) * (point_2[0] - point_3[0]) + (point_2[1] - point_3[1]) * (point_2[1] - point_3[1]))
  b = math.sqrt(
    (point_1[0] - point_3[0]) * (point_1[0] - point_3[0]) + (point_1[1] - point_3[1]) * (point_1[1] - point_3[1]))
  c = math.sqrt(
    (point_1[0] - point_2[0]) * (point_1[0] - point_2[0]) + (point_1[1] - point_2[1]) * (point_1[1] - point_2[1]))
  A = math.degrees(math.acos((a * a - b * b - c * c) / (-2 * b * c)))
  B = math.degrees(math.acos((b * b - a * a - c * c) / (-2 * a * c)))
  C = math.degrees(math.acos((c * c - a * a - b * b) / (-2 * a * b)))
  return B

#【1】二值化+ 查找轮廓
img = cv2.imread('11.png')
# cv2.imshow('src',img)

gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(gray, 70, 255, cv2.THRESH_BINARY)

contours,hierarchy=cv2.findContours(thresh,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)

#【2】查找轮廓凸包缺陷,确定圆弧起点和终点坐标
hull = cv2.convexHull(contours[0],returnPoints=False)#默认returnPoints=True

defects = cv2.convexityDefects(contours[0],hull)
start = end = (0,0)
for i in range(0,defects.shape[0]):
  s,e,f,d = defects[i,0]
  start = tuple(contours[0][s][0])
  end = tuple(contours[0][e][0])
  far = tuple(contours[0][f][0])
  if d > 5000:
    cv2.line(img,start,end,[0,255,0],2)#凸包
    #cv2.circle(img,far,5,[0,0,255],-1)#凸包缺陷点
    cv2.circle(img,end,5,[0,0,255],-1)#凸包缺陷点
    cv2.circle(img,start,5,[0,0,255],-1)#凸包缺陷点
    break
cv2.imshow('find', img)


#【3】获取轮廓最小外接圆,获取圆心,计算圆弧角度
center,radius = cv2.minEnclosingCircle(contours[0])
cv2.circle(img,(int(center[0]),int(center[1])),8,(255,0,255),-1)
cv2.circle(img,end,8,[0,255,255],-1)#凸包缺陷点
cv2.circle(img,start,8,[0,255,255],-1)#凸包缺陷点
cv2.line(img,start,(int(center[0]),int(center[1])),[0,255,0],2)#凸包
cv2.line(img,end,(int(center[0]),int(center[1])),[0,255,0],2)#凸包

angle = cal_ang(start,center,end)
print('angle = %0.2f' % angle)


#【4】通过外接圆周长角度比例来计算弧长
length = (1 - angle / 360.0) * math.pi * radius * 2
print((angle / 360.0))
print('radius = %0.2f' % radius)
strL = 'length=%0.2f' % length

cv2.putText(img,strL,(int(center[0]-40),int(center[1]+40)),0,0.8,(255,0,0),2)
cv2.imshow('result', img)

angle_1 = cal_ang(start, center, ((center[0]+100),(center[1])))
angle_2 = cal_ang(end, center, ((center[0]+100),(center[1])))
cv2.ellipse(img,(int(center[0]),int(center[1])),(int(radius),int(radius)),0,-angle_1,0,(255,0,255),2, cv2.LINE_AA)
cv2.ellipse(img,(int(center[0]),int(center[1])),(int(radius),int(radius)),0,0,angle_2,(255,0,255),2,cv2.LINE_AA)

cv2.imshow('result', img)
# cv2.imwrite('result.png',img)

cv2.waitKey(0)
cv2.destroyAllWindows()

'''
#法二:将步骤【2】替换为通过角点检测来获取弧线端点坐标
feature_params = dict(maxCorners = 2,
                      qualityLevel = 0.3,
                      minDistance = 50,
                      blockSize = 5 )

corners = cv2.goodFeaturesToTrack(thresh,mask=None,**feature_params)

print ('cornerNum = ' + str(len(corners)))

for i in range(0,len(corners)):
    cv2.circle(img,(int(corners[i][0][0]),int(corners[i][0][1])),8,(0,255,0),-1, cv2.LINE_AA)
cv2.imshow('cornerNum', img)


'''

おすすめ

転載: blog.csdn.net/weixin_52051554/article/details/129081361