绘图驱动-OSD原理2

转载自:http://blog.pfan.cn/programming/21209.html

现在已经可以通过修改存储单元内容来改变OSD的像素,但还有个关键的问题是如何根据需要来进行操作,即如何将某个像素设置为指定颜色。接下来就要介绍一下色板的概念。

如下图,某个Byte中的低四Bit内容与一个像素一一对应,其值为“3”,那么数字“3”所代表的颜色便由色板来决定,然后再驱动OSD屏幕将像素设置为制定颜色。同样地,这种色板和物理OSD显示屏幕的对应关系一般也是通过寄存器设置,由硬件上来保障实现的。对于特定的显示环境,这种色板一般是固定的。

 

为了能使固定的图像数据在进行OSD显示时可以以不同的颜色输出,便可以采用逻辑色板这种方法。逻辑色板实际上是长度为颜色数的数组,将图像数据写入OSDBuffer时,可以通过该数组进行特定映射,本质上还是只能使用物理色板上的颜色数,只是颜色被改变。原理如下图。

 

转载于:https://www.cnblogs.com/itloverhpu/p/3151557.html

我的屏幕画面为什么只显示黑色的背景 import gc import os import time import heapq import aicube import image import nncase_runtime as nn import ujson import ulab.numpy as np from libs.PipeLine import ScopedTiming from libs.Utils import * from media.display import * from media.media import * from media.sensor import * display_mode = "lcd" if display_mode == "lcd": DISPLAY_WIDTH = ALIGN_UP(800, 16) DISPLAY_HEIGHT = 480 else: DISPLAY_WIDTH = ALIGN_UP(1920, 16) DISPLAY_HEIGHT = 1080 OUT_RGB888P_WIDTH = ALIGN_UP(640, 16) OUT_RGB888P_HEIGH = 360 root_path = "/sdcard/mp_deployment_source/" config_path = root_path + "deploy_config.json" deploy_conf = {} debug_mode = 1 # 定义9x9地图 grid_size = 9 # 柱子位置 (行, 列) pillar_positions = [ (2, 2), (2, 4), (2, 6), (4, 2), (4, 4), (4, 6), (6, 2), (6, 4), (6, 6) ] # 固定位置分配顺序 (从左到右排序后对应位置) fixed_positions = [ (6, 2), (4, 2), (2, 2), # 左列 (从下到上) (6, 4), (4, 4), (2, 4), # 中列 (从下到上) (2, 6), (4, 6), (6, 6) # 右列 (从上到下) ] # 多帧确认参数 MIN_CONFIRMATION_FRAMES = 15 PILLAR_CONFIRMATION_THRESHOLD = 0.85 # 提高确认阈值 max_history_length = MIN_CONFIRMATION_FRAMES + 10 def initialize_grid(): """初始化9x9网格,柱子位置设为2,其他为0""" grid = [[0] * grid_size for _ in range(grid_size)] for pos in pillar_positions: row, col = pos grid[row][col] = 2 # 设置边界为-1 for i in range(grid_size): for j in range(grid_size): if i == 0 or i == grid_size-1 or j == 0 or j == grid_size-1: grid[i][j] = -1 # 设置特定点为0(覆盖边界和柱子设置) grid[8][5] = 0 # (8,5) grid[0][3] = 0 # (0,3) return grid def map_pixel_to_grid(x, y): """改进的像素坐标到网格坐标映射 - 使用整个图像区域""" # 使用整个图像区域 (0%到100%) grid_top = 0 grid_bottom = OUT_RGB888P_HEIGH grid_left = 0 grid_right = OUT_RGB888P_WIDTH # 确保点在图像范围内 if not (grid_left <= x <= grid_right and grid_top <= y <= grid_bottom): return None # 计算在网格坐标系中的位置 grid_x = (x - grid_left) / (grid_right - grid_left) * grid_size grid_y = (y - grid_top) / (grid_bottom - grid_top) * grid_size # 四舍五入到最近的整数索引 col = round(grid_x) row = round(grid_y) # 确保索引在有效范围内 col = max(0, min(col, grid_size - 1)) row = max(0, min(row, grid_size - 1)) return int(row), int(col) # 返回(行, 列) def two_side_pad_param(input_size, output_size): ratio_w = output_size[0] / input_size[0] # 宽度缩放比例 ratio_h = output_size[1] / input_size[1] # 高度缩放比例 ratio = min(ratio_w, ratio_h) # 取较小的缩放比例 new_w = int(ratio * input_size[0]) # 新宽度 new_h = int(ratio * input_size[1]) # 新高度 dw = (output_size[0] - new_w) / 2 # 宽度差 dh = (output_size[1] - new_h) / 2 # 高度差 top = int(round(dh - 0.1)) bottom = int(round(dh + 0.1)) left = int(round(dw - 0.1)) right = int(round(dw - 0.1)) return top, bottom, left, right, ratio def read_deploy_config(config_path): # 打开JSON文件以进行读取deploy_config with open(config_path, "r") as json_file: try: # 从文件中加载JSON数据 config = ujson.load(json_file) except ValueError as e: print("JSON 解析错误:", e) return config def mark_blocked_paths(grid): # 标记位于两个1之间的0为不可行走(-2) for i in range(1, 8): for j in range(1, 8): if grid[i][j] != 0: continue # 检查左右是否都是1 if grid[i][j-1] == 1 and grid[i][j+1] == 1: grid[i][j] = -2 # 检查上下是否都是1 elif grid[i-1][j] == 1 and grid[i+1][j] == 1: grid[i][j] = -2 def heuristic(a, b): """曼哈顿距离启发式函数""" return abs(a[0] - b[0]) + abs(a[1] - b[1]) def find_shortest_path(grid): """使用A*算法寻找最短路径""" start = (8, 5) end = (0, 3) # 使用优先队列 open_set = [] heapq.heappush(open_set, (0, start)) came_from = {} g_score = {start: 0} f_score = {start: heuristic(start, end)} directions = [(0, 1), (1, 0), (0, -1), (-1, 0)] # 右、下、左、上 while open_set: _, current = heapq.heappop(open_set) if current == end: # 回溯标记路径 path = [] while current in came_from: path.append(current) current = came_from[current] path.append(start) path.reverse() # 标记路径 for pos in path: grid[pos[0]][pos[1]] = 3 return True for dx, dy in directions: neighbor = (current[0] + dx, current[1] + dy) # 检查边界 if not (0 <= neighbor[0] < grid_size and 0 <= neighbor[1] < grid_size): continue # 检查是否可通行 if grid[neighbor[0]][neighbor[1]] != 0: continue # 计算新的g分数 tentative_g = g_score[current] + 1 # 如果新路径更好 if neighbor not in g_score or tentative_g < g_score[neighbor]: came_from[neighbor] = current g_score[neighbor] = tentative_g f_score[neighbor] = tentative_g + heuristic(neighbor, end) heapq.heappush(open_set, (f_score[neighbor], neighbor)) return False # 没有找到路径 def assign_fixed_positions(pillars): """为检测到的柱子分配固定位置,按x坐标从左到右排序""" if len(pillars) != 9: print(f"Error: Expected 9 pillars, got {len(pillars)}. Using default positions.") # 返回默认位置 (中心位置) return [(4, 4)] * 9 # 按x坐标排序(从左到右) sorted_pillars = sorted(pillars, key=lambda p: p[0]) # 分配固定位置 grid_positions = [] for i, pillar in enumerate(sorted_pillars): if i < len(fixed_positions): grid_positions.append(fixed_positions[i]) else: grid_positions.append((4, 4)) # 默认位置 return grid_positions def detection(): print("det_infer start") # 增加内存池 gc.collect() nn.shrink_memory_pool() try: # 尝试增加内存池大小 nn.set_memory_pool_size(1024*1024*10) # 10MB内存池 except: print("Warning: Failed to increase memory pool") # 使用json读取内容初始化部署变量 try: deploy_conf = read_deploy_config(config_path) except Exception as e: print(f"Error reading config: {e}") return -1 kmodel_name = deploy_conf["kmodel_path"] labels = deploy_conf["categories"] confidence_threshold = deploy_conf["confidence_threshold"] nms_threshold = deploy_conf["nms_threshold"] img_size = deploy_conf["img_size"] num_classes = deploy_conf["num_classes"] color_four = get_colors(num_classes) nms_option = deploy_conf["nms_option"] model_type = deploy_conf["model_type"] if model_type == "AnchorBaseDet": anchors = deploy_conf["anchors"][0] + deploy_conf["anchors"][1] + deploy_conf["anchors"][2] kmodel_frame_size = img_size frame_size = [OUT_RGB888P_WIDTH, OUT_RGB888P_HEIGH] strides = [8, 16, 32] # 计算padding值 top, bottom, left, right, ratio = two_side_pad_param(frame_size, kmodel_frame_size) # 初始化kpu kpu = nn.kpu() try: kpu.load_kmodel(root_path + kmodel_name) except Exception as e: print(f"Failed to load model: {e}") return -1 # 初始化ai2d ai2d = nn.ai2d() ai2d.set_dtype(nn.ai2d_format.NCHW_FMT, nn.ai2d_format.NCHW_FMT, np.uint8, np.uint8) ai2d.set_pad_param(True, [0, 0, 0, 0, top, bottom, left, right], 0, [114, 114, 114]) ai2d.set_resize_param(True, nn.interp_method.tf_bilinear, nn.interp_mode.half_pixel) ai2d_builder = ai2d.build( [1, 3, OUT_RGB888P_HEIGH, OUT_RGB888P_WIDTH], [1, 3, kmodel_frame_size[1], kmodel_frame_size[0]] ) # 初始化并配置sensor sensor = Sensor() sensor.reset() # 设置镜像 sensor.set_hmirror(False) # 设置翻转 sensor.set_vflip(False) # 通道0直接给到显示VO,格式为YUV420 sensor.set_framesize(width=DISPLAY_WIDTH, height=DISPLAY_HEIGHT) sensor.set_pixformat(PIXEL_FORMAT_YUV_SEMIPLANAR_420) # 通道2给到AI做算法处理,格式为RGB888 sensor.set_framesize(width=OUT_RGB888P_WIDTH, height=OUT_RGB888P_HEIGH, chn=CAM_CHN_ID_2) sensor.set_pixformat(PIXEL_FORMAT_RGB_888_PLANAR, chn=CAM_CHN_ID_2) # 获取绑定信息 sensor_bind_info = sensor.bind_info(chn=CAM_CHN_ID_0) print("Sensor bind info:", sensor_bind_info) # 初始化显示 if display_mode == "lcd": # 设置为ST7701显示,默认800x480 Display.init(Display.ST7701, to_ide=True) else: # 设置为LT9611显示,默认1920x1080 Display.init(Display.LT9611, to_ide=True) # 简化显示绑定 - 使用默认值 # 创建OSD图像 osd_img = image.Image(DISPLAY_WIDTH, DISPLAY_HEIGHT, image.ARGB8888) # media初始化 MediaManager.init() # 启动sensor sensor.run() rgb888p_img = None ai2d_input_tensor = None data = np.ones((1, 3, kmodel_frame_size[1], kmodel_frame_size[0]), dtype=np.uint8) ai2d_output_tensor = nn.from_numpy(data) # 多帧确认系统初始化 - 使用列表代替deque position_history = [] # 使用列表存储历史帧 confirmed_pillars = set() frame_count = 0 while True: try: with ScopedTiming("total", debug_mode > 0): rgb888p_img = sensor.snapshot(chn=CAM_CHN_ID_2) if rgb888p_img.format() == image.RGBP888: ai2d_input = rgb888p_img.to_numpy_ref() ai2d_input_tensor = nn.from_numpy(ai2d_input) # 使用ai2d进行预处理 ai2d_builder.run(ai2d_input_tensor, ai2d_output_tensor) # 设置模型输入 kpu.set_input_tensor(0, ai2d_output_tensor) # 模型推理 kpu.run() # 获取模型输出 results = [] for i in range(kpu.outputs_size()): out_data = kpu.get_output_tensor(i) result = out_data.to_numpy() result = result.reshape((result.shape[0] * result.shape[1] * result.shape[2] * result.shape[3])) del out_data results.append(result) # 使用aicube模块封装的接口进行后处理 det_boxes = aicube.anchorbasedet_post_process( results[0], results[1], results[2], kmodel_frame_size, frame_size, strides, num_classes, confidence_threshold, nms_threshold, anchors, nms_option, ) # ====== 多帧确认系统 ====== # 初始化网格 grid = initialize_grid() current_frame_detections = set() # 处理所有检测到的柱子 for det_box in det_boxes: # 确保类别索引是整数且在有效范围内 class_id = int(det_box[0]) if class_id < 0 or class_id >= len(labels): continue # 跳过无效的类别索引 conf = det_box[1] if conf < 0.25: # 置信度阈值 continue # 计算边界框中心点 x1, y1, x2, y2 = det_box[2], det_box[3], det_box[4], det_box[5] center_x = (x1 + x2) / 2 center_y = (y1 + y2) / 2 # 记录检测到的柱子(包括类别) current_frame_detections.add((center_x, center_y, class_id, labels[class_id], conf)) # 更新位置历史记录 - 使用列表代替deque position_history.append(current_frame_detections) # 控制历史记录长度 if len(position_history) > max_history_length: position_history.pop(0) # 更新柱子确认系统 new_confirmed = set() # 1. 保留之前已确认的柱子(除非连续多帧未检测到) for pos in confirmed_pillars: # 检查最近5帧中是否有该柱子 recent_detections = 0 # 获取最近5帧(如果不足5帧则取全部) recent_frames = position_history[-5:] if len(position_history) >= 5 else position_history for frame in recent_frames: # 检查是否在历史帧中 for hist_pos in frame: hist_x, hist_y, _, _, _ = hist_pos cur_x, cur_y, _, _, _ = pos # 使用欧氏距离检查是否为同一个柱子 distance = ((hist_x - cur_x)**2 + (hist_y - cur_y)**2)**0.5 if distance < 20: # 距离阈值 recent_detections += 1 break # 如果最近5帧中检测到至少3次,则保留 if recent_detections >= 3: new_confirmed.add(pos) # 2. 检查新柱子是否达到确认阈值 for pos in current_frame_detections: # 检查是否已确认 already_confirmed = False for conf_pos in confirmed_pillars: conf_x, conf_y, _, _, _ = conf_pos cur_x, cur_y, _, _, _ = pos distance = ((conf_x - cur_x)**2 + (conf_y - cur_y)**2)**0.5 if distance < 20: already_confirmed = True break if already_confirmed: continue # 计算该位置在历史帧中的出现频率 detection_count = 0 for frame in position_history: for frame_pos in frame: frame_x, frame_y, _, _, _ = frame_pos cur_x, cur_y, _, _, _ = pos distance = ((frame_x - cur_x)**2 + (frame_y - cur_y)**2)**0.5 if distance < 20: detection_count += 1 break # 计算确认比例 MIN_HISTORY_FRAMES = max(5, min(len(position_history), MIN_CONFIRMATION_FRAMES)) if MIN_HISTORY_FRAMES > 0: confirmation_ratio = detection_count / MIN_HISTORY_FRAMES else: confirmation_ratio = 0 # 如果达到确认阈值,则添加为新柱子 if confirmation_ratio >= PILLAR_CONFIRMATION_THRESHOLD: new_confirmed.add(pos) if debug_mode > 0: print(f"Confirmed new pillar at ({pos[0]}, {pos[1]}) (ratio: {confirmation_ratio:.2f})") # 更新确认的柱子集合 confirmed_pillars = new_confirmed # 3. 确保不超过9个柱子 if len(confirmed_pillars) > 9: print(f"Warning: Too many pillars confirmed ({len(confirmed_pillars)}), selecting the top 9 by confidence") # 按置信度排序并取前9个 sorted_pillars = sorted(confirmed_pillars, key=lambda p: p[4], reverse=True) confirmed_pillars = set(sorted_pillars[:9]) # ====== 显示处理 ====== osd_img.clear() # 1. 显示已确认的柱子数量 status_text = f"Confirmed: {len(confirmed_pillars)}/9" color = (0, 255, 0) if len(confirmed_pillars) == 9 else (255, 255, 0) osd_img.draw_string(10, 10, status_text, scale=2, color=color) # 显示警告信息(如果柱子数量不等于9) if len(confirmed_pillars) != 9: warning_text = f"WARNING: Expected 9, got {len(confirmed_pillars)}" osd_img.draw_string(10, 40, warning_text, scale=1.5, color=(255, 0, 0)) # 2. 在图像上标记已确认的柱子位置 for pos in confirmed_pillars: center_x, center_y, class_id, class_name, conf = pos # 转换为显示坐标 display_x = int(center_x * DISPLAY_WIDTH / OUT_RGB888P_WIDTH) display_y = int(center_y * DISPLAY_HEIGHT / OUT_RGB888P_HEIGH) # 根据类别设置颜色 if class_name == "hs": color = (0, 0, 255) # 红色表示黑色柱子 else: color = (255, 255, 255) # 白色表示白色柱子 # 绘制圆圈标记柱子 osd_img.draw_circle(display_x, display_y, 15, color=color, thickness=3) # 显示类别标签 osd_img.draw_string(display_x-20, display_y-30, class_name, scale=1.2, color=color) # 显示置信度 osd_img.draw_string(display_x-30, display_y+20, f"{conf:.2f}", scale=1.0, color=color) # 3. 绘制检测结果 if det_boxes: for det_box in det_boxes: # 确保类别索引是整数且在有效范围内 class_id = int(det_box[0]) if class_id < 0 or class_id >= len(labels): continue # 跳过无效的类别索引 conf = det_box[1] if conf < 0.25: # 置信度阈值 continue x1, y1, x2, y2 = det_box[2], det_box[3], det_box[4], det_box[5] x = int(x1 * DISPLAY_WIDTH // OUT_RGB888P_WIDTH) y = int(y1 * DISPLAY_HEIGHT // OUT_RGB888P_HEIGH) w = int((x2 - x1) * DISPLAY_WIDTH // OUT_RGB888P_WIDTH) h = int((y2 - y1) * DISPLAY_HEIGHT // OUT_RGB888P_HEIGH) # 获取颜色 color = color_four[class_id][1:] if class_id < len(color_four) else (255, 0, 0) osd_img.draw_rectangle(x, y, w, h, color=color) # 获取标签 label = labels[class_id] if class_id < len(labels) else "unknown" text = f"{label} {conf:.2f}" osd_img.draw_string_advanced(x, y - 40, 32, text, color=color) # 检查是否达到九个柱子 if len(confirmed_pillars) >= 9: print("\n九个柱子已全部确认!开始分配位置...") # 提取柱子的中心坐标和类别 pillars = [] for pos in confirmed_pillars: center_x, center_y, class_id, class_name, conf = pos pillars.append((center_x, center_y, class_name)) try: # 按x坐标从左到右排序 pillars_sorted = sorted(pillars, key=lambda p: p[0]) # 分配固定位置 grid_positions = assign_fixed_positions([(p[0], p[1]) for p in pillars_sorted]) # 确保我们正好有9个位置 if len(grid_positions) != 9: print(f"Warning: Got {len(grid_positions)} grid positions, using fixed positions") grid_positions = fixed_positions.copy() # 初始化网格 grid = initialize_grid() # 标记黑色柱子位置为1 for i, pillar in enumerate(pillars_sorted): center_x, center_y, class_name = pillar if class_name == "hs": # 如果是黑色柱子 row, col = grid_positions[i] grid[row][col] = 1 if debug_mode > 0: print(f"Black pillar at ({center_x}, {center_y}) mapped to grid ({row}, {col})") else: # 白色柱子保持为2 row, col = grid_positions[i] if debug_mode > 0: print(f"White pillar at ({center_x}, {center_y}) mapped to grid ({row}, {col})") # 标记阻塞路径并寻找最短路径 mark_blocked_paths(grid) path_found = find_shortest_path(grid) # 打印最终网格状态 print("\n最终网格状态:") for row in grid: print(" ".join(str(x) for x in row)) # 在图像上标记最终位置 for i, pillar in enumerate(pillars_sorted): center_x, center_y, class_name = pillar row, col = grid_positions[i] # 计算网格位置对应的像素坐标 pixel_x = (col + 0.5) * (OUT_RGB888P_WIDTH / grid_size) pixel_y = (row + 0.5) * (OUT_RGB888P_HEIGH / grid_size) display_x = int(pixel_x * DISPLAY_WIDTH / OUT_RGB888P_WIDTH) display_y = int(pixel_y * DISPLAY_HEIGHT / OUT_RGB888P_HEIGH) # 根据类别设置颜色 if class_name == "hs": color = (0, 0, 255) # 红色表示黑色柱子 else: color = (255, 255, 255) # 白色表示白色柱子 # 绘制位置标记 osd_img.draw_circle(display_x, display_y, 20, color=color, thickness=3) osd_img.draw_string(display_x-20, display_y-40, f"({row},{col})", scale=1.5, color=color) # 显示成功消息 if path_found: osd_img.draw_string(200, 200, "ALL PILLARS MAPPED! PATH FOUND", scale=3, color=(0, 255, 0)) else: osd_img.draw_string(200, 200, "ALL PILLARS MAPPED! NO PATH", scale=3, color=(255, 0, 0)) except Exception as e: print(f"Error in grid processing: {e}") # 在屏幕上显示错误信息 osd_img.draw_string(200, 200, f"GRID ERROR: {str(e)[:30]}", scale=2, color=(255, 0, 0)) Display.show_image(osd_img, 0, 0, Display.LAYER_OSD3) # 等待3秒后退出 time.sleep(3) sensor.stop() Display.deinit() MediaManager.deinit() gc.collect() nn.shrink_memory_pool() print("检测完成") return 0 # 显示当前帧结果 Display.show_image(osd_img, 0, 0, Display.LAYER_OSD3) frame_count += 1 # 定期垃圾回收 if frame_count % 10 == 0: gc.collect() # 限制帧率 time.sleep(0.05) # 约20FPS except Exception as e: print(f"Error in frame processing: {e}") # 显示错误信息 osd_img.clear() osd_img.draw_string(10, 10, "Processing Error", scale=2, color=(255,0,0)) osd_img.draw_string(10, 50, f"Frame: {frame_count}", scale=1.5, color=(255,0,0)) osd_img.draw_string(10, 80, str(e)[:50], scale=1, color=(255,0,0)) Display.show_image(osd_img, 0, 0, Display.LAYER_OSD3) time.sleep(1) # 尝试恢复 try: rgb888p_img = None gc.collect() except: pass # 清理资源 del ai2d_input_tensor del ai2d_output_tensor sensor.stop() Display.deinit() MediaManager.deinit() gc.collect() time.sleep(1) nn.shrink_memory_pool() print("det_infer end") return 0 if __name__ == "__main__": detection() 现在我只要你稍微的修改: 现在画面是黑色,我想要显示真实的画面,帮我该,最小改动,
最新发布
08-15
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值