svjack commited on
Commit
d861daf
·
verified ·
1 Parent(s): e659d7b

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +128 -0
app.py ADDED
@@ -0,0 +1,128 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import cv2
3
+ import numpy as np
4
+ from PIL import Image, ImageDraw, ImageFont
5
+ import tempfile
6
+ import os
7
+
8
+ def process_video_with_mask(video_path, mask_path, text="Joker"):
9
+ # 创建临时输出文件
10
+ output_path = os.path.join(tempfile.gettempdir(), "output.mp4")
11
+
12
+ # 打开视频和mask视频
13
+ cap_video = cv2.VideoCapture(video_path)
14
+ cap_mask = cv2.VideoCapture(mask_path)
15
+
16
+ # 获取视频参数
17
+ fps = cap_video.get(cv2.CAP_PROP_FPS)
18
+ width = int(cap_video.get(cv2.CAP_PROP_FRAME_WIDTH))
19
+ height = int(cap_video.get(cv2.CAP_PROP_FRAME_HEIGHT))
20
+
21
+ # 创建视频写入器
22
+ fourcc = cv2.VideoWriter_fourcc(*'mp4v')
23
+ out = cv2.VideoWriter(output_path, fourcc, fps, (width, height))
24
+
25
+ while True:
26
+ ret_video, frame_video = cap_video.read()
27
+ ret_mask, frame_mask = cap_mask.read()
28
+
29
+ if not ret_video or not ret_mask:
30
+ break
31
+
32
+ # 处理mask为单通道
33
+ if len(frame_mask.shape) == 3:
34
+ frame_mask = cv2.cvtColor(frame_mask, cv2.COLOR_BGR2GRAY)
35
+
36
+ # 找到mask中的白色区域
37
+ _, binary = cv2.threshold(frame_mask, 200, 255, cv2.THRESH_BINARY)
38
+
39
+ # 查找轮廓
40
+ contours, _ = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
41
+
42
+ # 转换为PIL图像处理文字
43
+ pil_image = Image.fromarray(cv2.cvtColor(frame_video, cv2.COLOR_BGR2RGB))
44
+ draw = ImageDraw.Draw(pil_image)
45
+
46
+ if contours:
47
+ # 找到面积最大的轮廓
48
+ max_contour = max(contours, key=cv2.contourArea)
49
+
50
+ # 获取旋转矩形
51
+ rect = cv2.minAreaRect(max_contour)
52
+ box = cv2.boxPoints(rect)
53
+ box = np.int0(box)
54
+
55
+ # 计算中心点和尺寸
56
+ center = rect[0]
57
+ size = rect[1]
58
+ angle = rect[2]
59
+
60
+ # 创建透明画布绘制文字
61
+ text_image = Image.new("RGBA", (int(size[0]), int(size[1])), (0, 0, 0, 0))
62
+ text_draw = ImageDraw.Draw(text_image)
63
+
64
+ try:
65
+ # 自动调整字体大小
66
+ font_size = int(min(size[0] * 0.8 / max(1, len(text)), size[1] * 0.8))
67
+ font = ImageFont.truetype("华文琥珀.ttf", font_size)
68
+ except:
69
+ font = ImageFont.load_default()
70
+
71
+ # 计算文字位置
72
+ bbox = text_draw.textbbox((0, 0), text, font=font)
73
+ text_w = bbox[2] - bbox[0]
74
+ text_h = bbox[3] - bbox[1]
75
+ pos_x = (size[0] - text_w) // 2
76
+ pos_y = (size[1] - text_h) // 2
77
+
78
+ # 绘制文字
79
+ text_draw.text((pos_x, pos_y), text, fill=(255, 255, 0, 255), font=font)
80
+
81
+ # 旋转文字
82
+ rotated_text = text_image.rotate(angle, expand=True, center=(size[0]/2, size[1]/2))
83
+
84
+ # 计算粘贴位置
85
+ paste_x = int(center[0] - rotated_text.width / 2)
86
+ paste_y = int(center[1] - rotated_text.height / 2)
87
+
88
+ # 合并到原图
89
+ pil_image.paste(rotated_text, (paste_x, paste_y), rotated_text)
90
+
91
+ # 转换回OpenCV格式
92
+ frame_processed = cv2.cvtColor(np.array(pil_image), cv2.COLOR_RGB2BGR)
93
+ out.write(frame_processed)
94
+
95
+ # 释放资源
96
+ cap_video.release()
97
+ cap_mask.release()
98
+ out.release()
99
+
100
+ return output_path
101
+
102
+ # 创建Gradio界面
103
+ with gr.Blocks() as demo:
104
+ gr.Markdown("## 视频文字替换工具")
105
+ with gr.Row():
106
+ with gr.Column():
107
+ video_input = gr.Video(label="原始视频")
108
+ mask_input = gr.Video(label="Mask视频")
109
+ text_input = gr.Textbox(label="要添加的文字", value="示例文字")
110
+ submit_btn = gr.Button("处理视频")
111
+ with gr.Column():
112
+ video_output = gr.Video(label="处理结果")
113
+
114
+ submit_btn.click(
115
+ fn=process_video_with_mask,
116
+ inputs=[video_input, mask_input, text_input],
117
+ outputs=video_output,
118
+ )
119
+
120
+ gr.Examples(
121
+ [
122
+ ["examples/20250511-013442_3331156457_.mp4", "examples/20250511-013442_3331156457__temp.mp4_alpha_temp.mp4", "今天天气怎么样?"]
123
+ ],
124
+ [video_input, mask_input, text_input]
125
+ )
126
+
127
+ if __name__ == "__main__":
128
+ demo.launch(share=True)