本帖最后由 jjjzw 于 2021-4-17 13:02 编辑
bad apple是这种黑白风格的视频,正适合拿来opencv练手
选用的视频是b站1440x1080 30fps的素材,下载后将其改名为bad apple.mp4
目标效果是把视频中黑色的部分变为像素点颗粒,(造成锯齿感很强的样子。。
一、提取视频帧
div_frame.py
[Python] 纯文本查看 复制代码 import cv2
import os
path = "pic/"
# 将视频按帧抽取出图像
def div(path_video):
cap = cv2.VideoCapture(path_video)
def save_image(image, addr, num):
address = addr + str(num) + '.jpg'
cv2.imwrite(address, image)
if os.path.exists(path):
pass
else:
os.makedirs(path)
success, frame = cap.read()
i = 0
while success:
i = i + 1
save_image(frame, path, i)
print("已抽取:" + str(i))
success, frame = cap.read()
视频的每一帧就会被提取出来保存到pic文件夹中
二、图像转视频
对一个文件夹中的图像文件,排序后按帧率、分辨率组合成视频
re_video.py
[Python] 纯文本查看 复制代码 import os
import cv2
# 将图像按帧重新制作成视频
def remake(path_pic, name, fps, a, b):
file_list = os.listdir(path_pic)
# 列表排序
file_list.sort(key=lambda x: int(x[:-4]))
count = 0
size = (a, b)
# 可以使用cv2.resize()进行修改
video = cv2.VideoWriter(name + ".avi", cv2.VideoWriter_fourcc('P', 'I', 'M', '1'), fps, size)
"""
cv2.VideoWriter_fourcc('I','4','2','0')---未压缩的YUV颜色编码,4:2:0色度子采样。兼容性好,但文件较大,注意是很大!!!(50M视频拆出的帧转换后大约15G)文件扩展名.avi。[/align][align=center]
cv2.VideoWriter_focurcc('P','I','M','1')---MPEG-1编码类型,文件扩展名.avi。
随机访问,灵活的帧率、可变的图像尺寸、定义了I帧、P帧和B帧、运动补偿
可跨越多个帧、半像素精度的运动向量、量化矩阵、GOF结构、slice结构、技术细节、输入视频格式。
cv2.VideoWriter_fourcc('X','V','I','D')---MPEG-4编码类型,视频大小为平均值,MPEG4所需要的空间是MPEG1或M-JPEG的1/10,
它对运动物体可以保证良好的清晰度,间/时间/画质具有可调性。文件扩展名.avi。
cv2.VideoWriter_fourcc('T','H','E','O')---OGGVorbis,音频压缩格式,有损压缩,类似于MP3等的音乐格式。
兼容性差,文件扩展名为.ogv。
cv2.VideoWriter_focurcc('F','L','V','1')---FLV是FLASH VIDEO的简称,FLV流媒体格式是一种新的视频格式。
由于它形成的文件极小、加载速度极快,使得网络观看视频文件成为可能,它的出现有效的解决了视频文件导入Flash后,使导出的SWF文件体积庞大,
不能在网络上很好的使用等缺点。文件扩展名为.flv
"""
for item in file_list:
count = count + 1
item = path_pic + item
img = cv2.imread(item)
video.write(img)
print("已加载: " + str(count))
video.release()
cv2.destroyAllWindows()
三、调制每一帧的图像
由于不确定原素材是否为完全的二值图像,对每一帧都进行灰度化、二值化后在处理像素
threshold_.py
[Python] 纯文本查看 复制代码 import cv2
# 图像灰度化、二值化
def grey(path):
img = cv2.imread(path)
e1 = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thr = cv2.threshold(e1, 100, 255, cv2.THRESH_BINARY)
return thr
cv2.imgread默认读取RGB三通道,因此需要转化为灰度图的单通道后才能进行二值化
接下来是对图像进行处理
思路是:将1440x1080完全拆分为4x4的像素块区域,对每一个像素块里黑色(0)的个数进行判断,如果个数超过一定数值(阈值),则认为区域有效,否则无效
对于有效像素块,将中间2x2的像素块画成黑色(0),周围画成白色(255)
对于无效像素块,全部画成白色(255)
这样设置的好处是白色和黑色均匀间隔,比较美观(当然猎奇一点也可以用其他规则)
main.py
[Python] 纯文本查看 复制代码 from div_frame import div, path
from threshold_ import grey
from re_vedio import remake
import cv2
import os
def save_image(image, addr):
address = addr
cv2.imwrite(address, image)
def change(img_path):
ig = grey(img_path)
def num(m, n):
count_pix = 0
for ii in range(0, 4):
for jj in range(0, 4):[/align][align=left]
# 像素值只有0和255,因此这里设置10和0和其它什么数都一样
if ig[4 * m + ii, 4 * n + jj] <= 10:
count_pix = count_pix + 1
return count_pix
def draw_black(m, n):
for ii in range(0, 4):
for jj in range(0, 4):
ig[4 * m + ii, 4 * n + jj] = 255
for ii in range(1, 3):
for jj in range(1, 3):
ig[4 * m + ii, 4 * n + jj] = 0
def draw_white(m, n):
for ii in range(0, 4):
for jj in range(0, 4):
ig[4 * m + ii, 4 * n + jj] = 255
# 遍历所有的像素块
for j in range(0, 360):
for i in range(0, 270):
if num(i, j) >= 8:
draw_black(i, j)
else:
draw_white(i, j)
return ig
if __name__ == "__main__":
path_video = "bad apple.mp4"
print("————开始抽取视频帧————")
div(path_video)
print("————视频帧抽取完毕————")
file_list = os.listdir(path)[/align][align=left]
# 对列表元素进行从小到大排序
file_list.sort(key=lambda x: int(x[:-4]))
print("————开始转换帧图像————")
for file in file_list:
file_path = path + file
print("已转换:" + file_path)
save_image(change(file_path), file_path)
print("————帧图像转换完毕————")
print("————开始制作视频————")[/align][align=left]
# 转换为视频,路径、名字、帧率、分辨率
remake(path, "BadApple", 30, 1440, 1080)
四、最后运行main.py开始处理视频
(每一帧处理的时间约为4秒)
在长达 7小时的运行后,视频终于转换完了
用多线程应该能处理得更快,不过写完正好是凌晨,睡一觉起来就差不多了,就没用线程
这是第318帧的图像:
视频效果:https://www.bilibili.com/video/BV1Cp4y1t7ot/
对每一帧的图像还可以采用其他的处理方式,比如对于有效像素块,可以不填充黑色,而填充其他随机颜色
但是这样需要将单通道重新转换为3通道(重新imread也可以)
[Python] 纯文本查看 复制代码 def random_color():
global color
a = random.randint(0, 5)
if a == 0:
color = [255, 0, 0]
elif a == 1:
color = [255, 64, 64]
elif a == 2:
color = [238, 130, 238]
elif a == 3:
color = [255, 218, 185]
elif a == 4:
color = [255, 231, 186]
elif a == 5:
color = [255, 127, 0]
return color
def change(img_path):
ig = cv2.imread(img_path, 1)
def draw_black(m, n):
for ii in range(0, 4):
for jj in range(0, 4):
ig[4 * m + ii, 4 * n + jj] = [255, 255, 255]
b = random_color()
for ii in range(1, 3):
for jj in range(1, 3):
ig[4 * m + ii, 4 * n + jj] = b
for j in range(0, 360):
for i in range(0, 270):
if (numpy.array(ig[4*i+1, 4*j+1]) == numpy.array([0, 0, 0])).all():
draw_black(i, j)
return ig
效果
(有彩色雪花屏那味了 ) |