剪映 自动打关键帧 AutoHotkey

4,216 阅读18分钟

牙叔教程 简单易懂

明确目的

做小说推文的话, 前面几分钟肯定要自己打关键帧,

所以这里的自动打关键帧指的是后面几分钟的图片,

对关键帧要求比较高的同学可以划走了,

因为这里介绍的是简单的 上上下下缩放的关键帧

要求

用剪映提取字幕以后, 字幕之间不可以有空隙,

因为我们用的是快捷键, 来回在字幕之间跳转,

如果字幕有缝隙的话, 那么按方向键 ↓ , 就不会跳到图片的尾部,

就不能自动打关键帧了

所以, 最重要的是要先处理好字幕, 为自动打关键帧做准备。

关键帧类型

关键帧有六种, 这里只说最普通的关键帧

  • 从上到下
  • 从下到上
  • 从左到右
  • 从右到左
  • 缩小
  • 放大

其实吧, 就算复杂的关键帧, 比如双开门, 四屏风, 也是可以自动打的, 就是要写更多的代码;

而且一般前几十张图片 ,还要加特效,还要根据图片来挑选合适的特效, 特效还要随着图片一起动,

所以前几十张图片, 不适合自动打

思路

第一步:文案

要么自己写, 要么ChatGPT写,

第二步: 文字转语音

我用的是 逗哥配音 , 他有 227 种声音

douge.club/index?from=…

音色用的是 云浩宇

没错, 就是你经常刷到的那个声音

第三步:

文案有了, 配音有了, 就剩下配图了,

配图

配图就用 Stable Diffusion, 你也可以用国内提供的服务,

不过我觉得都挺贵的, 你搞几张图片是可以免费的,

但是一个小说推文的作品, 动辄几百张图片, 不是很划算

我加入了一个星球, 可以用 Stable Diffusion , 支持各种模型

我用的大模型

大模型的话, 我用的是 MeinaPastel

这个模型自带lora, 如果你有更高的要求, 也可以去C站找基于这个模型的 lora

C站 civitai.com/

大模型文件夹: stable-diffusion-webui/models/Stable-diffusion

怎么选择大模型

模型太多了, 你要根据文案来选择自己的模型,

推文的话, 只能选漫画风格的, 绝对不能真人模型。

我把看的顺眼的几个模型都生成了几次图片对比了一下, 最终选择的 MeinaPastel


视频组成

一个视频是由音频, 图片, 字幕组成的,

  • 音频 用 逗哥配音 生成了音频
  • 图片, 用SD生成
  • 字幕, 剪映中, 在音频上右击即可提取字幕

万事俱备, 可以开始自动化了


自动化步骤(一) 切割图片

  1. 去除字幕之间的缝隙
  2. 取一张图片放到轨道上
  3. 把图片拉长到和音频一样的长度
  4. 按方向键 ↓ ,
  5. 按切割快捷键 Ctrl + B
  6. 重复 4 和 5

图片切割完了以后, 我们就可以选择自己喜欢的图片, 替换切割后的图片了,

就不用自己再手动切割图片了

这里我们要自动化的就是 4 和 5, 因为这是非常机械的动作。

自动化软件

两个都差不多吧, 都可以做自动化,

ahk感觉轻便一些, 所以我选择 autohotkey,

autohotkey现在已经更新到V2版本了

实操

第一步 去除字幕之间的缝隙

观察音频的波形图, 播放声音听一下, 看看应该向左还是向右拖动字幕

第二步 放一张图片到轨道, 并长图片到音频时长

要把字幕的锁锁住, 不然会这样

锁住字幕

拉长图片

切割图片

按Home, 播放头回到第一帧, 视频开始的地方。

接下来就是autohotkey的代码了

切割图片代码

  1. 按方向键 ↓
  2. 按切割快捷键 Ctrl + B

autohotkey中, 英文分号 ; 表示注释的意思

