Files
ailai_show/Vision/tool/utils.py
2025-07-29 13:16:30 +08:00

394 lines
12 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
'''
@Project AutoControlSystem-master
@File utils.py
@IDE PyCharm
@Author hjw
@Date 2024/8/29 15:07
'''
import numpy as np
import cv2
import psutil
from psutil._common import bytes2human
def uv_to_XY(cameraType, u, v):
"""
像素坐标转相机坐标
Args:
cameraType:
u:
v:
Returns:
如本:
ExtrinsicMatrix:
[-0.9916700124740601, -0.003792409785091877, 0.12874870002269745, 0.10222162306308746, -0.003501748666167259, 0.9999907612800598, 0.002483875723555684, -0.08221593499183655, -0.12875692546367645, 0.0020123394206166267, -0.9916741251945496, 0.6480034589767456, 0.0, 0.0, 0.0, 1.0]
IntrinsicParameters:
[2402.101806640625, 0.0, 739.7069091796875,
0.0, 2401.787353515625, 584.73046875,
0.0, 0.0, 1.0]
distortion:
[-0.04248141124844551, 0.24386045336723328, -0.38333430886268616, -0.0017840253422036767, 0.0007602088153362274]
图漾:
depth image format list:
0 -size[640x480] - desc:DEPTH16_640x480
1 -size[1280x960] - desc:DEPTH16_1280x960
2 -size[320x240] - desc:DEPTH16_320x240
delth calib info:
calib size :[1280x960]
calib intr :
(1048.3614501953125, 0.0, 652.146240234375,
0.0, 1048.3614501953125, 500.26397705078125,
0.0, 0.0, 1.0)
calib extr : (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
calib distortion : (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
"""
x = None
y = None
zc = 1 # 设深度z为1
if cameraType == 'RVC':
u0 = 739.70
v0 = 584.73
fx = 2402.10
fy = 2401.78
x = (u-u0)*zc/fx
y = (v-v0)*zc/fy
elif cameraType == 'Pe':
u0 = 652.14
v0 = 500.26
fx = 1048.36
fy = 1048.36
x = (u - u0) * zc / fx
y = (v - v0) * zc / fy
return x, y, zc
def out_bounds_dete(pm_y, pm_x, piont_y, piont_x):
if piont_y>=pm_y:
piont_y = pm_y-1
print('四坐标点超出点云大小')
if piont_y<0:
piont_y=0
print('四坐标点超出点云大小')
if piont_x>=pm_x:
piont_x = pm_x-1
print('四坐标点超出点云大小')
if piont_x<0:
piont_x=0
print('四坐标点超出点云大小')
return piont_y, piont_x
def remove_nan_mean_value(pm, y, x, iter_max=50):
y, x = out_bounds_dete(pm.shape[0], pm.shape[1], y, x)
point_x, point_y, point_z = pm[y, x]
if np.isnan(point_x):
point_x_list = []
point_y_list = []
point_z_list = []
iter_current = 1
pm_shape_y = pm.shape[0]
pm_shape_x = pm.shape[1]
remove_nan_isok = False
print('Nan值去除')
while iter_current < iter_max:
# 计算开始点
if y - iter_current > 0:
y_start = y - iter_current
else:
y_start = 0
if x - iter_current > 0:
x_start = x - iter_current
else:
x_start = 0
for idx_y in range(iter_current*2 + 1):
y_current = y_start + idx_y
if y_current > pm_shape_y-1:
continue
for idx_x in range(iter_current*2 + 1):
x_current = x_start + idx_x
if x_current > pm_shape_x-1:
continue
elif np.isnan(pm[y_current, x_current][0]) == False:
point_x_list.append(pm[y_current, x_current][0])
point_y_list.append(pm[y_current, x_current][1])
point_z_list.append(pm[y_current, x_current][2])
len_point_x = len(point_x_list)
if len_point_x > 0:
point_x = sum(point_x_list)/len_point_x
point_y = sum(point_y_list)/len_point_x
point_z = sum(point_z_list)/len_point_x
remove_nan_isok = True
break
iter_current += 1
else:
remove_nan_isok = True
if remove_nan_isok == True:
return point_x, point_y, point_z
else:
print(f'{iter_max}*{iter_max}范围中未找到有效值,所有点云值为无效值')
return np.nan, np.nan, np.nan
def remove_nan(pm, y, x):
point_x, point_y, point_z = pm[y, x]
if np.isnan(point_x):
for i in range(10):
point_x, point_y, point_z = pm[y+i, x]
if np.isnan(point_x)==False:
break
return point_x, point_y, point_z
def get_disk_space(path='C:'):
usage = psutil.disk_usage(path)
space_free = bytes2human(usage.free)
# space_total = bytes2human(usage.total)
# space_used = bytes2human(usage.used)
# space_free = bytes2human(usage.free)
# space_used_percent = bytes2human(usage.percent)
space_free = float(space_free[:-1])
return space_free
def find_position(Depth_Z, RegionalArea, RegionalArea_Threshold, first_depth=True):
if first_depth == True:
sorted_id = sorted(range(len(Depth_Z)), key=lambda k: Depth_Z[k], reverse=False)
# Depth_Z1 = [Depth_Z[i] for i in sorted_id]
# RegionalArea1 = [RegionalArea[i] for i in sorted_id]
# for i in range(len(Depth_Z1)):
# if RegionalArea1[i] > RegionalArea_Threshold:
# return sorted_id[i]
if len(sorted_id)>0:
return sorted_id[0]
else:
return
else:
sorted_id = sorted(range(len(RegionalArea)), key=lambda k: RegionalArea[k], reverse=True)
# Depth_Z1 = [Depth_Z[i] for i in sorted_id]
# RegionalArea1 = [RegionalArea[i] for i in sorted_id]
# for i in range(len(Depth_Z1)):
# if RegionalArea1[i] > RegionalArea_Threshold:
# return sorted_id[i]
if len(sorted_id)>0:
return sorted_id[0]
else:
return
class_names = ['box', 'other']
# Create a list of colors for each class where each color is a tuple of 3 integer values
rng = np.random.default_rng(3)
colors = rng.uniform(0, 255, size=(len(class_names), 3))
def nms(boxes, scores, iou_threshold):
# Sort by score
sorted_indices = np.argsort(scores)[::-1]
keep_boxes = []
while sorted_indices.size > 0:
# Pick the last box
box_id = sorted_indices[0]
keep_boxes.append(box_id)
# Compute IoU of the picked box with the rest
ious = compute_iou(boxes[box_id, :], boxes[sorted_indices[1:], :])
# Remove boxes with IoU over the threshold
keep_indices = np.where(ious < iou_threshold)[0]
# print(keep_indices.shape, sorted_indices.shape)
sorted_indices = sorted_indices[keep_indices + 1]
return keep_boxes
def compute_iou(box, boxes):
# Compute xmin, ymin, xmax, ymax for both boxes
xmin = np.maximum(box[0], boxes[:, 0])
ymin = np.maximum(box[1], boxes[:, 1])
xmax = np.minimum(box[2], boxes[:, 2])
ymax = np.minimum(box[3], boxes[:, 3])
# Compute intersection area
intersection_area = np.maximum(0, xmax - xmin) * np.maximum(0, ymax - ymin)
# Compute union area
box_area = (box[2] - box[0]) * (box[3] - box[1])
boxes_area = (boxes[:, 2] - boxes[:, 0]) * (boxes[:, 3] - boxes[:, 1])
union_area = box_area + boxes_area - intersection_area
# Compute IoU
iou = intersection_area / union_area
return iou
def xywh2xyxy(x):
# Convert bounding box (x, y, w, h) to bounding box (x1, y1, x2, y2)
y = np.copy(x)
y[..., 0] = x[..., 0] - x[..., 2] / 2
y[..., 1] = x[..., 1] - x[..., 3] / 2
y[..., 2] = x[..., 0] + x[..., 2] / 2
y[..., 3] = x[..., 1] + x[..., 3] / 2
return y
def sigmoid(x):
return 1 / (1 + np.exp(-x))
def draw_detections(image, boxes, scores, class_ids, mask_alpha=0.3, mask_maps=None):
img_height, img_width = image.shape[:2]
size = min([img_height, img_width]) * 0.0006
text_thickness = int(min([img_height, img_width]) * 0.001)
mask_img = draw_masks(image, boxes, class_ids, mask_alpha, mask_maps)
# Draw bounding boxes and labels of detections
for box, score, class_id in zip(boxes, scores, class_ids):
color = colors[class_id]
x1, y1, x2, y2 = box.astype(int)
# Draw rectangle
cv2.rectangle(mask_img, (x1, y1), (x2, y2), color, 2)
label = class_names[class_id]
caption = f'{label} {int(score * 100)}%'
(tw, th), _ = cv2.getTextSize(text=caption, fontFace=cv2.FONT_HERSHEY_SIMPLEX,
fontScale=size, thickness=text_thickness)
th = int(th * 1.2)
cv2.rectangle(mask_img, (x1, y1),
(x1 + tw, y1 - th), color, -1)
cv2.putText(mask_img, caption, (x1, y1),
cv2.FONT_HERSHEY_SIMPLEX, size, (255, 255, 255), text_thickness, cv2.LINE_AA)
return mask_img
def draw_masks(image, boxes, class_ids, mask_alpha=0.3, mask_maps=None):
mask_img = image.copy()
# Draw bounding boxes and labels of detections
for i, (box, class_id) in enumerate(zip(boxes, class_ids)):
color = colors[class_id]
x1, y1, x2, y2 = box.astype(int)
# Draw fill mask image
if mask_maps is None:
cv2.rectangle(mask_img, (x1, y1), (x2, y2), color, -1)
else:
crop_mask = mask_maps[i][y1:y2, x1:x2, np.newaxis]
crop_mask_img = mask_img[y1:y2, x1:x2]
crop_mask_img = crop_mask_img * (1 - crop_mask) + crop_mask * color
mask_img[y1:y2, x1:x2] = crop_mask_img
return cv2.addWeighted(mask_img, mask_alpha, image, 1 - mask_alpha, 0)
def draw_comparison(img1, img2, name1, name2, fontsize=2.6, text_thickness=3):
(tw, th), _ = cv2.getTextSize(text=name1, fontFace=cv2.FONT_HERSHEY_DUPLEX,
fontScale=fontsize, thickness=text_thickness)
x1 = img1.shape[1] // 3
y1 = th
offset = th // 5
cv2.rectangle(img1, (x1 - offset * 2, y1 + offset),
(x1 + tw + offset * 2, y1 - th - offset), (0, 115, 255), -1)
cv2.putText(img1, name1,
(x1, y1),
cv2.FONT_HERSHEY_DUPLEX, fontsize,
(255, 255, 255), text_thickness)
(tw, th), _ = cv2.getTextSize(text=name2, fontFace=cv2.FONT_HERSHEY_DUPLEX,
fontScale=fontsize, thickness=text_thickness)
x1 = img2.shape[1] // 3
y1 = th
offset = th // 5
cv2.rectangle(img2, (x1 - offset * 2, y1 + offset),
(x1 + tw + offset * 2, y1 - th - offset), (94, 23, 235), -1)
cv2.putText(img2, name2,
(x1, y1),
cv2.FONT_HERSHEY_DUPLEX, fontsize,
(255, 255, 255), text_thickness)
combined_img = cv2.hconcat([img1, img2])
if combined_img.shape[1] > 3840:
combined_img = cv2.resize(combined_img, (3840, 2160))
return combined_img
def fit_plane_vision(box_list, normal_vector):
plane_x = []
plane_y = []
plane_z = []
print(box_list)
plane_x.append(box_list[0][0][0])
plane_x.append(box_list[0][1][0])
plane_x.append(box_list[0][2][0])
plane_x.append(box_list[0][3][0])
plane_y.append(box_list[0][0][1])
plane_y.append(box_list[0][1][1])
plane_y.append(box_list[0][2][1])
plane_y.append(box_list[0][3][1])
plane_z.append(box_list[0][0][2])
plane_z.append(box_list[0][1][2])
plane_z.append(box_list[0][2][2])
plane_z.append(box_list[0][3][2])
# 定义平面方程的参数
a = normal_vector[0]
b = normal_vector[1]
c = normal_vector[2]
d = normal_vector[3]
# 定义平面的范围
x_range = (int(min(plane_x)), int(max(plane_x)))
y_range = (int(min(plane_y)), int(max(plane_y)))
z_range = (int(min(plane_z)), int(max(plane_z)))
# 生成平面网格
x = np.linspace(x_range[0], x_range[1], 10)
y = np.linspace(y_range[0], y_range[1], 20)
X, Y = np.meshgrid(x, y)
Z = -(a * X + b * Y + d) / c # 根据平面方程计算 Z 坐标
# 确保 Z 坐标在指定范围内
Z = np.clip(Z, z_range[0], z_range[1])
# 创建 TriangleMesh 对象
import open3d as o3d
plane_mesh = o3d.geometry.TriangleMesh()
plane_mesh.vertices = o3d.utility.Vector3dVector(np.vstack((X.ravel(), Y.ravel(), Z.ravel())).T)
plane_mesh.triangles = o3d.utility.Vector3iVector(
np.array([[i, i + 1, i + 100] for i in range(99)] + [[i + 1, i + 101, i + 100] for i in range(99)]))
plane_mesh.paint_uniform_color([1, 0.5, 0.5]) # 设置平面颜色
return plane_mesh