模块缝合完成
This commit is contained in:
parent
1714f45ef5
commit
3ce5aa3711
9
acdr-ui/env/.env
vendored
9
acdr-ui/env/.env
vendored
@ -7,10 +7,11 @@ VITE_WX_APPID = 'wxf2c6d4b7361366b4'
|
|||||||
# h5部署网站的base,配置到 manifest.config.ts 里的 h5.router.base
|
# h5部署网站的base,配置到 manifest.config.ts 里的 h5.router.base
|
||||||
VITE_APP_PUBLIC_BASE=/acdr/
|
VITE_APP_PUBLIC_BASE=/acdr/
|
||||||
|
|
||||||
VITE_SERVER_BASEURL = 'http://47.99.70.12:28184/api'
|
# VITE_SERVER_BASEURL = 'http://47.99.70.12:28184/api'
|
||||||
# VITE_UPLOAD_BASEURL = 'http://47.99.70.12:28184'
|
# VITE_UPLOAD_BASEURL = 'http://47.99.70.12:28184'
|
||||||
# VITE_SERVER_BASEURL = 'http://localhost:28184/api'
|
# VITE_SERVER_BASEURL = 'http://localhost:28184/api'
|
||||||
VITE_WS_BASEURL = 'ws://47.99.70.12:28184/api'
|
VITE_SERVER_BASEURL = 'http://localhost:48080/app-api'
|
||||||
|
# VITE_WS_BASEURL = 'ws://47.99.70.12:28184/api'
|
||||||
VITE_UPLOAD_BASEURL = 'http://localhost:28184'
|
VITE_UPLOAD_BASEURL = 'http://localhost:28184'
|
||||||
VITE_OSS_BASEURL = 'http://116.204.119.171:9000/linghe'
|
VITE_OSS_BASEURL = 'http://116.204.119.171:9000/linghe'
|
||||||
|
|
||||||
@ -25,8 +26,8 @@ SHOPRO_VERSION = v1.8.3
|
|||||||
SHOPRO_BASE_URL = http://api-dashboard.yudao.iocoder.cn
|
SHOPRO_BASE_URL = http://api-dashboard.yudao.iocoder.cn
|
||||||
|
|
||||||
# 后端接口 - 测试环境(通过 process.env.NODE_ENV = development)
|
# 后端接口 - 测试环境(通过 process.env.NODE_ENV = development)
|
||||||
# SHOPRO_DEV_BASE_URL = http://127.0.0.1:48080
|
SHOPRO_DEV_BASE_URL = http://127.0.0.1:48080
|
||||||
SHOPRO_DEV_BASE_URL = http://47.99.70.12:48080
|
# SHOPRO_DEV_BASE_URL = http://47.99.70.12:48080
|
||||||
### SHOPRO_DEV_BASE_URL = http://yunai.natapp1.cc
|
### SHOPRO_DEV_BASE_URL = http://yunai.natapp1.cc
|
||||||
|
|
||||||
# 后端接口前缀(一般不建议调整)
|
# 后端接口前缀(一般不建议调整)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "宠屋",
|
"name": "宠屋",
|
||||||
"appid": "H57F2ACE4",
|
"appid": "__UNI__9D479DC",
|
||||||
"description": "",
|
"description": "",
|
||||||
"versionName": "1.0.0",
|
"versionName": "1.0.0",
|
||||||
"versionCode": "100",
|
"versionCode": "100",
|
||||||
|
@ -38,7 +38,7 @@ import { ref, onMounted, onUnmounted } from 'vue'
|
|||||||
import { httpGet, httpPost } from '@/utils/http'
|
import { httpGet, httpPost } from '@/utils/http'
|
||||||
import { useUserStore } from '@/store/user'
|
import { useUserStore } from '@/store/user'
|
||||||
import TopBar from '@/components/TopBar.vue'
|
import TopBar from '@/components/TopBar.vue'
|
||||||
import { imgUrl } from '@/utils/commUtils'
|
import { imgUrl, toast, toPath } from "@/utils/commUtils";
|
||||||
|
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
|
|
||||||
@ -50,26 +50,15 @@ let timer = null
|
|||||||
const sendCode = async () => {
|
const sendCode = async () => {
|
||||||
if (countdown.value === 0) {
|
if (countdown.value === 0) {
|
||||||
if (!phoneNumber.value) {
|
if (!phoneNumber.value) {
|
||||||
uni.showToast({
|
toast('请输入手机号')
|
||||||
title: '请输入手机号',
|
|
||||||
icon: 'none',
|
|
||||||
})
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
console.log('发送验证码到', phoneNumber.value)
|
|
||||||
const res = await httpGet('/public/getCode', { phone: phoneNumber.value })
|
const res = await httpGet('/public/getCode', { phone: phoneNumber.value })
|
||||||
console.log(res)
|
|
||||||
countdown.value = 60
|
countdown.value = 60
|
||||||
if (res.code == 200) {
|
if (res.code === 200) {
|
||||||
uni.showToast({
|
toast(res.message)
|
||||||
title: res.message,
|
|
||||||
icon: 'none',
|
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
uni.showToast({
|
toast(res.message)
|
||||||
title: res.message,
|
|
||||||
icon: 'none',
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
timer = setInterval(() => {
|
timer = setInterval(() => {
|
||||||
countdown.value -= 1
|
countdown.value -= 1
|
||||||
@ -96,29 +85,24 @@ const login = async () => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
const res = await httpPost('/public/login', {}, { phone: phoneNumber.value, code: code.value })
|
const res = await httpPost('/public/login', {}, { phone: phoneNumber.value, code: code.value })
|
||||||
if (res.code == 200) {
|
if (res.code === 200) {
|
||||||
uni.showToast({
|
toast(res.message)
|
||||||
title: res.message,
|
const data = res.data
|
||||||
icon: 'none',
|
userStore.setUserInfo({
|
||||||
|
id: data.userId ,
|
||||||
|
token: data.accessToken,
|
||||||
|
expiresTime: data.expiresTime,
|
||||||
|
refreshToken: data.refreshToken
|
||||||
})
|
})
|
||||||
userStore.setUserInfo({ token: res.data.userToken, shopLoginUser: res.data.shopLoginUser })
|
|
||||||
const userRes = await httpGet('/user/userinfo')
|
const userRes = await httpGet('/user/userinfo')
|
||||||
if (userRes.code == 200) {
|
if (userRes.code === 200) {
|
||||||
userStore.setUserInfo(userRes.data)
|
userStore.setUserInfo(userRes.data)
|
||||||
uni.switchTab({
|
toPath('/')
|
||||||
url: '/pages/index/index',
|
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
uni.showToast({
|
toast(userRes.message || '登录失败请重新登录!')
|
||||||
title: userRes.message,
|
|
||||||
icon: 'none',
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
uni.showToast({
|
toast(res.message || '登录失败请重新登录!')
|
||||||
title: res.message,
|
|
||||||
icon: 'none',
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,17 +6,16 @@ const initState = {
|
|||||||
avatar: '',
|
avatar: '',
|
||||||
id: null,
|
id: null,
|
||||||
name: '',
|
name: '',
|
||||||
phone: '',
|
mobile: '',
|
||||||
email: '',
|
cardId: '',
|
||||||
typeId: '',
|
|
||||||
createTime: '',
|
createTime: '',
|
||||||
updateTime: '',
|
updateTime: '',
|
||||||
token: '',
|
token: '',
|
||||||
sex: '',
|
sex: '',
|
||||||
openid: '', // 微信openid,如果不为空就证明用户是用微信登录的
|
|
||||||
isRealName: false,
|
isRealName: false,
|
||||||
isPetNursery: false,
|
isPetNursery: false,
|
||||||
shopLoginUser: null,
|
expiresTime: '',
|
||||||
|
refreshToken: '',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useUserStore = defineStore(
|
export const useUserStore = defineStore(
|
||||||
|
45
acdr-ui/tootls/gif制作脚本.py
Normal file
45
acdr-ui/tootls/gif制作脚本.py
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import tkinter as tk
|
||||||
|
from tkinter import filedialog, messagebox
|
||||||
|
from PIL import Image
|
||||||
|
|
||||||
|
class GIFMakerApp:
|
||||||
|
def __init__(self, root):
|
||||||
|
self.root = root
|
||||||
|
self.root.title("GIF Maker")
|
||||||
|
|
||||||
|
# 选择图片按钮
|
||||||
|
self.select_button = tk.Button(root, text="选择图片", command=self.select_images)
|
||||||
|
self.select_button.pack(pady=10)
|
||||||
|
|
||||||
|
# 保存 GIF 按钮
|
||||||
|
self.save_button = tk.Button(root, text="保存 GIF", command=self.save_gif, state=tk.DISABLED)
|
||||||
|
self.save_button.pack(pady=10)
|
||||||
|
|
||||||
|
self.images = [] # 保存选择的图片
|
||||||
|
|
||||||
|
def select_images(self):
|
||||||
|
# 选择多张图片
|
||||||
|
image_paths = filedialog.askopenfilenames(title="选择图片", filetypes=[("Image files", "*.jpg;*.png;*.jpeg;*.bmp"), ("All files", "*.*")])
|
||||||
|
if image_paths:
|
||||||
|
self.images = [Image.open(image_path) for image_path in image_paths] # 打开所有选择的图片
|
||||||
|
messagebox.showinfo("已选择图片", f"已选择 {len(self.images)} 张图片")
|
||||||
|
self.save_button.config(state=tk.NORMAL) # 启用保存按钮
|
||||||
|
|
||||||
|
def save_gif(self):
|
||||||
|
if not self.images:
|
||||||
|
messagebox.showwarning("警告", "没有选择图片!")
|
||||||
|
return
|
||||||
|
|
||||||
|
# 设置保存文件名
|
||||||
|
save_path = filedialog.asksaveasfilename(defaultextension=".gif", filetypes=[("GIF files", "*.gif")])
|
||||||
|
if save_path:
|
||||||
|
# 保存为GIF,指定每帧的时间间隔
|
||||||
|
self.images[0].save(save_path, save_all=True, append_images=self.images[1:], duration=10, loop=0)
|
||||||
|
messagebox.showinfo("成功", f"GIF 已保存到: {save_path}")
|
||||||
|
|
||||||
|
# 启动 GUI 应用
|
||||||
|
if __name__ == "__main__":
|
||||||
|
root = tk.Tk()
|
||||||
|
app = GIFMakerApp(root)
|
||||||
|
root.geometry("300x200")
|
||||||
|
root.mainloop()
|
126
acdr-ui/tootls/图片截取位置.py
Normal file
126
acdr-ui/tootls/图片截取位置.py
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
import tkinter as tk
|
||||||
|
from tkinter import filedialog, messagebox
|
||||||
|
from PIL import Image, ImageTk
|
||||||
|
import os
|
||||||
|
|
||||||
|
class ImageCropApp:
|
||||||
|
def __init__(self, root):
|
||||||
|
self.root = root
|
||||||
|
self.root.title("Multi Image Crop Tool")
|
||||||
|
|
||||||
|
# 选择图片按钮
|
||||||
|
self.select_button = tk.Button(root, text="选择图片", command=self.select_images)
|
||||||
|
self.select_button.pack(pady=10)
|
||||||
|
|
||||||
|
# 画布,用于显示图片
|
||||||
|
self.canvas = tk.Canvas(root, cursor="cross")
|
||||||
|
self.canvas.pack(fill=tk.BOTH, expand=True)
|
||||||
|
|
||||||
|
self.images = [] # 用于保存选择的多张图片路径
|
||||||
|
self.image = None # 当前显示的图片
|
||||||
|
self.rect_start_x = 0
|
||||||
|
self.rect_start_y = 0
|
||||||
|
self.rect_end_x = 0
|
||||||
|
self.rect_end_y = 0
|
||||||
|
self.rect = None
|
||||||
|
self.tk_image = None
|
||||||
|
self.save_dir = None # 保存路径
|
||||||
|
self.image_display_width = 0 # 显示图片的宽度
|
||||||
|
self.image_display_height = 0 # 显示图片的高度
|
||||||
|
self.image_original_width = 0 # 图片的原始宽度
|
||||||
|
self.image_original_height = 0 # 图片的原始高度
|
||||||
|
|
||||||
|
# 鼠标事件
|
||||||
|
self.canvas.bind("<Button-1>", self.start_selection)
|
||||||
|
self.canvas.bind("<B1-Motion>", self.update_selection)
|
||||||
|
self.canvas.bind("<ButtonRelease-1>", self.finish_selection)
|
||||||
|
|
||||||
|
def select_images(self):
|
||||||
|
# 多文件选择
|
||||||
|
image_paths = filedialog.askopenfilenames(title="选择多张图片", filetypes=[("Image files", "*.jpg;*.png;*.jpeg;*.bmp"), ("All files", "*.*")])
|
||||||
|
if image_paths:
|
||||||
|
self.images = list(image_paths) # 将文件路径保存为列表
|
||||||
|
self.load_first_image()
|
||||||
|
|
||||||
|
def load_first_image(self):
|
||||||
|
# 加载第一张图片并显示在画布上
|
||||||
|
if self.images:
|
||||||
|
self.image = Image.open(self.images[0])
|
||||||
|
self.image_original_width, self.image_original_height = self.image.size # 获取原始尺寸
|
||||||
|
self.display_image()
|
||||||
|
|
||||||
|
def display_image(self):
|
||||||
|
# 调整图片大小适应窗口
|
||||||
|
self.image.thumbnail((self.root.winfo_width(), self.root.winfo_height())) # 缩放图片
|
||||||
|
self.tk_image = ImageTk.PhotoImage(self.image)
|
||||||
|
|
||||||
|
self.image_display_width, self.image_display_height = self.image.size # 显示的宽高
|
||||||
|
|
||||||
|
self.canvas.create_image(0, 0, anchor="nw", image=self.tk_image)
|
||||||
|
|
||||||
|
def start_selection(self, event):
|
||||||
|
# 记录起始点
|
||||||
|
self.rect_start_x = event.x
|
||||||
|
self.rect_start_y = event.y
|
||||||
|
# 创建一个选择框
|
||||||
|
self.rect = self.canvas.create_rectangle(self.rect_start_x, self.rect_start_y, self.rect_start_x, self.rect_start_y, outline="red", width=2)
|
||||||
|
|
||||||
|
def update_selection(self, event):
|
||||||
|
# 更新选择框大小
|
||||||
|
self.rect_end_x = event.x
|
||||||
|
self.rect_end_y = event.y
|
||||||
|
self.canvas.coords(self.rect, self.rect_start_x, self.rect_start_y, self.rect_end_x, self.rect_end_y)
|
||||||
|
|
||||||
|
def finish_selection(self, event):
|
||||||
|
self.rect_end_x = event.x
|
||||||
|
self.rect_end_y = event.y
|
||||||
|
self.crop_images()
|
||||||
|
|
||||||
|
def crop_images(self):
|
||||||
|
if self.images:
|
||||||
|
# 计算图像与显示窗口的比例
|
||||||
|
x_ratio = self.image_original_width / self.image_display_width
|
||||||
|
y_ratio = self.image_original_height / self.image_display_height
|
||||||
|
|
||||||
|
# 获取选择框的坐标,并转换为图片的实际坐标
|
||||||
|
left = min(self.rect_start_x, self.rect_end_x) * x_ratio
|
||||||
|
top = min(self.rect_start_y, self.rect_end_y) * y_ratio
|
||||||
|
right = max(self.rect_start_x, self.rect_end_x) * x_ratio
|
||||||
|
bottom = max(self.rect_start_y, self.rect_end_y) * y_ratio
|
||||||
|
|
||||||
|
# 让用户选择保存文件夹,只选择一次
|
||||||
|
if self.save_dir is None:
|
||||||
|
self.save_dir = filedialog.askdirectory(title="选择保存文件夹")
|
||||||
|
if not self.save_dir:
|
||||||
|
messagebox.showwarning("警告", "未选择保存文件夹,操作已取消")
|
||||||
|
return
|
||||||
|
|
||||||
|
for image_path in self.images:
|
||||||
|
img = Image.open(image_path)
|
||||||
|
img_original_width, img_original_height = img.size # 获取每张图片的原始大小
|
||||||
|
|
||||||
|
# 根据比例缩放选择区域并裁剪
|
||||||
|
left_scaled = left * (img_original_width / self.image_original_width)
|
||||||
|
top_scaled = top * (img_original_height / self.image_original_height)
|
||||||
|
right_scaled = right * (img_original_width / self.image_original_width)
|
||||||
|
bottom_scaled = bottom * (img_original_height / self.image_original_height)
|
||||||
|
|
||||||
|
cropped_image = img.crop((left_scaled, top_scaled, right_scaled, bottom_scaled))
|
||||||
|
|
||||||
|
# 自动生成默认文件名
|
||||||
|
base_name = os.path.basename(image_path)
|
||||||
|
default_filename = f"cropped_{base_name}"
|
||||||
|
|
||||||
|
# 保存路径与文件名
|
||||||
|
save_path = os.path.join(self.save_dir, default_filename)
|
||||||
|
cropped_image.save(save_path)
|
||||||
|
print(f"图片已保存到: {save_path}")
|
||||||
|
|
||||||
|
messagebox.showinfo("成功", "所有图片裁剪完成!")
|
||||||
|
|
||||||
|
# 启动 GUI 应用
|
||||||
|
if __name__ == "__main__":
|
||||||
|
root = tk.Tk()
|
||||||
|
app = ImageCropApp(root)
|
||||||
|
root.geometry("800x600") # 设置初始窗口大小
|
||||||
|
root.mainloop()
|
83
acdr-ui/tootls/图片截取单个位置.py
Normal file
83
acdr-ui/tootls/图片截取单个位置.py
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
import tkinter as tk
|
||||||
|
from tkinter import filedialog, messagebox
|
||||||
|
from PIL import Image, ImageTk, ImageGrab
|
||||||
|
|
||||||
|
class ImageCropApp:
|
||||||
|
def __init__(self, root):
|
||||||
|
self.root = root
|
||||||
|
self.root.title("Image Crop Tool")
|
||||||
|
|
||||||
|
# 选择图片按钮
|
||||||
|
self.select_button = tk.Button(root, text="选择图片", command=self.select_image)
|
||||||
|
self.select_button.pack(pady=10)
|
||||||
|
|
||||||
|
# 画布,用于显示图片
|
||||||
|
self.canvas = tk.Canvas(root, cursor="cross")
|
||||||
|
self.canvas.pack(fill=tk.BOTH, expand=True)
|
||||||
|
|
||||||
|
self.image = None # 用于保存选择的图片
|
||||||
|
self.rect_start_x = 0
|
||||||
|
self.rect_start_y = 0
|
||||||
|
self.rect_end_x = 0
|
||||||
|
self.rect_end_y = 0
|
||||||
|
self.rect = None
|
||||||
|
self.tk_image = None
|
||||||
|
|
||||||
|
# 鼠标事件
|
||||||
|
self.canvas.bind("<Button-1>", self.start_selection)
|
||||||
|
self.canvas.bind("<B1-Motion>", self.update_selection)
|
||||||
|
self.canvas.bind("<ButtonRelease-1>", self.finish_selection)
|
||||||
|
|
||||||
|
def select_image(self):
|
||||||
|
image_path = filedialog.askopenfilename(title="选择图片", filetypes=[("Image files", "*.jpg;*.png;*.jpeg;*.bmp"), ("All files", "*.*")])
|
||||||
|
if image_path:
|
||||||
|
self.image = Image.open(image_path)
|
||||||
|
self.display_image()
|
||||||
|
|
||||||
|
def display_image(self):
|
||||||
|
# 调整图片大小适应窗口
|
||||||
|
self.image.thumbnail((self.root.winfo_width(), self.root.winfo_height()))
|
||||||
|
self.tk_image = ImageTk.PhotoImage(self.image)
|
||||||
|
self.canvas.create_image(0, 0, anchor="nw", image=self.tk_image)
|
||||||
|
|
||||||
|
def start_selection(self, event):
|
||||||
|
# 记录起始点
|
||||||
|
self.rect_start_x = event.x
|
||||||
|
self.rect_start_y = event.y
|
||||||
|
# 创建一个选择框
|
||||||
|
self.rect = self.canvas.create_rectangle(self.rect_start_x, self.rect_start_y, self.rect_start_x, self.rect_start_y, outline="red", width=2)
|
||||||
|
|
||||||
|
def update_selection(self, event):
|
||||||
|
# 更新选择框大小
|
||||||
|
self.rect_end_x = event.x
|
||||||
|
self.rect_end_y = event.y
|
||||||
|
self.canvas.coords(self.rect, self.rect_start_x, self.rect_start_y, self.rect_end_x, self.rect_end_y)
|
||||||
|
|
||||||
|
def finish_selection(self, event):
|
||||||
|
self.rect_end_x = event.x
|
||||||
|
self.rect_end_y = event.y
|
||||||
|
self.crop_image()
|
||||||
|
|
||||||
|
def crop_image(self):
|
||||||
|
if self.image:
|
||||||
|
# 获取选择框的坐标
|
||||||
|
left = min(self.rect_start_x, self.rect_end_x)
|
||||||
|
top = min(self.rect_start_y, self.rect_end_y)
|
||||||
|
right = max(self.rect_start_x, self.rect_end_x)
|
||||||
|
bottom = max(self.rect_start_y, self.rect_end_y)
|
||||||
|
|
||||||
|
# 根据选择框坐标进行裁剪
|
||||||
|
cropped_image = self.image.crop((left, top, right, bottom))
|
||||||
|
|
||||||
|
# 让用户选择保存路径
|
||||||
|
save_path = filedialog.asksaveasfilename(defaultextension=".png", filetypes=[("PNG files", "*.png"), ("All files", "*.*")])
|
||||||
|
if save_path:
|
||||||
|
cropped_image.save(save_path)
|
||||||
|
messagebox.showinfo("成功", f"图片已保存到: {save_path}")
|
||||||
|
|
||||||
|
# 启动 GUI 应用
|
||||||
|
if __name__ == "__main__":
|
||||||
|
root = tk.Tk()
|
||||||
|
app = ImageCropApp(root)
|
||||||
|
root.geometry("800x600") # 设置初始窗口大小
|
||||||
|
root.mainloop()
|
73
acdr-ui/tootls/视频处理工具.py
Normal file
73
acdr-ui/tootls/视频处理工具.py
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
import tkinter as tk
|
||||||
|
from tkinter import filedialog, messagebox
|
||||||
|
import cv2
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
# GUI 界面
|
||||||
|
class VideoToFramesApp:
|
||||||
|
def __init__(self, root):
|
||||||
|
self.root = root
|
||||||
|
self.root.title("Video to Frames Converter")
|
||||||
|
|
||||||
|
# 文件选择按钮
|
||||||
|
self.select_button = tk.Button(
|
||||||
|
root, text="选择视频文件", command=self.select_video
|
||||||
|
)
|
||||||
|
self.select_button.pack(pady=10)
|
||||||
|
|
||||||
|
# 选择输出文件夹按钮
|
||||||
|
self.select_folder_button = tk.Button(
|
||||||
|
root, text="选择输出文件夹", command=self.select_output_folder
|
||||||
|
)
|
||||||
|
self.select_folder_button.pack(pady=10)
|
||||||
|
|
||||||
|
# 开始转换按钮
|
||||||
|
self.convert_button = tk.Button(
|
||||||
|
root, text="开始转换", command=self.convert_video
|
||||||
|
)
|
||||||
|
self.convert_button.pack(pady=10)
|
||||||
|
|
||||||
|
self.video_path = None
|
||||||
|
self.output_folder = None
|
||||||
|
|
||||||
|
def select_video(self):
|
||||||
|
self.video_path = filedialog.askopenfilename(
|
||||||
|
title="选择视频文件",
|
||||||
|
filetypes=(("MP4 files", "*.mp4"), ("All files", "*.*")),
|
||||||
|
)
|
||||||
|
if self.video_path:
|
||||||
|
messagebox.showinfo("文件已选择", f"已选择视频文件:{self.video_path}")
|
||||||
|
|
||||||
|
def select_output_folder(self):
|
||||||
|
self.output_folder = filedialog.askdirectory(title="选择输出文件夹")
|
||||||
|
if self.output_folder:
|
||||||
|
messagebox.showinfo("文件夹已选择", f"输出文件夹:{self.output_folder}")
|
||||||
|
|
||||||
|
def convert_video(self):
|
||||||
|
if not self.video_path or not self.output_folder:
|
||||||
|
messagebox.showwarning("错误", "请先选择视频文件和输出文件夹!")
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
cap = cv2.VideoCapture(self.video_path)
|
||||||
|
count = 0
|
||||||
|
while True:
|
||||||
|
ret, frame = cap.read()
|
||||||
|
if not ret:
|
||||||
|
break
|
||||||
|
frame_filename = os.path.join(self.output_folder, f"frame_{count}.jpg")
|
||||||
|
cv2.imwrite(frame_filename, frame)
|
||||||
|
count += 1
|
||||||
|
|
||||||
|
cap.release()
|
||||||
|
messagebox.showinfo("成功", f"成功提取了 {count} 帧图片")
|
||||||
|
except Exception as e:
|
||||||
|
messagebox.showerror("错误", f"发生错误:{e}")
|
||||||
|
|
||||||
|
|
||||||
|
# 启动 GUI 应用
|
||||||
|
if __name__ == "__main__":
|
||||||
|
root = tk.Tk()
|
||||||
|
app = VideoToFramesApp(root)
|
||||||
|
root.mainloop()
|
Loading…
Reference in New Issue
Block a user