python 中使用tkinter构建一个图片的剪切器-附源码

news2024/9/20 9:33:01

由于项目需要,需要构建一个间的软件,方便查看图片的剪切的位置,并对其中的图像进行分析,实现如下的功能

  1. 简单的UI
  2. 加载图片
  3. 剪切图片
  4. 显示剪切后的图片
  • 针对图片的内容进行识别
  • 图片质量分析
    在这里插入图片描述

前端的具体代码如下,

有需要其他功能的,需定制化开发的,得加钱

import tkinter as tk  
from tkinter import filedialog  , Toplevel, Label 
from PIL import Image, ImageTk  
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg  
from matplotlib.figure import Figure  
from matplotlib.patches import Rectangle  
import matplotlib.pyplot as plt 



""" 

v8.修改整体的布局

"""

def img_analysis(img_name):
    img=cv2.imread(filename)
    part_img=img[540:673,371:702]##y1,y2,x1,x2    
    img_grey=cv2.cvtColor(part_img,cv2.COLOR_RGB2GRAY)#灰度图片#COLOR_BGR2GRAY  COLOR_RGB2GRAY IMREAD_GRAYSCALE
    img_grey_draw=img_grey#用于画图    
    hist = cv2.calcHist([img_grey],[0],None,[256],[0,255])  # 应用高斯模糊,以减少图像噪声  #统计直方图数据
    ret, thresh = cv2.threshold(img_grey, 80, 255, cv2.THRESH_BINARY)  #80# 应用二值化 
    # ------------计算黑色像素的数量
    black_pixels = np.count_nonzero(thresh == 0)# 计算黑色像素的数量    
    total_pixels = thresh.shape[0] * thresh.shape[1]# ------------计算总的像素数量
    black_ratio = black_pixels / total_pixels# ------------计算黑色像素的占比print(f"黑色像素的占比: {black_ratio:.4f}")   
    # 数据
    black = black_ratio*100
    white = 100-black
    # 标签
    labels = ['Black', 'White']    
    edges = cv2.Canny(thresh, threshold1=100, threshold2=200)# 应用Canny边缘检测    
    contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)# 寻找轮廓    
    cv2.drawContours(img_grey_draw, contours, -1, (0, 255, 0), 3)# 绘制轮廓

#new windows to show the feature of opencv

class ImageGridWindow(Toplevel):  
    def __init__(self, master, images):  
        super().__init__(master)  
        self.title("Image Grid")  
        # 返回按钮  
        self.return_button = tk.Button(self, text="Return", command=self.destroy)  
        self.return_button.pack(side=tk.BOTTOM, fill=tk.X, pady=10)  

        # 假设images是一个包含图片路径的列表,且长度为9  
        self.grid_size = 3  
        self.create_widgets(images)   
  
    def create_widgets(self, images):  
        for i, img_path in enumerate(images):  
            # 这里假设所有图片大小相同,或者您已经根据需要进行了调整  
            img = Image.open(img_path)  
            img = img.resize((100, 100), Image.ANTIALIAS)  # 假设每个图片调整为100x100  
            photo = ImageTk.PhotoImage(img)   
            label = Label(self, image=photo)  
            label.image = photo  # 避免垃圾回收  
            row, col = divmod(i, self.grid_size)  
            label.grid(row=row, column=col, padx=5, pady=5) 


