Advanced drawing

In this section, we are going to see how to combine some of the aforementioned functions to draw basic shapes in OpenCV (for example, lines, circles, rectangles, and text, among others) to render a more advanced drawing. To put all these pieces together, we have built an analog clock to show you the current time (hour, minutes, and seconds). For this, two scripts are coded:

The analog_clock_opencv.py script draws an analog clock, using cv.line(), cv.circle(), cv.rectangle(), and cv2.putText(). In this script, we first draw the static drawing. In this sense, you can see that there are two arrays containing fixed coordinates:

hours_orig = np.array(
[(620, 320), (580, 470), (470, 580), (320, 620), (170, 580), (60, 470), (20, 320), (60, 170), (169, 61), (319, 20),
(469, 60), (579, 169)])

hours_dest = np.array(
[(600, 320), (563, 460), (460, 562), (320, 600), (180, 563), (78, 460), (40, 320), (77, 180), (179, 78), (319, 40),
(459, 77), (562, 179)])

These arrays are necessary to render the hour markings, as they define the origin and destiny of the lines for every hour of the clock. So, these markings are drawn as follows:

for i in range(0, 12):
cv2.line(image, array_to_tuple(hours_orig[i]), array_to_tuple(hours_dest[i]), colors['black'], 3)

Additionally, a big circle is drawn, corresponding to the shape of the analog clock:

cv2.circle(image, (320, 320), 310, colors['dark_gray'], 8)

Finally, we draw the rectangle containing the Mastering OpenCV 4 with Python text, which will be rendered inside the clock:

cv2.rectangle(image, (150, 175), (490, 270), colors['dark_gray'], -1)
cv2.putText(image, "Mastering OpenCV 4", (150, 200), 1, 2, colors['light_gray'], 1, cv2.LINE_AA)
cv2.putText(image, "with Python", (210, 250), 1, 2, colors['light_gray'], 1, cv2.LINE_AA)

Once this static information is drawn in the image, we copy it to the image_original image:

image_original = image.copy()

To draw the dynamic information, several steps are performed:

  1. Get the hour, minute, and second from the current time:
# Get current date:
date_time_now = datetime.datetime.now()
# Get current time from the date:
time_now = date_time_now.time()
# Get current hour-minute-second from the time:
hour = math.fmod(time_now.hour, 12)
minute = time_now.minute
second = time_now.second
  1. Transform these values (hour, minute, and second) to angles:
# Get the hour, minute and second angles:
second_angle = math.fmod(second * 6 + 270, 360)
minute_angle = math.fmod(minute * 6 + 270, 360)
hour_angle = math.fmod((hour*30) + (minute/2) + 270, 360)
  1. Draw the lines corresponding to the hour, minute, and second needles:
# Draw the lines corresponding to the hour, minute and second needles:
second_x = round(320 + 310 * math.cos(second_angle * 3.14 / 180))
second_y = round(320 + 310 * math.sin(second_angle * 3.14 / 180))
cv2.line(image, (320, 320), (second_x, second_y), colors['blue'], 2)

minute_x = round(320 + 260 * math.cos(minute_angle * 3.14 / 180))
minute_y = round(320 + 260 * math.sin(minute_angle * 3.14 / 180))
cv2.line(image, (320, 320), (minute_x, minute_y), colors['blue'], 8)

hour_x = round(320 + 220 * math.cos(hour_angle * 3.14 / 180))
hour_y = round(320 + 220 * math.sin(hour_angle * 3.14 / 180))
cv2.line(image, (320, 320), (hour_x, hour_y), colors['blue'], 10)
  1. Finally, a small circle is drawn, corresponding to the point where the three needles join:
cv2.circle(image, (320, 320), 10, colors['dark_gray'], -1)

In the next screenshot, you can see how the analog clock looks:

The script analog_clock_values.py script calculates the fixed coordinates for both the hours_orig and hours_dest arrays. To calculate the (x, y) coordinates for the hour markings, we use the parametric equation of a circle, as can be seen in the next screenshot:

We have followed the equation in the previous screenshot to calculate the coordinates for the 12 points P(x, y) at every 30 degrees and starting at 0 degrees (0, 30, 60, 90, 120, 150, 180, 210, 240, 270, 300, and 330) with two different radii. This way, we are able to define the coordinates for the lines defining the hour markings. The code to calculate these coordinates is as follows:

radius = 300
center = (320, 320)

for x in (0, 30, 60, 90, 120, 150, 180, 210, 240, 270, 300, 330):
x_coordinate = center[0] + radius * math.cos(x * 3.14/180)
y_coordinate = center[1] + radius * math.sin(x * 3.14/180)
print("x: {} y: {}".format(round(x_coordinate), round(y_coordinate)))

for x in (0, 30, 60, 90, 120, 150, 180, 210, 240, 270, 300, 330):
x_coordinate = center[0] + (radius - 20) * math.cos(x * 3.14/180)
y_coordinate = center[1] + (radius - 20) * math.sin(x * 3.14/180)
print("x: {} y: {}".format(round(x_coordinate), round(y_coordinate)))

The full code for this script can be seen in analog_clock_values.py. It should be noted that we could have included the code to calculate these coordinates inside the other script, but it can be a good exercise for you to do it.