作者 | Marcelo Rovai
来源 | Medium
编辑 | 代码医生团队
该项目基于Richard Zhang,Phillip Isola和Alexei A. Efros在加州大学伯克利分校开发的研究工作:彩色图像着色
https://arxiv.org/pdf/1603.08511.pdf
本教程是开发一种全自动方法,让黑白照片和视频扩展的生成逼真色彩。正如原始论文中所解释的那样,作者通过在训练时使用类重新平衡来增加结果中颜色的多样性,将问题视为分类任务,从而接受了问题的潜在不确定性。人工智能(AI)方法在测试时作为CNN(“ 卷积神经网络 ”)中的前馈通道实施,并且训练超过一百万个彩色图像。
1906年拍摄了一张照片,展示了Santos Dumont在巴黎的“14-bis”飞机的首次测试:
它的彩色版本使用这些AI技术开发的模型:
相同的技术可以应用于旧视频。这里是1932年巴西里约热内卢市的黑白录像:
和彩色版本:
1.实验室色彩空间
通常习惯使用RGB模型对彩色照片进行编码。RGB颜色模型是一种加色模型,其中红色,绿色和蓝色光以各种方式加在一起,以再现各种颜色。模型的名称来自三种加色原色的首字母,红色,绿色和蓝色。
但是,将在该项目中使用的模型是“LAB”。
在CIELAB颜色空间(也称为CIE的L * a * b *表或有时简称为简单的“实验室”的色彩空间)是由国际照明委员会(CIE)于1976年定义的颜色空间它表达的颜色作为三个数值,L *表示亮度,a *和b *表示绿红色和蓝黄色成分。
颜色空间L * a * b *是在相反颜色理论之后创建的,其中两种颜色不能同时为绿色和红色,或者同时为黄色和蓝色。CIELAB被设计成在人类色觉方面在感知上是均匀的,这意味着这些值中相同数量的数值变化对应于大约相同量的视觉感知变化。
与RGB颜色模型不同,Lab颜色设计用于近似人类视觉。它渴望感性均匀性,其L分量与人类对亮度的感知紧密相关。L分量恰好是用作AI模型的输入,用于估计剩余分量“a”和“b”。
2. AI(深度学习)过程
正如在介绍中所评论的那样,人工智能(AI)方法在测试时被实现为CNN(“卷积神经网络”)中的前馈传递,并且被训练超过一百万个彩色图像。换句话说,使用Lab模型分解了数百万张彩色照片,并用作输入特征(“L”)和分类标签(“a”和“b”)。简单起见将其分为两部分:“L”和“a + b”,如框图所示:
拥有经过训练的模型(可公开获得),可以使用它来为新的黑白照片着色,其中这张照片将是模型或组件“L”的输入。模型的输出将是其他组件“a”和“b”,一旦添加到原始“L”,将返回完整的彩色照片,如下所示:
简而言之,使用来自ImageNet的1.3 Millon照片的广泛且多样化的对象和场景数据集以及应用深度学习算法(前馈CNN),生成最终模型并可在以下位置获得:
彩色图像着色 - 模型
https://github.com/richzhang/colorization/blob/master/models/fetch_release_models.sh
3.工作环境
首先要做的是组织一个将要工作的环境。创建一个文件夹并命名它:
在这个主目录下,创建子文件夹:
转到彩色图像着色模型并下载3个文件并将其加载到创建的子文件夹“/ model”。文件是:
假设机器上安装了Python(版本3.6)和OpenCV(4.0)。将使用Jupyter笔记本逐步描述所有着色过程。可以去GitHub下载Notebook和测试照片:
Photo_Video_Colorization
https://github.com/Mjrovai/Python4DS/tree/master/Photo_Video_Colorization
4.黑白照片着色
按照步骤着色黑白照片:
导入重要的库:
import numpy as np
import matplotlib.pyplot as plt
import cv2
定义要着色的图像:
IMAGE = "soldiers_1941"
注意:可以在此处使用任何照片。在这种情况下,在第二次世界大战中使用1941年的黑白战士照片。照片可以在GitHub上找到。
定义模型路径:
prototxt = "./model/colorization_deploy_v2.prototxt"
model = "./model/colorization_release_v2.caffemodel"
points = "./model/pts_in_hull.npy"
image = "./input_images/"+IMAGE
加载序列化黑白颜色模型和集群:
net = cv2.dnn.readNetFromCaffe(prototxt, model)
pts = np.load(points)
将群集中心添加为模型的1x1卷积:
class8 = net.getLayerId("class8_ab")
conv8 = net.getLayerId("conv8_313_rh")
pts = pts.transpose().reshape(2, 313, 1, 1)
net.getLayer(class8).blobs = [pts.astype("float32")]
net.getLayer(conv8).blobs = [np.full([1, 313], 2.606, dtype="float32")]
加载输入图像,缩放它并将其转换为Lab:
请注意,首先将图像转换为灰度。这个步骤并不是必需的,但是意识到一些黑白照片,特别是旧照片,在这些年中得到一些治疗,最好稍微清理一下。
image = cv2.imread(image)
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
image = cv2.cvtColor(image, cv2.COLOR_GRAY2RGB)
此时有原始图像,但为了在Jupyter单元格上直接显示,应该使用pyplot库:
plt.imshow(image)
plt.axis('off');
提取“L”:
现在采用“图像”并继续着色过程,首先应该重新缩放,转换为Lab以提取组件“L”并将其居中:
scaled = image.astype("float32") / 255.0
lab = cv2.cvtColor(scaled, cv2.COLOR_RGB2LAB)
resized = cv2.resize(lab, (224, 224))
L = cv2.split(resized)[0]
L -= 50
预测“a”和“b”:
net.setInput(cv2.dnn.blobFromImage(L))
ab = net.forward()[0, :, :, :].transpose((1, 2, 0))
ab = cv2.resize(ab, (image.shape[1], image.shape[0]))
创建彩色实验室照片(L + a + b):
L = cv2.split(lab)[0]
colorized = np.concatenate((L[:, :, np.newaxis], ab), axis=2)
与对灰度图像一样,检查彩色图像的样子:
plt.imshow(colorized)
plt.axis('off');
plt.title('colorized LAB image');
似乎Lab图像无法告诉我们多少,将其转换为RGB并查看结果:
转换为RGB:
colorized = cv2.cvtColor(colorized, cv2.COLOR_LAB2RGB)
colorized = np.clip(colorized, 0, 1)
colorized = (255 * colorized).astype("uint8")
plt.imshow(colorized)
plt.axis('off');
相当了不起!!!!!这是一张1941年的照片,似乎真的是以全彩色拍摄的!保存吧:
保存最终的RGB照片:
cv2.imwrite("./colorized_images/Color_"+IMAGE,
cv2.cvtColor(colorized, cv2.COLOR_RGB2BGR))
还有一个:查尔斯·达尔文于1832年访问巴西里约热内卢:
尝试使用其他黑白照片,看看人工智能有多么神奇!
5.着色视频
一旦对照片进行着色,将视频着色并不是一项复杂的任务。必须遵循以下一般步骤:
来做一个真实的案例:
可以从GitHub下载Notebook B_W_Video_Colorization.ipynb,或按照步骤操作。
https://github.com/Mjrovai/Python4DS/blob/master/Photo_Video_Colorization/B_W_Video_Colorization.ipynb
做的第一件事就是从YouTube下载一部黑白电影,在这种情况下:
https://www.youtube.com/watch?v=InWifglIkQ0
使用了免费工具:VidPaw下载它。把它命名为:“rio_32.mp4”并将其保存在input_video子文件夹中。
https://www.vidpaw.com/
应用上述步骤,最后将所有彩色化的帧存储在子文件夹colorized_video_frames上。
1.开始定义应该着色的文件:
VIDEO = "rio_32.mp4"
2.定义路径,常量和视频变量:
prototxt = "./model/colorization_deploy_v2.prototxt"
model = "./model/colorization_release_v2.caffemodel"
points = "./model/pts_in_hull.npy"
video = "./input_video/"+VIDEO
width = 500
vs = cv2.VideoCapture(video)
3.加载和准备模型:
net = cv2.dnn.readNetFromCaffe(prototxt,model)
pts = np.load(points)
class8 = net.getLayerId("class8_ab")
conv8 = net.getLayerId("conv8_313_rh")
pts = pts.transpose().reshape(2, 313, 1, 1)
net.getLayer(class8).blobs = [pts.astype("float32")]
net.getLayer(conv8).blobs = [np.full([1, 313], 2.606, dtype="float32")]
4.逐帧分割视频并应用模型:
count = 0
success = True
while success:
success, frame = vs.read()
if frame is None:
break
frame = imutils.resize(frame, 500)
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
frame = cv2.cvtColor(frame, cv2.COLOR_GRAY2RGB)
scaled = frame.astype("float32") / 255.0
lab = cv2.cvtColor(scaled, cv2.COLOR_RGB2LAB)
resized = cv2.resize(lab, (224, 224))
L = cv2.split(resized)[0]
L -= 50
net.setInput(cv2.dnn.blobFromImage(L))
ab = net.forward()[0, :, :, :].transpose((1, 2, 0))
ab = cv2.resize(ab, (frame.shape[1], frame.shape[0]))
L = cv2.split(lab)[0]
colorized = np.concatenate((L[:, :, np.newaxis], ab), axis=2)
colorized = cv2.cvtColor(colorized, cv2.COLOR_LAB2BGR)
colorized = np.clip(colorized, 0, 1)
colorized = (255 * colorized).astype("uint8")
cv2.imshow("Original", frame)
cv2.imshow("Colorized", colorized)
cv2.imwrite("./colorized_video_frames/frame%d.jpg" % count, colorized)
count += 1
key = cv2.waitKey(1) & 0xFF
if key == ord("q"):
break
vs.release()
cv2.destroyAllWindows()
上述循环过程通常需要一段时间。例如这部视频的彩色化过程(8分钟)有大约14,000帧,在MacBook Pro上花了大约3个小时--2.9GHz Core i7和16GB 2133MHz的RAM。
5.获得带有框架的文件后,必须“重新组装”它以创建视频。bellow功能可以做到:
def convert_frames_to_video(pathIn, pathOut, fps):
frame_array = []
files = [f for f in os.listdir(pathIn) if isfile(join(pathIn, f))]
#for sorting the file names properly
files.sort(key = lambda x: int(x[5:-4]))
for i in range(len(files)):
filename=pathIn + files[i]
#reading each files
img = cv2.imread(filename)
height, width, layers = img.shape
size = (width,height)
print(filename)
#inserting the frames into an image array
frame_array.append(img)
out = cv2.VideoWriter(pathOut,cv2.VideoWriter_fourcc(*'MJPG'), fps, size)
for i in range(len(frame_array)):
# writing to a image array
out.write(frame_array[i])
out.release()
请注意,根据在计算机上安装的视频控制器,应更改编解码器(*'MJPG')。请查看OpenCV文档。最后将是“尝试和错误”体验。
现在应该在彩色框架上应用上述功能:
pathIn= './colorized_video_frames/'
pathOut = './colorized_videos/video.avi'
fps = 30.0
convert_frames_to_video(pathIn, pathOut, fps)
由此产生的“原始”视频可以在这里看到:
“文章开始的黑白视频”
请注意,视频显然没有声音。做的是从黑白电影中剥离原始声音,并使用iMovie将其添加到彩色电影中。最终结果如下:
“文章开始的彩色视频”
6.向Santos Dumont致敬
借此机会为旧照片和视频着色,决定向上个世纪的伟大发明家Alberto Santos-Dumont致敬。
Santos-Dumont是巴西的发明家和航空先驱,是为空气轻于空气和重于空气的飞机发展做出重大贡献的极少数人之一。
Santos-Dumont是一个富裕的咖啡生产商家族的继承人,他致力于巴黎的航空研究和实验,在那里度过了他大部分的成年生活。在他早期的职业生涯中,他设计,建造并飞行了热气球和早期的飞船,最终于1901年10月19日赢得了德意志德梅尔特奖,用于绕埃菲尔铁塔航行。然后他转向重于空气的机器,并于1906年10月23日,他的14 - 是欧洲第一个动力重于空中的飞行,由法国Aéro-Club和国际航空联合会认证。他相信航空业将迎来一个全球和平与繁荣的时代,这使他能够自由地发布他的设计并放弃对他的各种创新申请专利。
在上面可以欣赏二十世纪前十年使用本教程中描述的技术着色的一些照片。在下面完成了视频拼贴。希望你能欣赏它。
7.结论
一如既往希望这个项目可以帮助其他人进入数据科学的激动人心的世界!
有关详细信息和最终代码,请访问GitHub存储库:MJRoBot-Python4DS
https://github.com/Mjrovai/Python4DS/tree/master/Photo_Video_Colorization