如何为tf$keras$preprocessing$image$apply_affine_transform旋转YOLO边界框?
解决YOLO边界框与旋转图像的坐标对齐问题
嘿,我看你在尝试用TensorFlow的apply_affine_transform做图像旋转时,遇到了YOLO格式边界框无法正确匹配的问题。你的rotate_boxes函数思路是对的,但有几个容易忽略的细节导致了偏差,咱们一步步来修正:
核心问题拆解
- 角度单位不匹配:你传入的
theta是90度,但R的cos()/sin()默认用弧度计算,直接用角度会导致旋转矩阵完全错误。 - 图像坐标系的特殊性:图像的y轴是向下的,而数学旋转矩阵基于y轴向上的坐标系,这会让旋转后的y坐标方向完全反了。
- 旋转中心的一致性:要确保边界框的旋转中心和
apply_affine_transform的旋转中心完全对齐(这个函数默认以图像中心为旋转点)。
修正后的rotate_boxes函数
rotate_boxes <- function(boxes, height, width, theta = 0) { # 把输入的角度(度)转换成弧度,同时适配tf顺时针旋转的规则 theta_rad <- -theta * pi / 180 # 图像中心的像素坐标 cx <- width / 2 cy <- height / 2 boxes %>% # 把归一化坐标转成像素坐标 mutate_at(vars("xmin", "xmax"), ~ . * width) %>% mutate_at(vars("ymin", "ymax"), ~ . * height) %>% pmap_df(function(label, xmin, ymin, xmax, ymax) { # 提取边界框的四个顶点 points <- tibble( x = c(xmin, xmin, xmax, xmax), y = c(ymin, ymax, ymin, ymax) ) # 转换到以图像中心为原点的坐标系,同时修正y轴方向(转成数学坐标系) points <- points %>% mutate( x_centered = x - cx, y_centered = cy - y # 这里反转y轴,匹配数学坐标系 ) # 应用旋转矩阵 points <- points %>% mutate( x_rotated = cos(theta_rad) * x_centered - sin(theta_rad) * y_centered, y_rotated = sin(theta_rad) * x_centered + cos(theta_rad) * y_centered ) # 转换回原图像坐标系(再把y轴反转回来) points <- points %>% mutate( x = x_rotated + cx, y = cy - y_rotated ) # 计算旋转后边界框的最小/最大坐标,转回YOLO归一化格式 tibble( label = label, xmin = min(points$x) / width, ymin = min(points$y) / height, xmax = max(points$x) / width, ymax = max(points$y) / height ) %>% # 确保坐标不会超出[0,1]范围,避免出界问题 mutate( xmin = pmax(0, xmin), ymin = pmax(0, ymin), xmax = pmin(1, xmax), ymax = pmin(1, ymax) ) }) }
关键修正说明
- 角度适配:用
-theta * pi /180把顺时针角度转换成符合数学旋转规则的弧度,确保和apply_affine_transform的旋转方向一致。 - y轴修正:通过
cy - y把图像坐标系反转成数学坐标系,旋转后再反转回来,解决了y轴方向导致的偏移问题。 - 边界保护:添加
pmax/pmin确保归一化坐标始终在[0,1]区间,避免后续绘图或训练报错。
测试调用示例
用你原来的测试代码调用修正后的函数即可:
plot_boxes( images_paths = test_img, boxes = list(rotate_boxes(test_bbox, height = 750, width = 1000, theta = 90)), correct_hw = TRUE, theta = 90 )
额外提示
- 如果后续你修改了
apply_affine_transform的旋转中心(比如通过cval或fill_mode调整),记得同步修改rotate_boxes里的cx和cy值。 - 对于旋转后完全超出图像的边界框,可以根据需求加个过滤逻辑(比如删除
xmin >= xmax或ymin >= ymax的框)。
内容的提问来源于stack exchange,提问作者Maju116
相关产品推荐
相关产品推荐

