用OpenCV测量图像中的角度

        今天Franpper给大家带来一个有趣的项目——使用OpenCV在图像中计算角度。想象一下,通过简单的点击,我们就能精确地测量出图像中任意三点形成的角度。这不仅仅是一项技术展示,更是开启我们对图像处理认知新大门的钥匙。

        首先Franpper先给大家展示一下效果   

示例1:     

 示例2:

        可以看到,当我们在图像上点击三个点时(顺序为:一条边上的某点->角的顶点->另一条边上的某点),算法会自动测量出由这三个点形成的角度。这得益于OpenCV的事件处理功能,它允许我们在图像上捕捉鼠标点击的位置,并实时显示这些点和它们之间的连线。下面正式开始今天的介绍!

目录

用OpenCV测量图像中的角度

1.  设置鼠标回调函数

2.  计算角度

3. 完整代码


1.  设置鼠标回调函数

        测量一个角需要三个点,即顶点与两条边上的各一点。设置鼠标的回调函数可以获取鼠标点击的点,并将一个角中的三个点进行连线(第二个点连第一个点,第三个点连第二个点)。

def get_mouse_points(events, x, y, flags, params):
    if events == cv2.EVENT_LBUTTONDOWN:
        size = len(point_list)

        if size != 0 and size % 3 != 0:
            cv2.line(self.image, tuple(self.point_list[-1]), (x, y), (0, 255, 0), 2)

        cv2.circle(self.image, (x, y), 5, (0, 255, 0), -1)
        self.point_list.append([x, y])
        print(self.point_list)

2.  计算角度

        获取到顶点与两条边上的各一点之后就可以计算角度了,这里Franpper给大家提供的是解三角形求角度

        具体原理如下:

实现代码为: 

def calculate_angle1(point_list):
    """

    :param point_list:
    :return:
    """
    p1, p2, p3 = np.array(point_list[-3:]) # 取出最后三个点
    # 计算两点之间的距离
    a = np.linalg.norm(p2 - p1)
    b = np.linalg.norm(p3 - p2)
    c = np.linalg.norm(p1 - p3)

    # 使用余弦定理计算每个角的余弦值
    cos_C = (a ** 2 + b ** 2 - c ** 2) / (2 * a * b)

    # 使用反余弦函数计算每个角的角度
    angle = np.arccos(cos_C) * 180 / np.pi
    print(angle)
    return angle, p2

3. 完整代码

完整的项目代码以及测试图片如下:

import cv2
import math
import numpy as np


class AngleCalculator:
    def __init__(self, image_path):
        self.point_list = []
        self.image = cv2.imread(image_path)
        self.refresh_image = self.image.copy()

    def get_mouse_points(self, events, x, y, flags, params):
        if events == cv2.EVENT_LBUTTONDOWN:
            size = len(self.point_list)

            if size != 0 and size % 3 != 0:
                cv2.line(self.image, tuple(self.point_list[-1]), (x, y), (0, 255, 0), 2)

            cv2.circle(self.image, (x, y), 5, (0, 255, 0), -1)
            self.point_list.append([x, y])
            print(self.point_list)

    def calculate_angle(self):
        p1, p2, p3 = np.array(self.point_list[-3:])
        a = np.linalg.norm(p2 - p1)
        b = np.linalg.norm(p3 - p2)
        c = np.linalg.norm(p1 - p3)
        cos_C = (a ** 2 + b ** 2 - c ** 2) / (2 * a * b)
        angle = int(np.arccos(cos_C) * 180 / np.pi)
        print(angle)
        return angle, p2

    def __call__(self):
        while True:
            if len(self.point_list) % 3 == 0 and len(self.point_list) > 0:
                angle, point = self.calculate_angle()
                cv2.putText(self.image, str(angle), (point[0] - 40, point[1] - 20),
                            cv2.FONT_HERSHEY_COMPLEX, 1.5, (0, 255, 0), 2)

            cv2.imshow('Image', self.image)
            cv2.setMouseCallback('Image', self.get_mouse_points)
            if cv2.waitKey(1) & 0xFF == ord('q'):
                self.point_list = []
                self.image = self.refresh_image.copy()


if __name__ == '__main__':
    image_path = r'E:\pythonProject\OpenCV\opencv_proj\angle.jpg'
    calculator = AngleCalculator(image_path)
    calculator()

 

 

GitHub 加速计划 / opencv31 / opencv
142
15
下载
OpenCV: 开源计算机视觉库
最近提交(Master分支:3 个月前 )
d9a139f9 Animated WebP Support #25608 related issues #24855 #22569 ### Pull Request Readiness Checklist See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request - [x] I agree to contribute to the project under Apache 2 License. - [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV - [x] The PR is proposed to the proper branch - [x] There is a reference to the original bug report and related work - [ ] There is accuracy test, performance test and test data in opencv_extra repository, if applicable Patch to opencv_extra has the same branch name. - [ ] The feature is well documented and sample code can be built with the project CMake 1 天前
09030615 V4l default image size #25500 Added ability to set default image width and height for V4L capture. This is required for cameras that does not support 640x480 resolution because otherwise V4L capture cannot be opened and failed with "Pixel format of incoming image is unsupported by OpenCV" and then with "can't open camera by index" message. Because of the videoio architecture it is not possible to insert actions between CvCaptureCAM_V4L::CvCaptureCAM_V4L and CvCaptureCAM_V4L::open so the only way I found is to use environment variables to preselect the resolution. Related bug report is [#25499](https://github.com/opencv/opencv/issues/25499) Maybe (but not confirmed) this is also related to [#24551](https://github.com/opencv/opencv/issues/24551) This fix was made and verified in my local environment: capture board AVMATRIX VC42, Ubuntu 20, NVidia Jetson Orin. ### Pull Request Readiness Checklist See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request - [X] I agree to contribute to the project under Apache 2 License. - [X] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV - [X] The PR is proposed to the proper branch - [X] There is a reference to the original bug report and related work - [ ] There is accuracy test, performance test and test data in opencv_extra repository, if applicable Patch to opencv_extra has the same branch name. - [ ] The feature is well documented and sample code can be built with the project CMake 1 天前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