对图像进行相关计算操作时注意的问题!

这里我以图像旋转为例,功能是图像旋转后依然被完全包含(且没有“蜂窝煤”效应)

def rotation(src_img_size , crop_img , src_box_info , angle):  #返回旋转后的pts坐标和boc框
    src_height = int(src_img_size[0])  #原始图片尺寸
    src_width = int(src_img_size[1])
    crop_height = crop_img.shape[0]  #截取的图片尺寸
    crop_width = crop_img.shape[1]
    #tar_rotation_pts = np.zeros((4 , 2) , dtype = int)
    tar_box_info = np.zeros((2 , 2) , dtype = int)  #存储缩放后的box框
    a = angle
    angle_pi = a * math.pi / 180.0
    #================================================================================================
    #图片进行旋转
    src_peak = np.zeros((4 , 2) , dtype = int)  #二维框的四个顶点
    src_peak[0][0] = int(src_box_info[0])  #左上角点
    src_peak[0][1] = int(src_box_info[1])
    src_peak[1][0] = int(src_box_info[0]) + crop_width  #右上角点
    src_peak[1][1] = int(src_box_info[1])
    src_peak[2][0] = int(src_box_info[0])  #左下角点
    src_peak[2][1] = int(src_box_info[1]) + crop_height
    src_peak[3][0] = int(src_box_info[0]) + crop_width #右下角点
    src_peak[3][1] = int(src_box_info[1]) + crop_height
    print(src_peak)
    tar_peak = np.zeros((4 , 2) , dtype = int)
    for i in range(len(src_peak)):
        tar_peak[i][0] = int(int(src_peak[i][0]) * math.cos(angle_pi) - int(src_peak[i][1]) * math.sin(angle_pi) - 0.5 * src_width * math.cos(angle_pi) + 0.5 * src_height * math.sin(angle_pi) + 0.5 * src_width)
        tar_peak[i][1] = int(int(src_peak[i][0]) * math.sin(angle_pi) + int(src_peak[i][1]) * math.cos(angle_pi) - 0.5 * src_width * math.sin(angle_pi) - 0.5 * src_height * math.cos(angle_pi) + 0.5 * src_height)
    
    print(tar_peak)
    max_x = tar_peak[0][0]
    for j in range(4):
        if(tar_peak[j][0] > max_x):
            max_x = tar_peak[j][0]
    min_x = tar_peak[0][0]
    for j in range(4):
        if(tar_peak[j][0] < min_x):
            min_x = tar_peak[j][0]
    max_y = tar_peak[0][1]
    for j in range(4):
        if(tar_peak[j][1] > max_y):
            max_y = tar_peak[j][1]
    min_y = tar_peak[0][1]
    for j in range(4):
        if(tar_peak[j][1] < min_y):
            min_y = tar_peak[j][1]

    origin_min_x = min_x
    origin_max_x = max_x
    origin_min_y = min_y
    origin_max_y = max_y 
    print(min_x , max_x)
    print(min_y , max_y)

    if(min_x > src_box_info[0]):
        min_x = src_box_info[0]
    if(max_x < src_box_info[2]):
        max_x = src_box_info[2]
    if(min_y > src_box_info[1]):
        min_y = src_box_info[1]
    if(max_y < src_box_info[3]):
        max_y = src_box_info[3]

    tar_width = max_x - min_x
    tar_height = max_y - min_y
    #对crop_img先进行操作,使得旋转后图片依然完全包含整个二维框
    rotation_size = (tar_height + 1 , tar_width + 1 , 3)  #rotation_size:(271 , 271);crop_size:(174 , 270)
    rotation_img = np.zeros(rotation_size , np.uint8)

    print(rotation_size)
    print(crop_height , crop_width)

    for i in range(crop_height):
        for j in range(crop_width):
            x = j + (src_box_info[0] - min_x)  #注意!这里的i和j是二维框的坐标系,而y和x是rotation_img的坐标系,所以需要先进行坐标系转换
            y = i + (src_box_info[1] - min_y)
            rotation_img[y , x] = crop_img[i , j]

    cv2.imwrite("D:/projects/three_views/gen_train_lmdb/small_test/2.jpg" , rotation_img)

    #crop_img进行旋转
    center = ((src_width / 2 - min_x) , (src_height / 2 - min_y))  #旋转中心设为图片中心,同时由于这儿是对crop_img(扩展后的)进行旋转,所以旋转中心的参考坐标系应该变成扩展后的crop_img的坐标系,所以这里也要进行一步操作
    M = cv2.getRotationMatrix2D(center, (a * (-1)), 1.0)  #顺时针旋转
    tar_rotation_img = cv2.warpAffine(rotation_img, M, (tar_width, tar_height))  #旋转后的图片
    #===============================================================================
    if(origin_min_x <= src_box_info[0]):
        origin_min_x = 0
    else:
        origin_min_x = origin_min_x - src_box_info[0]
    if(origin_max_x >= src_box_info[2]):
        origin_max_x = tar_width
    else:
        origin_max_x = origin_max_x - min_x
    #=======
    if(origin_min_y >= src_box_info[1]):
        origin_min_y = origin_min_y - src_box_info[1]
    else:
        origin_min_y = 0
    if(origin_max_y <= src_box_info[3]):
        origin_max_y = origin_max_y - min_y
    else:
        origin_max_y = tar_height
    #=================================================================================
    tar_rotation_img = tar_rotation_img[int(origin_min_y) : int(origin_max_y) , int(origin_min_x) : int(origin_max_x) , :]
    #======================================================================================================
    #box信息:(cx , cy , w , h)
    tar_box_info[0][0] = src_width / 2
    tar_box_info[0][1] = src_height / 2
    tar_box_info[1][0] = origin_max_x - origin_min_x
    tar_box_info[1][1] = tar_height
    #======================================================================================================
    #旋转后的pts信息
    '''for i in range(len(src_pts) / 2):
        tar_rotation_pts[i][0] = int(int(src_pts[2 * i]) * math.cos(angle_pi) - int(src_pts[2 * i + 1]) * math.sin(angle_pi) - 0.5 * src_width * math.cos(angle_pi) + 0.5 * src_height * math.sin(angle_pi) + 0.5 * src_width)
        tar_rotation_pts[i][1] = int(int(src_pts[2 * i]) * math.sin(angle_pi) + int(src_pts[2 * i + 1]) * math.cos(angle_pi) - 0.5 * src_width * math.sin(angle_pi) - 0.5 * src_height * math.cos(angle_pi) + 0.5 * src_height)'''
    return tar_rotation_img , tar_box_info 

在操作的时候,要非常注意的一个问题就是:要能敏锐地察觉到图像中坐标系的变换!!!举下面这个例子:

for i in range(crop_height):
        for j in range(crop_width):
            x = j + (src_box_info[0] - min_x)  #注意!这里的i和j是二维框的坐标系,而y和x是rotation_img的坐标系,所以需要先进行坐标系转换
            y = i + (src_box_info[1] - min_y)
            rotation_img[y , x] = crop_img[i , j]

其中i和j是在crop_img坐标系下,而y和x是在rotation_img坐标系下,所以在操作的时候一定要注意先变换到同一坐标系下;

上面这个例子还比较明显,但还有很多时候是不明显的,所以就需要我们敏锐地观察力,否则的确是个很难查的BUG呢!

原文地址:https://www.cnblogs.com/zf-blog/p/8985360.html