Course notes: Angle Finder

Preamble

Notes from

Related video courses

See also

Courses

Course notes

Required files

  • test.jpg – image of angles – I took a screenshot

Required packages

  • opencv-python
  • math

Notes

Process:

  • Find points where we click
  • Find the angle
import cv2
import math

path = 'test_angles.png'
image = cv2.imread(path)

def mousePoints(event, x, y, flags, parameters):
    if event == cv2.EVENT_LBUTTONDOWN:
        print(x,y)


cv2.imshow('Test', image)
cv2.setMouseCallback('Test', mousePoints)
cv2.waitKey(0)

Note the window title specified in the setMouseCallback() must be the same. See:

Then to draw a circle

import cv2
import math

path = 'test_angles.png'
image = cv2.imread(path)
pointsList = []

def mousePoints(event, x, y, flags, parameters):
    if event == cv2.EVENT_LBUTTONDOWN:
        cv2.circle(image, (x,y), 14, (0,0,255), cv2.FILLED)
        pointsList.append((x,y))
        print(x,y)
        print(pointsList)


cv2.imshow('Test', image)
cv2.setMouseCallback('Test', mousePoints)
cv2.waitKey(0)

To set the points correctly, click the angle first then the two extensions.

To see the dot when clicked, need to add a loop and change the argument to waitKey()

import cv2
import math

path = 'test_angles.png'
image = cv2.imread(path)
pointsList = []

def mousePoints(event, x, y, flags, parameters):
    if event == cv2.EVENT_LBUTTONDOWN:
        cv2.circle(image, (x,y), 14, (0,0,255), cv2.FILLED)
        pointsList.append((x,y))
        print(x,y)
        print(pointsList)

while True:
    cv2.imshow('Test', image)
    cv2.setMouseCallback('Test', mousePoints)
    cv2.waitKey(1)

Add ability to clear the dots and start again (in case we miss the correct spot we wanted to record as a point)

import cv2
import math

path = 'test_angles.png'
image = cv2.imread(path)
pointsList = []

def mousePoints(event, x, y, flags, parameters):
    if event == cv2.EVENT_LBUTTONDOWN:
        cv2.circle(image, (x,y), 14, (0,0,255), cv2.FILLED)
        pointsList.append((x,y))
        print(x,y)
        print(pointsList)

while True:
    cv2.imshow('Test', image)
    cv2.setMouseCallback('Image', mousePoints)
    # cv2.waitKey(0)
    # cv2.waitKey(1)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        pointsList = []
        im = cv2.imread(path)

Video 2

Adding

def getAngle():
    print("Angle")

while True:

    if len(pointsList) == 3:
        getAngle()

But what about finding multiple angles? Change to check for modulus

if len(pointsList) % 3 == 0:
    getAngle()

but also check that there are some points

if len(pointsList) % 3 == 0 and len(pointsList):
    getAngle()

How to get the angle

Gradient is {y2 - y1)/(x2 - x1)

def gradient(pt1, pt2):
    # {y2 - y1)/(x2 - x1)
    return (pt2[1] - pt1[1]) / (pt2[0] - pt1[0])

Only work on the last three elements of the pointsList

def getAngle():
    pt1, pt2, pt3 = pointsList[-3:]
    print("Angle")
    print(pt1, pt2, pt3)
    m1 = gradient(pt1,pt2)
    m2 = gradient(pt1, pt3)
    angleRadians = math.atan((m2 - m1)/(1+m1*m2))
    angleDegrees = round(math.degrees(angleRadians))
    print(angleDegrees, angleRadians)

Video 3

Draw lines and write the angle.

First get the length of the list of points

size = len(pointsList)

Only draw the lines on the second and third click. Also if we start back from zero, don’t draw the line.

if size == 0 and size%3 !=0:

Note that the first point is either the previous point (for the first line) or two points previous (for the second line). Its position in the pointsList is

round((size - 1) / 3) * 3

So

size = len(pointsList)
if size != 0 and size % 3 != 0:
    cv2.line(image, tuple(pointsList[round((size - 1) / 3) * 3]), (x, y), (0, 0, 255), 2)

Now draw the angle

cv2.putText(image, f'{str(angleDegrees)}°', (pt1[0] - 40, pt1[1] - 20), cv2.FONT_HERSHEY_COMPLEX, 1.5, (0, 0, 255),

Full code

# AngleFinder.py

import cv2
import math

path = 'test_angles.png'
image = cv2.imread(path)
pointsList = []


def mousePoints(event, x, y, flags, params):
    if event == cv2.EVENT_LBUTTONDOWN:
        size = len(pointsList)
        if size != 0 and size % 3 != 0:
            cv2.line(image, tuple(pointsList[round((size - 1) / 3) * 3]), (x, y), (0, 0, 255), 3)

        cv2.circle(image, (x, y), 14, (0, 0, 255), cv2.FILLED)
        pointsList.append((x, y))
        print(x, y)
        print(pointsList)


def gradient(pt1, pt2):
    # {y2 - y1)/(x2 - x1)
    return (pt2[1] - pt1[1]) / (pt2[0] - pt1[0])


def getAngle():
    pt1, pt2, pt3 = pointsList[-3:]
    print("Angle")
    print(pt1, pt2, pt3)
    m1 = gradient(pt1, pt2)
    m2 = gradient(pt1, pt3)
    angleRadians = math.atan((m2 - m1) / (1 + m1 * m2))
    angleDegrees = round(math.degrees(angleRadians))
    print(angleDegrees, angleRadians)
    cv2.putText(image, f'{str(angleDegrees)}°', (pt1[0] - 40, pt1[1] - 20), cv2.FONT_HERSHEY_COMPLEX, 1.5, (0, 0, 255),
                3)


while True:

    if len(pointsList) % 3 == 0 and len(pointsList):
        getAngle()
    cv2.imshow('Test', image)
    cv2.setMouseCallback('Test', mousePoints)
    # cv2.waitKey(0)
    # cv2.waitKey(1)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        pointsList = []
        image = cv2.imread(path)

 

This is the end, my friend

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s