京韵同创 发表于 2023-12-9 12:38

【原创开源】Python开发的视频抽帧,自动抠图,自动添背景

本帖最后由 京韵同创 于 2023-12-9 20:18 编辑

前言:

在吾爱破解也这么多年了,做开发也好多年了,这次也支持下论坛!


介绍:

主要就是把视频分割为图片,然后自动抠图,自动加背景。【这次先贡献一个小软件,如果支持多的话,下次再放出一些商用的软件【开源】】

界面:




对了抠图接口调用的是remove,源码和软件都打包啦,感谢大家的支持!

import os
import cv2
import mysql.connector
import numpy as np
from tkinter import filedialog
from tkinter import *
from datetime import datetime, timedelta
import json
from tkinter importmessagebox, Toplevel
from concurrent.futures import ThreadPoolExecutor
import requests
from threading import Thread
import random




# 建立连接
mydb = mysql.connector.connect(
host="你的服务器IP",
user="数据库账号",
password="数据库密码",
database="数据库名"
)

# 创建游标
mycursor = mydb.cursor()

# 从视频中提取图片
# 修改 extract_images_from_video 函数以添加弹窗提示
def extract_images_from_video(video_path, output_dir, n_images):
    if n_images > 1:
      messagebox.showwarning("提示", "如果分割多张图片,有时候只能扣一张,国外接口有并发限制,同一个视频尽量就分割一张,不然浪费次数!")
    vidcap = cv2.VideoCapture(video_path)
    total_frames = int(vidcap.get(cv2.CAP_PROP_FRAME_COUNT))
    frames_step = total_frames // n_images
    success, image = vidcap.read()
    count = 0
    while success:
      if count % frames_step == 0:
            cv2.imwrite(os.path.join(output_dir, "frame%d.jpg" % count), image)
            remove_background(os.path.join(output_dir, "frame%d.jpg" % count))
      success, image = vidcap.read()
      count += 1



# 修改 remove_background 函数,使其支持异步执行
with open('api.json') as f:
    config = json.load(f)

removebg_api_key = config['removebg_api_key']

def remove_background(image_path):
    def update_warning_label():
      warning_text.set("正在抠图中,请稍后!")# 更新提示内容

    root.after(0, update_warning_label)# 在主线程中更新 GUI

    response = requests.post(
      'https://api.remove.bg/v1.0/removebg',
      files={'image_file': open(image_path, 'rb')},
      data={'size': 'auto'},
      headers={'X-Api-Key': removebg_api_key},
    )
    if response.status_code == requests.codes.ok:
      with open(image_path.replace(".jpg", ".png"), 'wb') as out:
            out.write(response.content)
      thread = Thread(target=add_gradient_background, args=(image_path.replace(".jpg", ".png"),))
      thread.start()
    else:
      print("错误:", response.status_code, response.text)





# 读取颜色列表
with open('colors.json') as f:
    color_list = json.load(f)['colors']

# 随机选择一组颜色
color1, color2 = random.choice(color_list)

# 现在color1和color2就是一组随机选择的颜色


def add_gradient_background(image_path):
    def update_warning_label():
      warning_text.set("正在换背景中,请稍后!")# 更新提示内容

    def reset_warning_label():
      warning_text.set("已处理完毕,请查看输出文件夹!")# 恢复默认提示

    root.after(0, update_warning_label)# 在主线程中更新 GUI

    image = cv2.imread(image_path, cv2.IMREAD_UNCHANGED)
    h, w = image.shape[:2]

    gradient = np.zeros((h, w, 3), dtype=np.uint8)
    # 创建渐变背景
    for i in range(w):
      if i < w / 2:
            gradient[:, i, :] = [(color2 - color1) * (i / w * 2) + color1 for j in range(3)]
      else:
            gradient[:, i, :] = [(color1 - color2) * ((i - w / 2) / w * 2) + color2 for j in range(3)]

    alpha_channel = image[:, :, 3] / 255.
    result = (image[:, :, :3] * alpha_channel[..., None] + gradient * (1 - alpha_channel[..., None])).astype(np.uint8)
    cv2.imwrite(image_path.replace(".png", "_with_gradient.png"), result)

    root.after(0, reset_warning_label)# 在函数末尾恢复默认提示




def validate_input(user_id, code):
    # SQL 查询语句
    query = "SELECT * FROM iscode WHERE code = %s"
    value = (code,)

    # 执行 SQL 查询
    mycursor.execute(query, value)

    # 获取所有记录
    records = mycursor.fetchall()

    # 如果找到记录
    if records:
      for row in records:
            db_user_id = row
            db_creation_date = row
            db_days = row

            # 检查激活码是否已过期
            if datetime.now() > db_creation_date + timedelta(days=db_days):
                print("您的激活码已过期。")
                return False

            # 检查激活码是否属于当前用户
            if user_id != db_user_id:
                print("您的用户ID与激活码不匹配。")
                return False

            print("激活码有效并已激活。")
            return True
    else:
      print("无效的激活码。")
      return False

