Python爬虫数据增强:用DeOldify自动上色爬取的历史图片
本文介绍了如何利用星图GPU平台自动化部署DeOldify图像上色镜像,构建一条高效的数据增强流水线。该方案结合Python爬虫批量获取历史黑白图片,并通过DeOldify基于U-Net深度学习模型实现自动化上色,典型应用于为历史研究、文化保护项目快速生成高质量的彩色影像数据集。
Python爬虫数据增强:用DeOldify自动上色爬取的历史图片
你有没有想过,那些尘封在历史网站里的黑白老照片,如果能恢复色彩,会是什么样子?对于做数字人文研究或者需要历史图像数据集的朋友来说,这往往是个难题。手动上色?工作量巨大,不现实。直接使用黑白图训练AI模型?效果又可能大打折扣。
最近我在做一个关于近代城市风貌变迁的项目,需要大量高质量的彩色历史图片。我发现,把Python爬虫和DeOldify这个AI上色神器结合起来,可以搭建一条全自动的“数据增强流水线”。简单来说,就是让爬虫去网上“搬砖”,把黑白老照片批量抓回来,然后自动交给DeOldify“上色”,最后得到一套崭新的彩色数据集。整个过程几乎不用人工干预,效率提升了好几个量级。
今天,我就来分享一下这个结合了数据采集和AI处理的实战方案,希望能给有类似需求的朋友一些启发。
1. 场景与痛点:为什么需要自动化上色?
在做历史研究、文化保护或者训练视觉AI模型时,我们常常受限于历史影像资料的匮乏和质量。很多珍贵的档案、报纸、书籍插图都是黑白的,直接使用这些数据存在几个明显的痛点:
- 信息缺失:色彩是重要的信息维度。黑白照片丢失了建筑的原色、服饰的纹样、自然景观的层次,这会影响研究的深度和AI模型学习的特征。
- 数据集质量低:直接用黑白图训练的图像识别、分类模型,其泛化能力在面对真实彩色世界时可能会打折扣。
- 人工处理成本高:传统的人工上色或修复需要专业的美术功底,耗时耗力,无法应对大规模数据处理的诉求。
- 数据获取分散:有价值的历史图片分散在各个博物馆、档案馆、图书馆的网站上,手动一张张下载整理,效率极低。
我遇到的正是这些问题。我需要一个能自动从多个公开资源库抓取图片,并批量将其转为可信彩色图像的工具链。Python爬虫负责解决“获取”的问题,而DeOldify则解决了“增强”的问题。
2. 技术方案选型:为什么是DeOldify?
给黑白照片上色的AI模型不止一个,比如也有基于GAN的模型。我选择DeOldify,主要是基于它在真实感和易用性上的平衡。
DeOldify的核心优势在于它生成的色彩通常比较自然、克制,不容易出现大面积色块溢出或过于艳丽的“塑料感”,这对于历史照片的修复尤为重要。它追求的是“可信”而非“炫技”。
从技术实现角度看,对于我们这个数据管道,DeOldify有几个好处:
- 有成熟的预训练模型:开箱即用,不需要我们自己从头收集数据训练,这对于快速启动项目至关重要。
- 提供多种接口:既有本地部署的库,也有封装好的工具函数,方便我们集成到Python自动化脚本中。
- 效果相对稳定:在人物、风景、建筑等常见历史题材上表现可靠,减少了后期人工筛选的工作量。
当然,它也不是万能的。对于某些特定场景(如极低分辨率、严重损坏的图片),效果可能不尽如人意。但对于从正规档案网站爬取的质量尚可的扫描件,它的表现足够胜任。
3. 构建自动化管道:从爬取到上色的全流程
整个管道的思路很清晰:爬虫获取图片列表和链接 -> 下载原始黑白图片 -> 调用DeOldify处理每张图片 -> 保存并整理结果。下面我们拆解每一步。
3.1 第一步:编写针对性爬虫抓取图片
爬虫部分的目标是精准、高效、友好地从目标网站获取图片。这里以某个假设的历史图片库为例。
import requests
from bs4 import BeautifulSoup
import os
import time
from urllib.parse import urljoin
class HistoricalImageCrawler:
def __init__(self, base_url, save_dir='./raw_images'):
self.base_url = base_url
self.save_dir = save_dir
os.makedirs(save_dir, exist_ok=True)
self.headers = {
'User-Agent': 'Mozilla/5.0 (历史研究数据采集脚本)'
}
def fetch_image_links(self, list_page_url):
"""从列表页解析出所有图片详情页链接"""
try:
resp = requests.get(list_page_url, headers=self.headers, timeout=10)
resp.raise_for_status()
soup = BeautifulSoup(resp.text, 'html.parser')
# 假设详情页链接在 class='item-link' 的a标签里
detail_links = []
for a_tag in soup.find_all('a', class_='item-link', href=True):
full_url = urljoin(self.base_url, a_tag['href'])
detail_links.append(full_url)
return detail_links
except Exception as e:
print(f"获取列表页失败 {list_page_url}: {e}")
return []
def download_image(self, detail_page_url):
"""访问详情页,找到并下载高清图片"""
try:
resp = requests.get(detail_page_url, headers=self.headers, timeout=10)
resp.raise_for_status()
soup = BeautifulSoup(resp.text, 'html.parser')
# 假设高清图片在 meta 标签的 og:image 属性中,或某个特定img标签
img_tag = soup.find('meta', property='og:image')
if img_tag and img_tag.get('content'):
img_url = urljoin(detail_page_url, img_tag['content'])
else:
# 备选方案:找最大的img标签
img_tag = soup.find('img', {'class': 'main-photo'})
if not img_tag:
return None
img_url = urljoin(detail_page_url, img_tag['src'])
# 下载图片
img_data = requests.get(img_url, headers=self.headers, timeout=15).content
# 生成文件名,可以用详情页的标题或ID
file_name = os.path.basename(img_url.split('?')[0]) or f"image_{int(time.time())}.jpg"
save_path = os.path.join(self.save_dir, file_name)
with open(save_path, 'wb') as f:
f.write(img_data)
print(f"下载成功: {save_path}")
return save_path
except Exception as e:
print(f"处理详情页失败 {detail_page_url}: {e}")
return None
def crawl(self, start_page, max_pages=5):
"""主爬取流程"""
all_downloaded = []
for page in range(1, max_pages + 1):
print(f"正在抓取第 {page} 页...")
list_url = f"{start_page}?page={page}" # 根据实际网站结构调整
detail_links = self.fetch_image_links(list_url)
for link in detail_links:
saved_path = self.download_image(link)
if saved_path:
all_downloaded.append(saved_path)
time.sleep(1) # 礼貌性延迟,避免对服务器造成压力
time.sleep(2)
return all_downloaded
# 使用示例
if __name__ == '__main__':
crawler = HistoricalImageCrawler(base_url="https://example-archive.org")
downloaded_images = crawler.crawl(start_page="https://example-archive.org/photos", max_pages=3)
print(f"总共下载了 {len(downloaded_images)} 张图片。")
关键点说明:
- 遵守规则:爬虫的
User-Agent要声明用途,并设置合理的延迟(time.sleep),尊重网站的robots.txt。 - 健壮性:代码中加入了异常处理,确保某个页面或图片失败时,流程不会完全中断。
- 灵活性:解析逻辑(
fetch_image_links和download_image中的选择器)需要根据目标网站的实际HTML结构进行调整。这里只是示例。
3.2 第二步:集成DeOldify进行批量上色
下载好一批黑白图片后,接下来就是调用DeOldify来上色。这里我们使用DeOldify的Python库进行本地处理。首先需要安装环境。
# 这是一个简化的环境准备步骤,实际可能需要根据DeOldify官方文档调整
git clone https://github.com/jantic/DeOldify.git
cd DeOldify
pip install -r requirements.txt
# 下载预训练模型文件到指定目录
然后,我们可以编写一个处理脚本:
import torch
from deoldify import device
from deoldify.device_id import DeviceId
from deoldify.visualize import get_image_colorizer
import os
from PIL import Image
import glob
class ImageColorizer:
def __init__(self, model_path='./models/ColorizeArtistic_gen.pth'):
# 设置设备,如果有GPU会快很多
device.set(device=DeviceId.GPU0 if torch.cuda.is_available() else DeviceId.CPU)
self.colorizer = get_image_colorizer(artistic=True) # artistic模型通常色彩更生动
def colorize_single(self, image_path, output_path=None, render_factor=35):
"""对单张图片进行上色
render_factor: 渲染因子,值越大细节越多但可能引入噪声,通常20-40之间
"""
try:
if output_path is None:
base, ext = os.path.splitext(image_path)
output_path = f"{base}_colorized{ext}"
# 调用DeOldify上色
result = self.colorizer.get_transformed_image(
path=image_path,
render_factor=render_factor,
watermarked=False
)
if result is not None:
result.save(output_path)
print(f"上色完成: {output_path}")
return output_path
else:
print(f"上色失败: {image_path}")
return None
except Exception as e:
print(f"处理图片时出错 {image_path}: {e}")
return None
def colorize_batch(self, input_dir, output_dir, file_pattern="*.jpg", render_factor=35):
"""批量处理一个目录下的所有图片"""
os.makedirs(output_dir, exist_ok=True)
image_paths = glob.glob(os.path.join(input_dir, file_pattern))
colorized_paths = []
for img_path in image_paths:
file_name = os.path.basename(img_path)
out_path = os.path.join(output_dir, f"colorized_{file_name}")
result = self.colorize_single(img_path, out_path, render_factor)
if result:
colorized_paths.append(result)
print(f"批量处理完成,成功处理 {len(colorized_paths)}/{len(image_paths)} 张图片。")
return colorized_paths
# 使用示例:连接爬虫和上色器
if __name__ == '__main__':
# 假设我们已经用爬虫下载了图片到 './raw_images'
raw_image_dir = './raw_images'
# 初始化上色器(首次运行会下载模型,需要一点时间)
print("正在初始化DeOldify上色器...")
colorizer = ImageColorizer()
# 设置输出目录
colorized_dir = './colorized_images'
# 开始批量上色
print("开始批量上色处理...")
processed_images = colorizer.colorize_batch(
input_dir=raw_image_dir,
output_dir=colorized_dir,
file_pattern="*.jpg",
render_factor=32 # 可以调整这个参数看效果
)
关键点说明:
- 渲染因子:
render_factor是一个重要参数。数值小(如15)色彩柔和但可能模糊;数值大(如40)细节更多但可能产生噪点。需要根据原始图片质量微调。 - 性能:如果有NVIDIA GPU,处理速度会快很多。批量处理时,注意GPU内存是否足够。
- 模型选择:DeOldify通常提供“Artistic”(艺术化)和“Stable”(稳定)两种风格的模型。对于历史照片,“Stable”可能更保守真实,但“Artistic”有时效果更惊艳。可以都试试。
3.3 第三步:组装完整管道与后期处理
将前两步串联起来,并增加一些实用功能,就形成了完整管道。
import json
import hashlib
class HistoricalImageEnhancementPipeline:
def __init__(self, crawler, colorizer):
self.crawler = crawler
self.colorizer = colorizer
self.metadata = [] # 用于记录每张图片的元数据
def run(self, start_url, max_pages=3):
print("=== 阶段1:爬取原始图片 ===")
raw_images = self.crawler.crawl(start_url, max_pages=max_pages)
print(f"\n=== 阶段2:批量AI上色 ===")
colorized_images = self.colorizer.colorize_batch(
self.crawler.save_dir,
'./enhanced_final'
)
# 简单的元数据记录(例如,记录原始文件和上色后文件的对应关系)
for raw, color in zip(raw_images, colorized_images):
self.metadata.append({
'source': raw,
'enhanced': color,
'file_hash': self._calculate_file_hash(raw) # 用于去重或标识
})
# 将元数据保存为JSON,方便后续管理
with open('./pipeline_metadata.json', 'w') as f:
json.dump(self.metadata, f, indent=2)
print(f"\n=== 流程结束!元数据已保存。===")
return colorized_images
def _calculate_file_hash(self, filepath):
"""计算文件哈希值,用于唯一标识"""
with open(filepath, 'rb') as f:
return hashlib.md5(f.read()).hexdigest()
# 主程序入口
if __name__ == '__main__':
# 初始化组件
my_crawler = HistoricalImageCrawler(base_url="https://example-archive.org", save_dir='./raw_historical')
my_colorizer = ImageColorizer()
# 初始化并运行管道
pipeline = HistoricalImageEnhancementPipeline(my_crawler, my_colorizer)
final_images = pipeline.run(start_url="https://example-archive.org/collection/1920s", max_pages=2)
print(f"成功生成 {len(final_images)} 张增强后的彩色历史图片。")
这个管道还加入了简单的元数据管理,记录了原始文件和生成文件的对应关系,这对于后续的数据集整理和溯源非常重要。
4. 实际效果与优化建议
跑通整个流程后,我得到了一批上色后的历史图片。整体来看,DeOldify对建筑、街道、自然风景的上色效果非常出色,色彩还原显得合理且富有时代感。例如,砖墙呈现出暗红色,天空是淡蓝色,树木是深浅不一的绿色,看起来非常自然。
当然,过程中也遇到一些需要调整的地方:
- 人脸肤色:对于某些人物特写,肤色有时会偏黄或偏红,可能需要针对性地调整
render_factor或尝试不同的预训练模型。 - 复杂纹理:对于极其模糊或破损严重的原图,上色后可能会产生一些不规则的色斑。这时,可以在上色前尝试用传统图像处理算法(如锐化、降噪)进行轻度预处理。
- 批量处理效率:如果图片数量成千上万,需要考虑任务队列(如Celery)和分布式处理,避免单机内存或显存不足。
- 结果审核:目前流程是全自动的,对于关键项目,建议加入一个“人工审核”环节,快速浏览生成结果,剔除明显失败(如全灰、色彩严重错乱)的个案。
一个更进阶的用法是,可以将这个管道产出的高质量彩色图像,作为训练数据,去微调一个专属的“历史影像上色模型”,可能在某些特定领域(如某个城市的旧照)获得比通用模型更好的效果。
5. 总结
把Python爬虫和DeOldify组合起来,相当于打造了一个“历史图片焕新工厂”。爬虫负责源源不断地输送原材料(黑白老照片),而DeOldify则是一个不知疲倦的AI画师,自动为它们填充上合理的色彩。
这套方案的价值在于它的自动化和可扩展性。一旦脚本写好,你就可以用它来处理成千上万张图片,极大地解放了人力。获取到的彩色数据集,无论是用于学术研究、文化展示,还是作为训练数据喂给其他AI模型(如图像分类、风格迁移),其价值都远高于原始的黑白数据集。
实际操作中,最关键的两步是针对目标网站编写健壮的爬虫和根据图片质量调整DeOldify的参数。如果效果不理想,多试试不同的render_factor,或者换用artistic=False的稳定模式,往往能有改善。
技术本身不是目的,用它来解决实际问题才是。希望这个“爬虫+AI”的搭配思路,能帮你打开一扇窗,更高效地挖掘和利用那些沉睡在数字角落里的历史宝藏。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。
更多推荐


所有评论(0)