【问题标题】:How to rotate a rectangle/bounding box together with an image如何将矩形/边界框与图像一起旋转
【发布时间】:2023-01-21 21:10:07
【问题描述】:

我正在研究数据扩充,我正在尝试生成数据集中每个图像的合成版本。所以我需要旋转图像以及图像中的边界框。

我只会将图像旋转 90、180、270 度。

我正在使用 here 所示的 pascal-voc 注释格式。结果我有以下信息。

x_min, y_min, x_max, y_max。图像的来源(我可以从图像大小中得到它)

我已经搜索了很多。但我找不到任何旋转边界框(或矩形)的解决方案

我试过这样的事情; 我从here 那里得到了这个解决方案,并尝试对其进行调整但没有奏效。

def rotateRect(bndbox, img_size, angle):
    angle = angle * math.pi/180 # conversion from degree to radian
    y_min, y_max, x_min, x_max = bndbox
    ox, oy = img_size[0]/2, img_size[1]/2 # coordinate of origin of image
    rect = [[x_min, y_min], [x_min, y_max],[x_max, y_min],[x_max, y_max]] # coordinates of points of corners of bounding box rectangle.
    nrp = [[0, 0], [0,0 ],[0,0],[0, 0]] #new rectangle position

    for i, pt in enumerate(rect):
        newPx = int(ox + math.cos(angle) * (pt[0] - ox) - math.sin(angle) * (pt[1] - oy)) # new coordinate of point x
        newPy = int(oy + math.sin(angle) * (pt[0] - ox) + math.cos(angle) * (pt[1] - oy))  # new coordinate of point y
        nrp[i] = newPx,newPy
        nx_min, ny_min, nx_max, ny_max = nrp[0][0], nrp[0][1], nrp[2][0], nrp[2][1] # new bounding boxes values. 
     return [ny_min, ny_max, nx_min, nx_max]

谢谢。

编辑:

我需要将此旋转与图像和边界框一起使用。 第一张图片是原始图片,第二张图片旋转了 90 度(逆时针),第三张图片旋转了 -90 度(逆时针)。 为了准确起见,我试着在油漆上手动旋转。所以我得到了这些结果。

   original of img size:(640x480)
   rotation orj, 90, -90
            --------------
    x_min = 98,  345, 17
    y_min = 345, 218, 98
    x_max = 420, 462, 420
    y_max = 462, 540, 134

【问题讨论】:

  • 绕什么点旋转?这是关键问题。矩形的中心?
  • 不,因为它没有意义。新边界框不适合旋转版本中的新对象位置。因此,我需要围绕图像中心旋转它。

标签: python computer-vision object-detection yolo data-augmentation


【解决方案1】:

我找到了更简单的方法。

基于这种方法。我们可以在不使用像这样的三角函数计算的情况下进行此计算:

def rotate90Deg(bndbox, img_width): # just passing width of image is enough for 90 degree rotation.
   x_min,y_min,x_max,y_max = bndbox
   new_xmin = y_min
   new_ymin = img_width-x_max
   new_xmax = y_max
   new_ymax = img_width-x_min
   return [new_xmin, new_ymin,new_xmax,new_ymax]


rotate90Deg([98,345,420,462],640)

这可以反复使用。并以 Pascal-voc 格式返回新的边界框值。

【讨论】:

    【解决方案2】:

    好的,也许这会有所帮助。假设您的矩形存储为一组标记角的 4 个点,这将围绕另一个点进行任意旋转。如果您以循环顺序存储点,则绘图甚至看起来像矩形。我没有在图上强制显示纵横比,因此旋转的矩形看起来像是倾斜的,但事实并非如此。

    import math
    import matplotlib.pyplot as plt
    
    def rotatebox( rect, center, degrees ):
        rads = math.radians(degrees)
    
        newpts = []
        for pts in rect:
            diag_x = center[0] - pts[0]
            diag_y = center[1] - pts[1]
    
            # Rotate the diagonal from center to top left
    
            newdx = diag_x * math.cos(rads) - diag_y * math.sin(rads)
            newdy = diag_x * math.sin(rads) + diag_y * math.cos(rads)
            newpts.append( (center[0] + newdx, center[1] + newdy) )
    
        return newpts
    
    # Return a set of X and Y for plotting.
    
    def corners(rect):
        return [k[0] for k in rect]+[rect[0][0]],[k[1] for k in rect]+[rect[0][1]]
    
    rect = [[50,50],[50,120],[150,120],[150,50]]
    plt.plot( *corners(rect) )
    rect = rotatebox( rect, (100,100), 135 )
    plt.plot( *corners(rect) )
    plt.show()
    

    对于 90/180/270 的情况,代码可以变得更简单,因为不需要三角函数。这只是加法、减法和交换点。这里,矩形只是存储 [minx,miny,maxx,maxy]。

    import matplotlib.pyplot as plt
    
    def rotaterectcw( rect, center ):
        x0 = rect[0] - center[0]
        y0 = rect[1] - center[1]
        x1 = rect[2] - center[0]
        y1 = rect[3] - center[1]
        return center[0]+y0, center[1]-x0, center[0]+y1, center[1]-x1
    
    def corners(rect):
        x0, y0, x1, y1 = rect
        return [x0,x0,x1,x1,x0],[y0,y1,y1,y0,y0]
    
    rect = (50,50,150,120)
    plt.plot( *corners(rect) )
    rect = rotaterectcw( rect, (60,100) )
    plt.plot( *corners(rect) )
    rect = rotaterectcw( rect, (60,100) )
    plt.plot( *corners(rect) )
    rect = rotaterectcw( rect, (60,100) )
    plt.plot( *corners(rect) )
    plt.show()
    

    【讨论】:

    • 好的,非常感谢。我试过代码。似乎是我想要的东西。我会尝试用它来适应我的工作。我回头告诉你。
    • 我只实现了顺时针 90 度,因为调用它三次与编写 270 度选项的代码一样有效。
    • 我已经尝试了这两种实现。但两者都没有给我正确的结果。为了更好地可视化问题,我添加了图片和旋转结果。我将 xmin、ymin、xmax、ymax 值和角点的值赋予函数。我没有得到正确的结果。我应该怎么办?
    【解决方案3】:

    我尝试了其他答案中提到的实现,但没有一个对我有用。我不得不将图像和边界框顺时针旋转 90 度所以我做了这个方法,

    def rotate90Deg( bndbox , image_width ):
        """
        image_width: Width of the image after clockwise rotation of 90 degrees
        """
        x_min,y_min,x_max,y_max = bndbox
        new_xmin = image_width - y_max # Reflection about center X-line
        new_ymin = x_min
        new_xmax = image_width - y_min # Reflection about center X-line
        new_ymax = x_max
        return [new_xmin, new_ymin,new_xmax,new_ymax]
    

    用法

    image = Image.open( "..." )
    image = image.rotate( -90 )
    new_bbox = rotate90Deg( bbox , image.width )
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-09-01
      • 2018-12-29
      • 2010-10-11
      • 1970-01-01
      • 1970-01-01
      • 2019-06-01
      • 1970-01-01
      • 2021-11-11
      相关资源
      最近更新 更多