批量手工截图的python程序

运行后,拖动鼠标画框,按q取消框,按c截取框中内容并保存,按f选择下一张图片,按e退出程序

import cv2
import os
import tkinter as tk
from tkinter import filedialog


class Cropper:
    def __init__(self, image):
        self.image = image
        self.clone = image.copy()
        self.temp_clone = image.copy()
        self.startX, self.startY, self.endX, self.endY = 0, 0, 0, 0
        self.cropping = False
        self.rectangles = []
        self.rect_size_text = ""  # 用于保存框的尺寸文本

    def display_rectangle_size(self, key_pressed):
        if self.cropping or (key_pressed == ord("c") or key_pressed == ord("q")):
            rect_height = abs(self.endY - self.startY)
            rect_width = abs(self.endX - self.startX)
            self.rect_size_text = f"{rect_height} x {rect_width}"
            cv2.putText(self.temp_clone, self.rect_size_text, (self.startX, self.startY - 10),
                        cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
        else:
            self.rect_size_text = ""

    def click_and_crop(self, event, x, y, flags, param):
        self.temp_clone = self.clone.copy()  # 在任何鼠标事件发生时更新临时克隆图像

        # 添加水平和垂直定位线
        cv2.line(self.temp_clone, (x, 0), (x, self.temp_clone.shape[0]), (0, 0, 255), 1)
        cv2.line(self.temp_clone, (0, y), (self.temp_clone.shape[1], y), (0, 0, 255), 1)

        if event == cv2.EVENT_LBUTTONDOWN:
            self.startX, self.startY = x, y
            self.endX, self.endY = x, y
            self.cropping = True

        elif event == cv2.EVENT_MOUSEMOVE:
            if self.cropping:
                self.endX, self.endY = x, y
                self.display_rectangle_size(cv2.EVENT_MOUSEMOVE)  # 显示框的尺寸
                cv2.rectangle(self.temp_clone, (self.startX, self.startY), (self.endX, self.endY), (0, 255, 0), 2)


        elif event == cv2.EVENT_LBUTTONUP:
            if self.cropping:
                self.endX, self.endY = x, y
                self.cropping = False
                cv2.rectangle(self.clone, (self.startX, self.startY), (self.endX, self.endY), (0, 255, 0), 2)
                self.rectangles.append(((self.startX, self.startY), (self.endX, self.endY)))

        # 绘制尺寸信息
        if self.cropping or self.rect_size_text != "":
            cv2.putText(self.temp_clone, self.rect_size_text, (self.startX, self.startY - 10),cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
        cv2.imshow('Original Image', self.temp_clone)

def main():
    cropper = None
    image = None
    save_counter = 1
    cropped_image_window = None  # 用于显示剪裁后的图片的窗口

    while True:
        key = cv2.waitKey(1) & 0xFF
        if key == ord("f") or image is None:
            root = tk.Tk()
            root.withdraw()  # 隐藏主窗口,只显示文件对话框
            image_path = filedialog.askopenfilename(title="选择图片",
                                                    filetypes=[("Image files", "*.jpg *.jpeg *.png *.bmp")])
            root.destroy()  # 关闭临时的 Tkinter 窗口

            if image_path:
                if cropper is not None:
                    cv2.destroyWindow('Original Image')  # 关闭之前的窗口
                    if cropped_image_window is not None:
                        if cv2.getWindowProperty('Cropped Image', cv2.WND_PROP_VISIBLE) > 0:
                            cv2.destroyWindow('Cropped Image')  # 仅在窗口可见时销毁
                    cropper.rectangles = []  # 清除之前的框
                    save_counter = 1  # 重置剪裁图片计数器

                image = cv2.imread(image_path)
                cv2.namedWindow('Original Image', cv2.WINDOW_NORMAL)  # 设置为可调整窗口大小
                cv2.imshow('Original Image', image)

                print("点击鼠标左键确定第一个点,按住鼠标左键拖动鼠标,放开鼠标左键确定框的第二个点。"
                      "按下 'c' 键确认剪裁,按下 'q' 键取消剪裁,按下 'e' 键退出程序。")

                cropper = Cropper(image)
                cv2.setMouseCallback('Original Image', cropper.click_and_crop)


        elif key == ord("c"):

            if cropper is not None and len(cropper.rectangles) > 0:
                startX, startY = cropper.rectangles[-1][0]
                endX, endY = cropper.rectangles[-1][1]

                # 确保起始点在左上角,结束点在右下角
                if startX > endX:
                    startX, endX = endX, startX
                if startY > endY:
                    startY, endY = endY, startY

                cropped_image = image[startY:endY, startX:endX]
                # 获取原始图片的文件名(不带路径)
                image_filename = os.path.basename(image_path)
                # 构造新的文件名
                cropped_image_filename = f"{os.path.splitext(image_filename)[0]}_cropped_image_{save_counter}.jpg"
                cv2.imshow("Cropped Image", cropped_image)
                # 在剪裁后的图片上显示框的尺寸
                rect_height = abs(endY - startY)
                rect_width = abs(endX - startX)
                cropper.display_rectangle_size(cv2.EVENT_LBUTTONUP)
                size_text = cropper.rect_size_text
                cv2.putText(cropped_image, size_text, (10, 30),
                            cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
                cv2.imwrite(cropped_image_filename, cropped_image)
                print(f"剪裁后的图片 {cropped_image_filename} 已保存")
                save_counter += 1
                # 清除上一次的框
                cropper.clone = image.copy()
                cv2.imshow('Original Image', cropper.clone)
                # 在新的窗口中显示剪裁后的图片
                if cropped_image_window is not None:
                    cv2.destroyWindow('Cropped Image')
                cv2.namedWindow('Cropped Image', cv2.WINDOW_NORMAL)
                cv2.imshow('Cropped Image', cropped_image)
                cropped_image_window = True
        elif key == ord("q"):
            if cropper is not None:
                # 清除当前绘制的框和尺寸文本
                cropper.clone = image.copy()
                cropper.display_rectangle_size(key)
                cv2.imshow('Original Image', cropper.clone)

                # 清除尺寸文本
                cropper.rect_size_text = ""

        elif key == ord("e"):
            break

    cv2.destroyAllWindows()


if __name__ == "__main__":
    main()

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值