spray_pesticide.py 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. import cv2
  2. from cv2 import aruco
  3. import numpy as np
  4. import time
  5. import sys
  6. from gpiozero import LED
  7. import os
  8. sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
  9. from default_config import *
  10. visualization = True
  11. def is_in_center(x_px, y_px, frame_w, frame_h, margin_ratio=0.25):
  12. margin_x = frame_w * margin_ratio
  13. margin_y = frame_h * margin_ratio
  14. return (margin_x < x_px < frame_w - margin_x) and (margin_y < y_px < frame_h - margin_y)
  15. def get_euler_angles_from_rvec(rvec):
  16. rot_matrix, _ = cv2.Rodrigues(rvec)
  17. sy = np.sqrt(rot_matrix[0, 0]**2 + rot_matrix[1, 0]**2)
  18. singular = sy < 1e-6
  19. if not singular:
  20. roll = np.arctan2(rot_matrix[2, 1], rot_matrix[2, 2])
  21. pitch = np.arctan2(-rot_matrix[2, 0], sy)
  22. yaw = np.arctan2(rot_matrix[1, 0], rot_matrix[0, 0])
  23. else:
  24. roll = np.arctan2(-rot_matrix[1, 2], rot_matrix[1, 1])
  25. pitch = np.arctan2(-rot_matrix[2, 0], sy)
  26. yaw = 0
  27. return np.degrees(roll), np.degrees(pitch), np.degrees(yaw)
  28. def is_roll_valid(roll):
  29. return (abs(roll) < ALLOWED_ANGLE_DEG) or (160 <= abs(roll) <= 180)
  30. calib_data_path = f"camera_calibration/calib_data/{set_resolution}/MultiMatrix.npz"
  31. calib_data = np.load(calib_data_path)
  32. print('resolution:', set_resolution)
  33. cam_mat = calib_data["camMatrix"]
  34. dist_coef = calib_data["distCoef"]
  35. marker_dict = aruco.getPredefinedDictionary(aruco.DICT_7X7_50)
  36. param_markers = aruco.DetectorParameters()
  37. cap = cv2.VideoCapture(0)
  38. # Thay đổi độ phân giải phù hợp với yêu cầu ban đầu
  39. new_height = RESOLUTION_STANDARDS[set_resolution]
  40. new_width, new_height = change_resolution(cap,new_height)
  41. print(f'Resolution camera {new_width}x{new_height}')
  42. fps = cap.get(cv2.CAP_PROP_FPS)
  43. print(f"Frames per second: {fps}")
  44. def start_spraying(marker_id):
  45. print(f"🟡 SPRAYING marker {marker_id}...")
  46. def stop_spraying(marker_id):
  47. print(f"✅ SPRAYED marker {marker_id}")
  48. spray_output = LED(17)
  49. def update_spray_output(should_spray):
  50. if should_spray:
  51. spray_output.on()
  52. else:
  53. spray_output.off()
  54. # --- Track state ---
  55. marker_states = {} # marker_id -> {"state": "NOT_SPRAYED"/"SPRAYING"/"SPRAYED", "start_time": float}
  56. while True:
  57. ret, frame = cap.read()
  58. if not ret:
  59. break
  60. gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
  61. detector = cv2.aruco.ArucoDetector(marker_dict, param_markers)
  62. marker_corners, marker_IDs, _ = detector.detectMarkers(gray_frame)
  63. current_time = time.time()
  64. need_to_spray = False
  65. if marker_corners:
  66. rVec, tVec, _ = aruco.estimatePoseSingleMarkers(marker_corners, MARKER_SIZE, cam_mat, dist_coef)
  67. for i, (ids, corners) in enumerate(zip(marker_IDs, marker_corners)):
  68. marker_id = int(ids[0])
  69. corners = corners.reshape(4, 2).astype(int)
  70. cx = int(np.mean(corners[:, 0]))
  71. cy = int(np.mean(corners[:, 1]))
  72. x, y, z = tVec[i][0]
  73. roll, pitch, yaw = get_euler_angles_from_rvec(rVec[i])
  74. # Kiểm tra đủ điều kiện
  75. in_center = is_in_center(cx, cy, new_width, new_height)
  76. within_angle = is_roll_valid(roll)
  77. within_xyz = (
  78. ALLOWED_XYZ_RANGE["x"][0] <= x <= ALLOWED_XYZ_RANGE["x"][1] and
  79. ALLOWED_XYZ_RANGE["y"][0] <= y <= ALLOWED_XYZ_RANGE["y"][1] and
  80. ALLOWED_XYZ_RANGE["z"][0] <= z <= ALLOWED_XYZ_RANGE["z"][1]
  81. )
  82. if marker_id not in marker_states:
  83. marker_states[marker_id] = {"state": "NOT_SPRAYED", "start_time": 0}
  84. state_info = marker_states[marker_id]
  85. if in_center and within_angle and within_xyz:
  86. if state_info["state"] == "NOT_SPRAYED":
  87. start_spraying(marker_id)
  88. marker_states[marker_id] = {
  89. "state": "SPRAYING",
  90. "start_time": current_time
  91. }
  92. elif state_info["state"] == "SPRAYING":
  93. elapsed = current_time - state_info["start_time"]
  94. if elapsed >= SPRAY_DURATION:
  95. stop_spraying(marker_id)
  96. marker_states[marker_id]["state"] = "SPRAYED"
  97. # Shared decision: still spraying?
  98. if marker_states[marker_id]["state"] in ("NOT_SPRAYED", "SPRAYING"):
  99. need_to_spray = True
  100. # --- Visualization ---
  101. status = marker_states[marker_id]["state"]
  102. color = {"NOT_SPRAYED": (0, 0, 255), "SPRAYING": (0, 255, 255), "SPRAYED": (0, 255, 0)}[status]
  103. if visualization:
  104. cv2.polylines(frame, [corners], True, color, 2)
  105. cv2.drawFrameAxes(frame, cam_mat, dist_coef, rVec[i], tVec[i], 4, 4)
  106. cv2.putText(frame, f"ID: {marker_id}", (cx + 10, cy), cv2.FONT_HERSHEY_SIMPLEX, 0.6, color, 2)
  107. cv2.putText(frame, f"{status}", (cx + 10, cy + 25), cv2.FONT_HERSHEY_SIMPLEX, 0.6, color, 2)
  108. cv2.putText(frame, f"x:{x:.1f} y:{y:.1f} z:{z:.1f}", (cx + 10, cy + 45), cv2.FONT_HERSHEY_PLAIN, 1, (255, 255, 255), 1)
  109. cv2.putText(frame, f"roll:{roll:.1f} pitch:{pitch:.1f} yaw:{yaw:.1f}", (cx + 10, cy + 65), cv2.FONT_HERSHEY_PLAIN, 1, (0, 255, 255), 1)
  110. update_spray_output(need_to_spray)
  111. if visualization:
  112. cv2.imshow("frame", frame)
  113. key = cv2.waitKey(1)
  114. if key == ord("q"):
  115. break
  116. cap.release()
  117. cv2.destroyAllWindows()