Draw rect and round with google map

本文介绍如何使用Google Maps API v3在地图上绘制矩形和圆形区域。通过提供的JavaScript代码示例,展示了如何设置边界坐标和计算圆形路径。

The topic is to dicuss how to draw rect and round under google map java-script. As we know, there are many resource about the two items. But``` it seems that most of them are written by google map v2. So we do this job with google map v3 as follow:

1. Drawing rect:
(1) Rule: It is simple to follow the sample "Bermuda Triangle", which is from google map v3 guide: http://code.google.com/intl/zh-CN/apis/maps/documentation/v3/overlays.html#Polygons

(2) Our sample source:

var rectRegion;
// parameter: rect cornerA(base pos): lng1/lat1; cornerB(mouse pos): lng2/lat2
// type: 0x00: refresh(default); 0x01: add rect and set center of map
function drawSingleRect(lng1, lat1, lng2, lat2, type) {
 if(type == 0) {
  if(rectRegion)
   rectRegion.setMap(null); 
 }
 else if(type == 1) {
  latlng = new google.maps.LatLng(lat1, lng1);
  map.setZoom(16);
  map.setCenter(latlng);
 }

 var rectCoords = [
  new google.maps.LatLng(lat1, lng1),
  new google.maps.LatLng(lat1, lng2),
  new google.maps.LatLng(lat2, lng2),
  new google.maps.LatLng(lat2, lng1),
  new google.maps.LatLng(lat1, lng1)
 ];

 rectRegion = new google.maps.Polygon({
  paths: rectCoords,
  strokeColor: "#FF0000",
  strokeOpacity: 0.8,
  strokeWeight: 2,
  fillColor: "#FF0000",
  fillOpacity: 0.35
 });

 rectRegion.setMap(map);
}

(3) Realizing:

sample1.jpg

2. Drawing circle:
(1) Rule:
The round is polyron also. If we calc enough points at the circle, then we can build the "circle" polyron. And we found the math rule with center lng/lat and radius from: http://maps.forum.nu/gm_sensitive_circle2.html , whose author is Marcelo Montagna. At fact, Marcelo's code run some slowly because of many sin/cos/atan and so on? Then we do little modification for quick it.
The other item is how to read the radius between two marker. The excellent job we found is from: http://www.barattalo.it/2009/12/19/ruler-for-google-maps-v3-to-measure-distance-on-map/ , the author is Giulio Pons. With Giulio's source we built a ruler also.

(2) Our sample Source:
Like the drawing rect, we simulate the paths parameter of polygon, which is the marker array calced by Marcelo's rule, then do setMap(). Everything seems ok.

var roundRegion;
// parameter: center pos: lng1/lat1; mouse pos: lng2/lat2
// type: 0x00: refresh(default); 0x01: add round and set center of map
function drawSingleRound(lng1, lat1, lng2, lat2, type) {

 radius = distance(lat1, lng1, lat2, lng2); // unit: m
 drawSingleRoundwithRadius(lng1, lat1, radius, type);
}

function drawSingleRoundwithRadius(lng1, lat1, radius, type) {
 if(type == 0) {
  if(roundRegion)
   roundRegion.setMap(null); 
 }
 else if(type == 1) {
  latlng = new google.maps.LatLng(lat1, lng1);
  map.setZoom(16);
  map.setCenter(latlng);
 }
 
 var d = radius/6378800;
 var roundCoords = [];

 var bequick1 = Math.PI/180;
 var bequick2 = 180/Math.PI;
 lat1 = bequick1* lat1;
 lng1 = bequick1* lng1;
 var bequick3 = Math.sin(lat1);
 var bequick4 = Math.cos(lat1);
 var bequick5 = Math.sin(d);
 var bequick6 = Math.cos(d);
 for (var a = 0 ; a < 361 ; a++) {
  var tc = bequick1*a;
  var y = Math.asin(bequick3*bequick6+bequick4*bequick5*Math.cos(tc));
  var dlng = Math.atan2(Math.sin(tc)*bequick5*bequick4, bequick6-bequick3*Math.sin(y));
  var x = ((lng1-dlng+Math.PI) % (2*Math.PI)) - Math.PI ; // MOD function
  var point = new google.maps.LatLng(parseFloat(y*bequick2), parseFloat(x*bequick2));
  roundCoords.push(point);
 }

 roundRegion = new google.maps.Polygon({
  paths: roundCoords,
  strokeColor: "#FF0000",
  strokeOpacity: 0.8,
  strokeWeight: 2,
  fillColor: "#FF0000",
  fillOpacity: 0.35
 });

 roundRegion.setMap(map);
}

// return delta with unit meter
function distance(lat1,lon1,lat2,lon2) {
 var R = 6371; // km (change this constant to get miles)
 var dLat = (lat2-lat1) * Math.PI / 180;
 var dLon = (lon2-lon1) * Math.PI / 180;
 var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
  Math.cos(lat1 * Math.PI / 180 ) * Math.cos(lat2 * Math.PI / 180 ) *
  Math.sin(dLon/2) * Math.sin(dLon/2);
 var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
 var d = R * c;
 //if (d>1) return Math.round(d)+"km";
 //else if (d<=1) return Math.round(d*1000)+"m";
 if (d>1) return Math.round(d)*1000;
 else if (d<=1) return Math.round(d*1000);
 //return d;
}

(3) Realizing:

sample2.jpg
#模块导入 import pygame,sys from pygame.locals import* #初始化pygame pygame.init() #设置窗口大小,单位是像素 screen = pygame.display.set_mode((500,400)) #设置背景颜色 screen.fill((0,0,0)) #设置窗口标题 pygame.display.set_caption("你好,我的朋友") # 绘制一条线 pygame.draw.rect(screen, (0,0,0), [0,100,70,40]) #加载图片 img = pygame.image.load("panda.jpg") #初始化图片位置 imgx = 0 imgy = 10 #加载和播放音频 sound = pygame.mixer.Sound('Sound_Of_The_Sea.ogg') sound.play() #加载背景音乐 pygame.mixer.music.load('TEST1.mp3') #播放背景音乐,第一个参数为播放的次数(-1表示无限循环),第二个参数是设置播放的起点(单位为秒) pygame.mixer.music.play(-1, 30.0) #导入文字格式 fontt=pygame.font.Font(None,50) #配置文字 tex=fontt.render("It is boring!!!",True,(0,0,128),(0,255,0)) #显示文字及坐标 texr=tex.get_rect() texr.center=(10,250) #初始化方向 dire = "right" #设置循环 while 1: #绘制文字 screen.blit(tex,texr) screen.fill((0,0,0)) screen.blit(img,(imgx,imgy)) if dire == "right": imgx+=5 if imgx == 380: dire = 'down' elif dire == 'down': imgy += 5 if imgy == 300: dire = 'left' elif dire == 'left': imgx -= 5 if imgx == 10: dire = 'up' elif dire == 'up': imgy -= 5 if imgy == 10: dire = 'right' #获取事件 for ss in pygame.event.get(): #判断事件 if ss.type == QUIT: #退出Pygame pygame.quit() #退出系统 sys.exit() #绘制屏幕内容 pygame.display.update() #设置帧率 pygame.time.delay(10)
import time, os, sys import math import cv_lite # 导入cv_lite扩展模块 import ulab.numpy as np # 导入numpy库 from media.sensor import * from media.display import * from media.media import * from machine import UART, FPIOA # --------------------------- 硬件初始化 --------------------------- # 串口初始化 fpioa = FPIOA() fpioa.set_function(3, FPIOA.UART1_TXD) fpioa.set_function(4, FPIOA.UART1_RXD) uart = UART(UART.UART1, 115200) # 屏幕分辨率设置 lcd_width = 800 lcd_height = 480 # 摄像头初始化(注意:保留RGB模式用于色块检测,后续转为灰度图用于矩形检测) sensor = Sensor(width=1280, height=960) sensor.reset() sensor.set_framesize(width=320, height=240) # 降低分辨率提高帧率 sensor.set_pixformat(Sensor.RGB565) # 保留彩色用于紫色色块检测 # 显示初始化 Display.init(Display.ST7701, width=lcd_width, height=lcd_height, to_ide=True) MediaManager.init() sensor.run() # --------------------------- 配置参数 --------------------------- # 矩形检测核心参数(基于cv_lite) canny_thresh1 = 50 # Canny边缘检测低阈值 canny_thresh2 = 150 # Canny边缘检测高阈值 approx_epsilon = 0.04 # 多边形拟合精度(越小越精确) area_min_ratio = 0.005 # 最小面积比例(相对于图像总面积) max_angle_cos = 0.3 # 角度余弦阈值(越小越接近矩形) gaussian_blur_size = 3 # 高斯模糊核尺寸(奇数) # 原有筛选参数 MIN_AREA = 100 # 最小面积阈值 MAX_AREA = 100000 # 最大面积阈值 MIN_ASPECT_RATIO = 0.3 # 最小宽高比 MAX_ASPECT_RATIO = 3.0 # 最大宽高比 # 虚拟坐标与圆形参数 BASE_RADIUS = 45 # 基础半径(虚拟坐标单位) POINTS_PER_CIRCLE = 24 # 圆形采样点数量 PURPLE_THRESHOLD = (20, 60, 15, 70, -70, -20) # 紫色色块阈值 # 基础矩形参数(固定方向,不再自动切换) RECT_WIDTH = 210 # 固定矩形宽度 RECT_HEIGHT = 95 # 固定矩形高度 # 移除自动切换方向的逻辑,始终使用固定宽高的虚拟矩形 # --------------------------- 工具函数 --------------------------- def calculate_distance(p1, p2): return math.sqrt((p2[0] - p1[0])**2 + (p2[1] - p1[1])** 2) def calculate_center(points): if not points: return (0, 0) sum_x = sum(p[0] for p in points) sum_y = sum(p[1] for p in points) return (sum_x / len(points), sum_y / len(points)) def is_valid_rect(corners): edges = [calculate_distance(corners[i], corners[(i+1)%4]) for i in range(4)] # 对边比例校验 ratio1 = edges[0] / max(edges[2], 0.1) ratio2 = edges[1] / max(edges[3], 0.1) valid_ratio = 0.5 < ratio1 < 1.5 and 0.5 < ratio2 < 1.5 # 面积校验 area = 0 for i in range(4): x1, y1 = corners[i] x2, y2 = corners[(i+1) % 4] area += (x1 * y2 - x2 * y1) area = abs(area) / 2 valid_area = MIN_AREA < area < MAX_AREA # 宽高比校验 width = max(p[0] for p in corners) - min(p[0] for p in corners) height = max(p[1] for p in corners) - min(p[1] for p in corners) aspect_ratio = width / max(height, 0.1) valid_aspect = MIN_ASPECT_RATIO < aspect_ratio < MAX_ASPECT_RATIO return valid_ratio and valid_area and valid_aspect def detect_purple_blobs(img): return img.find_blobs( [PURPLE_THRESHOLD], pixels_threshold=100, area_threshold=100, merge=True ) def send_circle_points(points): if not points: return count = len(points) msg = f"$$C,{count}," for x, y in points: msg += f"{x},{y}," msg = msg.rstrip(',') + "##" uart.write(msg) # print(f"发送圆形点: {msg}") def get_perspective_matrix(src_pts, dst_pts): """计算透视变换矩阵""" A = [] B = [] for i in range(4): x, y = src_pts[i] u, v = dst_pts[i] A.append([x, y, 1, 0, 0, 0, -u*x, -u*y]) A.append([0, 0, 0, x, y, 1, -v*x, -v*y]) B.append(u) B.append(v) # 高斯消元求解矩阵 n = 8 for i in range(n): max_row = i for j in range(i, len(A)): if abs(A[j][i]) > abs(A[max_row][i]): max_row = j A[i], A[max_row] = A[max_row], A[i] B[i], B[max_row] = B[max_row], B[i] pivot = A[i][i] if abs(pivot) < 1e-8: return None for j in range(i, n): A[i][j] /= pivot B[i] /= pivot for j in range(len(A)): if j != i and A[j][i] != 0: factor = A[j][i] for k in range(i, n): A[j][k] -= factor * A[i][k] B[j] -= factor * B[i] return [ [B[0], B[1], B[2]], [B[3], B[4], B[5]], [B[6], B[7], 1.0] ] def transform_points(points, matrix): """应用透视变换将虚拟坐标映射到原始图像坐标""" transformed = [] for (x, y) in points: x_hom = x * matrix[0][0] + y * matrix[0][1] + matrix[0][2] y_hom = x * matrix[1][0] + y * matrix[1][1] + matrix[1][2] w_hom = x * matrix[2][0] + y * matrix[2][1] + matrix[2][2] if abs(w_hom) > 1e-8: transformed.append((x_hom / w_hom, y_hom / w_hom)) return transformed def sort_corners(corners): """将矩形角点按左上、右上、右下、左下顺序排序""" center = calculate_center(corners) sorted_corners = sorted(corners, key=lambda p: math.atan2(p[1]-center[1], p[0]-center[0])) # 调整顺序为左上、右上、右下、左下 if len(sorted_corners) == 4: left_top = min(sorted_corners, key=lambda p: p[0]+p[1]) index = sorted_corners.index(left_top) sorted_corners = sorted_corners[index:] + sorted_corners[:index] return sorted_corners def get_rectangle_orientation(corners): """计算矩形的主方向角(水平边与x轴的夹角)""" if len(corners) != 4: return 0 # 计算上边和右边的向量 top_edge = (corners[1][0] - corners[0][0], corners[1][1] - corners[0][1]) right_edge = (corners[2][0] - corners[1][0], corners[2][1] - corners[1][1]) # 选择较长的边作为主方向 if calculate_distance(corners[0], corners[1]) > calculate_distance(corners[1], corners[2]): main_edge = top_edge else: main_edge = right_edge # 计算主方向角(弧度) angle = math.atan2(main_edge[1], main_edge[0]) return angle # --------------------------- 主循环 --------------------------- clock = time.clock() image_shape = [sensor.height(), sensor.width()] # [高, 宽] 用于cv_lite while True: clock.tick() img = sensor.snapshot() # 1. 检测紫色色块(保留原有功能) purple_blobs = detect_purple_blobs(img) for blob in purple_blobs: img.draw_rectangle(blob[0:4], color=(255, 0, 255), thickness=1) img.draw_cross(blob.cx(), blob.cy(), color=(255, 0, 255), thickness=1) # 2. 矩形检测(使用cv_lite替换原有实现) # 2.1 将RGB图像转为灰度图(用于矩形检测) gray_img = img.to_grayscale() img_np = gray_img.to_numpy_ref() # 转为numpy数组供cv_lite使用 # 2.2 调用cv_lite矩形检测函数(带角点) rects = cv_lite.grayscale_find_rectangles_with_corners( image_shape, # 图像尺寸 [高, 宽] img_np, # 灰度图数据 canny_thresh1, # Canny低阈值 canny_thresh2, # Canny高阈值 approx_epsilon, # 多边形拟合精度 area_min_ratio, # 最小面积比例 max_angle_cos, # 角度余弦阈值 gaussian_blur_size # 高斯模糊尺寸 ) # 3. 筛选最小矩形(保留原有逻辑) min_area = float('inf') smallest_rect = None smallest_rect_corners = None # 存储最小矩形的角点 for rect in rects: # rect格式: [x, y, w, h, c1.x, c1.y, c2.x, c2.y, c3.x, c3.y, c4.x, c4.y] x, y, w, h = rect[0], rect[1], rect[2], rect[3] # 提取四个角点 corners = [ (rect[4], rect[5]), # 角点1 (rect[6], rect[7]), # 角点2 (rect[8], rect[9]), # 角点3 (rect[10], rect[11]) # 角点4 ] # 验证矩形有效性 if is_valid_rect(corners): # 计算面积 area = w * h # 直接使用矩形宽高计算面积(更高效) # 更新最小矩形 if area < min_area: min_area = area smallest_rect = (x, y, w, h) smallest_rect_corners = corners # 4. 处理最小矩形(修改后:固定虚拟矩形方向) if smallest_rect and smallest_rect_corners: x, y, w, h = smallest_rect corners = smallest_rect_corners # 对矩形角点进行排序 sorted_corners = sort_corners(corners) # 绘制矩形边框和角点 for i in range(4): x1, y1 = sorted_corners[i] x2, y2 = sorted_corners[(i+1) % 4] img.draw_line(x1, y1, x2, y2, color=(255, 0, 0), thickness=2) for p in sorted_corners: img.draw_circle(p[0], p[1], 5, color=(0, 255, 0), thickness=2) # 计算并绘制矩形中心点 rect_center = calculate_center(sorted_corners) rect_center_int = (int(round(rect_center[0])), int(round(rect_center[1]))) img.draw_circle(rect_center_int[0], rect_center_int[1], 4, color=(0, 255, 255), thickness=2) # 计算矩形主方向角(仅用于参考,不再影响虚拟矩形方向) angle = get_rectangle_orientation(sorted_corners) # 【核心修改】移除自动切换方向逻辑,固定使用预设的虚拟矩形尺寸和方向 # 固定虚拟矩形(不再根据实际宽高比切换) virtual_rect = [ (0, 0), (RECT_WIDTH, 0), (RECT_WIDTH, RECT_HEIGHT), (0, RECT_HEIGHT) ] # 【核心修改】固定圆形半径参数(不再根据实际宽高比调整) radius_x = BASE_RADIUS radius_y = BASE_RADIUS # 【核心修改】固定虚拟中心(基于固定的宽高) virtual_center = (RECT_WIDTH / 2, RECT_HEIGHT / 2) # 在虚拟矩形中生成椭圆点集(映射后为正圆) virtual_circle_points = [] for i in range(POINTS_PER_CIRCLE): angle_rad = 2 * math.pi * i / POINTS_PER_CIRCLE x_virt = virtual_center[0] + radius_x * math.cos(angle_rad) y_virt = virtual_center[1] + radius_y * math.sin(angle_rad) virtual_circle_points.append((x_virt, y_virt)) # 计算透视变换矩阵并映射坐标 matrix = get_perspective_matrix(virtual_rect, sorted_corners) if matrix: mapped_points = transform_points(virtual_circle_points, matrix) int_points = [(int(round(x)), int(round(y))) for x, y in mapped_points] # 绘制圆形 for (px, py) in int_points: img.draw_circle(px, py, 2, color=(255, 0, 255), thickness=2) # 绘制圆心 mapped_center = transform_points([virtual_center], matrix) if mapped_center: cx, cy = map(int, map(round, mapped_center[0])) img.draw_circle(cx, cy, 3, color=(0, 0, 255), thickness=1) # 发送坐标 send_circle_points(int_points) # 5. 显示与性能统计 fps = clock.fps() img.draw_string_advanced(10, 10, 20, f"FPS: {fps:.1f}", color=(255, 255, 255)) # 显示FPS # 显示图像 Display.show_image(img, x=round((lcd_width-sensor.width())/2), y=round((lcd_height-sensor.height())/2)) print(f"FPS: {fps:.1f}") # 打印FPS 给这个矩形识别加一个面积限制,排除面积过小的矩形
08-03
k230坐标控制舵机, import time, os, sys import math from media.sensor import * from media.display import * from media.media import * from machine import UART, FPIOA from machine import Pin,Timer from time import ticks_ms fpioa = FPIOA() fpioa.set_function(44, FPIOA.UART2_TXD) fpioa.set_function(45, FPIOA.UART2_RXD) uart= UART(UART.UART2, baudrate=115200, bits=UART.EIGHTBITS, parity=UART.PARITY_NONE, stop=UART.STOPBITS_ONE) # 定义颜色阈值和blob设置 thresholds = [(0, 70)] # 二值化阈值 MIN_AREA = 1000 # 最小面积阈值 MAX_AREA = 100000 # 最大面积阈值 MIN_ASPECT_RATIO = 0.3 # 最小宽高比 MAX_ASPECT_RATIO = 3.0 # 最大宽高比 BASE_RADIUS = 45 # 基础半径(虚拟坐标单位) POINTS_PER_CIRCLE = 24 # 增加采样点使圆形更平滑 PURPLE_THRESHOLD = (20, 60, 15, 70, -70, -20) # 紫色色块阈值 lcd_width = 800 lcd_height = 480 # 基础矩形比例(可根据实际需求调整) RECT_WIDTH = 210 RECT_HEIGHT = 95 TARGET_ASPECT_RATIO = RECT_WIDTH / RECT_HEIGHT # 目标宽高比 # --------------------------- 工具函数 --------------------------- def calculate_distance(p1, p2): return math.sqrt((p2[0] - p1[0])**2 + (p2[1] - p1[1])**2) def calculate_center(points): if not points: return (0, 0) sum_x = sum(p[0] for p in points) sum_y = sum(p[1] for p in points) return (sum_x / len(points), sum_y / len(points)) def is_valid_rect(corners): edges = [calculate_distance(corners[i], corners[(i+1)%4]) for i in range(4)] ratio1 = edges[0] / max(edges[2], 0.1) ratio2 = edges[1] / max(edges[3], 0.1) valid_ratio = 0.5 < ratio1 < 1.5 and 0.5 < ratio2 < 1.5 area = 0 for i in range(4): x1, y1 = corners[i] x2, y2 = corners[(i+1) % 4] area += (x1 * y2 - x2 * y1) area = abs(area) / 2 valid_area = MIN_AREA < area < MAX_AREA width = max(p[0] for p in corners) - min(p[0] for p in corners) height = max(p[1] for p in corners) - min(p[1] for p in corners) aspect_ratio = width / max(height, 0.1) valid_aspect = MIN_ASPECT_RATIO < aspect_ratio < MAX_ASPECT_RATIO return valid_ratio and valid_area and valid_aspect def detect_purple_blobs(img): return img.find_blobs( [PURPLE_THRESHOLD], pixels_threshold=100, area_threshold=100, merge=True ) def send_circle_points(points): if not points: return count = len(points) msg = f"$$C,{count}," for x, y in points: msg += f"{x},{y}," msg = msg.rstrip(',') + "##" uart.write(msg) print(f"发送圆形点: {msg}") def get_perspective_matrix(src_pts, dst_pts): """计算透视变换矩阵""" A = [] B = [] for i in range(4): x, y = src_pts[i] u, v = dst_pts[i] A.append([x, y, 1, 0, 0, 0, -u*x, -u*y]) A.append([0, 0, 0, x, y, 1, -v*x, -v*y]) B.append(u) B.append(v) # 高斯消元求解矩阵 n = 8 for i in range(n): max_row = i for j in range(i, len(A)): if abs(A[j][i]) > abs(A[max_row][i]): max_row = j A[i], A[max_row] = A[max_row], A[i] B[i], B[max_row] = B[max_row], B[i] pivot = A[i][i] if abs(pivot) < 1e-8: return None for j in range(i, n): A[i][j] /= pivot B[i] /= pivot for j in range(len(A)): if j != i and A[j][i] != 0: factor = A[j][i] for k in range(i, n): A[j][k] -= factor * A[i][k] B[j] -= factor * B[i] return [ [B[0], B[1], B[2]], [B[3], B[4], B[5]], [B[6], B[7], 1.0] ] def transform_points(points, matrix): """应用透视变换将虚拟坐标映射到原始图像坐标""" transformed = [] for (x, y) in points: x_hom = x * matrix[0][0] + y * matrix[0][1] + matrix[0][2] y_hom = x * matrix[1][0] + y * matrix[1][1] + matrix[1][2] w_hom = x * matrix[2][0] + y * matrix[2][1] + matrix[2][2] if abs(w_hom) > 1e-8: transformed.append((x_hom / w_hom, y_hom / w_hom)) return transformed def sort_corners(corners): """将矩形角点按左上、右上、右下、左下顺序排序""" center = calculate_center(corners) sorted_corners = sorted(corners, key=lambda p: math.atan2(p[1]-center[1], p[0]-center[0])) # 调整顺序为左上、右上、右下、左下 if len(sorted_corners) == 4: # 找到最接近左上角的点 left_top = min(sorted_corners, key=lambda p: p[0]+p[1]) index = sorted_corners.index(left_top) sorted_corners = sorted_corners[index:] + sorted_corners[:index] return sorted_corners def get_rectangle_orientation(corners): """计算矩形的主方向角(水平边与x轴的夹角)""" # 假设排序后的角点顺序为:左上、右上、右下、左下 if len(corners) != 4: return 0 # 计算上边和右边的向量 top_edge = (corners[1][0] - corners[0][0], corners[1][1] - corners[0][1]) right_edge = (corners[2][0] - corners[1][0], corners[2][1] - corners[1][1]) # 选择较长的边作为主方向 if calculate_distance(corners[0], corners[1]) > calculate_distance(corners[1], corners[2]): main_edge = top_edge else: main_edge = right_edge # 计算主方向角(弧度) angle = math.atan2(main_edge[1], main_edge[0]) return angle def main(): try: sensor = Sensor(width=1280, height=960) sensor.reset() sensor.set_framesize(width=320, height=240) sensor.set_pixformat(Sensor.RGB565) time.sleep(2)# 延时2秒确保传感器稳定 # 显示初始化 Display.init(Display.ST7701, width=lcd_width, height=lcd_height, to_ide=True) MediaManager.init() sensor.run() # 暂时不调用 skip_frames # 初始化显示 clock = time.clock() while True: clock.tick() img = sensor.snapshot() # 图像处理 gray_img = img.to_grayscale() binary_img = gray_img.binary(thresholds) binary_img.erode(1) binary_img.dilate(3) # 检测紫色色块 purple_blobs = detect_purple_blobs(img) for blob in purple_blobs: img.draw_rectangle(blob[0:4], color=(255, 0, 255), thickness=1) img.draw_cross(blob.cx(), blob.cy(), color=(255, 0, 255), thickness=1) # 检测所有矩形并筛选出最小的一个 min_area = float('inf') smallest_rect = None for r in binary_img.find_rects(threshold=12000): corners = r.corners() if is_valid_rect(corners): # 计算矩形面积 area = 0 for i in range(4): x1, y1 = corners[i] x2, y2 = corners[(i+1) % 4] area += (x1 * y2 - x2 * y1) area = abs(area) / 2 # 更新最小矩形 if area < min_area: min_area = area smallest_rect = corners # 只处理最小的矩形 if smallest_rect: # 对矩形角点进行排序 sorted_corners = sort_corners(smallest_rect) # 绘制矩形边框和角点 for i in range(4): x1, y1 = sorted_corners[i] x2, y2 = sorted_corners[(i+1) % 4] img.draw_line(x1, y1, x2, y2, color=(255, 0, 0), thickness=1) for p in sorted_corners: img.draw_circle(p[0], p[1], 5, color=(0, 255, 0), thickness=1) # 计算矩形主方向角 angle = get_rectangle_orientation(sorted_corners) # 计算矩形实际宽高 width = calculate_distance(sorted_corners[0], sorted_corners[1]) height = calculate_distance(sorted_corners[1], sorted_corners[2]) actual_aspect = width / max(height, 0.1) # 确定矩形是横向还是纵向(考虑旋转) is_horizontal = actual_aspect >= 1.0 # 构建虚拟矩形(根据方向调整) if is_horizontal: virtual_rect = [ (0, 0), (RECT_WIDTH, 0), (RECT_WIDTH, RECT_HEIGHT), (0, RECT_HEIGHT) ] else: virtual_rect = [ (0, 0), (RECT_HEIGHT, 0), (RECT_HEIGHT, RECT_WIDTH), (0, RECT_WIDTH) ] # 计算校正半径(基于实际宽高比) if is_horizontal: radius_x = BASE_RADIUS radius_y = BASE_RADIUS / actual_aspect else: radius_x = BASE_RADIUS * actual_aspect radius_y = BASE_RADIUS # 计算虚拟矩形中心 virtual_center = (RECT_WIDTH/2, RECT_HEIGHT/2) if is_horizontal else (RECT_HEIGHT/2, RECT_WIDTH/2) # 在虚拟矩形中生成椭圆点集(映射后为正圆) virtual_circle_points = [] for i in range(POINTS_PER_CIRCLE): angle = 2 * math.pi * i / POINTS_PER_CIRCLE x = virtual_center[0] + radius_x * math.cos(angle) y = virtual_center[1] + radius_y * math.sin(angle) virtual_circle_points.append((x, y)) # 计算透视变换矩阵并映射坐标 matrix = get_perspective_matrix(virtual_rect, sorted_corners) if matrix: mapped_points = transform_points(virtual_circle_points, matrix) int_points = [(int(round(x)), int(round(y))) for x, y in mapped_points] # 绘制圆形 for (x, y) in int_points: img.draw_circle(x, y, 2, color=(255, 0, 255), thickness=2) # 绘制圆心 mapped_center = transform_points([virtual_center], matrix) if mapped_center: cx, cy = map(int, map(round, mapped_center[0])) img.draw_circle(cx, cy, 3, color=(0, 0, 255), thickness=1) center_points=[(int(round(cx)), int(round(cy))) for x, y in mapped_center] # 发送坐标 # send_circle_points(int_points) send_circle_points(center_points) # 显示FPS fps = clock.fps() img.draw_string_advanced(10, 10, 20, f"FPS: {fps:.1f}", color=(255, 255, 255)) # img.compressed_for_ide() # 显示图像 Display.show_image(img, x=round((lcd_width-sensor.width())/2), y=round((lcd_height-sensor.height())/2)) print(fps) time.sleep_ms(10) except KeyboardInterrupt: print("Program stopped by user") except Exception as e: print(f"Error occurred: {str(e)}") finally: # 清理资源 if 'sensor' in locals() and isinstance(sensor, Sensor): sensor.stop() Display.deinit() os.exitpoint(os.EXITPOINT_ENABLE_SLEEP) time.sleep_ms(100) MediaManager.deinit() print("System shutdown complete") if __name__ == "__main__": main() 代码已知目标坐标,控制舵机运行到指定位置
08-03
/* -------------- 2. Canvas Overlay(挂最上层) -------------- */ let svgOverlay, sectorRAF; function createSvgOverlay() { if (svgOverlay) return; svgOverlay = new google.maps.OverlayView(); svgOverlay.div = document.createElement('div'); svgOverlay.div.style.cssText = 'position:absolute;top:0;left:0;width:100%;height:100%;' + 'pointer-events:none;z-index:9999;'; svgOverlay.onAdd = function () { this.getPanes().overlayMouseTarget.appendChild(this.div); }; svgOverlay.draw = function () { const rect = map.getDiv(); svgOverlay.div.style.width = rect.clientWidth + 'px'; svgOverlay.div.style.height = rect.clientHeight + 'px'; }; svgOverlay.onRemove = function () { svgOverlay.div.remove(); }; svgOverlay.setMap(map); } /* -------------- 3. 实时扇形绘制(SVG 路径) -------------- */ const EARTH_R = 6371000; function drawSector(lat, lng, bearingDeg, targetRadiusMeters, sectorAngle) { if (sectorRAF) cancelAnimationFrame(sectorRAF); createSvgOverlay(); const fps = 60; const duration = 800; // 动画时长 const frames = Math.round(duration / 1000 * fps); let frame = 0; const proj = svgOverlay.getProjection(); if (!proj) return; const centerPx = proj.fromLatLngToContainerPixel(new google.maps.LatLng(lat, lng)); /* 米 → 像素 换算(当前缩放级别) */ const metersPerPx = 156543.03392 * Math.cos(lat * Math.PI / 180) / Math.pow(2, map.getZoom()); const pxRadius = targetRadiusMeters / metersPerPx; function animate() { if (frame >= frames) return; const ratio = frame / frames; // 0 → 1 const rNow = ratio * pxRadius; /* 生成 SVG 扇形路径 */ const steps = 60; const startRad = (bearingDeg - sectorAngle / 2) * Math.PI / 180; const stepRad = sectorAngle * Math.PI / 180 / steps; let path = `M0,0 `; for (let i = 0; i <= steps; i++) { const angle = startRad + stepRad * i; const x = rNow * Math.cos(angle); const y = rNow * Math.sin(angle); path += `${x},${y} `; } path += 'Z'; /* 更新 SVG */ svgOverlay.div.innerHTML = ` <svg width="100%" height="100%" style="position:absolute;top:0;left:0;"> <path d="${path}" fill="rgba(255,0,0,0.5)" stroke="rgba(255,0,0,1)" stroke-width="2" transform="translate(${centerPx.x},${centerPx.y})"/> </svg> `; frame++; sectorRAF = requestAnimationFrame(animate); } animate(); }用svg方法,但是圆心总是会随着鼠标拖动地图而变化,如何像Polygon一样在地图上圆心不变呢
07-18
【RIS 辅助的 THz 混合场波束斜视下的信道估计与定位】在混合场波束斜视效应下,利用太赫兹超大可重构智能表面感知用户信道与位置(Matlab代码实现)内容概要:本文围绕“IS 辅助的 THz 混合场波束斜视下的信道估计与定位”展开,重点研究在太赫兹(THz)通信系统中,由于混合近场与远场共存导致的波束斜视效应下,如何利用超大可重构智能表面(RIS)实现对用户信道状态信息和位置的联合感知与精确估计。文中提出了一种基于RIS调控的信道参数估计算法,通过优化RIS相移矩阵提升信道分辨率,并结合信号到达角(AoA)、到达时间(ToA)等信息实现高精度定位。该方法在Matlab平台上进行了仿真验证,复现了SCI一区论文的核心成果,展示了其在下一代高频通信系统中的应用潜力。; 适合人群:具备通信工程、信号处理或电子信息相关背景,熟悉Matlab仿真,从事太赫兹通信、智能反射面或无线定位方向研究的研究生、科研人员及工程师。; 使用场景及目标:① 理解太赫兹通信中混合场域波束斜视问题的成因与影响;② 掌握基于RIS的信道估计与用户定位联合实现的技术路径;③ 学习并复现高水平SCI论文中的算法设计与仿真方法,支撑学术研究或工程原型开发; 阅读建议:此资源以Matlab代码实现为核心,强调理论与实践结合,建议读者在理解波束成形、信道建模和参数估计算法的基础上,动手运行和调试代码,深入掌握RIS在高频通信感知一体化中的关键技术细节。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值