综合设计——多源异构数据采集与融合应用综合实践
这个项目属于哪个课程 | 2024数据采集与融合技术实践 |
---|---|
组名 | 在大大的数据里面挖呀挖呀挖 |
项目简介 | 项目名称:城市记忆 Logo:
项目需求:整合城市历史文化资源:需要以交互式的方式展示城市的历史发展、新旧照片、方言特色以及名人故事等内容。增强用户参与感:为用户提供交互性体验,如照片上色、语音生成、内容检索等。利用多媒体技术提升展示效果:通过地图、视频、音频、图像等多种形式,全方位展示城市记忆,构建沉浸式体验。 项目开展技术路线:python、html、JavaScript、flask、mysql |
团队成员学号 | 102202114农晨曦,102202118杨美荔、102202144傅钰、102202147赖越、102202150魏雨萱、102202152张静雯 |
这个项目的目标 | 建立多模块融合的城市记忆平台:打造一个集历史资源展示、文化传承和科技互动为一体的平台。 提升用户体验与交互性:通过地图导航、名人故事展示、黑白照片上色和方言音频生成等功能,让用户更生动地了解城市文化。 促进文化保护与传承:利用现代技术对城市历史资源进行数字化存档,帮助大众更便捷地探索与分享城市记忆。 探索跨学科技术融合:结合深度学习、多模态技术与地理信息系统等技术,提升文化展示的深度与广度。 |
其他参考文献 | 近20 年城市记忆研究综述 城市记忆与城市形态——从心理学、社会学视角探讨城市历史文化的延续 星火认知大模型Web API文档 |
综合设计——多源异构数据采集与融合应用综合实践
项目介绍
项目Logo
项目gitee链接
https://gitee.com/wei-yuxuan6/myproject/tree/master/实践作业
项目背景
城市记忆承载着一座城市的历史、文化与情感,其背后的故事和影像是研究城市变迁与文化保护的重要资源。然而,许多城市的历史资源缺乏系统化的整理与展示,普通大众难以方便地接触这些内容。随着人工智能与多媒体技术的快速发展,利用技术手段将历史内容与现代形式结合,可以更好地传递城市文化,增强公众的文化认同感。
功能介绍
- 时空地图
功能描述:
用户通过交互式地图探索城市历史文化资源。
点击地图标记点:显示对应城市的方言音频、新旧照片对比、历史发展时间轴信息。
查看名人故事:点击标记点的“名人故事”按钮跳转到城市的名人集页面,展示与该城市相关的名人列表。
名人故事展示:点击名人列表中的名人姓名,可以查看详细的名人故事,包括其生平事迹、贡献和与城市的关联性。
技术实现:
使用 高德地图 API 提供地图展示与交互功能。
数据库存储包含城市地理信息及相关文化资源。
名人资源使用Spark 4.0 Ultra搜索并整理名人集和名人故事。 - 照片上色
功能描述:
用户上传黑白照片,系统自动将其转换为色彩丰富的上色照片,直观展现历史影像的色彩还原效果。
支持多种照片格式,快速处理。
生成对比图,展示黑白原图与上色图的差异。
技术实现:
使用 百度图片上色接口 提供高精度的图片上色服务。
后端实现文件上传和上色结果的高效存储与展示。 - 方言之声
功能描述:
用户输入一段文本并选择城市名称,系统自动生成对应城市方言的音频文件。
支持多种方言生成,包括普通话、粤语、东北话等。
生成音频后提供播放功能,用户可以在线收听或下载保存。
技术实现:
使用 讯飞星火语音合成 API 实现高质量的多方言语音合成。 - 时光影像
功能描述:
用户输入城市名称,系统搜索该城市的老视频并在页面中展示。
视频内容涵盖城市建设、名
技术实现:
使用Whisper模型,从视频中提取音频并进行精准的转录,从而生成标准格式的字幕文件
个人分工
1.数据采集
利用Selenium和yt-dlp实现B站视频批量下载
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
from bs4 import BeautifulSoup
import os
import subprocess
import time
import threading
# 设置基本URL和目标网页
BASE_URL = "https://space.bilibili.com/402595174/channel/collectiondetail?sid=1261067"
# 设置保存视频的目录
SAVE_DIR = "E:/video"
if not os.path.exists(SAVE_DIR):
os.makedirs(SAVE_DIR)
# 设置cookies文件路径
COOKIES_FILE = "E:/cookies.txt"
# 每个线程下载视频的数量限制
MAX_VIDEOS = 200 # 假设下载最多200个视频
# 计数已下载的视频数量
downloaded_videos = 0
lock = threading.Lock()
# 增加重试次数
RETRY_LIMIT = 3
# 使用Selenium来获取页面
def get_html_using_selenium(driver):
"""获取当前页面的HTML"""
time.sleep(5) # 等待页面加载完成
return driver.page_source
# 提取视频链接
def extract_video_links(html):
"""从页面HTML中提取视频链接"""
soup = BeautifulSoup(html, "html.parser")
video_links = []
for li_tag in soup.find_all('li', class_="small-item"):
data_aid = li_tag.get('data-aid')
if data_aid:
video_url = f"https://www.bilibili.com/video/{data_aid}/"
video_links.append(video_url)
return video_links
# 下载视频
def download_video(video_url):
"""下载视频并删除未合并的文件"""
global downloaded_videos
if downloaded_videos >= MAX_VIDEOS:
print(f"已下载 {MAX_VIDEOS} 个视频,停止下载。")
return
# 获取视频标题
video_title = video_url.split("/")[-1]
video_file_path = os.path.join(SAVE_DIR, f"{video_title}.mp4")
if os.path.exists(video_file_path):
print(f"视频已存在,跳过下载: {video_title}")
return
with lock: # 使用锁来防止多线程时的竞争
downloaded_videos += 1
print(f"正在下载第 {downloaded_videos} 个视频: {video_url}")
# 设置命令以下载视频并保存文件
command = f'yt-dlp --cookies "{COOKIES_FILE}" -f 30064+30280 "{video_url}" -o "{SAVE_DIR}/%(title)s.%(ext)s" -k'
try:
print(f"执行命令: {command}")
subprocess.run(command, shell=True, check=True)
print(f"视频下载成功: {video_url}")
# 删除多余的.m4a文件,仅保留.mp4
cleanup_files(video_title)
except subprocess.CalledProcessError as e:
print(f"下载失败: {e}")
# 重试下载
for retry in range(RETRY_LIMIT):
print(f"正在重试下载: {video_url},重试 {retry + 1}/{RETRY_LIMIT}")
try:
subprocess.run(command, shell=True, check=True)
print(f"视频下载成功: {video_url}")
# 删除多余的.m4a文件,仅保留.mp4
cleanup_files(video_title)
break
except subprocess.CalledProcessError as retry_error:
print(f"重试失败: {retry_error}")
if retry == RETRY_LIMIT - 1:
print(f"重试 {RETRY_LIMIT} 次后下载失败: {video_url}")
# 加入文件合并后延迟,防止文件占用
time.sleep(2) # 休眠 2 秒,确保文件完全释放
一共下载了60多GB的视频,因为前面调试代码重复下载了很多视频
接下来清理文件夹中的冗余文件
import os
import glob
import re
# 定义文件夹路径
folder_path = r'E:\video'
# 遍历目录中的所有 .mp4 文件
mp4_files = glob.glob(os.path.join(folder_path, '**', '*.mp4'), recursive=True)
# 打印所有找到的 mp4 文件
print("所有 .mp4 文件:")
for file in mp4_files:
print(repr(file)) # 使用 repr 来检查路径中是否有隐藏字符
for file in mp4_files:
# 使用正则表达式匹配带有 [ ] 的文件(带附加标识的文件)
if re.search(r'\[.*\]\.mp4$', file): # 匹配带有方括号的文件
# 去除文件名中的附加标识部分 [BV1DE41127GQ],保留基本文件名
base_file = re.sub(r'\[.*\]\.mp4$', '.mp4', file) # 去除 [内容].mp4 部分
# 打印检查信息,查看文件名匹配情况
print(f"检查文件: {repr(file)}")
print(f"对应的基文件: {repr(base_file)}")
# 去掉路径中的额外空格,强制清除文件名和路径的末尾空格
file = file.strip() # 去除文件路径两端的空格
base_file = base_file.strip() # 去除基文件路径两端的空格
# 强制去除路径末尾空格
file = re.sub(r'\s+$', '', file) # 去除路径结尾的空格
base_file = re.sub(r'\s+$', '', base_file) # 去除路径结尾的空格
结果展示
2.使用 Whisper 和 FFmpeg 自动提取视频字幕
因为爬取到的老视频大部分都是早期的网络视频、电影或者纪录片都没有提供字幕,这使得听力障碍者或非母语观众无法完全理解视频的内容,因此我们选用Whisper模型,帮助我们从视频中提取音频并进行精准的转录,从而生成标准格式的字幕文件。
import os
import whisper
import subprocess # 使用 subprocess 来调用 ffmpeg
import srt
# 加载 Whisper 模型(small)
model = whisper.load_model("small")
model = model.float()
# 视频文件目录
video_directory = r"E:\video1" # 使用原始字符串处理路径
srt_directory = os.path.join(video_directory, "video_srt") # 保存字幕
audio_directory = os.path.join(video_directory, "video_wav") # 保存音频
# 确保目录存在
os.makedirs(srt_directory, exist_ok=True)
os.makedirs(audio_directory, exist_ok=True)
# 遍历目录中的所有视频文件
for filename in os.listdir(video_directory):
if filename.endswith(".mp4"): # 如果是 .mp4 文件
video_path = os.path.join(video_directory, filename)
audio_path = os.path.join(audio_directory, f"{os.path.splitext(filename)[0]}.wav")
srt_path = os.path.join(srt_directory, f"{os.path.splitext(filename)[0]}.srt")
try:
# 提取音频文件
print(f"开始提取音频: {video_path} -> {audio_path}")
subprocess.run(['ffmpeg', '-i', video_path, audio_path, '-y'], check=True)
print(f"音频文件已提取: {audio_path}")
except Exception as e:
print(f"音频提取失败: {e}")
continue
try:
# 对音频进行转录
print(f"开始转录音频: {audio_path}")
result = model.transcribe(audio_path)
print(f"转录成功: {audio_path}")
# 创建 SRT 字幕列表
subtitles = []
for segment in result["segments"]:
start = segment["start"]
end = segment["end"]
text = segment["text"]
subtitle = srt.Subtitle(index=len(subtitles) + 1, start=srt.timedelta(seconds=start),
end=srt.timedelta(seconds=end), content=text)
subtitles.append(subtitle)
# 保存字幕为 SRT 文件
with open(srt_path, "w", encoding="utf-8") as srt_file:
srt_file.write(srt.compose(subtitles))
生成的srt文件展示:
将字幕嵌入到视频中,结果展示:
3.心得体会
参与构建城市记忆的网站让我感到意义非凡。在爬取和处理老视频的过程中,我深刻体会到技术不仅是工具,更是一座桥梁,连接过去与未来。通过为这些记录着城市历史的视频提取字幕并规范化处理,我仿佛与历史对话,感受到了那些承载时光的影像背后的人文情怀。能够为城市记忆的保存和传承贡献一份力量,让更多人了解这些珍贵的历史片段,我倍感自豪。技术与情怀结合,让这份工作更加温暖且有意义。