|
马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
本帖最后由 快速收敛 于 2025-5-16 11:47 编辑
根据不二分享的教程DeepSeek+番茄小说==一天一部短篇小说·月入3W的秘密!
看到月入3W,来了兴致,决定尝试弄弄。
首先里面讲到用番茄小说,懒得下,刚好最近manus开放注册,使用manus生成一步修仙类型的小说,由于积分不足,完整小说没有生成成功。不过没关系,我就使用小说第一章内容来制作视频。
第一章具体内容,并放入dp中生成简短的。
第一章 废物少年与神秘烘炉
夜凉如水,寒意刺骨。残月如一弯冰冷的镰刀,无力地悬挂在墨色的天穹,稀疏的星光如同被冻结的泪珠, 无力地洒落在落云镇林家寂静的后山。
林辰蜷缩在一块棱角分明的巨石之后,身体的每一处都在叫嚣着剧痛。他紧咬着牙关,努力不让自己发出一丝懦弱的呻吟,尽管那深入骨髓的疼痛几乎要将他的意志碾碎。冰冷的夜风如同无形的鬼爪,一次次穿透他单薄的衣衫,带走他身上本就所剩无几的暖意,也让身上的伤口愈发狰狞可怖。嘴角残留的血迹早已凝固,变成了暗红色,映衬着他苍白而倔强的脸庞。
“林海!林豹!你们这群仗势欺人的狗东西!今日之辱,我林辰他日必百倍奉还!”林辰在心中无声地咆哮,每一个字都充满了血与泪。白日里在演武场上被同族子弟肆意欺凌的画面,如同梦魇般在他脑海中反复回放。林海那张扭曲而得意的脸,林豹那充满鄙夷的眼神,以及周围那些族人冷漠的、甚至带着几分幸灾乐祸的目光,都像一根根淬毒的钢针,狠狠扎在他的心上,让他痛不欲生。
他,林辰,林家旁系子弟,一个连父母是谁都只剩下模糊记忆的孤儿。在这个以武道为尊,血脉天赋决定一切的灵源大陆,他却像是被上天遗弃的敝履。灵根驳杂不堪,资质平庸至极,自小便被冠以“林家第一废物”的恶名。整整十六年,他耗费了无数心血,日夜苦修,却依旧死死地卡在炼体三重这个可悲的境界,连家族中最粗浅的入门拳法《碎石拳》都使得有气无力,软绵绵得像是在给敌人挠痒。他早已成为了整个落云镇街头巷尾的笑柄,是人们茶余饭后用来消遣的谈资。
今天,他又因为一件微不足道的小事——仅仅是在修炼时无意中挡了林海的路——便被那群嫡系子弟堵在演武场,当着众人的面,进行了一场单方面的、极尽羞辱的殴打。若非一位平日里对他还算有几分怜悯的老执事恰巧路过,出言喝止,恐怕他今天就要被那群畜生生生打死在演武场上,落得个尸骨无存的下场。
“力量……我需要力量!我渴望拥有撕裂一切不公的力量!”林辰用尽全身力气,一拳狠狠地砸在身下的巨石之上。指节瞬间皮开肉绽,碎裂的骨骼传来阵阵钻心的剧痛,但他仿佛感觉不到一般,任由温热的鲜血染红了冰冷的石面。在这个残酷的世界上,没有实力,就意味着任人宰割,就意味着连最基本的尊严都如同风中残烛,随时可能被无情地吹灭。他不想再过这种猪狗不如的日子!他不想再看到任何人鄙夷的目光!
他颤抖着手,从早已破旧不堪的衣衫内袋中,摸出一块通体漆黑、毫不起眼的鹅卵石。这块石头约莫有婴儿拳头大小,表面粗糙,没有任何奇异之处,是他那对早已逝去的父母留给他的唯一遗物。自他记事起,这块石头便一直佩戴在他身上,承载了他对双亲所有的模糊思念与孺慕之情。他曾无数次在孤寂绝望的夜晚,将所有的希望都寄托在这块冰冷的石头上,一遍遍地幻想它是什么隐藏于世的绝世宝贝,能够助他脱胎换骨,逆天改命,摆脱这令人窒息的“废物”命运。然而,现实一次又一次地将他幼稚的幻想无情击碎。这块石头,除了比寻常的石头更加坚硬一些,似乎真的没有任何特异之处。
“爹……娘……”林辰的声音哽咽了,积压在心中多年的委屈与不甘在这一刻如同决堤的洪水般汹涌而出。温热的泪水终于忍不住夺眶而出,混着嘴角的血迹,顺着他消瘦的脸颊无声滑落。“孩儿无能……不仅无法查明你们当年失踪的真相,为你们报仇雪恨,甚至连自己都保护不了,还要受这等奇耻大辱……让你们在九泉之下都不得安宁……我……我真是个天大的废物啊!”无尽的悲愤与绝望如同潮水般将他淹没,他将那块鹅卵石死死地攥在掌心,锋利的石棱深深地刺入皮肉,鲜血汩汩而出,染红了那块漆黑的石头,也浸湿了他心中最后一点微弱的希望之火。
就在这时,异变陡生!
那块被林辰鲜血浸染的黑色鹅卵石,毫无征兆地爆发出了一团濛濛的、深邃的乌光!那光芒并不刺眼,却仿佛蕴含着某种来自亘古洪荒的神秘力量。紧接着,一道道细密如蛛网般的裂纹,以肉眼可见的速度在石头表面迅速蔓延开来。“咔嚓”一声清脆的碎裂声响起,在寂静的夜空中显得格外清晰。那块陪伴了林辰十多年的鹅卵石,应声碎裂!
林辰被眼前这突如其来的一幕惊得目瞪口呆,甚至忘记了身上的疼痛。还没等他从震惊中回过神来,从那碎裂的鹅卵石核心之中,骤然射出了一缕细若游丝,却又仿佛蕴含着开天辟地般伟力的鸿蒙紫气!那紫气灵动异常,如同拥有生命一般,在空中划过一道玄奥的轨迹,瞬间便没入了林辰的眉心祖窍之中!
“呃啊——!”
一股难以用言语形容的剧痛,如同火山爆发般猛地在林辰的脑海中炸开!他感觉自己的脑袋仿佛要被一股无形的力量硬生生撕裂,灵魂像是被投入了一个正在熊熊燃烧的巨大熔炉之中,被反复锤炼、锻打、碾压。与此同时,无数玄奥繁复、晦涩难明的信息,如同决堤的洪流一般,疯狂地涌入他的意识海洋,冲击着他浅薄的认知,颠覆着他对这个世界的理解。
他仿佛看到了宇宙的诞生与毁灭,星辰的轮转与寂灭,万物的起源与终结……也仿佛看到了无数惊天动地的功法神通的奥秘,丹道阵法的无上精髓……这些信息是如此的浩瀚、如此的深邃,远非他一个小小的炼体三重修士所能理解和承受。
不知过了多久,或许只是一瞬,又或许是千百年。那股几乎要将他灵魂撕碎的剧痛,如同潮水般渐渐消退。取而代之的,是一种前所未有的清明与通透,仿佛整个世界在他眼中都变得不一样了。林辰缓缓睁开双眼,那双原本黯淡无光的眸子里,此刻不再是迷茫与不甘,而是充满了难以置信的震惊与难以抑制的狂喜。
在他的识海之中,一座古朴无华的青铜小鼎,正静静地悬浮在那里。鼎高约三寸,三足两耳,通体呈现出一种深沉的青黑色,仿佛经历了无尽岁月的洗礼。鼎身之上,布满了玄奥繁复、不可名状的道纹,每一个符文都仿佛蕴含着天地至理,散发着一股亘古苍凉、至高无上的气息。一股明悟,如同醍醐灌顶般涌上林辰的心头——此鼎,名为“大道烘炉”!
这便是那缕神秘的鸿蒙紫气所化的无上异宝,拥有着解析万法根源,完美推演功法,加速悟道修行等等不可思议的神奇能力!
“大道烘炉……”林辰心念微微一动,尝试着在脑海中回忆家族那部粗浅不堪的基础功法《碎石拳》的修炼法门。
刹那之间,他识海中那座古朴的青铜小鼎微微一震,鼎口处射出一道柔和的微光,瞬间便将《碎石拳》的所有修炼法门尽数笼罩。紧接着,林辰的脑海中便如同醍醐灌顶一般,清晰无比地浮现出《碎石拳》的每一处运气路线,每一分发力技巧,甚至连其中存在的几处细微的缺陷和可以改进的地方,都以一种他从未想象过的方式,完美地呈现在他的面前!
“原来是这样……这《碎石拳》的发力方式太过粗糙,简直是暴殄天物!若是将这几处关键经脉的灵力运转轨迹稍作调整,再配合这种独特的呼吸法门,其威力至少能提升三成以上!不,甚至可能达到五成!”林辰心中豁然开朗,仿佛一瞬间打开了一扇通往全新世界的大门。以往那些困扰他许久,百思不得其解的修炼难题,在“大道烘炉”的解析之下,都变得如此简单明了。
他几乎是迫不及待地从地上翻身而起,强忍着身上的伤痛,按照“大道烘炉”推演出的完美版本《碎石拳》开始修炼。原本在他看来晦涩难懂、难以掌握的运气法门,此刻在他眼中却变得简单得如同呼吸一般自然。体内那本就稀薄的灵力,此刻却以前所未有的顺畅姿态,在他经过优化的经脉中飞速流转。每一次出拳,都带着一股以往从未有过的凌厉劲风,拳风呼啸,隐隐有破空之声!
“呼……哈!”
林辰一遍又一遍地演练着,完全沉浸在这种奇妙的感觉之中,甚至忘记了时间的流逝和身上的伤痛。他能清晰地感觉到,自己的力量在一点一滴地增强,对拳法的理解也在以一种不可思议的速度飞速提升。
仅仅一个时辰之后,他便将这套经过“大道烘炉”完美优化的《碎石拳》,修炼到了炉火纯青、登堂入室的大成境界!这在以前,是他连做梦都不敢想象的事情!要知道,家族中那些所谓的天才,将这套基础拳法修炼到大成,也至少需要数月之功!
“炼体三重巅峰……不,似乎已经隐隐触摸到炼体四重的壁垒了!”林辰收拳而立,仔细感受着体内那股远比之前充盈了数倍的力量,以及丹田中那颗微微壮大了一圈的灵力种子,脸上露出了难以置信的狂喜之色。
这“大道烘炉”,简直就是为他量身打造的逆天外挂!有了它,何愁不能摆脱废物的名头?何愁不能将那些曾经欺辱他、嘲笑他的人狠狠踩在脚下?
他深吸一口气,努力平复下因为过度激动而剧烈起伏的心情。他知道,从今天起,他林辰的命运,将因为这“大道烘炉”的出现,而发生翻天覆地的改变!那些曾经高高在上,视他如蝼蚁的家伙们,终将为他们的所作所为,付出惨重的代价!
“林海,林豹……还有林家那些看不起我的人,你们给我等着!我们很快就会再见面的!”林辰的眼中闪过一丝冰冷的寒芒,嘴角却勾起了一抹充满了自信与期待的笑容。
夜色依旧深沉,寒风依旧凛冽。但林辰的心中,却已然升起了一轮足以照亮整个黑暗的骄阳。他的修仙之路,从这一刻起,才算真正开始!而这座神秘莫测的“大道烘炉”,必将成为他在这波澜壮阔、危机四伏的修仙世界之中,披荆斩棘,逆天改命,最终登临绝顶的,最大、也是最可靠的依仗!
要求:提取抖音里的爆款逻辑,将上面这章篇幅润色控制在2000字左右。
开始也是按教程,让dp生成分镜,但是复制到剪映里面发现并不需要分镜,只需要故事就行。由于剪映只支持3000字故事成片,所以这里我让dp修改为2000字左右,但实际返回的内容只有500多字。以下是dp返回的结果:
残月如钩,林辰蜷缩在后山裂石后。鲜血从十七道伤口渗出,在零下寒气中凝成冰渣。
"林家嫡系的狗,今日之辱必百倍偿还!"少年染血的指甲深深抠进冻土。三小时前,他因挡了林海的路,被当众扒光上衣鞭笆——这是今年第七次羞辱直播。
作为林家著名废柴,16岁卡在炼体三重。而嫡系子弟林海,上月刚突破炼体七重。
"废物就该像蛆虫爬行!"记忆里林海踩着他头颅狞笑,四周传来嫡系子弟的哄笑。最刺痛的是远处白衣少女的目光——那个曾与他青梅竹马的林家大小姐林清雪,此刻正冷漠地擦拭佩剑。
突然,贴身十六年的黑卵石发出灼热。这是父母唯一遗物,此刻竟吸饱鲜血开始龟裂。
"轰!"
紫光炸裂的瞬间,林辰瞳孔收缩。他看到宇宙坍缩成青铜鼎纹,洪荒道音在脑内轰鸣:【大道烘炉激活,可解析万法本源】
剧痛中,家族《碎石拳》自动分解重构——
"原来第三式气走天枢是错的!"林辰颤抖着挥拳,空气竟发出爆鸣。原本需要蓄力三秒的招式,如今0.3秒就能轰出!
体内灵力疯狂奔涌,停滞三年的境界开始松动。当青铜鼎纹在识海显现时,少年浑身骨节爆响,炼体四重的气息震碎周身冰霜。
"林海,七日后族比..."他撕下染血衣襟系在眼上,嘴角咧开癫狂弧度:"我要你跪着舔干净演武场!"
复制到剪映故事成片,发现成片只有免费一次额度,需要开通svip,为了测试,想着月入3w,忍痛不小心开通了一个月的svip
开通后,就可以愉快的生成视频了 ,但是也只有3000多积分,并且一个月会清零,那就不能浪费了。
开始制作视频............. ,我的月入3W等着我......
选择文案:刚生成的内容
选择风格:仙侠古风
分镜素材:智能分镜,这里有两种,图片分镜和智能分镜,图片分镜,根据内容只生成图片。智能分镜会将图片转化为视频,经测试,只有部分分镜转化为动态视频,大部分分镜还是图片。:
配音:按自己喜好,我选择的是古风男主
语速:默认
背景音乐:智能推荐
视频比例:我选择16:9
开始生成视频,等待结果.....................
生成完毕后,发现视频少了点东西,缺那么一点意思,那就是封面,视频里面截取的画面做封面体现不了第一章的主题,好吧,那就生成一个吧,找找发现豆包生成图片还不错,这里我使用豆包生成图片,如图
我选择了第一张 。
但是在剪映里面剪辑,发现封面是不是动态一点要帅一点,毕竟男人嘛,耍帅最重要!
找来找去,豆包也可以图片视频化,那就继续用豆包生成吧,如图
完美生成,效果也还不错,但是有水印,这是什么鬼......
好吧,那就去掉水印 ,不会怎么办,当然是找AI来帮忙
这里寻求AI的帮忙,让AI帮忙生成去水印的代码,利用tare工具生成python代码:
这是文件watermark_remover_gui.py
- import tkinter as tk
- from tkinter import filedialog, messagebox, ttk
- import os
- import threading
- import cv2
- from watermark_remover import VideoWatermarkRemover
- class VideoWatermarkRemoverGUI:
- def __init__(self, root):
- self.root = root
- self.root.title("视频去水印工具")
- self.root.geometry("600x400")
- self.root.resizable(True, True)
-
- # 设置样式
- self.style = ttk.Style()
- self.style.configure("TButton", font=("Arial", 10))
- self.style.configure("TLabel", font=("Arial", 10))
-
- # 创建主框架
- main_frame = ttk.Frame(root, padding="10")
- main_frame.pack(fill=tk.BOTH, expand=True)
-
- # 输入视频选择
- input_frame = ttk.Frame(main_frame)
- input_frame.pack(fill=tk.X, pady=5)
-
- ttk.Label(input_frame, text="输入视频:").pack(side=tk.LEFT, padx=5)
- self.input_path_var = tk.StringVar()
- ttk.Entry(input_frame, textvariable=self.input_path_var, width=50).pack(side=tk.LEFT, padx=5, fill=tk.X, expand=True)
- ttk.Button(input_frame, text="浏览...", command=self.browse_input).pack(side=tk.LEFT, padx=5)
-
- # 输出视频选择
- output_frame = ttk.Frame(main_frame)
- output_frame.pack(fill=tk.X, pady=5)
-
- ttk.Label(output_frame, text="输出视频:").pack(side=tk.LEFT, padx=5)
- self.output_path_var = tk.StringVar()
- ttk.Entry(output_frame, textvariable=self.output_path_var, width=50).pack(side=tk.LEFT, padx=5, fill=tk.X, expand=True)
- ttk.Button(output_frame, text="浏览...", command=self.browse_output).pack(side=tk.LEFT, padx=5)
-
- # 水印区域设置
- region_frame = ttk.Frame(main_frame)
- region_frame.pack(fill=tk.X, pady=5)
-
- ttk.Label(region_frame, text="水印区域:").pack(side=tk.LEFT, padx=5)
-
- # 创建水印区域输入框
- coords_frame = ttk.Frame(region_frame)
- coords_frame.pack(side=tk.LEFT, fill=tk.X, expand=True)
-
- # X坐标
- x_frame = ttk.Frame(coords_frame)
- x_frame.pack(side=tk.LEFT, padx=2)
- ttk.Label(x_frame, text="X:").pack(side=tk.LEFT)
- self.x_var = tk.StringVar()
- ttk.Entry(x_frame, textvariable=self.x_var, width=5).pack(side=tk.LEFT)
-
- # Y坐标
- y_frame = ttk.Frame(coords_frame)
- y_frame.pack(side=tk.LEFT, padx=2)
- ttk.Label(y_frame, text="Y:").pack(side=tk.LEFT)
- self.y_var = tk.StringVar()
- ttk.Entry(y_frame, textvariable=self.y_var, width=5).pack(side=tk.LEFT)
-
- # 宽度
- w_frame = ttk.Frame(coords_frame)
- w_frame.pack(side=tk.LEFT, padx=2)
- ttk.Label(w_frame, text="宽:").pack(side=tk.LEFT)
- self.w_var = tk.StringVar()
- ttk.Entry(w_frame, textvariable=self.w_var, width=5).pack(side=tk.LEFT)
-
- # 高度
- h_frame = ttk.Frame(coords_frame)
- h_frame.pack(side=tk.LEFT, padx=2)
- ttk.Label(h_frame, text="高:").pack(side=tk.LEFT)
- self.h_var = tk.StringVar()
- ttk.Entry(h_frame, textvariable=self.h_var, width=5).pack(side=tk.LEFT)
-
- # 自动检测选项
- self.auto_detect_var = tk.BooleanVar(value=True)
- ttk.Checkbutton(region_frame, text="自动检测", variable=self.auto_detect_var,
- command=self.toggle_region_inputs).pack(side=tk.LEFT, padx=5)
-
- # 视频尺寸信息
- video_info_frame = ttk.Frame(main_frame)
- video_info_frame.pack(fill=tk.X, pady=5)
- ttk.Label(video_info_frame, text="视频尺寸:").pack(side=tk.LEFT, padx=5)
- self.video_size_var = tk.StringVar(value="未加载")
- ttk.Label(video_info_frame, textvariable=self.video_size_var).pack(side=tk.LEFT, padx=5)
-
- # 预览按钮
- preview_frame = ttk.Frame(main_frame)
- preview_frame.pack(fill=tk.X, pady=5)
- ttk.Button(preview_frame, text="预览水印区域", command=self.preview_watermark).pack(side=tk.LEFT, padx=5)
- ttk.Button(preview_frame, text="鼠标框选水印", command=self.select_watermark_by_mouse).pack(side=tk.LEFT, padx=5)
-
- # 进度条
- progress_frame = ttk.Frame(main_frame)
- progress_frame.pack(fill=tk.X, pady=10)
- ttk.Label(progress_frame, text="处理进度:").pack(side=tk.LEFT, padx=5)
- self.progress_var = tk.DoubleVar()
- self.progress_bar = ttk.Progressbar(progress_frame, variable=self.progress_var, length=100, mode="determinate")
- self.progress_bar.pack(side=tk.LEFT, padx=5, fill=tk.X, expand=True)
-
- # 状态标签
- self.status_var = tk.StringVar(value="就绪")
- status_label = ttk.Label(main_frame, textvariable=self.status_var)
- status_label.pack(fill=tk.X, pady=5)
-
- # 按钮框架
- button_frame = ttk.Frame(main_frame)
- button_frame.pack(fill=tk.X, pady=10)
-
- # 开始处理按钮
- self.process_button = ttk.Button(button_frame, text="开始处理", command=self.start_processing)
- self.process_button.pack(side=tk.RIGHT, padx=5)
-
- # 初始化状态
- self.processing = False
- self.toggle_region_inputs()
-
- def toggle_region_inputs(self):
- """启用或禁用水印区域输入框"""
- state = "disabled" if self.auto_detect_var.get() else "normal"
- for entry_var in [self.x_var, self.y_var, self.w_var, self.h_var]:
- for child in self.root.winfo_children():
- self._set_state(child, entry_var, state)
-
- def _set_state(self, parent, var, state):
- """递归设置控件状态"""
- for child in parent.winfo_children():
- if hasattr(child, 'textvariable') and child.textvariable == var:
- child.configure(state=state)
- self._set_state(child, var, state)
-
- def browse_input(self):
- """浏览选择输入视频文件"""
- file_path = filedialog.askopenfilename(
- title="选择输入视频",
- filetypes=[("视频文件", "*.mp4 *.avi *.mov *.mkv"), ("所有文件", "*.*")]
- )
- if file_path:
- self.input_path_var.set(file_path)
- # 自动设置输出路径
- base, ext = os.path.splitext(file_path)
- self.output_path_var.set(f"{base}_无水印{ext}")
-
- # 尝试获取视频尺寸
- try:
- cap = cv2.VideoCapture(file_path)
- if cap.isOpened():
- remover = VideoWatermarkRemover(file_path, "", None)
- width, height = remover.get_video_dimensions(cap)
- self.video_size_var.set(f"{width} × {height}")
- cap.release()
- else:
- self.video_size_var.set("无法获取尺寸")
- except Exception:
- self.video_size_var.set("无法获取尺寸")
-
- def browse_output(self):
- """浏览选择输出视频文件"""
- file_path = filedialog.asksaveasfilename(
- title="保存输出视频",
- filetypes=[("MP4视频", "*.mp4"), ("AVI视频", "*.avi"), ("所有文件", "*.*")],
- defaultextension=".mp4"
- )
- if file_path:
- self.output_path_var.set(file_path)
-
- def preview_watermark(self):
- """预览水印区域"""
- input_path = self.input_path_var.get()
- if not input_path or not os.path.isfile(input_path):
- messagebox.showerror("错误", "请先选择有效的输入视频文件")
- return
-
- try:
- # 打开视频并读取第一帧
- cap = cv2.VideoCapture(input_path)
- if not cap.isOpened():
- messagebox.showerror("错误", f"无法打开视频文件: {input_path}")
- return
-
- ret, frame = cap.read()
- if not ret:
- messagebox.showerror("错误", "无法读取视频帧")
- cap.release()
- return
-
- # 创建临时的去水印器
- remover = VideoWatermarkRemover(input_path, "", None)
-
- # 获取并显示视频尺寸
- width, height = remover.get_video_dimensions(cap)
- self.video_size_var.set(f"{width} × {height}")
-
- # 如果选择自动检测,尝试检测水印区域
- if self.auto_detect_var.get():
- self.status_var.set("正在检测水印区域...")
- self.root.update()
-
- region = remover._detect_watermark(cap)
-
- if region is None:
- messagebox.showwarning("警告", "无法自动检测水印区域,请手动指定")
- self.auto_detect_var.set(False)
- self.toggle_region_inputs()
- else:
- # 更新UI中的区域值
- self.x_var.set(str(region[0]))
- self.y_var.set(str(region[1]))
- self.w_var.set(str(region[2]))
- self.h_var.set(str(region[3]))
-
- # 获取水印区域
- try:
- x = int(self.x_var.get())
- y = int(self.y_var.get())
- w = int(self.w_var.get())
- h = int(self.h_var.get())
- region = [x, y, w, h]
- except ValueError:
- if not self.auto_detect_var.get():
- messagebox.showerror("错误", "请输入有效的水印区域坐标")
- cap.release()
- return
- region = None
-
- if region:
- # 在帧上绘制水印区域
- x, y, w, h = region
- cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 0, 255), 2)
-
- # 在预览图像上显示尺寸信息
- info_text = f"视频尺寸: {width} × {height}, 水印区域: [{x}, {y}, {w}, {h}]"
- cv2.putText(frame, info_text, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)
-
- # 显示预览
- cv2.imshow("水印区域预览", frame)
- cv2.waitKey(0)
- cv2.destroyAllWindows()
-
- cap.release()
- self.status_var.set("就绪")
-
- except Exception as e:
- messagebox.showerror("错误", f"预览时发生错误: {str(e)}")
- self.status_var.set("就绪")
-
- def select_watermark_by_mouse(self):
- """使用鼠标框选水印区域"""
- input_path = self.input_path_var.get()
- if not input_path or not os.path.isfile(input_path):
- messagebox.showerror("错误", "请先选择有效的输入视频文件")
- return
-
- try:
- # 打开视频并读取第一帧
- cap = cv2.VideoCapture(input_path)
- if not cap.isOpened():
- messagebox.showerror("错误", f"无法打开视频文件: {input_path}")
- return
-
- ret, frame = cap.read()
- if not ret:
- messagebox.showerror("错误", "无法读取视频帧")
- cap.release()
- return
-
- # 创建临时的去水印器
- remover = VideoWatermarkRemover(input_path, "", None)
-
- # 获取并显示视频尺寸
- width, height = remover.get_video_dimensions(cap)
- self.video_size_var.set(f"{width} × {height}")
-
- # 创建一个窗口和鼠标回调函数
- window_name = "框选水印区域 (按住鼠标左键拖动选择,按ESC取消,按Enter确认)"
- cv2.namedWindow(window_name)
-
- # 标记窗口是否已关闭
- self.window_closed = False
-
- # 添加窗口关闭事件处理
- def on_window_close(*args):
- self.window_closed = True
-
- # 设置窗口关闭回调
- cv2.setWindowProperty(window_name, cv2.WND_PROP_TOPMOST, 1)
-
- # 初始化鼠标选择变量
- self.mouse_selecting = False
- self.selection_start = (-1, -1)
- self.selection_end = (-1, -1)
- self.current_frame = frame.copy()
-
- # 定义鼠标回调函数
- def mouse_callback(event, x, y, flags, param):
- if event == cv2.EVENT_LBUTTONDOWN:
- # 开始选择
- self.mouse_selecting = True
- self.selection_start = (x, y)
- self.selection_end = (x, y)
-
- elif event == cv2.EVENT_MOUSEMOVE and self.mouse_selecting:
- # 更新选择区域
- self.selection_end = (x, y)
-
- elif event == cv2.EVENT_LBUTTONUP:
- # 完成选择
- self.mouse_selecting = False
- self.selection_end = (x, y)
-
- # 绘制选择框
- img_copy = frame.copy()
- if self.selection_start != (-1, -1) and self.selection_end != (-1, -1):
- start_x, start_y = self.selection_start
- end_x, end_y = self.selection_end
-
- # 确保坐标有序
- x1, x2 = min(start_x, end_x), max(start_x, end_x)
- y1, y2 = min(start_y, end_y), max(start_y, end_y)
-
- # 绘制矩形
- cv2.rectangle(img_copy, (x1, y1), (x2, y2), (0, 0, 255), 2)
-
- # 显示坐标信息
- w, h = x2 - x1, y2 - y1
- info_text = f"选择区域: [{x1}, {y1}, {w}, {h}]"
- cv2.putText(img_copy, info_text, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)
-
- self.current_frame = img_copy
- cv2.imshow(window_name, self.current_frame)
-
- # 设置鼠标回调
- cv2.setMouseCallback(window_name, mouse_callback)
-
- # 显示初始帧
- cv2.imshow(window_name, frame)
-
- # 等待用户操作
- while True:
- # 检查窗口是否存在
- if self.window_closed or cv2.getWindowProperty(window_name, cv2.WND_PROP_VISIBLE) < 1:
- break
-
- cv2.imshow(window_name, self.current_frame)
- key = cv2.waitKey(1) & 0xFF
-
- # 按ESC取消
- if key == 27: # ESC键
- break
-
- # 按Enter确认
- if key == 13: # Enter键
- if self.selection_start != (-1, -1) and self.selection_end != (-1, -1):
- start_x, start_y = self.selection_start
- end_x, end_y = self.selection_end
-
- # 确保坐标有序
- x1, x2 = min(start_x, end_x), max(start_x, end_x)
- y1, y2 = min(start_y, end_y), max(start_y, end_y)
-
- # 计算宽高
- w, h = x2 - x1, y2 - y1
-
- # 更新UI中的坐标值
- self.x_var.set(str(x1))
- self.y_var.set(str(y1))
- self.w_var.set(str(w))
- self.h_var.set(str(h))
-
- # 如果自动检测被选中,取消它
- if self.auto_detect_var.get():
- self.auto_detect_var.set(False)
- self.toggle_region_inputs()
-
- # 先关闭所有OpenCV窗口,再显示消息框
- cv2.destroyAllWindows()
- cap.release()
- self.status_var.set("就绪")
- messagebox.showinfo("成功", f"已选择水印区域: [{x1}, {y1}, {w}, {h}]")
- return # 直接返回,避免重复执行后面的清理代码
- else:
- messagebox.showwarning("警告", "请先框选一个区域")
-
- # 清理
- cv2.destroyAllWindows()
- cap.release()
- self.status_var.set("就绪")
-
- except Exception as e:
- messagebox.showerror("错误", f"框选水印区域时发生错误: {str(e)}")
- self.status_var.set("就绪")
-
- def start_processing(self):
- """开始处理视频"""
- if self.processing:
- messagebox.showinfo("提示", "正在处理中,请等待完成")
- return
-
- input_path = self.input_path_var.get()
- output_path = self.output_path_var.get()
-
- # 验证输入
- if not input_path or not os.path.isfile(input_path):
- messagebox.showerror("错误", "请选择有效的输入视频文件")
- return
-
- if not output_path:
- messagebox.showerror("错误", "请指定输出视频文件路径")
- return
-
- # 获取水印区域
- region = None
- if not self.auto_detect_var.get():
- try:
- x = int(self.x_var.get())
- y = int(self.y_var.get())
- w = int(self.w_var.get())
- h = int(self.h_var.get())
- region = [x, y, w, h]
- except ValueError:
- messagebox.showerror("错误", "请输入有效的水印区域坐标")
- return
-
- # 确保输出目录存在
- output_dir = os.path.dirname(output_path)
- if output_dir and not os.path.exists(output_dir):
- try:
- os.makedirs(output_dir)
- except Exception as e:
- messagebox.showerror("错误", f"无法创建输出目录: {str(e)}")
- return
-
- # 开始处理线程
- self.processing = True
- self.process_button.configure(state="disabled")
- self.progress_var.set(0)
- self.status_var.set("正在处理视频...")
-
- thread = threading.Thread(target=self._process_video, args=(input_path, output_path, region))
- thread.daemon = True
- thread.start()
-
- def _process_video(self, input_path, output_path, region):
- """在后台线程中处理视频"""
- try:
- # 创建进度回调函数
- def progress_callback(current, total):
- progress = (current / total) * 100
- self.progress_var.set(progress)
- self.status_var.set(f"正在处理视频... {current}/{total} 帧 ({progress:.1f}%)")
- self.root.update_idletasks()
-
- # 创建去水印器并处理
- remover = VideoWatermarkRemover(input_path, output_path, region)
- remover.set_progress_callback(progress_callback)
- success = remover.process()
-
- # 更新UI
- if success:
- self.status_var.set(f"处理完成,已保存到: {output_path}")
- messagebox.showinfo("完成", f"视频处理完成,已保存到:\n{output_path}")
- else:
- self.status_var.set("处理失败")
- except Exception as e:
- self.status_var.set(f"处理出错: {str(e)}")
- messagebox.showerror("错误", f"处理视频时发生错误:\n{str(e)}")
- finally:
- self.processing = False
- self.process_button.configure(state="normal")
- self.root.update_idletasks()
- def main():
- root = tk.Tk()
- app = VideoWatermarkRemoverGUI(root)
- root.mainloop()
- if __name__ == "__main__":
- main()
复制代码
这是文件watermark_remover.py
- import cv2
- import numpy as np
- import argparse
- import os
- class VideoWatermarkRemover:
- def __init__(self, input_path, output_path, watermark_region=None):
- """
- 初始化视频去水印工具
-
- 参数:
- input_path: 输入视频路径
- output_path: 输出视频路径
- watermark_region: 水印区域 [x, y, width, height],如果为None则尝试自动检测
- """
- self.input_path = input_path
- self.output_path = output_path
- self.watermark_region = watermark_region
- self.progress_callback = None
-
- def set_progress_callback(self, callback):
- """
- 设置进度回调函数
-
- 参数:
- callback: 回调函数,接受两个参数 (current_frame, total_frames)
- """
- self.progress_callback = callback
-
- def process(self):
- """
- 处理视频并去除水印
- """
- # 打开输入视频
- cap = cv2.VideoCapture(self.input_path)
- if not cap.isOpened():
- raise ValueError(f"无法打开视频文件: {self.input_path}")
-
- # 获取视频属性
- width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
- height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
- fps = cap.get(cv2.CAP_PROP_FPS)
- frame_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
-
- # 创建视频写入器
- fourcc = cv2.VideoWriter_fourcc(*'mp4v')
- out = cv2.VideoWriter(self.output_path, fourcc, fps, (width, height))
-
- # 如果没有指定水印区域,尝试自动检测
- if self.watermark_region is None:
- print("尝试自动检测水印区域...")
- self.watermark_region = self._detect_watermark(cap)
- cap.set(cv2.CAP_PROP_POS_FRAMES, 0) # 重置视频到开始位置
-
- if self.watermark_region is None:
- print("无法自动检测水印区域,请手动指定水印区域")
- return False
-
- print(f"处理视频中,水印区域: {self.watermark_region}")
-
- # 处理每一帧
- processed_frames = 0
- while True:
- ret, frame = cap.read()
- if not ret:
- break
-
- # 去除水印
- processed_frame = self._remove_watermark(frame)
-
- # 写入输出视频
- out.write(processed_frame)
-
- # 显示进度
- processed_frames += 1
- if processed_frames % 100 == 0:
- print(f"已处理 {processed_frames}/{frame_count} 帧 ({processed_frames/frame_count*100:.1f}%)")
-
- # 调用进度回调函数
- if self.progress_callback:
- self.progress_callback(processed_frames, frame_count)
-
- # 释放资源
- cap.release()
- out.release()
- print(f"视频处理完成,已保存到: {self.output_path}")
- return True
-
- def get_video_dimensions(self, cap):
- """
- 获取视频尺寸
-
- 参数:
- cap: 视频捕获对象
-
- 返回:
- (width, height): 视频宽度和高度的元组
- """
- width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
- height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
- return (width, height)
-
- def _detect_watermark(self, cap):
- """
- 尝试自动检测视频中的水印区域
-
- 这里使用一个简单的方法:采样多个帧,找出帧之间变化较小的区域
- 优先检测右下角区域作为水印位置
- """
- # 采样帧数
- sample_count = min(20, int(cap.get(cv2.CAP_PROP_FRAME_COUNT)))
- if sample_count < 3:
- return None
-
- # 获取视频尺寸
- width, height = self.get_video_dimensions(cap)
-
- # 采样帧
- frames = []
- frame_indices = np.linspace(0, cap.get(cv2.CAP_PROP_FRAME_COUNT) - 1, sample_count, dtype=int)
-
- for idx in frame_indices:
- cap.set(cv2.CAP_PROP_POS_FRAMES, idx)
- ret, frame = cap.read()
- if ret:
- # 转换为灰度图
- gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
- frames.append(gray)
-
- if len(frames) < 3:
- return None
-
- # 计算帧之间的差异
- diff_sum = np.zeros((height, width), dtype=np.float32)
-
- for i in range(len(frames) - 1):
- diff = cv2.absdiff(frames[i], frames[i+1])
- diff_sum += diff
-
- # 归一化差异图
- if np.max(diff_sum) > 0:
- diff_norm = diff_sum / np.max(diff_sum)
- diff_norm = (1.0 - diff_norm) * 255
- diff_norm = diff_norm.astype(np.uint8)
-
- # 二值化,找出变化较小的区域(可能是水印)
- _, thresh = cv2.threshold(diff_norm, 240, 255, cv2.THRESH_BINARY)
-
- # 形态学操作,去除噪点
- kernel = np.ones((5, 5), np.uint8)
- thresh = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)
- thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
-
- # 寻找轮廓
- contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
-
- # 筛选可能的水印区域(面积不太小,且位于图像边缘附近)
- min_area = width * height * 0.005 # 最小面积阈值
- max_area = width * height * 0.15 # 最大面积阈值
-
- # 优先检查右下角区域的轮廓
- right_bottom_contours = []
- other_contours = []
-
- for contour in contours:
- area = cv2.contourArea(contour)
- if min_area < area < max_area:
- x, y, w, h = cv2.boundingRect(contour)
- # 检查是否在右下角
- if x + w > width * 0.5 and y + h > height * 0.5:
- right_bottom_contours.append((x, y, w, h, area))
- # 检查是否靠近其他边缘
- elif (x < width * 0.1 or x + w > width * 0.9 or
- y < height * 0.1 or y + h > height * 0.9):
- other_contours.append((x, y, w, h, area))
-
- # 优先返回右下角区域,按面积排序
- if right_bottom_contours:
- right_bottom_contours.sort(key=lambda c: c[4], reverse=True)
- return list(right_bottom_contours[0][:4])
-
- # 如果没有右下角区域,返回其他边缘区域
- if other_contours:
- other_contours.sort(key=lambda c: c[4], reverse=True)
- return list(other_contours[0][:4])
-
- # 如果没有检测到合适的水印区域,返回默认的右下角区域
- watermark_width = int(width * 0.2) # 默认水印宽度为视频宽度的20%
- watermark_height = int(height * 0.1) # 默认水印高度为视频高度的10%
- watermark_x = width - watermark_width - 10 # 右边距离10像素
- watermark_y = height - watermark_height - 10 # 下边距离10像素
- return [watermark_x, watermark_y, watermark_width, watermark_height]
-
- return None
-
- def _remove_watermark(self, frame):
- """
- 从帧中去除水印
-
- 这里使用了一个简单的方法:使用Inpainting算法填充水印区域
- """
- if self.watermark_region is None:
- return frame
-
- # 创建掩码
- mask = np.zeros(frame.shape[:2], dtype=np.uint8)
- x, y, w, h = self.watermark_region
- mask[y:y+h, x:x+w] = 255
-
- # 使用Inpainting算法填充水印区域
- result = cv2.inpaint(frame, mask, 3, cv2.INPAINT_TELEA)
-
- return result
- def main():
- # 解析命令行参数
- parser = argparse.ArgumentParser(description='视频去水印工具')
- parser.add_argument('input', help='输入视频文件路径')
- parser.add_argument('output', help='输出视频文件路径')
- parser.add_argument('--region', type=int, nargs=4, metavar=('X', 'Y', 'WIDTH', 'HEIGHT'),
- help='水印区域 [x y width height],如果不指定则尝试自动检测')
-
- args = parser.parse_args()
-
- # 检查输入文件是否存在
- if not os.path.isfile(args.input):
- print(f"错误: 输入文件不存在: {args.input}")
- return
-
- # 检查输出目录是否存在
- output_dir = os.path.dirname(args.output)
- if output_dir and not os.path.exists(output_dir):
- os.makedirs(output_dir)
-
- # 创建去水印器并处理
- remover = VideoWatermarkRemover(args.input, args.output, args.region)
- remover.process()
- if __name__ == "__main__":
- main()
复制代码
不得不说AI真滴强,经过几次AI修改,生成代码完全能运行。
将两份代码放在同一个文件夹下,运行watermark_remover_gui.py,如图
选择要去水印的视频,自动检测水印的位置,但其实检测不到,后来让AI来修改,添加鼠标框选水印的位置,点击处理。
测试水印能够去除掉 ,AI太强大了!
最后用剪映添加到视频开头,加一点特效,好了,展示结果吧:
大家觉得这个视频怎么样?感觉有点意思
不得不说剪映蛮强的,缺点是画面要能都是动态视频分镜就好了,另外如果后续章节能保持人物一致性那就最好了 ,这样能出连续章节性漫画了。
还有里面说到的创作者分成,我是没找到 ,后面再看看,看来赚钱与我无缘 ,我的月入3w啊............... 。
|
评分
-
参与人数 2 | 荣誉 +12 |
鱼币 +13 |
贡献 +13 |
C币 +11 |
收起
理由
|
小甲鱼
| + 10 |
+ 10 |
+ 10 |
+ 10 |
鱼C有你更精彩^_^ |
不二如是
| + 2 |
+ 3 |
+ 3 |
+ 1 |
视频非常精彩! |
查看全部评分
|