第一步、用即梦AI 生成动画
提示词:
一个Q版招财猫形象,夸张的头身比,头大身小,胖乎乎的可爱脸,睁眼,微笑,单手向你招手,元宝在旁边,发光背景,“财从四面八方来”的书法中文字体位于猫猫头顶上方,柔和的光影,3D模型,OC渲染,8K,高分辨率,
小手不停向你 招手
第二步、主代码部份mao.py
import cv2
import time
import math
import threading
import keyboard
import mouse
import sys
import os
IDLE_TIME = 2 # 秒
def resource_path(relative_path):
if hasattr(sys, '_MEIPASS'):
# PyInstaller打包后的临时目录
return os.path.join(sys._MEIPASS, relative_path)
return os.path.join(os.path.abspath("."), relative_path)
VIDEO_PATH = resource_path('mao.mp4')
def play_video():
should_exit = False
last_mouse_pos = [None]
def on_keyboard(event):
nonlocal should_exit
should_exit = True
def on_mouse_move(event):
nonlocal should_exit
# if event.event_type == 'move':
should_exit = True
# 只在播放时 hook
keyboard_hook = keyboard.hook(on_keyboard)
mouse_hook = mouse.hook(on_mouse_move)
cap = cv2.VideoCapture(VIDEO_PATH)
cv2.namedWindow("Screensaver", cv2.WND_PROP_FULLSCREEN)
cv2.setWindowProperty("Screensaver", cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN)
while cap.isOpened():
if should_exit:
break
ret, frame = cap.read()
if not ret:
cap.set(cv2.CAP_PROP_POS_FRAMES, 0)
continue
# 获取当前日期和时间
now = time.strftime("%H:%M:%S")
today = time.strftime("%Y-%m-%d")
font = cv2.FONT_HERSHEY_SIMPLEX
font_scale_time = 1.5 # 时间稍小一点
font_scale_date = 1.0 # 日期更小
thickness_time = 3
thickness_date = 2
color = (255, 255, 255) # 白色
# 计算时间和日期的尺寸
(text_w_time, text_h_time), _ = cv2.getTextSize(now, font, font_scale_time, thickness_time)
(text_w_date, text_h_date), _ = cv2.getTextSize(today, font, font_scale_date, thickness_date)
text_w = max(text_w_time, text_w_date)
text_h = text_h_date + text_h_time + 10 # 10像素间隔
h, w = frame.shape[:2]
x = w - text_w - 30
y = h - 30
# 画蓝色半透明底框
rect_x1 = x - 12
rect_y1 = y - text_h - 12
rect_x2 = x + text_w + 12
rect_y2 = y + 12
overlay = frame.copy()
cv2.rectangle(overlay, (rect_x1, rect_y1), (rect_x2, rect_y2), (255, 102, 0), -1) # 蓝色(BGR)
alpha = 0.5
frame = cv2.addWeighted(overlay, alpha, frame, 1 - alpha, 0)
# 日期位置
date_x = x + (text_w - text_w_date) // 2
date_y = y - text_h + text_h_date
# 时间位置
time_x = x + (text_w - text_w_time) // 2
time_y = y
# 先画黑色描边
cv2.putText(frame, today, (date_x, date_y), font, font_scale_date, (0,0,0), thickness_date+2, cv2.LINE_AA)
cv2.putText(frame, now, (time_x, time_y), font, font_scale_time, (0,0,0), thickness_time+2, cv2.LINE_AA)
# 再画白色文字
cv2.putText(frame, today, (date_x, date_y), font, font_scale_date, color, thickness_date, cv2.LINE_AA)
cv2.putText(frame, now, (time_x, time_y), font, font_scale_time, color, thickness_time, cv2.LINE_AA)
# 左上角画更大的圆形时钟,位置更靠近左上角
clock_radius = 100
clock_center = (20 + clock_radius, 20 + clock_radius)
# 表盘
cv2.circle(frame, clock_center, clock_radius, (0, 0, 0), 8)
cv2.circle(frame, clock_center, clock_radius-4, (255,255,255), -1)
# 刻度
for i in range(12):
angle = math.radians(i * 30 - 90)
x1 = int(clock_center[0] + (clock_radius-15) * math.cos(angle))
y1 = int(clock_center[1] + (clock_radius-15) * math.sin(angle))
x2 = int(clock_center[0] + (clock_radius-4) * math.cos(angle))
y2 = int(clock_center[1] + (clock_radius-4) * math.sin(angle))
cv2.line(frame, (x1, y1), (x2, y2), (0,0,0), 5)
# 获取当前时间
t = time.localtime()
sec = t.tm_sec
minute = t.tm_min
hour = t.tm_hour % 12
# 秒针
sec_angle = math.radians(sec * 6 - 90)
sec_x = int(clock_center[0] + (clock_radius-30) * math.cos(sec_angle))
sec_y = int(clock_center[1] + (clock_radius-30) * math.sin(sec_angle))
cv2.line(frame, clock_center, (sec_x, sec_y), (0,0,255), 3)
# 分针
min_angle = math.radians(minute * 6 - 90)
min_x = int(clock_center[0] + (clock_radius-45) * math.cos(min_angle))
min_y = int(clock_center[1] + (clock_radius-45) * math.sin(min_angle))
cv2.line(frame, clock_center, (min_x, min_y), (0,128,255), 8)
# 时针
hour_angle = math.radians((hour + minute/60) * 30 - 90)
hour_x = int(clock_center[0] + (clock_radius-65) * math.cos(hour_angle))
hour_y = int(clock_center[1] + (clock_radius-65) * math.sin(hour_angle))
cv2.line(frame, clock_center, (hour_x, hour_y), (0,128,0), 14)
# 圆心
cv2.circle(frame, clock_center, 10, (0,0,0), -1)
cv2.imshow("Screensaver", frame)
if cv2.waitKey(30) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
keyboard.unhook(keyboard_hook)
mouse.unhook(mouse_hook)
sys.exit(0)
def monitor():
last_activity = time.time()
def update_activity(event):
nonlocal last_activity
last_activity = time.time()
keyboard_hook = keyboard.hook(update_activity)
mouse_hook = mouse.hook(update_activity)
print("屏保程序已启动,按 Ctrl+C 退出。")
while True:
if time.time() - last_activity > IDLE_TIME:
keyboard.unhook(keyboard_hook)
mouse.unhook(mouse_hook)
play_video()
break
time.sleep(0.5)
def main():
monitor()
if __name__ == "__main__":
main()
第三步 生成exe 转成scr
可以!你可以用 PyInstaller 的 --add-data
参数把 mao.mp4
一起打包进可执行文件。这样生成的 .exe
(或 .scr
)文件在任何电脑上都能直接运行,无需单独拷贝视频。
步骤如下
1. 修改代码,适配资源路径
PyInstaller 打包后,资源文件会被放到临时目录。你需要用如下方法获取正确路径:
import sys
import os
def resource_path(relative_path):
if hasattr(sys, '_MEIPASS'):
# PyInstaller打包后的临时目录
return os.path.join(sys._MEIPASS, relative_path)
return os.path.join(os.path.abspath("."), relative_path)
VIDEO_PATH = resource_path('mao.mp4')
2. 用 PyInstaller 打包并添加视频
在命令行运行(注意分号和路径写法,Windows下用分号,Linux/Mac用冒号):
pyinstaller --onefile --noconsole --add-data "mao.mp4;." mao.py
"mao.mp4;."
表示把当前目录下的mao.mp4
打包到可执行文件的同级目录下(PyInstaller内部)。- 如果你用的是 Linux/Mac,把分号换成冒号:
mao.mp4:.
3. 生成 .scr
并使用
- 打包后,
dist/mao.exe
就包含了视频文件。 - 按前述方法改名为
mao.scr
,放到C:\Windows\SysWOW64
。
注意:
- 代码用
resource_path
获取视频路径。 - 打包时用
--add-data
把视频一起打包。 - 这样生成的屏保文件是“自带视频”的,无需额外拷贝。