不用Premiere,不用PhotoShop,不用App,也可以用OpenCV制作视频滤镜!
最近流行起一股复古风,于是不懂剪辑视频的我也想搞一搞这种复古风格老视频。
![](https://img.haomeiwen.com/i11381603/e815496798062218.jpg)
![](https://img.haomeiwen.com/i11381603/7f1f75edfbe6f37f.jpg)
首先看看有什么特点:
- 标清分辨率(大约480)
- 既有模糊又有锐化
- 色彩饱和度低
- 紫边(镜头色散)
- 色调偏黄(索尼大法黄?)
那么一步一步来
- 首先读取一张图片,或视频里的每一帧
img = cv2.imread('test.jpg')
- 调整图片大小
copy = cv2.resize(img, (640, 480))
- 高斯模糊,然后锐化
# blur
copy = cv2.GaussianBlur(copy, (3, 3), 0)
# sharpen
kernel = np.array([[0, -1, 0], [-1, 5, -1], [0, -1, 0]])
copy = cv2.filter2D(copy, -1, kernel)
![](https://img.haomeiwen.com/i11381603/c840f6602edb2b6c.jpg)
- 降低色彩饱和度
这里的思路是将图片转成HSV色彩空间,降低S的值即可降低色彩饱和度,最后再转回默认的BGR色彩空间
HSV = cv2.cvtColor(copy, cv2.COLOR_BGR2HSV)
S = HSV[:, :, 1]
S[:, :] = S[:, :] * 0.8
copy = cv2.cvtColor(HSV, cv2.COLOR_HSV2BGR)
可以看见原本的鲜艳红色变得暗淡了
![](https://img.haomeiwen.com/i11381603/09b1b7670f08d764.jpg)
- 制作紫边
紫边的出现是因为镜头对不同颜色的折射率不同而导致的色散现象,老的摄影机镜头对色散的处理都不是很好,因此紫边是老视频里最重要的特点之一!
主要思路是让R、G、B分别上下左右移动若干像素。
例如让所有的红色向左移动5像素
cols = copy.shape[1]
move = 5
# pick one channel to translate, 0:B 1:G 2:R
toLeft = copy[:, :, 2]
toLeft[:, :cols - move] = toLeft[:, move:]
![](https://img.haomeiwen.com/i11381603/95a6aacb3ea06a87.jpg)
如上图,可以看见移动5像素太过于夸张了,那么移动1或2像素就比较像了
那么将B左移1,G上移1,R右移1,得到下面的效果
move = 1
cols = copy.shape[1]
toLeft = copy[:, :, 0]
toLeft[:, :cols - move] = toLeft[:, move:]
toRight = copy[:, :, 2]
toRight[:, move:] = toRight[:, :cols - move]
rows = copy.shape[0]
toUp = copy[:, :, 1]
toUp[:rows - move:] = toUp[move:, :]
![](https://img.haomeiwen.com/i11381603/07fb571bc8e7c260.jpg)
- 让图片变黄(如果不喜欢黄色可以跳过这一步)
直接让减小B和G的值就行了
B = copy[:, :, 0]
B[:, :] = B[:, :] * 0.94
G = copy[:, :, 1]
G[:, :] = G[:, :] * 0.99
![](https://img.haomeiwen.com/i11381603/7f1f75edfbe6f37f.jpg)
- 其他
也许还有一些例如黑线、随机噪点等操作,看个人口味
将上述操作用于视频
- 首先将上述操作封装成一个函数:
def VHSImage(src):
# blablabla
return result
- 读取原视频,处理每一帧,写入新视频,最后合并新视频和旧音频
def doWithVideo(src, output = 'out.mp4'):
cap = cv2.VideoCapture(src)
width = cap.get(cv2.CAP_PROP_FRAME_WIDTH)
height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT)
fps = cap.get(cv2.CAP_PROP_FPS)
framecount = cap.get(cv2.CAP_PROP_FRAME_COUNT)
print('total frame: {}'.format(framecount))
videoheight = int(480)
videowidth = int(float(videoheight) / float(height) * float(width))
videosize = (videowidth, videoheight)
cachePrefixName = time.strftime('%Y%m%d_%H%M%S')
cacheVideoName = "{}.cachevideo.mp4".format(cachePrefixName)
cacheAudioName = "{}.cacheaudio.mp3".format(cachePrefixName)
cc = cv2.VideoWriter_fourcc(*'mp4v')
out = cv2.VideoWriter(cacheVideoName, cc, fps, videosize)
if out.isOpened() == False:
print('fail to open video writer')
return False
currentframeindex = 0
while cap.isOpened():
ret, frame = cap.read()
if ret == False:
break
frame = cv2.resize(frame, videosize)
frame = VHSImage(frame)
# cv2.imshow('frame', frame)
# cv2.waitKey(1)
out.write(frame)
print('progress:{}/{}'.format(currentframeindex, framecount))
currentframeindex += 1
cap.release()
out.release()
print('finish progress')
# ffmpeg -i INPUT_VIDEO -f mp3 -vn OUTPUT_AUDIO
# ffmpeg -i INPUT_VIDEO -i INPUT_AUDIO -c:v copy OUTPUT_VIDEO
print('remix audio and video')
os.system("ffmpeg -i {} -f mp3 -vn {}".format(src, cacheAudioName))
# check audio file if exists
if os.path.exists(cacheAudioName):
# remix audio and video
os.system("ffmpeg -i {} -i {} -c:v copy {}".format(cacheVideoName, cacheAudioName, output))
print("cleaning cache")
os.system("rm -rf {} {}".format(cacheAudioName, cacheVideoName))
else :
# rename this no-audio video
os.system("mv {} {}".format(cacheVideoName, output))
print("finish remix")
print("done")
网友评论