Sleep 3000
; 发送方向键↓
Send "{Down}"
; 等待100毫秒(可根据需要调整)
Sleep 100
; 发送组合键Ctrl+B
Send "^b"
; 等待100毫秒(可根据需要调整)
Sleep 100

这是一次切割, 我们先按 F5 测一下

没问题, 图片切割成功

然后我们加入循环, 再次测试代码

Sleep 3000
Loop {
  ; 发送方向键↓
  Send "{Down}"
  ; 等待100毫秒(可根据需要调整)
  Sleep 2000
  ; 发送组合键Ctrl+B
  Send "^b"
  ; 等待100毫秒(可根据需要调整)
  Sleep 2000
}

没问题, 工作正常

那么, 再加入, 启动和停止

g_Toggle := false
; 使用热键Ctrl+Alt+T来启动和停止循环
^!t:: {
  global g_Toggle
  g_Toggle := !g_Toggle
  return
}
Loop {
  global g_Toggle
  if (!g_Toggle)
  {
    Sleep 1000
    continue
  }
  Send "{Down}"
  Sleep 2000
  Send "^b"
  Sleep 2000
}

再次测试代码, 注意, 测试的时候, Sleep延迟加长, 防止延时太短, 脚本停止不了,

没问题, 工作正常,

然后我们就可以缩短延迟了, 就改成100ms,

g_Toggle := false
sleepTime := 100
; 使用热键Ctrl+Alt+T来启动和停止循环
^!t:: {
  global g_Toggle
  g_Toggle := !g_Toggle
  return
}
Loop {
  if (!g_Toggle)
  {
    Sleep sleepTime
    continue
  }
  Send "{Down}"
  Sleep sleepTime
  Send "^b"
  Sleep sleepTime
}

我是十分钟的视频, 计时看看用多久时间可以切完图片, 大概一分三十秒;

停止的时候, 由于Sleep太短, 可能autohotkey反应不过来, 我们可以点击电脑任务栏右下角的autohotkey按钮来停止程序。

可以看到图片已经切割的稀碎


自动化步骤(二) 打关键帧

打关键帧的时候, 可以把其他轨道都锁定, 以防错误的修改

打关键帧需要知道的数据

图片比例 4:3

  • 图片统一都是512X512

调试关键帧准备

把背景色改为红色, 背景填充选择红色,

这样可以更清楚的看到我们的图片是否会充满全屏

缩放数据

没有缩放的时候

缩放 134%

在 134% 的时候, 512X512的图片会充满屏幕,

我们的要求是不会漏出黑边, 也就是图片始终完全充满屏幕

此刻, 这张图片就可以做两种关键帧了,

  • 从上到下
  • 从下到上

那么他的起始帧和结束帧数值是多少呢?

这个就看你自己了, 就是一个数字, 随便改, 完全由你自己的喜好决定,

为了尽可能的显示整张图片, 我们先计算一下数值.

512 × 1.34 =686.08

686.08 - 512 = 174.08

也就是说, 我们上下活动的空间是174,

174.08 / 2 = 87.04

剪映的坐标轴

竖轴向上, 数值增加, 反之数值减少;

横轴向右, 数值增加, 反之数值减少;

关键帧真正的数值计算

对吧, 一般都是上面的想法, 可是当我们把y轴的数值调整到 -84 的时候,

图片是这样显示的

看起来好像没问题, 对吧, 我们放大到 134% 再看看

图片中圆球上下方的灰色就看不到了

这是为什么呢?

这个数值到底怎么算? 自己先想一下


我们点击导出静态帧

静态帧默认1080P, 他的分辨率是 1440X1080,

我们就按照这个分辨率来调试看看

宽1440 高1080

我们把y轴设置为1080

即使我们没有放大, y轴移动1080, 图片还是可以显示,

那么我们静态帧选择最高的4K, 再次查看图片的分辨率 2880X2160

宽2880 高2160

我们把y轴设置为2160再试试

还是不行, 再试试2880

终于成功了, 图片完全上去了,

趁热打铁, 我们再试试x轴