#Everybody to reset your data. 
class ImageLabelerApp:  
    def __init__(self, root):  
        self.root = root  
        self.root.title("Image Labeler")  
        #------------------------ 顶部按钮 
        # 创建一个新的框架用于grid布局  
        top_frame = tk.Frame(root)  
        top_frame.pack(fill=tk.X, expand=False)    

        self.load_button = tk.Button(top_frame, text="Load Image", command=self.load_image)  
        self.load_button.grid(row=0, column=1, padx=10,pady=10)  
        # Tkinter reset button  
        self.reset_button = tk.Button(top_frame, text="Reset", command=self.reset) 
        self.reset_button.grid(row=0, column=2, padx=10) 
        # Tkinter button  
        self.button = tk.Button(top_frame, text="Show Cropped Image", command=self.show_cropped_image)  
        self.button.grid(row=0, column=3, padx=10)  
        # 添加打开图片网格的按钮  
        self.grid_button = tk.Button(top_frame, text="Open Image Grid", command=self.open_image_grid)  
        self.grid_button.grid(row=0, column=4,  padx=10)  
 
        #------------------------  中部图片
            # 底部左右两个图像显示区域  
        bottom_images_frame = tk.Frame(root)  
        bottom_images_frame.pack(fill=tk.BOTH, expand=True)  
        # ------------right_image_label  Label for cropped image    
        self.cropped_label = tk.Label(bottom_images_frame, bg='white')  #, width=40, height=20
        self.cropped_label.grid(row=0, column=1, sticky='nsew', padx=5, pady=5)  
        #------------left image 
       #left_image_label  = tk.Label(bottom_images_frame, bg='white', width=40, height=20)  
        #left_image_label.grid(row=0, column=0, sticky='nsew', padx=5, pady=5)
        self.fig, self.ax = plt.subplots(figsize=(6, 6))  
        self.canvas = FigureCanvasTkAgg(self.fig, master=bottom_images_frame)  
        self.canvas.get_tk_widget().grid(row=0, column=0, sticky='nsew', padx=5, pady=5) 
 
        # 添加文本框来显示矩形坐标 


        # #------------------------  底部文字
        self.coord_label = tk.Label(root, text="No rectangle selected", width=30, height=20)  
        self.coord_label.pack(side=tk.BOTTOM, fill=tk.X,padx=10) 

        self.img_path = None  
        self.img = None  
        self.rect = None  
        self.drawing = False  
        self.cropped_img = None  
        self.cropped_photo = None   
  
        # Connect events  
        self.canvas.mpl_connect('button_press_event', self.on_button_press)  
        self.canvas.mpl_connect('button_release_event', self.on_button_release) # 绑定事件以在鼠标释放时更新坐标  
        self.canvas.mpl_connect('motion_notify_event', self.on_mouse_move)                  
 
  
    def load_image(self):  
        path=filedialog.askopenfilename(filetypes=[("Image files", "*.jpg")])#;*.png;*.gif  09-07 only jpg,
        self.img_path = path  
        self.img = plt.imread(path)  
        self.ax.imshow(self.img)  
        self.ax.set_title('Original Image')  
        self.canvas.draw()  
  
    def on_button_press(self, event):  
        if not self.rect and event.button == 1:  
            self.x0, self.y0 = event.xdata, event.ydata  
            self.drawing = True  
  
    def on_mouse_move(self, event):  
        if self.drawing:  
            x1, y1 = event.xdata, event.ydata  
            if self.rect is None:  
                self.rect = Rectangle((self.x0, self.y0), 0, 0, edgecolor='r', facecolor='none')  
                self.ax.add_patch(self.rect)  
  
            self.rect.set_width(x1 - self.x0)  
            self.rect.set_height(y1 - self.y0)  
            self.canvas.draw()  
  
    def on_button_release(self, event):  
        if self.drawing and event.button == 1:  
            self.drawing = False  
        # -----------------检查是否正在绘制矩形  -----------------
        if self.rect is not None:  
            # 获取矩形的坐标(注意:这里获取的是数据坐标,不是像素坐标)  
            x0, y0 = self.rect.get_xy()  
            width, height = self.rect.get_width(), self.rect.get_height()  
            x1, y1 = x0 + width, y0 + height  
            # 格式化坐标字符串  
            coord_str = f"Rectangle Coordinates: ({x0:.2f}, {y0:.2f}) to ({x1:.2f}, {y1:.2f})"  
            # 更新文本框的文本  
            self.coord_label.config(text=coord_str) 

    def show_cropped_image(self):  
        if self.rect:  
            x0, y0 = int(self.rect.get_x()), int(self.rect.get_y())  
            width, height = int(self.rect.get_width()), int(self.rect.get_height())             
            cropped_img = self.img[y0:y0+height, x0:x0+width]  
            self.cropped_img = Image.fromarray(cropped_img)  
            self.cropped_photo = ImageTk.PhotoImage(self.cropped_img)  
            self.cropped_label.config(image=self.cropped_photo)  
            self.cropped_label.image = self.cropped_photo  # Keep a reference  
    def reset(self):  
        # 清除Axes上的所有内容(包括矩形)  
        self.ax.clear()  
        self.ax.imshow(self.img)  # 重新加载原始图像  
        self.ax.set_title('Original Image')  
        self.cropped_img = None  
        self.cropped_photo = None         
        self.rect = None   # 如果之前绘制了矩形,则将其设置为None           
        self.canvas.draw()# 重新绘制画布 
    def open_image_grid(self):  
        # 这里需要一个图片列表,这里只是示例  
        # 假设您已经有了一个包含9个图片路径的列表  
        image_paths = [  
            'path/to/image1.jpg', 'path/to/image2.jpg', 'path/to/image3.jpg',  
            'path/to/image4.jpg', 'path/to/image5.jpg', 'path/to/image6.jpg',  
            'path/to/image7.jpg', 'path/to/image8.jpg', 'path/to/image9.jpg'  
        ]  
        ImageGridWindow(self.root, image_paths) 
