mirror of
https://github.com/zhenyan121/dotfiles.git
synced 2026-04-10 14:34:09 +08:00
feat: 上传我的配置
This commit is contained in:
105
.config/waybar/scripts/longshot-sh/stitch.py
Executable file
105
.config/waybar/scripts/longshot-sh/stitch.py
Executable file
@@ -0,0 +1,105 @@
|
||||
#!/usr/bin/env python3
|
||||
import cv2
|
||||
import numpy as np
|
||||
import sys
|
||||
import os
|
||||
|
||||
def stitch_video(video_path, output_path):
|
||||
if not os.path.exists(video_path):
|
||||
return
|
||||
|
||||
cap = cv2.VideoCapture(video_path)
|
||||
if not cap.isOpened():
|
||||
print("❌ 无法打开视频")
|
||||
return
|
||||
|
||||
frames = []
|
||||
ret, prev_frame = cap.read()
|
||||
if not ret: return
|
||||
|
||||
frames.append(prev_frame)
|
||||
anchor_frame = prev_frame.copy()
|
||||
|
||||
# ==========================
|
||||
# 核心参数 (手动滚动优化)
|
||||
# ==========================
|
||||
MIN_SCROLL = 2
|
||||
MATCH_CONFIDENCE = 0.5
|
||||
|
||||
# 忽略上下边缘 (防止浏览器地址栏/状态栏干扰)
|
||||
IGNORE_Y_TOP = 0.15
|
||||
IGNORE_Y_BOTTOM = 0.15
|
||||
IGNORE_X = 0.15
|
||||
|
||||
h, w, _ = anchor_frame.shape
|
||||
|
||||
# 有效特征区
|
||||
x1 = int(w * IGNORE_X)
|
||||
x2 = int(w * (1 - IGNORE_X))
|
||||
y1 = int(h * IGNORE_Y_TOP)
|
||||
template_h = int(h * 0.2)
|
||||
|
||||
print(f"⚡ 正在分析 (梯度匹配模式)...")
|
||||
|
||||
last_shift = 0
|
||||
SEARCH_WINDOW = 50
|
||||
|
||||
while True:
|
||||
ret, curr_frame = cap.read()
|
||||
if not ret: break
|
||||
|
||||
# 1. 梯度处理 (解决白底黑字问题)
|
||||
curr_gray = cv2.cvtColor(curr_frame, cv2.COLOR_BGR2GRAY)
|
||||
anchor_gray = cv2.cvtColor(anchor_frame, cv2.COLOR_BGR2GRAY)
|
||||
|
||||
curr_grad = cv2.Sobel(curr_gray, cv2.CV_8U, 0, 1, ksize=3)
|
||||
anchor_grad = cv2.Sobel(anchor_gray, cv2.CV_8U, 0, 1, ksize=3)
|
||||
|
||||
# 2. 提取模板
|
||||
template = curr_grad[y1 : y1 + template_h, x1:x2]
|
||||
roi = anchor_grad[y1:, x1:x2]
|
||||
|
||||
# 3. 匹配
|
||||
res = cv2.matchTemplate(roi, template, cv2.TM_CCOEFF_NORMED)
|
||||
|
||||
# 4. 惯性约束
|
||||
if last_shift > 0:
|
||||
mask = np.zeros_like(res)
|
||||
target_y = last_shift
|
||||
y_min = max(0, target_y - SEARCH_WINDOW)
|
||||
y_max = min(res.shape[0], target_y + SEARCH_WINDOW)
|
||||
mask[y_min:y_max, :] = 1
|
||||
res = np.multiply(res, mask)
|
||||
|
||||
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
|
||||
shift = max_loc[1]
|
||||
|
||||
# 5. 判定
|
||||
if max_val > MATCH_CONFIDENCE and shift > MIN_SCROLL and shift < (roi.shape[0] - 5):
|
||||
new_content_start_y = h - shift
|
||||
if new_content_start_y < h:
|
||||
new_part = curr_frame[new_content_start_y:, :, :]
|
||||
frames.append(new_part)
|
||||
anchor_frame = curr_frame.copy()
|
||||
|
||||
if last_shift == 0: last_shift = shift
|
||||
else: last_shift = int(last_shift * 0.6 + shift * 0.4)
|
||||
|
||||
cap.release()
|
||||
|
||||
if len(frames) > 1:
|
||||
try:
|
||||
full_image = np.vstack(frames)
|
||||
cv2.imwrite(output_path, full_image, [cv2.IMWRITE_PNG_COMPRESSION, 3])
|
||||
print(f"🎉 处理完成")
|
||||
except Exception as e:
|
||||
print(f"❌ 保存失败: {e}")
|
||||
else:
|
||||
print("⚠️ 未检测到滚动,保存第一帧")
|
||||
cv2.imwrite(output_path, frames[0])
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 3:
|
||||
print("Usage: python stitch.py <input_video> <output_image>")
|
||||
else:
|
||||
stitch_video(sys.argv[1], sys.argv[2])
|
||||
Reference in New Issue
Block a user