2880也不行,

我们算一下, 按照4:3的比例,

2880 * 4 / 3 = 3,840

由于图片两侧有空白, 我们还要减去这个空白

两图片两侧的空白宽度是3840-2880 = 960

960 / 2 = 480

那么要让图片刚好移动到右侧, 和边框贴边,

那么移动的距离就是 3840 - 480 = 3,360

可是看到, 图片刚好移动到右侧, 并且贴着边框

大家可以想象一下, 我们看到的是电脑前面的这个小小的屏幕,

电脑屏幕后面还有一个大大的屏幕

就是说, 剪映把512X512的图片, 投射到了4:3的屏幕上面, 就像在电影院一样,

大屏幕的比例是3840X2880

宽度 3840

高度 2880

所以我们计算距离的时候, 就要按照真正的分辨率计算 ,

也就是 3840X2880,

此时, 我们不再将图片看做512X512, 而是2880X2880

关键帧从上到下

这里涉及到移动的距离, 选择多少合适呢?

你觉得那种距离效果好, 就用那种距离, 纯粹看个人感觉.

而且, 对于代码来说, 改个数字是很容易的事情, 所以这个距离多少, 无所谓

暂且按照10%的比例来移动距离吧

那么移动的距离就是 2880 * 0.1 = 288

记住, 任何关键帧, 我们都要让图片充满屏幕, 即使移动的时候.

所以第一步就是放大图片,

图片宽度现在是2880, 要放大到3840, 那么放大的比例就是 1.333333333,

取个整数, 我们放大到 134%

可以看到, 图片周围的选框是个正方形, 也就是 3840X3840

关键帧是从上到下, 基准是当前的高度, 也就是 2880

10% 的话, 就是 288

起始帧 x轴0 y轴 288 放大134%

结束帧 x轴0 y轴 0 放大134%

关键帧从下到上

起始帧 x轴0 y轴 -288 放大134%

结束帧 x轴0 y轴 0 放大134%

关键帧从左往右

上面说过了, 我们要把图片看做 2880X2880

基准是当前图片的宽度, 也就是 2880,

我们移动的距离仍然是 10%, 也就是 288

图片的初始状态

此时, 缩放应该设置多少呢?

背景宽度是 3840,

我们要求图片始终充满全屏, 不可以漏出红色,

那么最终图片的宽度就是

背景的宽度3840 + 移动距离 288 = 4128

我们要把图片缩放到4128

2880 * X = 4128

X = 1.43333333333

为了不漏出红色, 我们向上取整, 也就是多放大一点, 向上取整 144%

放大 144% 的效果

放大后的图片宽度是 2880 X 144% = 4,147.2, 就认为是4147就可以了

减去背景的宽度 3840

4147 - 3840 = 307

307 / 2 = 153.5

像素是不可能有小数的, 因此为了放置暴露红色, 我们取153

那么我们的关键帧数值就出来了

起始帧 x轴-153 y轴 0 放大144%

结束帧 x轴 0 y轴 0 放大144%

关键帧从右往左

起始帧 x轴153 y轴 0 放大144%

结束帧 x轴 0 y轴 0 放大144%

关键帧 缩放从大到小

仍然是先给出原始图片

仍然按照10的比例来缩放

图片分辨率2880X2880

背景分辨率3840X2880

缩放的时候, x轴y轴两个方向, 图片都会缩放,

必然我们要选择缩放做大的那个,

也就是和x轴的缩放一样的大小 144%

缩放到多少呢? 自然是图片刚充满屏幕的时候, 也就是 134%

起始帧 x轴0 y轴 0 放大144%

结束帧 x轴0 y轴 0 放大134%

缩放从大到小, 就不截图了, 反过来填就可以了


上面的关键帧数值, 该分析的都分析完了, 下面开始写代码

自动化打关键帧

确切的说是半自动化, 因为剪映没有选中素材的快捷键,

只能鼠标选中,

而且, 也没有播放头居中的快捷键,

