ymj_bim_test/utils.py

182 lines
7.0 KiB
Python
Raw Permalink Normal View History

2025-02-27 17:31:43 +08:00
import json
import logging
import cv2
2025-03-02 16:25:35 +08:00
def re_cal_point(point, offset):
2025-03-02 20:49:58 +08:00
"""
根据裁剪之后的图片,每个点的坐标需要重新计算,以新的图片的宽高作为坐标系
"""
2025-02-28 15:15:33 +08:00
# 相当于所有的x坐标向左平移了offset个距离
point['x'] = point['x'] - offset
2025-02-27 17:31:43 +08:00
2025-02-28 15:15:33 +08:00
2025-03-02 16:25:35 +08:00
2025-03-02 22:28:43 +08:00
def filter_rectangle(image_width,image_height, points, wide_cam_left_cut_rate, wide_cam_right_cut_rate):
2025-03-02 20:49:58 +08:00
"""
根据左右裁剪之后的图像过滤矩形在裁剪之后整个矩形已经不在图片里面的就去掉
1 高度过大的不要
2 整个矩形全部身体都在裁剪区域之外的不要
2025-03-02 22:28:43 +08:00
image_width:原始广角图片的宽度
image_height:原始广角图片的高度
2025-03-02 20:49:58 +08:00
points要过滤的点
wide_cam_left_cut_rate# 左边界的裁剪比例,从左边开始裁剪百分之多少
wide_cam_right_cut_rate # 右边界的裁剪比例,从右边开始裁剪百分之多少
返回值:
2025-03-02 22:28:43 +08:00
filtered_points过滤之后的全部都矩形坐标
wide_cam_img_width_after_cut裁剪之后的图片的宽度
2025-03-02 20:49:58 +08:00
"""
2025-02-28 15:15:33 +08:00
# 高度过大矩形过滤参数
2025-03-02 16:25:35 +08:00
max_height_rate = 0.5 # 矩形高度占整个画面高度的最大比例,如果超过该比例,则认为是无效矩形
2025-02-27 17:31:43 +08:00
2025-03-02 16:25:35 +08:00
image_x_min = int(image_width * wide_cam_left_cut_rate) # 左边界的裁剪点
image_x_max = int(image_width * (1 - wide_cam_right_cut_rate)) # 右边界的裁剪点
2025-02-27 17:31:43 +08:00
2025-03-02 16:25:35 +08:00
# 开始过滤矩形
2025-02-27 17:31:43 +08:00
bad_point_index = []
2025-02-28 15:15:33 +08:00
print(f'开始过滤矩形,原有矩形数为{len(points)}')
2025-02-27 17:31:43 +08:00
for index in range(len(points)):
point = points[index]
2025-02-28 15:15:33 +08:00
2025-02-27 17:31:43 +08:00
# 高度过大过滤
if point['height'] > image_height * max_height_rate:
bad_point_index.append(index)
continue
2025-02-28 15:15:33 +08:00
# x坐标范围过滤,整个矩形全部身体都在裁剪区域之外的不要
2025-03-02 16:25:35 +08:00
x_min = point['x'] # 矩形四个矩形坐标中x的最小值
x_max = point['x'] + point['width'] # 矩形四个矩形坐标中x的最大值
2025-02-28 15:15:33 +08:00
# 如果矩形x的 最大值 小于 左边界,去除这个矩形
if x_max < image_x_min:
2025-02-27 17:31:43 +08:00
bad_point_index.append(index)
continue
2025-02-28 15:15:33 +08:00
# 如果矩形x的 最小值 大于 右边界,去除这个矩形
if x_min > image_x_max:
2025-02-27 17:31:43 +08:00
bad_point_index.append(index)
continue
2025-02-28 15:15:33 +08:00
# 过滤,只保留有效矩形
2025-02-27 17:31:43 +08:00
filtered_points = []
for i, point in enumerate(points):
2025-02-28 15:15:33 +08:00
# 如果当前矩形的索引在bad_point_index中则去除这个矩形
2025-02-27 17:31:43 +08:00
if i not in bad_point_index:
2025-02-28 15:15:33 +08:00
# 重新计算点的坐标
2025-03-02 16:25:35 +08:00
re_cal_point(point, image_x_min)
2025-02-28 15:15:33 +08:00
# 塞入结果
2025-02-27 17:31:43 +08:00
filtered_points.append(point)
2025-02-28 15:15:33 +08:00
print(f'过滤矩形结束,过滤之后的矩形数为{len(filtered_points)}')
# 图片裁剪
# 裁剪图片 (height方向不变宽度方向裁剪)
2025-03-02 22:28:43 +08:00
# cropped_image = image[:, image_x_min:image_x_max]
2025-02-28 15:15:33 +08:00
# 展示
# cv2.imshow("cropped_image", cropped_image)
# cv2.imshow("image", image)
# for i in range(len(filtered_points)):
# p = filtered_points[i]
# cv2.rectangle(cropped_image, (p['x'], p['y']), (p['x'] + p['width'], p['y'] + p['height']), (0, 0, 255), 2)
# # 写编号
# cv2.putText(cropped_image, str(i), (p['x'], p['y']), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 2)
# cv2.imshow("cropped_image_draw", cropped_image)
# cv2.waitKey(0)
2025-03-02 22:28:43 +08:00
wide_cam_img_width_after_cut = image_x_max - image_x_min
return filtered_points, wide_cam_img_width_after_cut
2025-02-27 17:31:43 +08:00
2025-03-02 16:25:35 +08:00
def get_hd_cam_rect(wide_cam_left_cut_rate):
2025-03-02 20:49:58 +08:00
"""
获取高清相机的视场矩形在广角相机里面的坐标cv2下的图片坐标系以左上角为坐标原点
wide_cam_left_cut_rate# 广角相机,左边界的裁剪比例,从左边开始裁剪百分之多少
"""
2025-03-02 16:25:35 +08:00
# 下面参数是几乎标准无偏差的高清相机在广角相机里面的视场角矩形 广角为640x480
x = 128
y = 140
w = 312
h = 234
# 按照k比例放大,因为高清在bim图上面定位的区域不一定是准确的可能比广角的原宽度要小。 所以适当放大高清相机的矩形框,
# 广角左边右边,裁剪之前,放大之后的矩形框
k = 0
width_scale_pixel = k * w
height_scale_pixel = k * h
scale_x = x - width_scale_pixel
scale_y = y - height_scale_pixel
scale_w = w + 2 * width_scale_pixel
scale_h = h + 2 * height_scale_pixel
# 广角裁剪之后,高清矩形在新的广角图片里面的坐标。
original_wide_cam_image_width = 640 # 原本广角图片的宽度
cut_image_x_min = int(original_wide_cam_image_width * wide_cam_left_cut_rate) # 左边界的裁剪点
scale_x = scale_x - cut_image_x_min # 因为只是左右裁剪只影响左上角坐标的x值
return int(scale_x), int(scale_y), int(scale_w), int(scale_h)
2025-02-27 17:31:43 +08:00
2025-03-02 20:49:58 +08:00
def get_hd_roi_from_txt(file_path):
"""
读取本地文件解析ROI矩形坐标
每八行为一个ROI矩形坐标每两行为xy顺序为左上右上右下左下顺时针
Args:
file_path (str): 文件路径
Returns:
list:数组格式第一层是全部都矩形第二次是每个矩形的全部的坐标第三层是每个坐标都xy
[
[[x1, y1], [x2, y2], [x3, y3], [x4, y4]],
[[x1, y1], [x2, y2], [x3, y3], [x4, y4]],
]
"""
roi_list = []
try:
with open(file_path, 'r') as f:
lines = f.readlines()
# 确保行数是8的倍数
if len(lines) % 8 != 0:
raise ValueError("文件格式错误行数不是8的倍数")
for i in range(0, len(lines), 8):
roi = []
for j in range(0, 8, 2):
x = float(lines[i + j].strip())
y = float(lines[i + j + 1].strip())
roi.append([x, y])
roi_list.append(roi)
except FileNotFoundError:
print(f"文件未找到: {file_path}")
except ValueError as e:
print(f"数据格式错误: {e}")
except Exception as e:
print(f"发生未知错误: {e}")
return roi_list
# 测试 get_hd_rou_from_txt
# rois = get_hd_roi_from_txt("data_sub/test_1/roi_conners.txt")
# print(rois[0])
# sub_im = cv2.imread("data_sub/test_1/output.jpg")
# for roi in rois:
# cv2.rectangle(sub_im, (int(roi[0][0]), int(roi[0][1])), (int(roi[2][0]), int(roi[2][1])), (0, 0, 255), 100)
# # 图片缩小展示
# sub_im = cv2.resize(sub_im, (int(sub_im.shape[1]/12), int(sub_im.shape[0]/12)))
# cv2.imshow("sub_im", sub_im)
# cv2.waitKey(0)
# 测试filter_rectangle
2025-02-27 17:31:43 +08:00
# def read_from_json(file_path):
# with open(file_path, 'r') as f:
# loaded_array = json.load(f)
# return loaded_array
# cnts = read_from_json("data_sub/test_1/data_sub.json")
2025-03-02 16:25:35 +08:00
# filter_rectangle("data_sub/test_1/wide_image.png",cnts)