samurai 旋转分类增强

samurai 旋转分类增强

samurai_xuanzhuan.py
import glob
import cv2
import numpy as np
import json
import os

import time


class Time_Str:
    def __init__(self):
        self.last_time, self.counter = '', 0

    def get_time(self, fmt="%m%d_%H%M_%S"):
        now_time = time.strftime(fmt)
        self.counter += 1
        if now_time != self.last_time:
            self.last_time, self.counter = now_time, 0
        return f"{now_time}_{self.counter}"

    def get_time_sec(self):
        return self.get_time("%m%d_%H%M_%S")

    def get_time_mm(self):
        return self.get_time("%m%d_%H%M")

    def get_time_hh(self):
        return self.get_time("%m%d_%H")
def rotate_image(image, angle, center):
    h, w = image.shape[:2]
    M = cv2.getRotationMatrix2D(center, angle, 1.0)
    rot = cv2.warpAffine(image, M, (w, h), flags=cv2.INTER_LINEAR, borderValue=(0, 0, 0))
    return rot, M

def rotate_points(points, M):
    pts = np.array(points, dtype=np.float32)
    ones = np.ones((pts.shape[0], 1), dtype=np.float32)
    pts_ex = np.hstack([pts, ones])
    rotated = M.dot(pts_ex.T).T
    return rotated

def get_AABB(rotated_contour):
    xs = rotated_contour[:, 0]
    ys = rotated_contour[:, 1]
    x1, y1 = int(np.min(xs)), int(np.min(ys))
    x2, y2 = int(np.max(xs)), int(np.max(ys))
    return (x1, y1, x2, y2)

def crop_AABB(rotated_img, box):
    x1, y1, x2, y2 = box
    x1, y1 = max(0, x1), max(0, y1)
    x2, y2 = min(rotated_img.shape[1], x2), min(rotated_img.shape[0], y2)
    if x2 <= x1 or y2 <= y1:
        return None
    return rotated_img[y1:y2, x1:x2]

def draw_center(img, center, color, text):
    pt = (int(round(center[0])), int(round(center[1])))
    cv2.circle(img, pt, 5, color, -1)
    cv2.putText(img, text, (pt[0]+6, pt[1]-6), cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 1, cv2.LINE_AA)


def visualize_contour(img, contour, winname="contour_vis", save_path=None):
    """
    在图像上可视化 contour(绿色),并显示每个点的 index(白色)
    """
    vis = img.copy()
    cnt_int = contour.astype(np.int32)

    # 绘制 contour
    cv2.polylines(vis, [cnt_int], True, (0, 255, 0), 2)

    # 标注每个点
    for i, (x, y) in enumerate(cnt_int):
        cv2.circle(vis, (x, y), 4, (0, 0, 255), -1)  # 点
        cv2.putText(vis, str(i), (x + 5, y - 5),
                    cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1, cv2.LINE_AA)

    # 显示
    try:
        cv2.imshow(winname, vis)
        cv2.waitKey(0)
        cv2.destroyWindow(winname)
    except:
        pass

if __name__ == '__main__':
    base_dir = r"D:\data\chantu\1120"   # 改成你的路径

    img_files = ['%s/%s' % (i[0].replace("\\", "/"), j) for i in os.walk(base_dir) for j in i[-1] if
                  j.lower().endswith(('jpg', 'xjson', 'xpeg'))]

    out_dir = "rotated_crop_results_viz"
    os.makedirs(out_dir, exist_ok=True)

    name_get=Time_Str()
    for img_path in img_files:
        basename = os.path.splitext(os.path.basename(img_path))[0]
        json_path = os.path.splitext(img_path)[0] + '.json'
        if not os.path.exists(json_path):
            print("No json for", img_path)
            continue
        print(json_path)
        with open(json_path, "r", encoding="utf-8") as f:
            data = json.load(f)

        img = cv2.imread(img_path)

        vis_orig = img.copy()

        # 找到第一个 contour
        contour = None
        for s in data.get("shapes", []):
            if s.get("shape_type") == "contour":
                contour = np.array(s["points"], dtype=np.int32)
                break
        if contour is None :
            print("No valid contour in", json_path)
            continue

        cv2.polylines(vis_orig, [contour], isClosed=True, color=(0,255,0), thickness=2)

        x1, y1, w, h = cv2.boundingRect(contour)
        bbox = [x1, y1, x1 + w, y1 + h]

        # 3. 绘制 bounding box(红色)
        cv2.rectangle(vis_orig, (bbox[0], bbox[1]), (bbox[2], bbox[3]), (0, 0, 255), 2)
        if 0:
            center = contour.mean(axis=0)  # [cx, cy]
            cx, cy = float(center[0]), float(center[1])
            center = (cx, cy)

        center = (x1 + w // 2, y1 + h // 2)

        draw_center(vis_orig, center, (0, 0, 255), "use")
        cv2.imshow('asf',vis_orig)

        # 对每个角度做可视化
        for angle in range(0, 360, 15):
            rotated_img, RM = rotate_image(img, angle, center)
            rotated_contour = rotate_points(contour, RM)
            # AABB
            x1, y1, x2, y2 = get_AABB(rotated_contour)
            crop_img = crop_AABB(rotated_img, (x1, y1, x2, y2))

            # 可视化旋转后图像(contour + AABB + center)
            vis_rot = rotated_img.copy()
            cv2.polylines(vis_rot, [rotated_contour.astype(np.int32)], True, (0,255,0), 2)
            cv2.rectangle(vis_rot, (x1, y1), (x2, y2), (0,0,255), 2)
            draw_center(vis_rot, center, (255,0,255), "center")
            # 在图上写角度信息
            cv2.putText(vis_rot, f"angle: {angle}", (10,30), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (0,255,255), 2, cv2.LINE_AA)

            # 显示 crop(若存在)
            if crop_img is None:
                crop_preview = np.zeros((100,200,3), dtype=np.uint8)
                cv2.putText(crop_preview, "invalid crop", (10,50), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0,0,255), 2)
            else:
                crop_preview = crop_img

            # 保存文件(包含源名与角度)
            # crop_save = os.path.join(out_dir, f"{basename}_crop_{name_get.get_time_mm()}.jpg")
            crop_save = os.path.join(out_dir, f"{name_get.get_time_mm()}.jpg")
            # cv2.imwrite(rot_save, rotated_img)

            cv2.imshow('rotated_img',rotated_img)
            cv2.imshow('vis_rot',vis_rot)
            if crop_img is not None:
                cv2.imwrite(crop_save, crop_img)

            # 键控:任意键继续,s = 保存(文件已保存), q = 跳到下张图, e = 退出程序
            k2 = cv2.waitKey(1) & 0xFF
            if k2 == ord('e'):
                print("Exit by user")
                cv2.destroyAllWindows()
                exit(0)
            if k2 == ord('q'):
                # 退出当前图片角度循环,进入下一个图片
                cv2.destroyWindow("rotated_vis")
                cv2.destroyWindow("crop_preview")
                break
            # 其它按键默认继续到下一个角度
        print(f"[{basename}] Done and saved to {out_dir}")
    cv2.destroyAllWindows()

    print("All files processed.")

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AI算法网奇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值