def main():  
    root = tk.Tk()  
    app = ImageLabelerApp(root)  
    root.mainloop()  
  
if __name__ == '__main__':  
    main()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2114547.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

5.8 切换保护模式(5)

1 首先测试 了, 之前的代码 是 没有问题的,确实会 停在 汇编处。 1 首先是 设置 除了 CS 之外的寄存器 进入 32为模式 //为了使除了 cs 之外的 段选择寄存器也进入 32位模式。mov $16, %ax // 16为数据段选择子mov %ax, %dsmov %ax, %ssmov %ax, %esmov…

axure动态面板

最近转管理岗了,作为项目负责人,需要常常与客户交流沟通,这时候画原型的能力就是不可或缺的本领之一了,关于axure可能很多it行业者都不是很陌生,简单的功能呢大家就自行去摸索,我们这次从动态面板开始讲起。…

C语言进阶版第8课—指针(2)

文章目录 1. 数组名的理解2. 指针访问数组3. 一维数组传参本质4. 冒泡排序5. 二级指针6. 指针数组7. 指针数组模拟二维数组 1. 数组名的理解 sizeof(数组名)— 这里的数组名代表整个数组,计算的也是整个数组的大小&数组名 — 这里的数组名…

adb devices找不到设备

重新启动ADB服务。在命令行窗口中输入adb kill-server,然后再输入adb start-server,重新启动ADB服务 再重启插入手机连入电脑的线,再次启动开发模式。 在在命令行窗口中输入adb version

【大数据】深入浅出Hadoop,干货满满

【大数据】深入浅出Hadoop 文章脉络 Hadoop HDFS MapReduce YARN Hadoop集群硬件架构 假设现在有一个PB级别的数据库表要处理。 在单机情况下,只能升级你的内存、磁盘、CPU,那么这台机器就会变成 “超算”,成本太高,商业公司肯…

Java基础知识回顾-匿名内部类

文章目录 知识学习实现案例第一步、父类定义方法第二步、子类中定义匿名内部类第三步、执行方法 最近在复习Java知识点的时候,在看匿名内部类,记录下来,方便备查。 知识学习 匿名内部类,即一种特殊的局部内部类,不需要…

java opencv no opencv_java490 in java.library.path

java使用opencv处理图片,idea运行程序,报错异常信息: Exception in thread "main" java.lang.UnsatisfiedLinkError: no opencv_java490 in java.library.path: /Users/carter/Library/Java/Extensions:/Library/Java/Extensions:…

Canvas Confetti - 免费开源的五彩纸屑飞舞特效的 JS 库,多用于在网页上实现欢乐庆祝的场景

今天看科技周刊看到的一个酷炫的动效库,使用简单,视觉效果很好,推荐给大家。 Canvas Confetti 是一个基于 JavaScript 的特效动画库,可以在网页界面上轻松地实现五彩纸屑飞舞的庆祝场景特效。这个特效库封装了几种酷炫的特效&…

