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

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

  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_GRAYSCALEimg_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*100white = 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 opencvclass 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=20self.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.xdnf.cn/news/1527532.html

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

相关文章

频谱分析仪和人工电源网络

安泰小课堂里面有详细的频谱分析仪的教程,可以学习: 【快速上手实操秘籍|频谱分析仪超详细基础操作|建议收藏】https://www.bilibili.com/video/BV1Wu4y197LW?vd_source3cc3c07b09206097d0d8b0aefdf07958 、、、、、、、、、、、、、、、、、、、、、…

Java 面试题:通过JProfile排查OOM问题 内存溢出与内存泄漏问题 --xunznux

文章目录 如何通过JProfile排查OOM或内存泄漏问题1、启动工具观测程序执行状态2、使用默认设置采样3、查看memory,Run GC无效4、查看 Live Memory发现两个byte大数组存在5、通过快照查看堆中的内存使用情况6、找到Full GC无法清除的对象通过大对象列表定位内存泄漏问…

Linux-【组管理、权限管理、定时任务调度】

目录 前言 Linux组基本介绍 文件/目录 所有者 查看文件 所有者 修改文件所有者 文件/目录 所在组 修改文件/目录 所在组 其它组 改变用户所在组 权限的基本介绍 rwx权限 rwx作用到文件 rwx作用到目录 修改权限 第一种方式:、-、变更权限 第二种方式…

openwrt的旁路模式无法访问国内网站

防火墙: 常规设置-> 区域: lan-> wan :编辑 IP 动态伪装:勾选

关于 QImage原始数据格式与cv::Mat原始数据进行手码数据转换 的解决方法

若该文为原创文章,转载请注明原文出处 本文章博客地址:https://hpzwl.blog.csdn.net/article/details/141996117 长沙红胖子Qt(长沙创微智科)博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV…

久久公益节||“携手万顺叫车一起做公益”

99公益日是由腾讯公益联合多家公益组织、企业及社会各界爱心人士共同举办的年度大型公益活动。随着99公益日的到来,同悦社工诚挚地邀请了万顺叫车一起参与今年的公益活动,共同为社会公益事业贡献力量。 在本次公益倡导活动中,万顺叫车将发挥其…

无人机飞控之光流知识小结

要完成飞行器的定位,则必须要有位置的反馈数据。在户外,我们一般使用GPS作为位置传感器,然而,在室内,GPS无法使用,要完成定位功能,可以选用光流传感器。 本讲主要介绍如何通过下视摄像头估计飞…

AtCoder ABC 359 F 题解

本题要看出性质并进行验证,程序难度低。(官方 Editorial 似乎没有写证明过程?难道是过于显而易见了吗…) 题意 给你一个数组 a a a,对于一棵 n n n 个节点的树 T T T, d i d_i di​ 为每个节点的度&am…

Gitness 基础安装

文章目录 Docker 安装注册账户创建项目导入已有仓库配置 Github Token同步源代码仓库 官方链接 Gitness was the next step in the evolution of Drone, from continuous integration to source code hosting, bringing code management and pipelines closer together. Gitnes…

八、Maven总结

1.为什么要学习Maven? 2.Maven 也可以配华为云和腾讯云等。 3.IDEA整合Maven 4.IDEA基于Maven进行工程的构建 5.基于Maven进行依赖管理(重点) 6. Maven的依赖传递和依赖冲突 7. Maven工程继承和聚合 8.仓库及查找顺序

解决面板安装Node.js和npm后无法使用的问题

使用面板(BT)安装Node.js和npm后,可能会遇到如下问题:即使成功安装了Node.js和npm,服务器仍提示“未安装”,在命令行中使用 node -v 或 npm -v 也没有任何响应。这种问题通常是由于环境变量配置错误或路径问…

【Hot100】LeetCode—215. 数组中的第K个最大元素

目录 1- 思路快速选择 2- 实现⭐215. 数组中的第K个最大元素——题解思路 3- ACM实现 原题连接:215. 数组中的第K个最大元素 1- 思路 快速选择 第 k 大的元素的数组下标: int target nums.length - k 1- 根据 partition 分割的区间来判断当前处理方式…

使用Node-API进行线程安全开发

一、Node-API线程安全机制概述 Node-API线程安全开发主要用于异步多线程之间共享和调用场景中使用,以避免出现竞争条件或死锁。 1、适用场景 异步计算:如果需要进行耗时的计算或IO操作,可以创建一个线程安全函数,将计算或IO操作放…

Linux block_device gendisk和hd_struct到底是个啥关系

本文的源码版本是Linux 5.15版本,有图有真相: 1.先从块设备驱动说起 安卓平台有一个非常典型和重要的块设备驱动:zram,我们来看一下zram这个块设备驱动加载初始化和swapon的逻辑,完整梳理完这个逻辑将对Linux块设备驱…

旅拍景区收银系统+押金原路退回+服装租赁-SAAS本地化及未来之窗行业应用跨平台架构

一、景区旅拍一体化系统 序号系统说明1提成系统用于给照相馆介绍照相拉客的人自动计算提成2押金系统用于服装租赁(汉服租赁),设备租赁 ,支持押金原路退回3收银系统计算每天收银汇总,月度收银汇总,支出4提成…

云原生之高性能web服务器学习(持续更新中)

高性能web服务器 1 Web服务器的基础介绍1.1 Web服务介绍1.1.1 Apache介绍1.1.2 Nginx-高性能的 Web 服务端 2 Nginx架构与安装2.1 Nginx概述2.1.1 Nginx 功能介绍2.1.2 基础特性2.1.3 Web 服务相关的功能 2.2 Nginx 架构和进程2.2.1 架构2.2.2 Ngnix进程结构 2.3 Nginx 模块介绍…

PyInstaller问题解决 onnxruntime-gpu 使用GPU和CUDA加速模型推理

前言 在模型推理时,需要使用GPU加速,相关的CUDA和CUDNN安装好后,通过onnxruntime-gpu实现。 直接运行python程序是正常使用GPU的,如果使用PyInstaller将.py文件打包为.exe,发现只能使用CPU推理了。 本文分析这个问题…

流媒体与直播的基础理论(其一)

欢迎诸位来阅读在下的博文~ 在这里,在下会不定期发表一些浅薄的知识和经验,望诸位能与在下多多交流,共同努力 文章目录 一、流媒体简介二、流媒体协议常见的流媒体协议 三、视频直播原理与流程通用的视频直播模型视频直播链路 一、流媒体简介…

隐私计算实训营:联邦学习在垂直场景的开发实践

纵向联邦学习 纵向联邦学习的参与方拥有相同样本空间、不同特征空间的数据,通过共有样本数据进行安全联合建模,在金融、广告等领域拥有广泛的应用场景。和横向联邦学习相比,纵向联邦学习的参与方之间需要协同完成数据求交集、模型联合训练和…

Openharmony 下载到rk3568实现横屏

前言: Openharmony 源码版本4.1 release 板子:rk3568 1.修改“abilities”中的“orientation”实现横竖屏 entyr->src->module.json5文件里面添加 "orientation": "landscape", 2.修改系统源码属性实现横竖屏切换 通过这…