所以不能批量设置关键帧,

只能给一张图片自动打关键帧,

然后鼠标选中下一张图片, 再打关键帧

图色的话, 我也试过了, 播放头不好找, 太细了

打关键帧流程

  1. 鼠标选中素材
  2. 播放头放到素材的起始帧
  3. 点击右上角关键帧按钮
  4. 修改x轴, y轴, 和缩放的值
  5. 按方向键 ↓ , 播放头跳到下一个素材的起始帧
  6. 按方向键 ← , 播放头跳到素材的结束帧
  7. 点击右上角关键帧按钮
  8. 修改x轴, y轴, 和缩放的值
  9. 按方向键 → , 播放头跳到下一个素材的起始帧

一共 9 个步骤, 一个素材的关键帧就打完了,

如果对关键帧要求不高, 只是简单的左右滑动, 酱紫就可以了.

对关键帧要求太高的话, 就不适合了, 可以划走了.


安装自动化软件

www.autohotkey.com/

autohotkey已经更新到 v2 版本了, 我现在的代码都是用v2版本写的

下一步, 下一步就安装完成了, 这个不用截图了吧


搜autohotkey的问题

www.autohotkey.com/search/


自动点击右上角关键帧按钮

要点击, 就必然要知道坐标,

获取坐标在autohotkey中, 有两种方法

第一种获取坐标的方法

按快捷键 Ctrl + F1

第二种获取坐标的方法

使用 Window spy

我们先获取关键帧按钮的坐标

1881, 157

点击指定坐标的代码

Sleep 2000
MouseClick "left", 1881, 157, 1

按F5执行代码, 我们马上切换到剪映,

然后鼠标就会点击关键帧按钮


用快捷键启动程序

前面说了, 我们得切换窗口到剪映, 那么总不能每次都切换吧,

这个切换的动作太多余了,

所以我们设置快捷键来启动程序

这里的快捷键是 Ctrl Alt T, 也就是 Ctrl 用^表示, Alt 用 ! 表示

分号表示注释

; 使用热键Ctrl+Alt+T来启动和停止循环
^!t:: {
  MouseClick "left", 1881, 157, 1
}

我测试了, 非常丝滑

写UI窗口

咱们有 6 中关键帧, 每种关键帧都用快捷键,

也没那么多快捷键可以使用, 我想用的快捷键都被其他软件占了,

那么, 就写个 UI 窗口 吧

最简单的窗口代码

MyGui := Gui()
MyBtn_Click(*) {
  MsgBox "Hello, world!"
}
MyBtn := MyGui.Add("Button", "Default w80", "点我")
MyBtn.OnEvent("Click", MyBtn_Click)
MyGui.Show()

运行以后会出现一个窗口

点击以后会出现一个弹框

我们把按钮的文本改一下, 宽高也改一下

MyGui := Gui()
从上到下_Click(*) {
  MsgBox "从上到下"
}
从上到下Btn := MyGui.Add("Button", "w80 h30", "从上到下")
从上到下Btn.OnEvent("Click", 从上到下_Click)
MyGui.Show()

我们需要 6 个按钮

MyGui := Gui()

从上到下Btn := MyGui.Add("Button", "w80 h30", "从上到下")
从上到下Btn.OnEvent("Click", 从上到下_Click)
从上到下_Click(*) {
  MsgBox "从上到下"
}
从下到上Btn := MyGui.Add("Button", "w80 h30 y+10", "从下到上")
从下到上Btn.OnEvent("Click", 从下到上_Click)
从下到上_Click(*) {
  MsgBox "从下到上"
}
从左往右Btn := MyGui.Add("Button", "w80 h30 y+10", "从左往右")
从左往右Btn.OnEvent("Click", 从左往右_Click)
从左往右_Click(*) {
  MsgBox "从左往右"
}
从右往左Btn := MyGui.Add("Button", "w80 h30 y+10", "从右往左")
从右往左Btn.OnEvent("Click", 从右往左_Click)
从右往左_Click(*) {
  MsgBox "从右往左"
}
由大到小Btn := MyGui.Add("Button", "w80 h30 y+10", "由大到小")
由大到小Btn.OnEvent("Click", 由大到小_Click)
由大到小_Click(*) {
  MsgBox "由大到小"
}
由小到大Btn := MyGui.Add("Button", "w80 h30 y+10", "由小到大")
由小到大Btn.OnEvent("Click", 由小到大_Click)
由小到大_Click(*) {
  MsgBox "由小到大"
}


