Always-on computer music
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

92 行
2.6KB

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