Always-on computer music
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

78 line
2.2KB

  1. import math
  2. import itertools as it
  3. import cv2
  4. from pythonosc import udp_client
  5. import numpy as np
  6. DENSITY = 4
  7. RED = [0, 0, 255]
  8. N_COLORS = 3
  9. def draw_rectangle(frame, sp, ep):
  10. """ Draw a rectangle on the frame """
  11. return cv2.rectangle(frame, sp, ep, RED, 1)
  12. def analyze_block(frame, osc, index, sp, ep):
  13. """ Analyze a block """
  14. block = frame[sp[1]:ep[1], sp[0]:ep[0], 0:3]
  15. average_color = np.average(block, (0, 1))
  16. sp2 = tuple(int(x) for x in (2 * np.array(sp) + np.array(ep)) / 3)
  17. ep2 = tuple(int(x) for x in (np.array(sp) + 2 * np.array(ep)) / 3)
  18. average_color = [int(x) for x in average_color]
  19. frame = cv2.rectangle(frame, sp2, ep2, average_color, -1)
  20. average_color = np.uint8([[average_color]])
  21. h, s, v = cv2.cvtColor(average_color, cv2.COLOR_BGR2HSV)[0][0]
  22. # Configure the oscillator
  23. osc.send_message(
  24. "/radio",
  25. [int(index),
  26. float(h / 255),
  27. float(s / 255),
  28. float(v / 255), .5])
  29. # Draw the image
  30. for thickness, color in ((3, (0, 0, 0)), (1, (255, 255, 255))):
  31. frame = cv2.putText(frame,
  32. text=f"{h:03d} {s:03d} {v:03d}",
  33. org=(sp[0] + 10, sp[1] + 20),
  34. fontScale=.5,
  35. color=color,
  36. fontFace=2,
  37. thickness=thickness)
  38. return frame
  39. def analyze(frame, osc):
  40. """ Analyze the full frame """
  41. height, width, d = frame.shape
  42. n = DENSITY
  43. m = math.ceil(n * (height / width))
  44. dx = width / n
  45. dy = height / m
  46. for index, (x, y) in enumerate(it.product(range(n), range(m))):
  47. sp = (int(x * dx), int(y * dy))
  48. ep = (int(x * dx + dx), int(y * dy + dy))
  49. frame = draw_rectangle(frame, sp, ep)
  50. frame = analyze_block(frame, osc, index, sp, ep)
  51. return frame
  52. if __name__ == '__main__':
  53. camera = cv2.VideoCapture(0)
  54. osc = udp_client.SimpleUDPClient("0.0.0.0", 5005)
  55. while True:
  56. ret, frame = camera.read()
  57. frame = analyze(frame, osc)
  58. cv2.imshow('Input', frame)
  59. c = cv2.waitKey(1)
  60. if c == 27:
  61. break
  62. camera.release()
  63. cv2.destroyAllWindows()