MyGui.Show()

如果你不喜欢按钮列表, 一行要放两个按钮的话

一行两个按钮,

MyGui := Gui()
RetrievedTitle := MyGui.Title

MyGui.Title := "剪映关键帧"
MyGui.Name := "NewName"
MyGui.BackColor := "8ed4d1"
distance := 66
WinSetTransColor("EEAA99", MyGui)
MyGui.Opt("AlwaysOnTop")
MyGui.Opt("Resize")
从上到下Btn := MyGui.Add("Button", "w80 h30", "从上到下")
从上到下Btn.OnEvent("Click", 从上到下_Click)
从上到下_Click(*) {
  MsgBox "从上到下"
}

从下到上Btn := MyGui.Add("Button", "w80 h30 x+" . String(distance), "从下到上")
从下到上Btn.OnEvent("Click", 从下到上_Click)
从下到上_Click(*) {
  MsgBox "从下到上"
}
从左往右Btn := MyGui.Add("Button", "w80 h30 xm+0", "从左往右")
从左往右Btn.OnEvent("Click", 从左往右_Click)
从左往右_Click(*) {
  MsgBox "从左往右"
}
从右往左Btn := MyGui.Add("Button", "w80 h30 x+" . String(distance), "从右往左")
从右往左Btn.OnEvent("Click", 从右往左_Click)
从右往左_Click(*) {
  MsgBox "从右往左"
}
由大到小Btn := MyGui.Add("Button", "w80 h30 xm+0", "由大到小")
由大到小Btn.OnEvent("Click", 由大到小_Click)
由大到小_Click(*) {
  MsgBox "由大到小"
}
由小到大Btn := MyGui.Add("Button", "w80 h30 x+" . String(distance), "由小到大")
由小到大Btn.OnEvent("Click", 由小到大_Click)
由小到大_Click(*) {
  MsgBox "由小到大"
}


MyGui.Show()

有可能以后会经常用, 所以我给窗口加了置顶

MyGui.Opt("AlwaysOnTop")

实战

给按钮添加关键帧功能

再次展示打关键帧的流程

  1. 鼠标选中素材
  2. 播放头放到素材的起始帧
  3. 点击右上角关键帧按钮
  4. 修改x轴, y轴, 和缩放的值
  5. 按方向键 ↓ , 播放头跳到下一个素材的起始帧
  6. 按方向键 ← , 播放头跳到素材的结束帧
  7. 点击右上角关键帧按钮
  8. 修改x轴, y轴, 和缩放的值
  9. 按方向键 → , 播放头跳到下一个素材的起始帧

打从上到下的关键帧的源码

CoordMode "Pixel", "Screen"
CoordMode "Mouse", "Screen"

MyGui := Gui()
RetrievedTitle := MyGui.Title

