【opencv有趣应用】测量图像上的特定角度值

今天做一个角度的测量器
在图像上如果想测量一个角度,只需要用鼠标选择这个角度的三个点,就能自动测量出这个角度值。
这里用到的知识是余弦定理
代码如下:

import math
import cv2
import numpy as np

point_list = []
img_show_windows = 'show'
image_path = 'images/angles.png'

def myMouseCallBbackFunc(event, x, y, flags, params_img):
    if event == cv2.EVENT_LBUTTONDOWN:  # 鼠标点击事件
        # 在鼠标的点击点画一个实心圆, 表示在这里取这个坐标点
        cv2.circle(img=params_img, center=(x, y), radius=5, color=(255, 0, 0), thickness=cv2.FILLED)
        # 将该点的位置信息保留记录
        point_list.append([x, y])
        print(point_list)

        # 根据实际情况画出角度的直线
        if len(point_list) == 3:
            p1, p2, p3 = point_list
            cv2.line(params_img, p1, p2, color=(0, 0, 255), thickness=3, lineType=cv2.LINE_AA)
            cv2.line(params_img, p1, p3, color=(0, 0, 255), thickness=3, lineType=cv2.LINE_AA)


def getEdgeTheta(pt_from, pt_to):
    k = abs(pt_to[1] - pt_from[1]) / (pt_to[0] - pt_from[0])
    theta = abs(math.atan(k) * 180 / math.pi)

    if pt_to[1] <= pt_from[1]:  # to点在from点的上面
        if pt_to[0] > pt_from[0]:  # 第一象限
            theta = theta
        elif pt_to[0] == pt_from[0]:  # 垂直
            theta = 90
        else:  # 第二象限
            theta = 180 - theta

    else:  # to点在from点的下面
        if pt_to[0] < pt_from[0]:  # 第三象限
            theta = theta + 180
        elif pt_to[0] == pt_from[0]:  # 垂直
            theta = 270
        else:  # 第二象限
            theta = 360 - theta

    print('theta:{}'.format(theta))
    return theta


def getOneAngle(img):
    # first point is center
    p1, p2, p3 = point_list
    len_a = math.sqrt(math.pow((p2[0] - p1[0]), 2) + math.pow((p2[1] - p1[1]), 2))
    len_b = math.sqrt(math.pow((p3[0] - p1[0]), 2) + math.pow((p3[1] - p1[1]), 2))
    len_c = math.sqrt(math.pow((p3[0] - p2[0]), 2) + math.pow((p3[1] - p2[1]), 2))

    print('len_a:{}, len_b:{}, len_c:{}'.format(len_a, len_b, len_c))

    # 求出c对应的角的角度,是使用余弦定理做的
    angle = math.acos((math.pow(len_a, 2) + math.pow(len_b, 2) - math.pow(len_c, 2)) / (2 * len_a * len_b))
    angle = angle * 180 / math.pi
    print('get angle: {}'.format(angle))

    # 在图上画出表示角度的圆弧出来
    theta_a = getEdgeTheta(p1, p2)
    theta_b = getEdgeTheta(p1, p3)

    # 计算起始角度和结束角度,角度值维持在180度以内
    maxval = max(int(theta_a), int(theta_b))
    minval = min(int(theta_a), int(theta_b))
    if minval + 180 < maxval:
        startAngle, endAngle = maxval, minval
    else:
        startAngle, endAngle = minval, maxval
    print('startAngle:{}, endAngle:{}'.format(startAngle, endAngle))

    radius = int(min(len_a, len_b) / 2)  # 计算画弧线的半径

    # 画出弧线
    cv2.ellipse(img=img, center=p1, axes=(radius, radius),
                angle=int(360 - int(endAngle)), startAngle=0, endAngle=int(angle),
                color=(0, 255, 0), thickness=1)

    cv2.putText(img=img, text='{}'.format("%.2f" % angle), org=(p1[0]-10, p1[1]), fontFace=cv2.FONT_HERSHEY_COMPLEX,
                fontScale=1, color=(0, 255, 0), thickness=3)  # 在图上画出这个


if __name__ == '__main__':
    img = cv2.imread(image_path)

    #cv2.namedWindow(img_show_windows)  # 定义一个window
    #cv2.setMouseCallback(img_show_windows, myMouseCallBbackFunc, img)  # 设置这个窗口的鼠标事件回调函数

    while True:
        cv2.imshow(img_show_windows, img)  # 在这个window上画图
        # 其实点击事件还在,设置这个窗口的鼠标事件回调函数的目的,这里主要是更新这个新读取的图像这个参数
        cv2.setMouseCallback(img_show_windows, myMouseCallBbackFunc, img)

        if cv2.waitKey(1) & 0xFF == ord('q'):  # 按下q键清空所有的保留的点,重新展示一个新的图像
            point_list.clear()  # 清空所有的点
            img = cv2.imread(image_path)  # 重新获取图像

        if len(point_list) == 3:  # 三个点够了,我们可以得到三个点的角度。
            getOneAngle(img)  # 得到角度,这里是使用余弦定理来做的。
            point_list.clear()  # 清空所有的点



比如我输入的原图是:
请添加图片描述
然后我们的效果是:
请添加图片描述
运用之前学习的图像标记知识。

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
前言: 开源的opencv真是一件伟大的产品,那么多个函数跟变量(具体多少还没数过)。要是结合起来综合运用几乎可以胜任任何有关图像识别和处理方面的工作。如果能更深入一点根据具体需要修改或优化里面的源码那更是如虎添翼。 花了点时间浏览了www.opencv.org.cn论坛里的所有贴子,还好不多才200多页。总体上对opencv里的一些常用函数功能作用大致有点了解,筛选一些跟元件识别有关的运用内容,但它论坛里的贴子回复的内容点到即止的居多。从网上下载了能搜到的教程跟代码全学习了解测试了一下,图像处理流程通常先开始都是要进行滤波,除燥,灰度,二化后再轮廓识别等。 开始动手 经过多次好多次运行测试组合,终于有一次显示出意外的惊人效果,而且相当简单只是调用了几个函数而以,就可以有这样效果实在出人意料。第一个是进行元件中心点获取,也是直接调用函数再加点东西就可以得出元件的四个矩形顶点坐标,有这几个坐标就可以直接算出元件中间点所在的坐标了。如果要检测元件摆放角度是否是垂直90度,只要判断边宽的长度为最小或最大时就是垂直90度。 但这个矩形框无法测出元件具体角度。如截图: 测试视频地址:https://v.youku.com/v_show/id_XMjU5NzY5NTI0.html 不过,还有另外一个函数可以提供这个功能,调用后可以直接求出最小外接矩形和角度 如截图: 测试视频地址:https://v.youku.com/v_show/id_XMjYwMDMzMDc2.html 说明:里面的光源不行,临时用手电筒,和在光盘上插几个LED做环形灯做照明,无法做到无阴影显示。如果光源做的好,效果应该是非常精确稳定。 识别包含下面2种做法: opencv里需要的头文件跟库文件都已编译好放在和设置在当前程序目录下,就可不用安装opencv 也能直接编译。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值