Python openCV实现旋转关键点的同时,保留所有图像信息,并裁剪掉空白区域

该代码示例展示了如何在Python中使用OpenCV和imutils库进行图像无损旋转,并在旋转后重新计算关键点坐标,同时裁剪掉图片中的空白区域。主要函数包括rotate_img_location()用于旋转并定位关键点,以及crop_img_empty()用于裁剪图片。
摘要由CSDN通过智能技术生成

做图像定位+关键点任务时,需要数据增样,遂写了这么一篇
当时只有三个关键点,就写的比较面向过程,想优化/加点的同学就交给你们了!

任务就三步:
imutils.rotate_bound无损旋转图片
②重新计算坐标
③裁剪无用区域
裁剪空白区域的方法来自这位同学的crop_img_empty,在其之上做了一些修改
https://blog.csdn.net/soderayer/article/details/123467979

import math

import cv2
import imutils
from crop_empty_zone import crop_img_empty


# 旋转图片后(顺时针),重新计算图片宽高+关键点位置
# 输入:CV图片,旋转角度,三个关键点坐标(已归一化)
# 输出:旋转完成图片,关键点新坐标
def rotate_img_location(img, angle, point_box):
    # 第一步:计算新宽高
    h, w = img.shape[0], img.shape[1]  # 注意:CV是高宽不是宽高

    radian = math.radians(angle)  # 角度转弧度
    new_w = abs(w * math.cos(radian)) + abs(h * math.sin(radian))  # 要加绝对值!!!!
    new_h = abs(h * math.cos(radian)) + abs(w * math.sin(radian))  # 要加绝对值!!!!!!!!

    # 第二步:计算新关键点位置
    x1, y1, x2, y2, x3, y3 = point_box
    x1, y1, x2, y2, x3, y3 = x1 * w, y1 * h, x2 * w, y2 * h, x3 * w, y3 * h  # 对归一化的数据进行还原

    old_center = w / 2, h / 2
    x1, y1 = rotate_point_on_point((x1, y1), old_center, angle)  # 计算旋转后关键点坐标
    x2, y2 = rotate_point_on_point((x2, y2), old_center, angle)
    x3, y3 = rotate_point_on_point((x3, y3), old_center, angle)

    new_o_x, new_o_y = (new_w - w) / 2, (new_h - h) / 2  # 新坐标系与原坐标系的差值
    x1, y1, x2, y2, x3, y3 = x1 + new_o_x, y1 + new_o_y, x2 + new_o_x, y2 + new_o_y, x3 + new_o_x, y3 + new_o_y

    # 第三步:顺时针旋转,rotate_bound保证图像旋转后完整,确保整个图都在视野范围
    rotated = imutils.rotate_bound(img, angle)

    # 第四步:裁掉空像素,并重新定位原点位置
    rotated, (o_x, o_y) = crop_img_empty(rotated)
    x1, y1, x2, y2, x3, y3 = int(x1 - o_x), int(y1 - o_y), int(x2 - o_x), int(y2 - o_y), int(x3 - o_x), int(y3 - o_y)
    # 预览结果
    cv2.circle(rotated, (x1, y1), 1, (0, 0, 255), 2)
    cv2.circle(rotated, (x2, y2), 1, (0, 255, 0), 2)
    cv2.circle(rotated, (x3, y3), 1, (255, 0, 0), 2)
    cv2.imshow("Rotated Without Cropping", rotated)
    cv2.waitKey(10)

    return rotated, (x1, y1, x2, y2, x3, y3)


# 计算某点绕另一点顺时针旋转后位置
# 输入:动点、中心点、角度
# 输出:动点新坐标
def rotate_point_on_point(point, center, angle):
    src_x, src_y = point
    center_x, center_y = center
    radian = math.radians(angle)
    # 顺时针
    dest_x = (src_x - center_x) * math.cos(radian) - (src_y - center_y) * math.sin(radian) + center_x
    dest_y = (src_x - center_x) * math.sin(radian) + (src_y - center_y) * math.cos(radian) + center_y
    # 逆时针
    # dest_x = (src_x - center_x) * math.cos(radian) + (src_y - center_y) * math.sin(radian) + center_x
    # dest_y = (src_y - center_y) * math.cos(radian) - (src_x - center_x) * math.sin(radian) + center_y

    return int(dest_x), int(dest_y)

# 裁剪图像空白区域
# 输入:cv图片对象
# 输出:裁剪后图片(cv),原点坐标偏移量(x, y)
def crop_img_empty(ImageArray):
    # image = Image.fromarray(cv2.cvtColor(ImageArray,cv2.COLOR_BGR2RGB))  # 打开tiff图像
    row = ImageArray.shape[0]
    col = ImageArray.shape[1]
    # print(row, col)
    # 先计算所有图片的裁剪范围,然后再统一裁剪并输出图片
    x_left = row
    x_top = col
    x_right = 0
    x_bottom = 0
    # 上下左右范围
    """
    Image.crop(left, up, right, below)
    left:与左边界的距离
    up:与上边界的距离
    right:还是与左边界的距离
    below:还是与上边界的距离
    简而言之就是,左上右下。
    """

    for r in range(row):
        for c in range(col):
            # if ImageArray[row][col][0] < 255 or ImageArray[row][col][0] ==0:
            if ImageArray[r][c][0] < 255 and ImageArray[r][c][0] != 0:  # 外框有个黑色边框,增加条件判断
                if x_top > r:
                    x_top = r  # 获取最小x_top
                if x_bottom < r:
                    x_bottom = r  # 获取最大x_bottom
                if x_left > c:
                    x_left = c  # 获取最小x_left
                if x_right < c:
                    x_right = c  # 获取最大x_right
    print(x_left, x_top, x_right, x_bottom)
    # 原为保留-5的裕量(如x_left - 5)。此处为了保证精度而去掉
    # cropped = image.crop((x_left, x_top, x_right, x_bottom))  # (left, upper, right, lower) PIL裁剪
    cropped = ImageArray[x_top:x_bottom, x_left:x_right]  # CV裁剪
    # cropped.save(r"C:\Users\Administrator\Desktop\out_cut_bg\{}.png".format(imageName[:-4], i))
    print("completed!")

    return cropped, (x_left, x_top)


if __name__ == '__main__':
    image = cv2.imread("0.png")
    point_location = (0.2, 0.38, 0.25, 0.45, 0.35, 0.61)
    rotate_angle = 90

    # rotate_img_location(image, rotate_angle, point_location)
    for i in range(360):
        rotate_img_location(image, i, point_location)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值