图片坐标提取软件/图片截图工具/图片坐标点和像素点颜色提取软件/图片坐标获取工具/Python图片坐标获取源码/图片像素坐标获取软件/查看图片点XY坐标(完全开源)
该软件使用python写的,可以提取像素点的坐标还有也能获取像素点的16进制数据RGB565和RGB888(RGB888仅最新的源码才支持),可以单点坐标也可以按键坐标,甚至可以使用简单的左右键配合使用,自动复制到粘贴板,如果图片太大或者太小,也支持图片缩小放大,但是软件会对像素进行处理不建议这么干,截图工具可以截取对应区域的图片,并输出,类似于微信的截图
该软件支持现有常用格式的bmp、jpg、gif和png等格式,也可以自定义xy复制到粘贴板的比例。
程序已经打包成exe文件可直接双击运行
exe文件在以下链接(推荐其他的下载方式支持开源,或者点赞评论不做白嫖怪)(2024.08.15做出修改):
百度网盘链接:https://pan.baidu.com/s/1aoE8RcjAgMZQ7BJ9zaKe1Q?pwd=a8b1
提取码:a8b1
如果需要自己修改,使用pyinstaller -F -w 指令来完成打包
打包步骤是打开cmd窗口,输入:pip install pyinstaller(安装pyinstaller,已经安装可跳过)
其他第三方库安装命令:
安装opencv : pip install opencv-python
安装pillow:pip install pillow
安装ny库:pip install numpy
安装pyperclip库:pip install pyperclip
然后输入pyinstaller -F -w 【文件路径】
例如:pyinstaller -F -w C:\\Users\MSN\Desktop\11\PythonApplication1.py
如果openCV无法打包则可以尝试使用此指令:pyinstaller -F -w C:\\Users\MSN\Desktop\11\ImageToolsv2.0.py --hidden-import opencv-python
也可以参考此链接Python PyInstaller安装和使用教程(详解版) (biancheng.net)
运行平台已经测试过win7,win8,win10,Win11都能运行(V1.7版本以下,V1.9以上可能需要单独下载各自系统的exe文件)
在后面的版本中有些第三方库存在系统兼容性问题,因此对windows各版本单独生成了独立的exe可执行文件,在以下的百度网盘链接中,源码维持不变
最新源码还是粘贴在最下面,加了注释
如有相关问题或者好建议可联系:QQ:1257784610
以下是最新更新展示
这里选择图片格式
截图小功能:
使用说明:
自动获取功能:
鼠标左键单击: 像素坐标鼠标左键按下移动: 矩形坐标鼠标滚轮单击: 像素颜色鼠标右键按下并移动: 贴图坐标
矩形坐标:(左上角X坐标,左上角Y坐标,右下角X坐标,右下Y坐标)
贴图坐标就是一个矩形坐标+放的坐标:(左上角X坐标,左上角Y坐标,右下角X坐标,右下Y坐标,左上角X坐标,左上角Y坐标)(此功能适合嵌入式贴图编程)
像素坐标就是一个点坐标:(X坐标,Y坐标)
Ctrl+鼠标上下滚轮可以缩小放大图片
像素颜色是16进制的RGB565和RGB888,默认是RGB565,勾上后输出RGB888
自动复制是指操作后坐标数据自动拷贝到粘贴板上
转换系数是指:比如我需要把800*600的图坐标放大为1024*768,就往里面输入1024/768 = 1.28,输入1.28并且点击设置xy系数就能获取比例放大的坐标信息,注意这个不会修改图片的任何信息,要保持原来的就输入1,算法是:显示的X坐标 = 获取的X坐标*X比例系数
例如:800 * 1.28 = 1024
把自动获取取消后,单击就是对应的坐标
软件也支持图片快捷键ctrl+鼠标滚轮进行缩小放大,但是不建议缩太小和放太大,除非你的电脑配置顶天,同时此功能会影响最大像素值的大小,放大缩小越多,误差会越大,请慎重使用
使用链接:图片坐标点和像素颜色获取/图片截图小工具_哔哩哔哩_bilibili
相比于第一版,后期更新支持如下
1、支持RGB888和RGB565
2、支持图片自由放大缩小(快捷键ctrl+鼠标滚轮)
3、新增图片复位
4、最大化不会gui布局错误
5、修复部分bug
6、图片放大缩小算法由近邻法修改为面积插值法
2024.04.11更新,版本号到V2.0:
1、新增了鼠标位置在画布中实时更新
2、不再限制图片格式,不用再单独选bmp或者jpg
3、新增代码注释,优化代码变量命名(起码能看懂一点了)
2024.5.20更新,版本号到V2.2:
1、新增了像素和坐标实时显示
2、新增放大缩小百分比显示
3、新增截图小功能
4、优化变量不再使用小数点表示放大缩小倍数
2024.8.15更新,版本号到V2.3:
1、新增十字光标显示
2、修复部分bug
以下是全部代码:
由于时间仓促并没有对代码进行整理,不然的话可以更简洁,由于工作使用的都是C语言,因此代码逻辑很像C语言,如果哪天我有空我会对代码进行整理,编译软件我用的是微软的VS2022,也可以使用Python 3.10版本的IDLE进行编程以下是代码所需的库,有特殊需求的可以自己修改源码
最新的源码可以自己去上面的链接中获取,如果不用RGB888的话,旧版的也够用了
from asyncio.windows_events import NULL
from cgitb import text
import time
import datetime
import tkinter as tk
from unittest import result
import cv2 as cv
import os
import numpy as np
import pyperclip
from PIL import Image
from PIL import ImageTk
from tkinter import filedialog
import sys
sys.setrecursionlimit(100000) #设置递归深度
#像素数必须为双数
'''Start_x = 1
Start_y = 1
End_x = 2
End_y = 2
YRadioVar = 1.0000#Y坐标比例
XRadioVar = 1.0000#X坐标比例
zoomRadioVar = 1.0000#缩放比例
YSetRadioVar = 1.0000#Y坐标比例
XSetRadioVar = 1.0000#X坐标比例
Win_height = 700
Win_width = 1100
Win_heightbuffer = 700
Win_widthbuffer = 1100'''
#whiletimes = 0
class Callback():
def __init__(self):
#初始化所有数据
self.按键坐标 = 1
self.切图坐标 = 2
self.单点坐标 = 3
self.像素颜色 = 4
self.自动获取 = 5
self.截图输出 = 6
self.image = NULL#图片缓冲
self.Start_x = 1#记录鼠标开始x坐标
self.Start_y = 1#记录鼠标开始Y坐标
self.End_x = 2#记录鼠标结束x坐标
self.End_y = 2#记录鼠标结束y坐标
self.high = 0#记录图片高有多少个像素
self.width = 0#记录图片宽有多少个像素
self.px = NULL#记录图片像素点颜色
self.get_fp = NULL#文件路径
self.R = 0#红色的数值
self.G = 0#绿色的数值
self.B = 0#蓝色的数值
self.Current_x = 0#用于第二entry显示,鼠标移动的坐标
self.Current_y = 0#用于第二entry显示,鼠标移动的坐标
self.rectangle1 = NULL#画布的矩形控件
self.vertical = NULL#画布的矩形控件
self.horizontal = NULL#画布的矩形控件
self.YRadioVar = 1.0000#放大缩小Y比例值,用于单像素定位
self.XRadioVar = 1.0000#放大缩小x比例值,用于单像素定位
self.zoomRadioVar = 10#给opencv用于放大缩小的中间变量,此变量放大十倍,用时要/10
self.Win_height = 700#窗口尺寸的初始值,用于调整窗口大小,而自动设定右边的选择栏
self.Win_width = 1100#窗口尺寸的初始值,用于调整窗口大小,而自动设定右边的选择栏
self.Win_heightbuffer = 700#窗口尺寸的缓冲,用于调整窗口大小,而自动设定右边的选择栏
self.Win_widthbuffer = 1100#窗口尺寸的缓冲,用于调整窗口大小,而自动设定右边的选择栏
self.YSetRadioVar = 1.0000#用户设置的坐标放大缩小,影响最终的坐标输出
self.XSetRadioVar = 1.0000#用户设置的坐标放大缩小,影响最终的坐标输出
self.screenshotpath = NULL#截图输出路径
def MotionEvent(self,event):#鼠标移动事件
radioup , raduodown = vertibar.get() #获取竖向滚动条的值
radioxleft , radioxright = horibar.get()#获取横向滚动条的值
self.Current_x,self.Current_y = ((event.x+self.width * radioxleft) -2), ((event.y + self.high * radioup)-2)#获取鼠标当前相对于窗口的值,左上画布开始为2,2,所以要减掉
#canvas.create_oval(x1 , y1, x2, y2, fill = "red")
#数值限位
if self.Current_x<0 :
self.Current_x = 0;
if self.Current_y <0:
self.Current_y = 0;
if self.Current_x >= self.width-1 :
self.Current_x = self.width-1;
if self.Current_y >= self.high-1:
self.Current_y = self.high-1;
self.R,self.G,self.B = self.image.getpixel((self.Current_x,self.Current_y))
if RGB888Flag.get() == 1:
self.px = str(hex((self.R<<16) | (self.G<<8)| self.B))
else :
self.px = str(hex((self.R>>3)<<11 | (self.G>>2)<<5 | self.B>>3))
result = str(int(self.Current_x*self.XRadioVar))+','+str(int(self.Current_y*self.YRadioVar))+'('+self.px+')'#将数字转成字符串
Current_Coordinate.set(str(result))#将字符串输出到entry控件中
if LargeCursor_Sel.get():
# 计算反色
self.R,self.G,self.B = (self.R)&0xFF,(self.G+125)&0xFF,(self.B)&0xFF
r_inv = format(255 - self.R,'02x')
g_inv = format(255 - self.G,'02x')
b_inv = format(255 - self.B,'02x')
self.px = '#'+r_inv+g_inv+b_inv
canvas.delete(self.horizontal) #删除原来的
canvas.delete(self.vertical) #删除原来的
self.horizontal = canvas.create_line(0, self.Current_y,self.width,self.Current_y, fill = self.px)
self.vertical = canvas.create_line(self.Current_x, 0,self.Current_x,self.high, fill = self.px)
#self.horizontal = canvas.create_line(0, self.Start_y,self.width,self.Start_y, fill = "red")
#self.vertical = canvas.create_line(self.Start_x, 0,self.Start_x,self.high, fill = "red")
def Mouse_Left_dowm(self,event):
radioup , raduodown = vertibar.get() #获取竖向滚动条的值
radioxleft , radioxright = horibar.get()#获取横向滚动条的值
self.Start_x,self.Start_y = ((event.x+self.width * radioxleft) -2), ((event.y + self.high * radioup)-2)#获取鼠标当前相对于窗口的值,左上画布开始为2,2,所以要减掉
#canvas.create_oval(x1 , y1, x2, y2, fill = "red")
#数值限位
if self.Start_x<0 :
self.Start_x = 0;
if self.Start_y <0:
self.Start_y = 0;
if self.Start_x >= self.width :
self.Start_x = self.width-1;
if self.Start_y >= self.high:
self.Start_y = self.high-1;
self.R,self.G,self.B = self.image.getpixel((self.Start_x,self.Start_y))
if RGB888Flag.get() == 1:
self.px = str(hex((self.R<<16) | (self.G<<8)| self.B))
else :
self.px = str(hex((self.R>>3)<<11 | (self.G>>2)<<5 | self.B>>3))
result = str(int(self.Start_x*self.XRadioVar))+','+str(int(self.Start_y*self.YRadioVar))+'('+self.px+')'#将数字转成字符串
Current_Coordinate.set(str(result))#将字符串输出到entry控件中
if User_Sel.get() == self.单点坐标 or User_Sel.get() == self.自动获取:
result = str(int(self.Start_x*self.XRadioVar))+','+str(int(self.Start_y*self.YRadioVar))
Coordinate.set(str(result))#将字符串输出到entry控件中
if Copy_Sel.get() == 1:#判断用户是否需要自动拷贝
pyperclip.copy(result)#拷贝到粘贴板中,此时用户只要直接CTRL+V就行
elif User_Sel.get() == self.像素颜色 :#判断用户是否选择了像素颜色
if self.Start_x #canvas.src_strlist = canvas.imagecolor.load() #self.R,self.G,self.B = canvas.src_strlist[self.Start_x, self.Start_y] if RGB888Flag.get() == 1: self.px = str(hex((self.R<<16) | (self.G<<8)| self.B)) else : self.px = str(hex((self.R>>3)<<11 | (self.G>>2)<<5 | self.B>>3)) Coordinate.set(self.px) if Copy_Sel.get() == 1:#判断用户是否需要自动拷贝 pyperclip.copy(self.px)#拷贝到粘贴板中,此时用户只要直接CTRL+V就行 return def Mouse_Middle_dowm(self,event): radioup , raduodown = vertibar.get() #获取竖向滚动条的值 radioxleft , radioxright = horibar.get()#获取横向滚动条,左右的值 self.Start_x,self.Start_y = ((event.x+self.width * radioxleft)-2), ((event.y + self.high * radioup)-2)#获取鼠标当前相对于窗口的值,左上画布开始为2,2,所以要减掉 #canvas.create_oval(x1 , y1, x2, y2, fill = "red") #数值限位 if self.Start_x<0 : self.Start_x = 0; if self.Start_y <0: self.Start_y = 0; if self.Start_x >= self.width : self.Start_x = self.width-1; if self.Start_y >= self.high: self.Start_y = self.high-1; self.R,self.G,self.B = self.image.getpixel((self.Start_x,self.Start_y)) if RGB888Flag.get() == 1: self.px = str(hex((self.R<<16) | (self.G<<8)| self.B)) else : self.px = str(hex((self.R>>3)<<11 | (self.G>>2)<<5 | self.B>>3)) #鼠标当前位置更新 self.Current_x,self.Current_y = self.Start_x,self.Start_y#将鼠标当前位置赋值 result = str(int(self.Current_x*self.XRadioVar))+','+str(int(self.Current_y*self.YRadioVar))+'('+self.px+')'#将数字转成字符串 Current_Coordinate.set(str(result))#将字符串输出到entry控件中 if self.Start_x if RGB888Flag.get() == 1: self.px = str(hex((self.R<<16) | (self.G<<8)| self.B)) else : self.px = str(hex((self.R>>3)<<11 | (self.G>>2)<<5 | self.B>>3)) Coordinate.set(self.px)#将字符串输出到entry控件中 if Copy_Sel.get() == 1:#判断用户是否需要自动拷贝 pyperclip.copy(self.px)#拷贝到粘贴板中,此时用户只要直接CTRL+V就行 return def Mouse_RIGHT_dowm(self,event): radioup , raduodown = vertibar.get() #获取竖向滚动条的值 radioxleft , radioxright = horibar.get()#获取横向滚动条,左右的值 self.Start_x,self.Start_y = ((event.x+self.width * radioxleft)-2 ), ((event.y + self.high * radioup)-2)#获取鼠标当前相对于窗口的值,左上画布开始为2,2,所以要减掉 #canvas.create_oval(x1 , y1, x2, y2, fill = "red") #数值限位 if self.Start_x<0 : self.Start_x = 0; if self.Start_y <0: self.Start_y = 0; if self.Start_x>= self.width : self.Start_x = self.width-1; if self.Start_y >= self.high: self.Start_y = self.high-1; self.R,self.G,self.B = self.image.getpixel((self.Start_x,self.Start_y)) if RGB888Flag.get() == 1: self.px = str(hex((self.R<<16) | (self.G<<8)| self.B)) else : self.px = str(hex((self.R>>3)<<11 | (self.G>>2)<<5 | self.B>>3)) #鼠标当前位置更新 self.Current_x,self.Current_y = self.Start_x,self.Start_y#将鼠标当前位置赋值 result = str(int(self.Current_x*self.XRadioVar))+','+str(int(self.Current_y*self.YRadioVar))+'('+self.px+')'#将数字转成字符串 Coordinate.set(str(result))#将字符串输出到entry控件中 Current_Coordinate.set(str(result))#将字符串输出到entry控件中 return def B1MotionEvent(self,event): radioup , raduodown = vertibar.get() #获取竖向滚动条的值 radioxleft , radioxright = horibar.get()#获取横向滚动条,左右的值 #self.End_x,self.End_y = ((canvas.canvasx(event.x)+self.width * radioxleft)-2 ), ((canvas.canvasx(event.y) + self.high * radioup)-2) #-2才是对上像素 self.End_x,self.End_y = ((event.x+self.width * radioxleft)-2 ), ((event.y + self.high * radioup)-2) #获取鼠标当前相对于窗口的值,左上画布开始为2,2,所以要减掉 #canvas.delete(tk.ALL) #数值限位 if self.End_x<0 : self.End_x = 0; if self.End_y <0: self.End_y = 0; if self.End_x >= self.width : self.End_x = self.width-1; if self.End_y >= self.high: self.End_y = self.high-1; canvas.delete(self.rectangle1) #删除原来的红色矩形框 self.rectangle1 = canvas.create_rectangle(self.Start_x, self.Start_y , self.End_x , self.End_y , outline = "red")#创建一个新的红色矩形框 self.R,self.G,self.B = self.image.getpixel((self.End_x,self.End_y)) if RGB888Flag.get() == 1: self.px = str(hex((self.R<<16) | (self.G<<8)| self.B)) else : self.px = str(hex((self.R>>3)<<11 | (self.G>>2)<<5 | self.B>>3)) #鼠标当前位置更新 self.Current_x,self.Current_y = self.End_x,self.End_y#将鼠标当前位置赋值 result = str(int(self.Current_x*self.XRadioVar))+','+str(int(self.Current_y*self.YRadioVar))+'('+self.px+')'#将数字转成字符串 Current_Coordinate.set(str(result))#在entry控件显示 if User_Sel.get() == self.按键坐标 or User_Sel.get() == self.自动获取: result = str(int(self.Start_x*self.XRadioVar))+','+str(int(self.Start_y*self.YRadioVar))+','+str(int(self.End_x*self.XRadioVar))+','+str(int(self.End_y*self.YRadioVar)) Coordinate.set(str(result))#将字符串输出到entry控件中 if Copy_Sel.get() == 1:#判断用户是否需要自动拷贝 pyperclip.copy(result)#拷贝到粘贴板中,此时用户只要直接CTRL+V就行 # elif User_Sel.get() == self.截图输出: # #cv_img = cv.imdecode(np.fromfile(self.get_fp, dtype=np.uint8), cv.IMREAD_COLOR) # #cv_img = cv.imread("./0_backCartoon.jpg") # #cropImg = self.image[self.Start_y:self.End_y,self.Start_x:self.End_x] #裁剪图像 # #cv.imwrite(dest,cropImg) #写入图像路径 # #cv.imencode('.jpg',cropImg)[1].tofile(self.screenshotpath) # img = Image.open(self.get_fp) # 读取图片 # a = (self.Start_x, self.Start_y , self.End_x , self.End_y) # img = img.crop(a) # img.save("C:/Users/Administrator/Desktop/666.bmp") # 存储图片 # print("ok") elif User_Sel.get() == self.切图坐标: result = str(int(self.Start_x*self.XRadioVar))+','+str(int(self.Start_y*self.YRadioVar))+','+str(int(self.End_x*self.XRadioVar))+','+str(int(self.End_y*self.YRadioVar))+','+str(int(self.Start_x*self.XRadioVar))+','+str(int(self.Start_y*self.YRadioVar)) Coordinate.set(str(result))#将字符串输出到entry控件中 if Copy_Sel.get() == 1:#判断用户是否需要自动拷贝 pyperclip.copy(result)#拷贝到粘贴板中,此时用户只要直接CTRL+V就行 '''canvas.src_strlist = canvas.imagecolor.load() self.R,self.G,self.B = canvas.src_strlist[self.End_x, self.End_y] self.px = str(hex((self.R>>3)<<11 | (self.G>>2)<<5 | self.B>>3)) Coordinate.set(self.px) print(self.px)''' if LargeCursor_Sel.get(): # 计算反色 self.R,self.G,self.B = (self.R)&0xFF,(self.G+125)&0xFF,(self.B)&0xFF r_inv = format(255 - self.R,'02x') g_inv = format(255 - self.G,'02x') b_inv = format(255 - self.B,'02x') self.px = '#'+r_inv+g_inv+b_inv canvas.delete(self.horizontal) #删除原来的 canvas.delete(self.vertical) #删除原来的 self.horizontal = canvas.create_line(0, self.End_y,self.width,self.End_y, fill = self.px) self.vertical = canvas.create_line(self.End_x, 0,self.End_x,self.high, fill = self.px) #self.horizontal = canvas.create_line(0, self.Start_y,self.width,self.Start_y, fill = "red") #self.vertical = canvas.create_line(self.Start_x, 0,self.Start_x,self.high, fill = "red") return def B3MotionEvent(self,event): radioup , raduodown = vertibar.get() #获取竖向滚动条的值 radioxleft , radioxright = horibar.get()#获取横向滚动条,左右的值 #self.End_x,self.End_y = ((canvas.canvasx(event.x)+self.width * radioxleft)-2 ), ((canvas.canvasx(event.y) + self.high * radioup)-2) #-2才是对上像素 self.End_x,self.End_y = ((event.x+self.width * radioxleft)-2 ), ((event.y + self.high * radioup)-2) #获取鼠标当前相对于窗口的值,左上画布开始为2,2,所以要减掉 #数值限位 if self.End_x<0 : self.End_x = 0; if self.End_y <0: self.End_y = 0; if self.End_x >= self.width : self.End_x = self.width-1; if self.End_y >= self.high: self.End_y = self.high-1; canvas.delete(self.rectangle1) #删除原来的红色矩形框 self.rectangle1 = canvas.create_rectangle(self.Start_x, self.Start_y , self.End_x , self.End_y , outline = "red")#创建一个新的红色矩形框 self.R,self.G,self.B = self.image.getpixel((self.End_x,self.End_y)) if RGB888Flag.get() == 1: self.px = str(hex((self.R<<16) | (self.G<<8)| self.B)) else : self.px = str(hex((self.R>>3)<<11 | (self.G>>2)<<5 | self.B>>3)) #鼠标当前位置更新 self.Current_x,self.Current_y = self.End_x,self.End_y#将鼠标当前位置赋值 result = str(int(self.Current_x*self.XRadioVar))+','+str(int(self.Current_y*self.YRadioVar))+'('+self.px+')'#将数字转成字符串 Current_Coordinate.set(str(result))#在entry控件显示 #重新计算一个需要停留显示的坐标 result = str(int(self.Start_x*self.XRadioVar))+','+str(int(self.Start_y*self.YRadioVar))+','+str(int(self.End_x*self.XRadioVar))+','+str(int(self.End_y*self.YRadioVar))+','+str(int(self.Start_x*self.XRadioVar))+','+str(int(self.Start_y*self.YRadioVar)) Coordinate.set(str(result))#将字符串输出到entry控件中 if Copy_Sel.get() == 1:#判断用户是否需要自动拷贝 pyperclip.copy(result)#拷贝到粘贴板中,此时用户只要直接CTRL+V就行 '''canvas.src_strlist = canvas.imagecolor.load() self.R,self.G,self.B = canvas.src_strlist[self.End_x, self.End_y] self.px = str(hex((self.R>>3)<<11 | (G>>2)<<5 | self.B>>3)) Coordinate.set(self.px) print(self.px)''' if LargeCursor_Sel.get(): # 计算反色 self.R,self.G,self.B = (self.R)&0xFF,(self.G+125)&0xFF,(self.B)&0xFF r_inv = format(255 - self.R,'02x') g_inv = format(255 - self.G,'02x') b_inv = format(255 - self.B,'02x') self.px = '#'+r_inv+g_inv+b_inv canvas.delete(self.horizontal) #删除原来的 canvas.delete(self.vertical) #删除原来的 self.horizontal = canvas.create_line(0, self.End_y,self.width,self.End_y, fill = self.px) self.vertical = canvas.create_line(self.End_x, 0,self.End_x,self.high, fill = self.px) #self.horizontal = canvas.create_line(0, self.Start_y,self.width,self.Start_y, fill = "red") #self.vertical = canvas.create_line(self.Start_x, 0,self.Start_x,self.high, fill = "red") return def zoomin_Picture(self):#图片放大 image1 = self.image#先保存,用于有异常时恢复 RadioVar = self.zoomRadioVar#先保存,用于有异常时恢复 try: # 捕获异常 #self.image = Image.open(self.get_fp) self.image = cv.imdecode(np.fromfile(self.get_fp,dtype = np.uint8),-1)#opencv图片解码 if self.zoomRadioVar <100:#限制幅度,以免溢出,这个程序只是简单的把图片放大了,对运行内存要求高,可能会造成卡顿 self.zoomRadioVar = self.zoomRadioVar+1 #self.image = self.image.resize((int(self.image.size[0]/self.zoomRadioVar), int(self.image.size[1]/self.zoomRadioVar)), 3 )# Image.LANCZOS) Resampling. self.image = cv.resize(self.image ,(0,0),fx = (self.zoomRadioVar/10), fy = (self.zoomRadioVar/10), interpolation = cv.INTER_AREA )#重新生成放大的图片 #elif self.zoomRadioVar>3 and self.zoomRadioVar<=10: # self.zoomRadioVar = self.zoomRadioVar-1 #resized_image = ImageTk.Photoimage(self.image) #self.high = cv.height #self.width = cv.width #Yradio1.set(self.XSetRadioVar) #Xradio1.set(self.YSetRadioVar) self.image = cv.cvtColor(self.image, cv.COLOR_BGR2RGBA)#转换颜色从BGR到RGBA self.image = Image.fromarray(self.image)#将图像转换成Image对象 self.high = self.image.height #高度 self.width = self.image.width #宽度 #print(self.width,self.high , self.zoomRadioVar) #像素不能是单的,不然会对不上 if (self.high%2) != 0: self.high = self.high-1 if (self.width%2) != 0: self.width = self.width-1 canvas.img_avatar = ImageTk.PhotoImage(self.image)#转成TKinter用的 self.image = self.image.convert('RGB')#转成rgb canvas.config( width=100, height=100, scrollregion=(0,0,self.width,self.high) ) #配置画布,指定滚动范围 #tk.canvasimage = canvas.create_image(float(self.width/2),float(self.high/2) , self.image=canvas.img_avatar ) tk.canvasimage = canvas.create_image(self.width/2,self.high/2 , image=canvas.img_avatar ) #创建画布图片 #canvas.after(image=photo) #canvas.configure(image = photo) canvas.itemconfig(tk.canvasimage, image=canvas.img_avatar)#修改画布设置 canvas.update()#刷新画布 result = str(int(Function.zoomRadioVar*10))+'%' Multiplystr.set(result) except OverflowError: # 处理异常,复原 self.zoomRadioVar = RadioVar self.image = image1 self.XRadioVar = self.XSetRadioVar/(self.zoomRadioVar/10) self.YRadioVar = self.YSetRadioVar/(self.zoomRadioVar/10) return def zoomout_Picture(self): image1 = self.image#先保存,用于有异常时恢复 RadioVar = self.zoomRadioVar try: # 捕获异常 self.image = cv.imdecode(np.fromfile(self.get_fp,dtype = np.uint8),-1)#opencv图片解码 if self.zoomRadioVar>1: self.zoomRadioVar = self.zoomRadioVar-1 #elif self.zoomRadioVar>=3 and self.zoomRadioVar<10: # self.zoomRadioVar = self.zoomRadioVar+1 self.image = cv.resize(self.image ,(0,0),fx = (self.zoomRadioVar/10), fy = (self.zoomRadioVar/10), interpolation = cv.INTER_AREA )#重新生成放大的图片 #elif self.zoomRadioVar>3 and self.zoomRadioVar<=10: # self.zoomRadioVar = self.zoomRadioVar-1 #resized_image = ImageTk.Photoimage(self.image) #self.high = cv.height #self.width = cv.width #Yradio1.set(self.XSetRadioVar) #Xradio1.set(self.YSetRadioVar) self.image = cv.cvtColor(self.image, cv.COLOR_BGR2RGBA)#转换颜色从BGR到RGBA self.image = Image.fromarray(self.image)#将图像转换成Image对象 self.high = self.image.height #高度 self.width = self.image.width #宽度 #print(self.width,self.high , self.zoomRadioVar) if (self.high%2) != 0: self.high = self.high-1 if (self.width%2) != 0: self.width = self.width-1 canvas.img_avatar = ImageTk.PhotoImage(self.image)#转成TKinter用的 self.image = self.image.convert('RGB')#转成rgb canvas.config( width=100, height=100, scrollregion=(0,0,self.width,self.high) ) #配置画布,指定滚动范围 #tk.canvasimage = canvas.create_image(float(self.width/2),float(self.high/2) , image=canvas.img_avatar ) tk.canvasimage = canvas.create_image(self.width/2,self.high/2 , image=canvas.img_avatar ) #创建画布图片,设置放置图片的一半 #canvas.after(image=photo) #canvas.configure(image = photo) canvas.itemconfig(tk.canvasimage, image=canvas.img_avatar)#修改画布设置 canvas.update()#刷新画布 result = str(int(Function.zoomRadioVar*10))+'%' Multiplystr.set(result) except cv.error: # 处理异常 self.zoomRadioVar = RadioVar self.image = image1 self.XRadioVar = self.XSetRadioVar/(self.zoomRadioVar/10) self.YRadioVar = self.YSetRadioVar/(self.zoomRadioVar/10) return def onMouseWheel(self,event): if event.delta>0: self.zoomin_Picture() else : self.zoomout_Picture() def OpenPicture(self): fp = self.get_fp #canvas.delete(tk.canvasimage) try: # 捕获异常 self.get_fp = filedialog.askopenfilename(filetypes = [("*",".*"),("BMP",".bmp"),("JPG",".jpg"),("PNG",".png"), ("GIF",".gif")])#打开文件,默认不限定格式 self.image = cv.imdecode(np.fromfile(self.get_fp,dtype = np.uint8),-1)#opencv图片解码 ws.title('ImageToolsV2.3 技术支持与合作QQ:1257784610 '+str(self.get_fp)) #获取图片像素点大小 #canvas.delete("all") self.image = cv.resize(self.image ,(0,0),fx = (self.zoomRadioVar/10), fy = (self.zoomRadioVar/10), interpolation = cv.INTER_AREA )#重新生成图片 self.image = cv.cvtColor(self.image, cv.COLOR_BGR2RGBA)#转换颜色从BGR到RGBA self.image = Image.fromarray(self.image)#将图像转换成Image对象 #resized_image = ImageTk.Photoimage(self.image) self.high = self.image.height self.width = self.image.width #print(self.high,self.width) if (self.high%2) != 0: self.high = self.high-1 if (self.width%2) != 0: self.width = self.width-1 canvas.img_avatar = ImageTk.PhotoImage(self.image)#转成TKinter用的 #canvas.imagecolor = self.image.convert('RGB') self.image = self.image.convert('RGB') canvas.config( width=100, height=100, scrollregion=(0,0,self.width,self.high)#配置画布,指定滚动范围 ) tk.canvasimage = canvas.create_image(float(self.width/2),float(self.high/2) , image=canvas.img_avatar )#创建画布图片,设置放置图片的一半 #canvas.after(image=photo) #canvas.configure(image = photo) canvas.itemconfig(tk.canvasimage, image=canvas.img_avatar)#修改画布设置 canvas.update()#刷新画布 except AttributeError: # 处理异常 self.get_fp =fp except FileNotFoundError: # 处理异常 self.get_fp =fp return def XYRadio_Set(self): self.XSetRadioVar = float(X_Radio.get())#读取控件输入的数值 self.YSetRadioVar = float(Y_Radio.get())#读取控件输入的数值 self.XRadioVar , self.YRadioVar = self.XSetRadioVar/(self.zoomRadioVar/10),self.YSetRadioVar/(self.zoomRadioVar/10)#设置输出的坐标 return def adjust_windows(self,event): if (self.Win_heightbuffer !=ws.winfo_height()) or (self.Win_widthbuffer !=ws.winfo_width()): self.Win_heightbuffer , self.Win_widthbuffer = ws.winfo_height() , ws.winfo_width() pw1.update()#先刷新,不然下面的会执行失败 pw1.sash_place(0,int(ws.winfo_width()-200),0)#放置中间的空间分割线 #heightRadio , widthRadio= ws.winfo_height()/Win_height , ws.winfo_width()/Win_width #print(event.type) #print(event.widget) def Reset_Picture(self): self.image = cv.imdecode(np.fromfile(self.get_fp,dtype = np.uint8),-1) self.zoomRadioVar = 10 self.XSetRadioVar = 1.0 self.YSetRadioVar = 1.0 self.XRadioVar = self.XSetRadioVar/(self.zoomRadioVar/10) self.YRadioVar = self.YSetRadioVar/(self.zoomRadioVar/10) '''interpolation:这个是指定插值的方式,图像缩放之后,肯定像素要进行重新计算的,就靠这个参数来指定重新计算像素的方式,有以下几种: INTER_NEAREST - 最邻近插值 INTER_LINEAR - 双线性插值,如果最后一个参数你不指定,默认使用这种方法 INTER_AREA - resampling using pixel area relation. It may be a preferred method for self.image decimation, as it gives moire’-free results. But when the self.image is zoomed, it is similar to the INTER_NEAREST method. INTER_CUBIC - 4x4像素邻域内的双立方插值 INTER_LANCZOS4 - 8x8像素邻域内的Lanczos插值 ———————————————— 版权声明:本文为CSDN博主「xidaoliang123」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/xidaoliang/article/details/86504720''' self.image = cv.resize(self.image ,(0,0),fx = (self.zoomRadioVar/10), fy = (self.zoomRadioVar/10), interpolation = cv.INTER_AREA ) #resized_image = ImageTk.Photoimage(self.image) self.image = cv.cvtColor(self.image, cv.COLOR_BGR2RGBA)#转换颜色从BGR到RGBA self.image = Image.fromarray(self.image)#将图像转换成Image对象 self.high = self.image.height self.width = self.image.width Yradio1.set(self.XSetRadioVar) Xradio1.set(self.YSetRadioVar) #print(self.width,self.high) #print(self.high,self.width) if (self.high%2) != 0: self.high = self.high-1 if (self.width%2) != 0: self.width = self.width-1 canvas.img_avatar = ImageTk.PhotoImage(self.image)#转成TKinter用的 self.image = self.image.convert('RGB')#转成rgb canvas.config( width=100, height=100, scrollregion=(0,0,self.width,self.high) ) #配置画布,指定滚动范围 tk.canvasimage = canvas.create_image(float(self.width/2),float(self.high/2) , image=canvas.img_avatar ) #创建画布图片,设置放置图片的一半 #canvas.after(image=photo) #canvas.configure(image = photo) canvas.itemconfig(tk.canvasimage, image=canvas.img_avatar)#修改画布设置 canvas.update()#刷新画布 result = str(int(Function.zoomRadioVar*10))+'%' Multiplystr.set(result) return def Getscreenshot_outputpath(self): #self.screenshotpath = filedialog.askdirectory()#获取目录 self.screenshotpath = filedialog.asksaveasfilename(initialfile='截图',filetypes=[("BMP",".bmp"),("JPG",".jpg"),("PNG",".png"),("TIF",".tif")], defaultextension='.bmp')#获取保存文件 if self.screenshotpath :#用户选择了文件 #print(int(self.Start_y),int(self.End_y),int(self.Start_x),int(self.End_x)) img = cv.imdecode(np.fromfile(self.get_fp,dtype = np.uint8),cv.IMREAD_COLOR)#opencv图片解码,重新打开一个来截图,避免图片失真 #截图,由于前面将self.XRadioVar和xy系数绑定了,这里直接用zoomRadioVar来反算原来的xy坐标,保持输出的和矩形圈住的是一样的 cropImg = img[int(self.Start_y/(self.zoomRadioVar/10)):int(self.End_y/(self.zoomRadioVar/10)),int(self.Start_x/(self.zoomRadioVar/10)):int(self.End_x/(self.zoomRadioVar/10))] # 裁剪【y1,y2:x1,x2】 #print(self.screenshotpath) cv.imencode(os.path.splitext(self.screenshotpath)[1], cropImg)[1].tofile(self.screenshotpath) #输出 else :#用户没有选择文件跳出 return def canvasFocusOut(self,event): if self.vertical!= NULL: canvas.delete(self.vertical) if self.horizontal!=NULL: canvas.delete(self.horizontal) return def canvasFocusIn(self,event): #print("out") '''if self.vertical!= NULL: canvas.delete(self.vertical) if self.horizontal!=NULL: canvas.delete(self.horizontal)''' return ws = tk.Tk() ws.title('ImageToolsV2.3 技术支持与合作QQ:1257784610') ws.geometry('1100x700') pw1=tk.PanedWindow(ws,orient=tk.HORIZONTAL,width = 900,height = 700,sashrelief='groove') # 创建横向分割面板 pw1.pack(fill=tk.BOTH,expand=True) # 尺寸扩展到整个窗体 frame = tk.Frame(pw1 ,width = 900,height = 700) ws.update_idletasks() ##########################################测试用代码####################################################### # print(time.time()) # print(datetime.datetime.now()) # print(datetime.datetime.now().year,datetime.datetime.now().month,datetime.datetime.now().day,datetime.datetime.now().hour,datetime.datetime.now().minute) #软件时长测试,也许直接判断天数更好 # year = 2025 # month = 3 # day = 20 # if datetime.datetime.now().year>=year: # if datetime.datetime.now().month>month: # strdisplay = "Your two-year subscription is end.Please contact us(Wechat:Q2596238662/QQ:1257784610)to obtain the new software and avoid any interruption in service!!!" # tk.messagebox.showinfo(title = "License Expiry Notice",message=strdisplay) # sys.exit() # elif datetime.datetime.now().month>=month: # if datetime.datetime.now().day>=day: # strdisplay = "Your two-year subscription is end.Please contact us(Wechat:Q2596238662/QQ:1257784610)to obtain the new software and avoid any interruption in service!!!" # tk.messagebox.showinfo(title = "License Expiry Notice",message=strdisplay) # sys.exit() # else : # remainderday = day - datetime.datetime.now().day # strdisplay = "Your two-year subscription is ending in "+str(remainderday)+" days. Please contact us(Wechat:Q2596238662/QQ:1257784610)to obtain the new software and avoid any interruption in service." # tk.messagebox.showinfo(title = "License Expiry Notice",message=strdisplay) # elif datetime.datetime.now().month>=month-1: # remainderday = 30+day-datetime.datetime.now().day # strdisplay = "Your two-year subscription is ending in "+str(remainderday)+" days. Please contact us(Wechat:Q2596238662/QQ:1257784610)to obtain the new software and avoid any interruption in service." # tk.messagebox.showinfo(title = "License Expiry Notice",message=strdisplay) ##########################################测试用代码####################################################### #软件时长测试,也许直接判断天数更好 # 获取当前日期 # now = datetime.datetime.now() # # 创建一个结束的日期,如果想要永久把这段代码删掉 # epoch = datetime.datetime(2024, 5, 19) # # 计算从1970年1月1日到当前日期的时间差 # total_seconds = (epoch-now).total_seconds() # # 将总秒数转换为总天数 # total_days = total_seconds / 86400 # #print(total_days) # if total_days>0 and total_days<=31: # strdisplay = "Your two-year subscription is ending in "+str(int(total_days))+" days. Please contact us(Wechat:Q2596238662/QQ:1257784610)to obtain the new software and avoid any interruption in service." # tk.messagebox.showinfo(title = "License Expiry Notice",message=strdisplay) # elif total_days <=0: # strdisplay = "Your two-year subscription is end.Please contact us(Wechat:Q2596238662/QQ:1257784610)to obtain the new software and avoid any interruption in service!!!" # tk.messagebox.showinfo(title = "License Expiry Notice",message=strdisplay) # sys.exit() ################################################################################################### try: # 捕获异常 Function = Callback() #Function.get_fp = filedialog.askopenfilename(filetypes = [("BMP",".bmp"),("JPG",".jpg"),("PNG",".png"), ("GIF",".gif")]) Function.get_fp = filedialog.askopenfilename(filetypes = [("*",".*"),("BMP",".bmp"),("JPG",".jpg"),("PNG",".png"), ("GIF",".gif")])#打开文件,默认不限定格式 ws.title('ImageToolsV2.3 技术支持与合作QQ:1257784610 '+str(Function.get_fp)) #image = Image.open(get_fp) Function.image = cv.imdecode(np.fromfile(Function.get_fp,dtype = np.uint8),-1) Function.image = cv.cvtColor(Function.image, cv.COLOR_BGR2RGBA)#转换颜色从BGR到RGBA Function.image = Image.fromarray(Function.image)#将图像转换成Image对象 #获取图片像素点大小 Function.high = Function.image.height #高度 Function.width = Function.image.width #宽度 #print(high,width) if (Function.high%2) != 0: Function.high = Function.high-1 if (Function.width%2) != 0: Function.width = Function.width-1 canvas=tk.Canvas( frame, bg='#4A7A8C', width=900, height=700, cursor="tcross", scrollregion=(0,0,Function.width,Function.high) ) #canvas.imagecolor = image.convert('RGB') Function.image = Function.image.convert('RGB')#RGB模式 Function.R,Function.G,Function.B = Function.image.getpixel((0,0)) #canvas.src_strlist = canvas.imagecolor.load() #R,G,B = canvas.src_strlist[1, 1] Function.px = str(hex((Function.R>>3)<<11 | (Function.G>>2)<<5 | Function.B>>3)) #垂直滑动条 vertibar=tk.Scrollbar( frame, orient=tk.VERTICAL ) vertibar.pack(side=tk.RIGHT,fill=tk.Y) vertibar.config(command=canvas.yview) #水平滑动条 horibar=tk.Scrollbar( frame, orient=tk.HORIZONTAL ) horibar.pack(side=tk.BOTTOM,fill=tk.X) horibar.config(command=canvas.xview) canvas.config( xscrollcommand=horibar.set, yscrollcommand=vertibar.set )#配置滑动条 canvas.img_avatar = ImageTk.PhotoImage(Function.image) #imgLabel = tk.Label(frame ,image = photo) #imgLabel.pack() tk.canvasimage = canvas.create_image(float(Function.width/2),float(Function.high/2) , image=canvas.img_avatar ) #此处加2是为了全部显示 #Function.rectangle1 = canvas.create_rectangle(0, 0 , 1 , 1 , outline = "red") canvas.pack(expand=True,side=tk.LEFT,fill=tk.BOTH) #ws.protocol( "WM_TAKE_FOCUS" , adjust_windows); #################################################### User_Sel = tk.IntVar() User_Sel.set(5) Copy_Sel = tk.IntVar() Copy_Sel.set(1) LargeCursor_Sel = tk.IntVar() LargeCursor_Sel.set(1) RGB888Flag = tk.IntVar() RGB888Flag.set(0) Coordinate = tk.StringVar() Current_Coordinate = tk.StringVar() Xradio1 = tk.StringVar() Yradio1 = tk.StringVar() Multiplystr = tk.StringVar() result = str(int(Function.zoomRadioVar*10))+'%' pw2=tk.PanedWindow(pw1,orient=tk.VERTICAL,width = 200,height = 700,sashrelief='groove') pw2.pack() # 尺寸扩展到整个窗体 frame1 = tk.Frame(pw2) frame2 = tk.Frame(pw2) textLabel = tk.Label(frame1 ,textvariable= Multiplystr ) textLabel.pack(expand=False) Multiplystr.set(result) Coordinateout = tk.Entry(frame1 , width = 30 , text = Coordinate , state = "readonly" , exportselection = 1) #Coordinateout.grid(column = 0 , row = 1) Coordinateout.pack() Current_Coordinate_out = tk.Entry(frame1 , width = 30 , text = Current_Coordinate , state = "readonly" , exportselection = 1) Current_Coordinate_out.pack() LANGS= [("矩形坐标" , 1), ("贴图坐标" , 2), ("像素坐标" , 3), ("像素颜色" , 4), ("快捷获取" , 5)] for lang ,num in LANGS: b= tk.Radiobutton(frame2 , text = lang , variable = User_Sel , value = num ) b.pack(fill =tk.X) Largecursorbutton = tk.Checkbutton(frame2 , text = "十字光标" , variable= LargeCursor_Sel) Largecursorbutton.pack() RGBModeButton = tk.Checkbutton(frame2 , text = "RGB888(565)" , variable= RGB888Flag) RGBModeButton.pack() Copybutton = tk.Checkbutton(frame2 , text = "自动复制到粘贴板" , variable= Copy_Sel) Copybutton.pack() OpenPictureButton = tk.Button(frame2 , text = "打开图片" , command = Function.OpenPicture,width = 10) OpenPictureButton.pack() screenshotpathButton = tk.Button(frame2 , text = "输出截图到" , command = Function.Getscreenshot_outputpath,width = 10) screenshotpathButton.pack() tk.Label(frame2 , text = '请输入X转换系数,默认为1').pack() X_Radio = tk.Entry(frame2 , width = 20 , textvariable = 1, text = Xradio1 , exportselection = 1) X_Radio.pack() Xradio1.set(1) tk.Label(frame2 , text = '请输入Y转换系数,默认为1').pack() Y_Radio = tk.Entry(frame2 , width = 20 , textvariable = 1,text = Yradio1 , exportselection = 1) Y_Radio.pack() Yradio1.set(1) SetxyButton = tk.Button(frame2 , text = "设置XY系数" , command = Function.XYRadio_Set ,width = 10) SetxyButton.pack() zoominButton = tk.Button(frame2 , text = "图片放大" , command = Function.zoomin_Picture ,width = 10) zoominButton.pack() zoomoutButton = tk.Button(frame2 , text = "图片缩小" , command = Function.zoomout_Picture,width = 10) zoomoutButton.pack() ResetButton = tk.Button(frame2 , text = "图片复位" , command = Function.Reset_Picture,width = 10) ResetButton.pack() #canvas.bind(" pw1.bind(" #pw2.bind(" canvas.bind(" canvas.bind(" canvas.bind(" canvas.bind(" canvas.bind(" canvas.bind(" canvas.bind(" canvas.bind(" canvas.bind(" canvas.bind(" ####################################################### pw1.add(frame) # pw1加入fr1组件 pw2.add(frame1) # pw2加入fr2组件 pw2.add(frame2) # pw2加入fr3组件 pw1.add(pw2) # pw1加入pw2组件 ws.mainloop() except FileNotFoundError: sys.exit()