Linux系统之实现dhcp功能(Implementation of DHCP Function in Linux System)

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:Linux运维老纪的首页…

tabBar设置底部菜单以及选项iconfont图标

1.tabBar设置底部菜单 在官网里面可以了解到tabBar组件的一些知识和注意点: 需要给页面设置一个底部导航的话可以在pages.json里面设置一个tabBar标签,在其里面设置pagePath和text属性。 可以看的pagePath是跳转的地址,text是下面导航的文字…

string详解

Golang详解string 文章目录 Golang详解stringGolang中为什么string是只读的?stirng和[]byte的转化原理[]byte转string一定需要内存拷贝吗?字符串拼接性能测试 Golang中为什么string是只读的? 在Go语言中,string其实就是一个结构体…

SSM项目使用AOP技术进行日志记录

本步骤只记录完成切面所需的必要代码 本人开发中遇到的问题: 切面一直切不进去,最后发现需要在springMVC的核心配置文件中中开启注解驱动才可以,只在spring的核心配置文件中开启是不会在web项目中生效的。 之后按照下面的代码进行配置&…

【Python篇】PyQt5 超详细教程——由入门到精通(中篇二)

文章目录 PyQt5超详细教程前言第7部分:生成图表与数据可视化7.1 matplotlib 与 PyQt5 的结合7.2 在 PyQt5 中嵌入 matplotlib 图表示例 1:嵌入简单的 matplotlib 图表代码详解: 7.3 动态生成图表示例 2:动态更新图表代码详解&…

jmeter之TPS计算公式

需求: 如何确定环境当中的TPS指标 PV:(Page View)即页面访问量,每打开一次页面PV计数1,刷新页面也是。PV只统计页面访问次 数。 UV(Unique Visitor),唯一访问用户数,用来衡量真实访问网站的用户数量。 一般…

在亚马逊云科技上利用Graviton4代芯片构建高性能Java应用(上篇)

简介 在AI迅猛发展的时代,芯片算力对于模型性能起到了至关重要的作用。一款能够同时兼具高性能和低成本的芯片,能够帮助开发者快速构建性能稳定的生成式AI应用,同时降低开发成本。今天小李哥将介绍亚马逊推出的4代高性能计算处理器Gravition…

【Python 千题 —— 算法篇】无重复字符最长子段

Python 千题持续更新中 …… 脑图地址 👉:⭐https://twilight-fanyi.gitee.io/mind-map/Python千题.html⭐ 题目背景 在编程过程中,处理字符串的任务时常遇到,其中一个经典问题是查找无重复字符的最长子串。这在很多应用场景中…

Linux网络测试和故障排查命令

文章目录 ping 命令常用选项:使用示例:域名解析和 IP 地址响应数据停止 ping 命令统计数据延迟统计 traceroute 命令常用选项:使用示例:命令执行:路由节点详情: mtr 命令使用示例:使用结果详解输…

【持续更新】Adoobe Acroobat Pro DC 2024 (v24.3.20054)最新修改版

Adoobe Acroobat Pro DC 拥有智能工具,为您的沟通能力增添更多力量。使用包含丰富媒体元素的PDF文件进行创建与编辑,更加安全地分享信息,并且更高效地收集反馈意见。这款先进的软件程序是商务专业人士的理想选择,能够创建、合并、…

jmeter之ForEach控制器使用

ForEach控制器作用: 一般和用户自定义变量或者正则表达式提取器配合使用,读取返回结果中一系列相关的变量值,该控制器下的取样器都会被执行一次或多次,每次读取不同的变量值(类似python当中的for语句,用来遍历操作) 本节代码已上…

Spring6详细学习笔记(IOC+AOP)

一、Spring系统架构介绍 1.1、定义 Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器(框架)。Spring官网 Spring是一款主流的Java EE 轻量级开源框架,目的是用于简化Java企业级引用的开发难度和开发周期。从简单性、可测试性和松耦…