def activate(user_id):
    code = entry2.get()
    if validate_input(user_id, code):
      # 用户激活成功,将用户ID和激活码写入配置文件
      with open('user_config.json', 'w') as f:
            json.dump({'user_id': user_id, 'code': code}, f)
      messagebox.showinfo('成功', '激活成功')
      root.withdraw()# 隐藏激活窗口
      openfile()
    else:
      messagebox.showwarning('错误', '无效的, 已使用的或过期的激活码')


def openfile_videos(entry):
    update_warning_label()# 在开始执行 extract_images_from_video 之前更新提示标签
    video_path = filedialog.askopenfilename(filetypes=(("MP4 files", "*.mp4"), ("all files", "*.*")))
    n_images = int(entry.get())
    messagebox.showinfo("下一步", "请选择输出目录")
    output_dir = filedialog.askdirectory()
    thread = Thread(target=extract_images_from_video, args=(video_path, output_dir, n_images))
    thread.start()

def openfile():
    # 创建新的tkinter窗口
    root2 = Toplevel(root)
    root2.title("从视频提取图片")

    # 创建标签和输入框
    label1 = Label(root2, text="图片数量:")
    label1.grid(row=0, column=0, padx=20, pady=20, sticky=W)
    entry = Entry(root2)
    entry.insert(0, "1")# 插入默认数据
    entry.grid(row=0, column=1, padx=20, pady=20, sticky=E)

    # 创建红色提示标签
    global warning_text# 将 warning_text 声明为全局变量
    warning_text = StringVar()# 创建一个 StringVar 变量
    warning_text.set("你的软件还未启动,请先输入需要分割的数量!")# 默认提示
    warning_label = Label(root2, textvariable=warning_text, fg="red")
    warning_label.grid(row=1, column=0, columnspan=2)

    # 创建按钮
    button = Button(root2, text="打开视频文件", command=lambda: openfile_videos(entry))
    button.grid(row=2, column=0, columnspan=2, padx=20, pady=20)

    # 在Tkinter窗口中添加Label
    status_var = StringVar()
    status_label = Label(root, textvariable=status_var)
    status_label.grid(row=3, column=0, columnspan=2, padx=20, pady=20)
    # 设置窗口尺寸并使其不可更改
    root2.geometry("280x150")
    root2.resizable(False, False)

def update_warning_label():
    warning_text.set("正在分割图片,请稍后!")# 更新提示内容

# 创建tkinter窗口
root = Tk()
root.title("激活")

# 创建标签和输入框
label1 = Label(root, text="用户ID:")
label1.grid(row=0, column=0, padx=20, pady=20, sticky=W)
entry1 = Entry(root)
entry1.grid(row=0, column=1, padx=20, pady=20, sticky=E)

label2 = Label(root, text="激活码:")
label2.grid(row=1, column=0, padx=20, pady=20, sticky=W)
entry2 = Entry(root)
entry2.grid(row=1, column=1, padx=20, pady=20, sticky=E)

# 检查配置文件是否存在,如果存在就读取用户ID和激活码
if os.path.exists('user_config.json'):
    with open('user_config.json', 'r') as f:
      config = json.load(f)
      entry1.insert(0, config['user_id'])
      entry2.insert(0, config['code'])

# 创建按钮
button = Button(root, text="点击激活", command=lambda: activate(entry1.get()))
button.grid(row=2, column=0, columnspan=2, padx=20, pady=20)

# 设置窗口尺寸并使其不可更改
root.geometry("300x200")
root.resizable(False, False)

try:
    root.mainloop()
except KeyboardInterrupt:
    print("程序已被用户手动关闭")
    # 这里可以进行一些清理工作,例如关闭数据库连接
    mydb.close()


下载链接:https://cowtransfer.com/s/1129aafbdf4c4f传输口令 hy4nzc

苏紫方璇 发表于 2023-12-9 19:30

本版块仅限分享编程技术和源码相关内容,发布帖子必须带上关键代码和具体功能介绍
请在帖中贴上全部或部分关键代码吧

京韵同创 发表于 2023-12-9 20:19

苏紫方璇 发表于 2023-12-9 19:30
本版块仅限分享编程技术和源码相关内容,发布帖子必须带上关键代码和具体功能介绍
请在帖中贴上全部或部分 ...

已经粘贴了~

fandazong 发表于 2023-12-12 22:24

支持楼主!!

obmil3 发表于 2023-12-12 22:39

支持楼主,这个厉害啊{:1_921:}

迈克杰克卢 发表于 2023-12-13 10:02

支持一下,看上去好厉害

sccwd 发表于 2023-12-14 21:20

学习了,正在学python中

liu20655 发表于 2024-3-23 15:56

看起来好厉害,学习

Wanfeng67 发表于 2024-4-8 13:52

我的领取被和谐了 还能正常下载吗

Wanfeng67 发表于 2024-4-8 13:57

Wanfeng67 发表于 2024-4-8 13:52
我的领取被和谐了 还能正常下载吗

是我的操作失误 点了转存 没点下载 还是正常的
页: [1] 2
查看完整版本: 【原创开源】Python开发的视频抽帧,自动抠图,自动添背景