MyGui.Title := "剪映关键帧"
MyGui.Name := "NewName"
MyGui.BackColor := "8ed4d1"
distance := 66
WinSetTransColor("EEAA99", MyGui)
MyGui.Opt("AlwaysOnTop")
MyGui.Opt("Resize")
从上到下Btn := MyGui.Add("Button", "w80 h30", "从上到下")
从上到下Btn.OnEvent("Click", 从上到下_Click)
从上到下_Click(*) {
  从上到下关键帧()
  播放素材()
}
关键帧按钮坐标 := [1882, 155]
缩放坐标 := [1819, 195]
x输入框坐标 := [1498, 239]
y输入框坐标 := [1616, 240]
从上到下关键帧() {
  修改起始帧()
  跳到结束帧()
  修改结束帧()
}
播放素材() {
  Send "{Up}"
  Sleep delayBetweenKeys
  Send "{Space}"
  Sleep delayBetweenKeys
}
delayBetweenKeys := 111 ; 设置延迟为500毫秒(0.5秒)
跳到结束帧() {
  Send "{Down}"
  Sleep delayBetweenKeys
  Send "{Left}"
  Sleep delayBetweenKeys
}
修改结束帧() {
  点击关键帧按钮()
  ; 起始帧 x轴0 y轴 288 放大134%
  ; 结束帧 x轴0 y轴 0   放大134%
  点击关键帧按钮()
  修改输入框的值(x输入框坐标, String(0))
  修改输入框的值(y输入框坐标, String(0))
  修改输入框的值(缩放坐标, String(134))
  ; MouseClick "left", 1854, 193, 1
  ; Sleep delayBetweenKeys
}
点击关键帧按钮() {
  MouseClick "left", 关键帧按钮坐标[1], 关键帧按钮坐标[2], 1
  Sleep delayBetweenKeys
}
修改起始帧() {
  点击关键帧按钮()
  ; 起始帧 x轴0 y轴 288 放大134%
  ; 结束帧 x轴0 y轴 0   放大134%
  修改输入框的值(x输入框坐标, String(0))
  修改输入框的值(y输入框坐标, String(288))
  修改输入框的值(缩放坐标, String(134))
}
修改输入框的值(coordinate, value) {
  x := coordinate[1]
  y := coordinate[2]
  MouseClick "left", x, y, 1
  Sleep delayBetweenKeys
  Send "^a"
  Sleep delayBetweenKeys
  Send value
  Sleep delayBetweenKeys
  Send "{Enter}"
  Sleep delayBetweenKeys
}

从下到上Btn := MyGui.Add("Button", "w80 h30 x+" . String(distance), "从下到上")
从下到上Btn.OnEvent("Click", 从下到上_Click)
从下到上_Click(*) {
  MsgBox "从下到上"
}
从左往右Btn := MyGui.Add("Button", "w80 h30 xm+0", "从左往右")
从左往右Btn.OnEvent("Click", 从左往右_Click)
从左往右_Click(*) {
  MsgBox "从左往右"
}
从右往左Btn := MyGui.Add("Button", "w80 h30 x+" . String(distance), "从右往左")
从右往左Btn.OnEvent("Click", 从右往左_Click)
从右往左_Click(*) {
  MsgBox "从右往左"
}
由大到小Btn := MyGui.Add("Button", "w80 h30 xm+0", "由大到小")
由大到小Btn.OnEvent("Click", 由大到小_Click)
由大到小_Click(*) {
  MsgBox "由大到小"
}
由小到大Btn := MyGui.Add("Button", "w80 h30 x+" . String(distance), "由小到大")
由小到大Btn.OnEvent("Click", 由小到大_Click)
由小到大_Click(*) {
  MsgBox "由小到大"
}

MyGui.Show()

注意

autohotkey的坐标有时候是相对某个窗口的坐标, 还要分析是相对于那个窗口的,

因此, 我统一为绝对坐标, 不然鼠标容易点错地方

CoordMode "Pixel", "Screen"
CoordMode "Mouse", "Screen"

效果

没有加速哦, 就是正常的自动化速度,

自动化, 啪啪啪, 点起来比手快,


声明

本文仅供学习研究使用, 禁止用于其他用途


配音选逗哥

逗哥配音 , 他有 227 种声音

douge.club/index?from=…

想省米, 就用这个星球的 Stable Diffusion

就不用你组别人的GPU啦, 它里面模型多的很, 生图也很快,

还有ChatGPT可以使用 ChatGPT联网版, Stable Diffusion画图, 这个星球全都有, 低调使用, 别外传

微信公众号 牙叔教程