压力表刻度图片识别

算法设计思想:

  1. 使用霍夫变换检测圆心的位置
  2. 使用sobel算子进行表盘刻度和0点位置的检测
  3. 从圆心出发画出一条水平线与检测出来的表盘刻度相交(记录两点所在的刻度值k1k_1k1k2k_2k2
  4. 计算每一个刻度所代表的度数值v=(k2k1)/πv=(k_2-k_1)/πv=(k2k1)/π
  5. 使用霍夫变换进行表盘中指针的检测,并得到直线的两点坐标
  6. 计算圆点与0点的直线与指针的直线的相交的夹角α
  7. 得出指针指向的刻度值:vαv*αvα

使用霍夫变换检测圆心的位置

# 获取表盘圆心坐标

image = cv2.imread('./data/001.jpg')  # 加载图像
output = image.copy()

gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)  # 转换成灰度图像

circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1, 200)  # 检测圆
center_point_x = 0
center_point_y = 0
if circles is not None:    
    circles = np.round(circles[0, :]).astype('int')  # 将圆(x, y)坐标和半径转换成int
    for (x, y, r) in circles:
        center_point_x = x
        center_point_y = y
print(f"圆心坐标为:({center_point_x},{center_point_y})")

使用sobel算子进行表盘刻度和0点位置的检测

# 识别表盘中刻度盘的位置以及0点的位置

rectKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (11, 11))  # 初始化一对结构化的内核:

gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)  # 转换为灰度图片 


tophat = cv2.morphologyEx(gray, cv2.MORPH_TOPHAT, rectKernel)  # 礼帽运算:分离比邻近点亮一些的斑块 


gradX = cv2.Sobel(tophat, ddepth=cv2.CV_32F, dx=1, dy=0, ksize=-1)  # Sobel算子进行边缘检测
gradX = np.absolute(gradX) 

(minVal, maxVal) = (np.min(gradX), np.max(gradX))  # 获取gradX矩阵中的最大数和最小数进行归一化操作  


gradX=(255*(gradX-minVal)/(maxVal-minVal))  # 归一化操作:使图像更加的清晰 
gradX = gradX.astype("uint8")

gradX = cv2.morphologyEx(gradX, cv2.MORPH_CLOSE, rectKernel)  # 对表盘图片做闭操作(类似模板图片操作)

thresh = cv2.threshold(gradX, 124, 250,cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]  # 二值化表盘图片

contours, _ = cv2.findContours(thresh.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE) # 计算表盘刻度轮廓

locs_ref2 = []
locs_ref3 = []
for (i, c_ref) in enumerate(contours):
    (x, y, w, h) = cv2.boundingRect(c_ref) # 最小矩形
    if 402>w and 350<w:
        locs_ref2.append((x, y, w, h)) # 获取分割后的模板图片
    if 36>w and 13<w and 34>h and 18<h:
        locs_ref3.append((x, y, w, h)) # 添加0点位置
locs_ref3 = sorted(locs_ref3, key=lambda x: x[0])
zero_point_x = locs_ref3[0][0]
zero_point_y = locs_ref3[0][1] + locs_ref3[0][3]
print(f"表盘的刻度位置和大小为:{locs_ref2}")
print(f"表盘零点的位置为:({zero_point_x},{zero_point_y})")

从圆心出发画出一条水平线与检测出来的表盘刻度相交

# 获取与圆心平行的两个点的坐标
dis_x = locs_ref2[0][0]
dis_y = locs_ref2[0][1]
dis_w = locs_ref2[0][2]
dis_h = locs_ref2[0][3]
left_point_x = dis_x
left_point_y = center_point_y
right_point_x = dis_x + dis_w
right_point_y = center_point_y
print(f"与圆心平行的刻度点坐标为:({left_point_x},{left_point_y})")
print(f"与圆心平行的刻度点坐标为:({right_point_x},{right_point_y})")

计算每一个刻度所代表的度数值

# 计算每一刻度对应的角度值
ratio = (1.3-0.18)/math.pi
print(f"每一刻度对应的弧度制为:{ratio}")

使用霍夫变换进行表盘中指针的检测,并得到直线的两点坐标

# 利用霍夫变换进行指针的检测
img = cv2.GaussianBlur(gray,(3,3),0)
result=img.copy()
cannyImage = cv2.Canny(img,120,243.20999999999998,apertureSize = 3)    
HoughLines=cv2.HoughLines(cannyImage,1, np.pi/ 180, 40 + 1)  
for line in HoughLines[0]:  
    rho = line[0]  # 第一个元素是距离rho  
    theta = line[1] # 第二个元素是角度theta  
    if  (theta < (np.pi/4. )) or (theta > (3.*np.pi/4.0)):  # 垂直直线  
        #该直线与第一行的交点  
        pt1 = (int(rho/np.cos(theta)),0)
        #该直线与最后一行的焦点  
        pt2 = (int((rho-result.shape[0]*np.sin(theta))/np.cos(theta)),result.shape[0]) 
        #绘制一条白线  
        cv2.line( result, pt1, pt2, (255))
    else: #水平直线  
        # 该直线与第一列的交点  
        pt1 = (0,int(rho/np.sin(theta))) 
        #该直线与最后一列的交点  
        pt2 = (result.shape[1], int((rho-result.shape[1]*np.cos(theta))/np.sin(theta)))
        #绘制一条直线  
        cv2.line(result,pt1,pt2,(255),1)
print(f"霍夫变换识别到的两个点是:({pt1},{pt2})")

计算圆点与0点的直线与指针的直线的相交的夹角α

# 计算两条直线之间的夹角
AB = [center_point_x,center_point_y,zero_point_x,zero_point_y]
CD = [pt2[0],pt2[1],pt1[0],pt1[1]]

def angle(v1, v2):
    dx1 = v1[2] - v1[0]
    dy1 = v1[3] - v1[1]
    dx2 = v2[2] - v2[0]
    dy2 = v2[3] - v2[1]
    angle1 = math.atan2(dy1, dx1)
    angle1 = int(angle1 * 180/math.pi)
    angle2 = math.atan2(dy2, dx2)
    angle2 = int(angle2 * 180/math.pi)
    if angle1*angle2 >= 0:
        included_angle = abs(angle1-angle2)
    else:
        included_angle = abs(angle1) + abs(angle2)
        if included_angle > 180:
            included_angle = 360 - included_angle
    return included_angle
degree = angle(AB, CD)
print(f"两条直线之间的夹角为{degree}度")

得出指针指向的刻度值

# 计算指针所指向的刻度值
scale_value = degree * ratio
print(f"指针指向的刻度值为{scale_value}")

在表盘上显示刻度

# 在表盘上标记识别的数据
cv2.putText(image, str(scale_value), (center_point_x-40,center_point_y-40), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 3)

cv2.imshow("image",image)
cv2.waitKey(0)

 

  

posted @ 2022-05-24 11:22  狗尾巴草word  阅读(870)  评论(0编辑  收藏  举报