提交 d3a4ce5a 编写于 作者: 三月三net's avatar 三月三net

Python超人-宇宙模拟器

上级 79a98bf0
import cv2
from PIL import ImageGrab
import numpy as np
import argparse
import time
import os
import win32gui
import win32ui
import win32con
import win32api
FFMPEG_PATH = "F:\\Tools\\ffmpeg"
def crop(mp4_file):
# "ffmpeg -i input.mp4 -vf crop=1724:972:194:108 output.mp4 -y"
cmd = 'SET PATH=%PATH%;"' + FFMPEG_PATH + '" & '
cmd = cmd + 'ffmpeg -i "' + mp4_file + '" -vf crop=1724:972:194:108 "' + mp4_file + '_crop.mp4" -y'
val = os.system(cmd)
if val == 0:
print("裁剪视频成功")
else:
print("裁剪视频失败")
def get_window_img_dc(window_name="宇宙模拟器(universe sim)"):
# 获取桌面
# hdesktop = win32gui.GetDesktopWindow()
handle = win32gui.FindWindow(None, window_name)
return handle
def record():
parser = argparse.ArgumentParser()
parser.add_argument('--fps', type=int, default=30, help='frame per second')
parser.add_argument('--window_name', type=str, default='宇宙模拟器(universe sim)', help='window_name')
parser.add_argument('--total_time', type=int, default=10000000, help='video total time')
parser.add_argument('--savename', type=str, default='video_right.mp4', help='save file name')
parser.add_argument('--screen_type', default=0, type=int, choices=[0, 1], help='1: full screen, 0: region screen')
args = parser.parse_args()
if args.screen_type == 0:
print('Press Esc to close window')
if args.screen_type:
curScreen = ImageGrab.grab() # 获取屏幕对象
height, width = curScreen.size
min_x, min_y, max_x, max_y = 0, 0, width, height
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
video = cv2.VideoWriter(args.savename, fourcc, args.fps, (height, width))
else:
# point1, point2 = select_roi(curScreen)
# print(point1, point2) # (184, 71) (1719, 932)
point1, point2 = (194, 108), (1724, 972)
print(point1, point2) # (184, 71) (1719, 932)
min_x = min(point1[0], point2[0])
min_y = min(point1[1], point2[1])
max_x = max(point1[0], point2[0])
max_y = max(point1[1], point2[1])
width, height = max_y - min_y, max_x - min_x
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
video = cv2.VideoWriter(args.savename, fourcc, args.fps, (height, width))
# wait_ms = 1000 / args.fps
imageNum = 0
print("查找模拟器窗口")
while True:
handle = get_window_img_dc()
if handle > 0:
print(handle)
break
time.sleep(0.001)
print("开始捕捉...")
while True:
handle = get_window_img_dc()
if handle == 0:
print("模拟器窗口关闭")
break
# current_time = time.time() * 1000
# next_frame_time = last_time + wait_ms
# if current_time < next_frame_time:
# time.sleep((next_frame_time - current_time) / 1000)
# print((next_frame_time - current_time) / 1000)
#
# last_time = time.time() * 1000
imageNum += 1
captureImage = ImageGrab.grab() # 抓取屏幕
frame = cv2.cvtColor(np.array(captureImage), cv2.COLOR_RGB2BGR)
if args.screen_type == 0:
frame = frame[min_y:max_y, min_x:max_x, :]
# print(imageNum, args.fps, args.total_time)
if imageNum < args.fps * args.total_time:
video.write(frame)
# 退出条件
# if cv2.waitKey(50) == ord('q') or imageNum > args.fps * args.total_time:
#
k = cv2.waitKey(1)
# print(k)
if k == 27 or imageNum > args.fps * args.total_time: # Esc key to stop
print("退出...")
break
print("视频保存")
video.release()
cv2.destroyAllWindows()
# crop('video.mp4')
print("完成")
if __name__ == '__main__':
record()
......@@ -20,6 +20,6 @@ cd %SimFilePath%
start python -m %SimFileName% 3d
cd %SimDir%\tools
python -m sim_video_3d_cap_ext --save_name=%SimFileName%.mp4 %param3%
python -m sim_video_3d_cap_ext --save_name=%param3%
import cv2
from PIL import ImageGrab, Image
import numpy as np
import argparse
import time
import os
import win32gui
import win32ui
import win32con
import win32api
import traceback
def get_window_handle(window_name="宇宙模拟器(universe sim)"):
"""
获取模拟器窗口句柄
@param window_name:
@return:
"""
handle = win32gui.FindWindow(None, window_name)
return handle
def get_args():
parser = argparse.ArgumentParser()
parser.add_argument('--fps', type=int, default=30, help='frame per second')
parser.add_argument('--total_time', type=int, default=10000000, help='video total time')
parser.add_argument('--save_name', type=str, default='video.mp4', help='save file name')
# parser.add_argument('--screen_type', default=0, type=int, choices=[0, 1], help='1: full screen, 0: region screen')
args = parser.parse_args()
print("total_time:", args.total_time)
print("fps:", args.fps)
print("save_name:", args.save_name)
return args
def screen_shot(window_img_dc):
width, height = win32api.GetSystemMetrics(win32con.SM_CXVIRTUALSCREEN), \
win32api.GetSystemMetrics(win32con.SM_CYVIRTUALSCREEN)
# 创建一个内存设备描述表
mem_dc = window_img_dc.CreateCompatibleDC()
# 创建位图对象
screenshot = win32ui.CreateBitmap() # win32ui.CreateBitmap() GetBitmapBits() MemoryError
screenshot.CreateCompatibleBitmap(window_img_dc, width, height)
mem_dc.SelectObject(screenshot)
# 截图至内存设备描述表
mem_dc.BitBlt((0, 0), (width, height), window_img_dc, (0, 0), win32con.SRCCOPY)
# 将截图保存到文件中
# screenshot.SaveBitmapFile(mem_dc, 'screenshot.bmp')
# TODO: Traceback (most recent call last):
# File "G:\works\gitcode\universe_sim\tools\sim_video_3d_cap.py", line 79, in sim_window_screen_shot
# img = screen_shot(img_dc)
# File "G:\works\gitcode\universe_sim\tools\sim_video_3d_cap.py", line 50, in screen_shot
# signedIntsArray = screenshot.GetBitmapBits(True)
# MemoryError
signedIntsArray = screenshot.GetBitmapBits(True)
# 下面3个语句都能实现转换,推荐第1个
# TODO: G:\works\gitcode\universe_sim\tools\sim_video_3d_cap.py:52:
# DeprecationWarning: The binary mode of fromstring is deprecated, as it behaves surprisingly on unicode inputs. Use frombuffer instead
# img = np.fromstring(signedIntsArray, dtype='uint8')
img = np.fromstring(signedIntsArray, dtype='uint8')
img.shape = (height, width, 4)
# 内存释放
mem_dc.DeleteDC()
win32gui.DeleteObject(screenshot.GetHandle())
img = img[:, :, 0:3] # 去掉透明数据
return img
# def is_blank_screen(img_arr):
# for x in range(500, 600):
# for y in range(10, 20):
# pix = img_arr[x, y, ]
# # 检查标题栏,此时标题栏的颜色为白色
# if pix.sum() > 600:
# return True
# return False
def sim_window_screen_shot(wait_ses=-1):
times = wait_ses * 100
while True:
handle = get_window_handle()
if handle > 0:
desktop_dc = win32gui.GetWindowDC(handle)
img_dc = win32ui.CreateDCFromHandle(desktop_dc)
try:
img = screen_shot(img_dc)
except Exception as e:
print("ERROR:", str(e))
traceback.print_exc()
return None
return img
if wait_ses < 0:
return None
time.sleep(0.01)
times -= 1
if times <= 0:
return None
def create_video(args, height, width):
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
video = cv2.VideoWriter(args.save_name, fourcc, args.fps, (width, height))
return video
def show_image(img):
from PIL import Image
image = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
image = Image.fromarray(image)
print(type(image)) # 结果为<class 'PIL.JpegImagePlugin.JpegImageFile'>
print(image.size) # 结果为(822,694),这里注意Image输出的结果先显示列数,后显示行数
image.show()
if __name__ == '__main__':
args = get_args()
handle = get_window_handle()
# print(get_args())
print("请在10秒内打开模拟器")
img = sim_window_screen_shot(10)
if img is None:
print("没有找到模拟器窗口,录屏失败!")
exit(1)
# show_image(img)
video = create_video(args, img.shape[0], img.shape[1])
imageNum = 0
index_base = 0
last_index = 0
r_frames = {}
l_frames = {}
print("开始录屏")
while True:
img = sim_window_screen_shot()
if img is None:
print("\n模拟器窗口已关闭,退出录屏")
break
_3d_card = img[4:20, 3:20, ]
_3d_card_p = _3d_card[10, 10,]
index = int(_3d_card_p[1]) + int(_3d_card_p[0])
if index < last_index:
index_base += (last_index + 1)
last_index = index
index = index + index_base
if _3d_card_p[2] < 100:
_3d_card_color = "b"
_3d_card_direct = "right"
if index not in r_frames.keys():
r_frames[index] = img[:864, :768, ]
else:
_3d_card_color = "w"
_3d_card_direct = "left"
if index not in l_frames.keys():
l_frames[index] = img[:864, :768, ]
# if is_blank_screen(img):
# if imageNum % args.fps == 0:
# print('x', end='')
#
# continue
if imageNum % args.fps == 0:
print('.', end='')
# else:
# print(imageNum, end='')
imageNum += 1
# frame = cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR)
# if imageNum < args.fps * args.total_time:
# # img = img[:432,:768,]
# # show_image(frame)
# video.write(img)
min_index = min(r_frames.keys())
max_index = max(r_frames.keys())
print("对视频进行3D处理")
for index in range(min_index, max_index + 1):
rv = r_frames.get(index, None)
lv = l_frames.get(index, None)
if rv is None or lv is None:
continue
merged_list = [np.concatenate((lv[i], sublist), axis=0) for i, sublist in enumerate(rv)]
# show_image(np.array(merged_list))
# TODO: Traceback (most recent call last):
# File "D:\Anaconda3\envs\pythoncr\lib\runpy.py", line 197, in _run_module_as_main
# return _run_code(code, main_globals, None,
# File "D:\Anaconda3\envs\pythoncr\lib\runpy.py", line 87, in _run_code
# exec(code, run_globals)
# File "G:\works\gitcode\universe_sim\tools\sim_video_3d_cap.py", line 180, in <module>
# video.write(np.array(merged_list))
# numpy.core._exceptions._ArrayMemoryError: Unable to allocate 3.80 MiB for an array with shape (864, 1536, 3) and data type uint8
try:
video.write(np.array(merged_list))
except Exception as e:
print("video.write ERROR:", str(e))
traceback.print_exc()
break
print("视频保存中")
video.release()
cv2.destroyAllWindows()
# crop('video.mp4')
print("视频保存完成")
......@@ -131,29 +131,29 @@ def video_write(video, l_frames, r_frames):
return
min_index = min(r_frames.keys())
max_index = max(r_frames.keys())
print("index:", end='')
# print("index:", end='')
for index in range(min_index, max_index + 1):
rv = r_frames.get(index, None)
lv = l_frames.get(index, None)
if rv is None and lv is None:
print('[' + str(index) + "], ", end='')
# print('[' + str(index) + "], ", end='')
continue
if rv is None:
rv = r_frames.get(index-1, None)
if rv is None:
rv = r_frames.get(index + 1, None)
if rv is None:
print('[R:'+str(index) + "], ", end='')
# print('[R:'+str(index) + "], ", end='')
continue
if lv is None:
lv = l_frames.get(index-1, None)
if lv is None:
lv = l_frames.get(index + 1, None)
if lv is None:
print('[L:' + str(index) + "], ", end='')
# print('[L:' + str(index) + "], ", end='')
continue
print(str(index) + ", ", end='')
# print(str(index) + ", ", end='')
merged_list = [np.concatenate((lv[i], sublist), axis=0) for i, sublist in enumerate(rv)]
try:
video.write(np.array(merged_list))
......@@ -361,6 +361,7 @@ def make_3d_video():
clear_frame_temp_files()
# crop('video.mp4')
print("视频保存完成")
print(args.save_name)
if __name__ == '__main__':
......
......@@ -20,6 +20,6 @@ cd %SimFilePath%
start python -m %SimFileName% %3
cd %SimDir%\tools
python -m sim_video_cap --save_name=%SimFileName%%param3%.mp4
python -m sim_video_cap --save_name=%param3%
......@@ -148,3 +148,4 @@ if __name__ == '__main__':
cv2.destroyAllWindows()
# crop('video.mp4')
print("视频保存完成")
print(args.save_name)
@REM @echo off
@REM 设置环境和参数
SET Anaconda3=D:/Anaconda3
SET env=pythoncr
SET DISK=D:
SET SimDir=%DISK%/gitee/universe_sim
SET SimFileDir=%1
SET SimFileName=%2
SET param3=%3
SET PYTHONPATH=%SimDir%;
SET SimFilePath=%SimDir%/sim_scenes/%SimFileDir%/
CALL %Anaconda3%/Scripts/activate.bat %Anaconda3%
CALL conda activate %env%
%DISK%
cd %SimFilePath%
@REM universe_sim.bat science speed_of_light_3d
python -m %SimFileName%
cd %SimDir%\tools
@REM @echo off
@REM 设置环境和参数
SET Anaconda3=D:/Anaconda3
SET env=pythoncr
SET DISK=D:
SET SimDir=%DISK%/gitee/universe_sim
SET SimFileName=%1
CALL %Anaconda3%/Scripts/activate.bat %Anaconda3%
CALL conda activate %env%
%DISK%
cd %SimDir%\tools
@REM video_cap.bat speed_of_light_3d
python -m sim_video_3d_cap_ext --save_name=%SimFileName%_2.mp4
import tkinter as tk
from tkinter import filedialog, messagebox
import os
initial_dir = os.path.join(os.getcwd(), "..", "sim_scenes")
def browse_file():
if len(output_entry.get()) == 0:
open_dir = initial_dir
else:
open_dir = os.path.dirname(input_entry.get())
file_path = filedialog.askopenfilename(initialdir=open_dir, filetypes=[("场景模拟Python文件", "*.py")])
if len(file_path) == 0:
return
input_entry.delete(0, tk.END)
input_entry.insert(0, file_path)
output_entry.delete(0, tk.END)
output_entry.insert(0, file_path[0:-3] + ".mp4")
check3d()
def browse_save():
if len(output_entry.get()) == 0:
save_dir = initial_dir
else:
save_dir = os.path.dirname(output_entry.get())
save_path = filedialog.asksaveasfilename(initialdir=save_dir, filetypes=[("MP4视频文件", "*.mp4")])
if len(save_path) > 4:
if not save_path.endswith(".mp4"):
save_path += ".mp4"
else:
return
output_entry.delete(0, tk.END)
output_entry.insert(0, save_path)
check3d()
def generate():
input = input_entry.get()
output = output_entry.get()
inputs = os.path.normpath(input).split(os.sep)
# outputs = os.path.normpath(output).split(os.sep)
if checkbox3d_var.get() == 1:
# sim_video_3d_cap.bat fiction transformed_mars_ani_3d
m_file = "sim_video_3d_cap"
else:
# sim_video_cap.bat science jupiter_moon_protects_earth
m_file = "sim_video_cap"
shell = u"%s %s %s \"%s\"" % (m_file, inputs[-2], inputs[-1][:-3], output)
# shell = u"%s %s %s" % (m_file, inputs[-2], inputs[-1][:-3])
import subprocess
import sys
# subprocess.Popen(shell, shell=True)
# shell =shell.encode(sys.getfilesystemencoding())
print(shell)
subprocess.call(shell, shell=True)
def open_output_dir():
output_file = output_entry.get()
if len(output_file) == 0:
return
# filedialog.askdirectory(initialdir=output_dir)
output_dir = os.path.dirname(output_file)
os.system('start ' + output_dir)
def start():
input = input_entry.get()
output = output_entry.get()
err_msg = ""
if len(input) == 0:
err_msg = "“模拟代码文件”不能为空\n"
if len(output) == 0:
err_msg += "“视频保存文件”不能为空\n"
if len(err_msg) > 0:
messagebox.showwarning("消息", err_msg)
return
if messagebox.askyesno("确认", "是否开始生成视频?"):
generate()
def check3d():
save_file = output_entry.get()
if checkbox3d_var.get() == 1:
if not save_file.endswith("_3d.mp4") and save_file.endswith(".mp4"):
output_entry.delete(0, tk.END)
output_entry.insert(0, save_file[:-4] + "_3d.mp4")
else:
if save_file.endswith("_3d.mp4"):
output_entry.delete(0, tk.END)
output_entry.insert(0, save_file[:-7] + ".mp4")
root = tk.Tk()
root.title("模拟器视频生成工具")
input_entry = tk.Entry(root, width=80)
input_entry.grid(row=0, column=2)
browse_button = tk.Button(root, text="模拟代码文件", command=browse_file)
browse_button.grid(row=0, column=1)
output_entry = tk.Entry(root, width=80)
output_entry.grid(row=1, column=2)
browse_save_button = tk.Button(root, text="视频保存文件", command=browse_save)
browse_save_button.grid(row=1, column=1)
open_output_dir_button = tk.Button(root, text="...", command=open_output_dir)
open_output_dir_button.grid(row=1, column=3)
checkbox3d_var = tk.IntVar()
checkbox3d = tk.Checkbutton(root, text="生成3D视频", command=check3d, variable=checkbox3d_var)
checkbox3d.grid(row=2, column=1)
generate_button = tk.Button(root, text="点击开始", width=20, command=start)
generate_button.grid(row=2, column=2)
# root.withdraw() # 隐藏主窗口
screen_width = 680
screen_height = 200
x = (screen_width / 2) - (root.winfo_width() / 2)
y = (screen_height / 2) - (root.winfo_height() / 2)
root.geometry("%dx%d+%d+%d" % (screen_width, screen_height, x, y))
root.mainloop()
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册