init
This commit is contained in:
8
.idea/.gitignore
generated
vendored
Normal file
8
.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# 默认忽略的文件
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# 基于编辑器的 HTTP 客户端请求
|
||||||
|
/httpRequests/
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
||||||
10
.idea/44.iml
generated
Normal file
10
.idea/44.iml
generated
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="PYTHON_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/.venv" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="jdk" jdkName="Python 3.12 (44)" jdkType="Python SDK" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
20
.idea/dataSources.xml
generated
Normal file
20
.idea/dataSources.xml
generated
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
|
||||||
|
<data-source source="LOCAL" name="i3d" uuid="db63001d-b47f-4218-89b6-8924a539bfad">
|
||||||
|
<driver-ref>sqlite.xerial</driver-ref>
|
||||||
|
<synchronize>true</synchronize>
|
||||||
|
<jdbc-driver>org.sqlite.JDBC</jdbc-driver>
|
||||||
|
<jdbc-url>jdbc:sqlite:D:\code\python\44\i3d.db</jdbc-url>
|
||||||
|
<working-dir>$ProjectFileDir$</working-dir>
|
||||||
|
<libraries>
|
||||||
|
<library>
|
||||||
|
<url>file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.45.1/org/xerial/sqlite-jdbc/3.45.1.0/sqlite-jdbc-3.45.1.0.jar</url>
|
||||||
|
</library>
|
||||||
|
<library>
|
||||||
|
<url>file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.45.1/org/slf4j/slf4j-api/1.7.36/slf4j-api-1.7.36.jar</url>
|
||||||
|
</library>
|
||||||
|
</libraries>
|
||||||
|
</data-source>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
31
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
31
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<profile version="1.0">
|
||||||
|
<option name="myName" value="Project Default" />
|
||||||
|
<inspection_tool class="PyPackageRequirementsInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="ignoredPackages">
|
||||||
|
<value>
|
||||||
|
<list size="10">
|
||||||
|
<item index="0" class="java.lang.String" itemvalue="watchfiles" />
|
||||||
|
<item index="1" class="java.lang.String" itemvalue="fastapi" />
|
||||||
|
<item index="2" class="java.lang.String" itemvalue="pydantic" />
|
||||||
|
<item index="3" class="java.lang.String" itemvalue="pydantic_core" />
|
||||||
|
<item index="4" class="java.lang.String" itemvalue="starlette" />
|
||||||
|
<item index="5" class="java.lang.String" itemvalue="anyio" />
|
||||||
|
<item index="6" class="java.lang.String" itemvalue="uvicorn" />
|
||||||
|
<item index="7" class="java.lang.String" itemvalue="click" />
|
||||||
|
<item index="8" class="java.lang.String" itemvalue="httptools" />
|
||||||
|
<item index="9" class="java.lang.String" itemvalue="websockets" />
|
||||||
|
</list>
|
||||||
|
</value>
|
||||||
|
</option>
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PyPep8NamingInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
||||||
|
<option name="ignoredErrors">
|
||||||
|
<list>
|
||||||
|
<option value="N803" />
|
||||||
|
<option value="N801" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
</inspection_tool>
|
||||||
|
</profile>
|
||||||
|
</component>
|
||||||
6
.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
6
.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<settings>
|
||||||
|
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||||
|
<version value="1.0" />
|
||||||
|
</settings>
|
||||||
|
</component>
|
||||||
6
.idea/misc.xml
generated
Normal file
6
.idea/misc.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="Black">
|
||||||
|
<option name="sdkName" value="Python 3.12 (44)" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/44.iml" filepath="$PROJECT_DIR$/.idea/44.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
49
1.py
Normal file
49
1.py
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import tempfile
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
# 根目录
|
||||||
|
input_dir = r"D:\DESKTOP\2025\44\a1\dataset" # 替换为你的视频根目录
|
||||||
|
video_exts = {".avi", ".mov", ".mkv", ".flv", ".webm", ".wmv", ".mp4",".m4s"}
|
||||||
|
|
||||||
|
def convert_and_replace(filepath):
|
||||||
|
ext = os.path.splitext(filepath)[1].lower()
|
||||||
|
if ext not in video_exts:
|
||||||
|
return
|
||||||
|
|
||||||
|
print(f"处理文件: {filepath}")
|
||||||
|
|
||||||
|
# 创建临时输出文件
|
||||||
|
temp_fd, temp_path = tempfile.mkstemp(suffix=".mp4")
|
||||||
|
os.close(temp_fd) # 不使用 open 的文件描述符
|
||||||
|
|
||||||
|
# ffmpeg 转换命令(保留前30秒,360p,输出mp4)
|
||||||
|
cmd = [
|
||||||
|
"ffmpeg",
|
||||||
|
"-y",
|
||||||
|
"-i", filepath,
|
||||||
|
"-t", "30",
|
||||||
|
"-vf", "scale=-2:480",
|
||||||
|
"-c:v", "libx264", # 改为 libx265 可使用 H.265
|
||||||
|
"-preset", "slow",
|
||||||
|
"-crf", "18",
|
||||||
|
"-c:a", "aac",
|
||||||
|
"-b:a", "64k",
|
||||||
|
temp_path
|
||||||
|
]
|
||||||
|
|
||||||
|
try:
|
||||||
|
subprocess.run(cmd, check=True)
|
||||||
|
shutil.move(temp_path, filepath)
|
||||||
|
print(f"已替换: {filepath}")
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
print(f"失败: {filepath}\n{e}")
|
||||||
|
if os.path.exists(temp_path):
|
||||||
|
os.remove(temp_path)
|
||||||
|
|
||||||
|
# 递归遍历处理
|
||||||
|
for root, _, files in os.walk(input_dir):
|
||||||
|
for name in files:
|
||||||
|
file_path = os.path.join(root, name)
|
||||||
|
convert_and_replace(file_path)
|
||||||
52
I3D.py
Normal file
52
I3D.py
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
import torch
|
||||||
|
import torch.nn.functional as F
|
||||||
|
import torchvision.transforms as transforms
|
||||||
|
from pytorchvideo.models.hub import i3d_r50
|
||||||
|
import cv2
|
||||||
|
import numpy as np
|
||||||
|
from PIL import Image
|
||||||
|
|
||||||
|
model = i3d_r50(pretrained=True).eval()
|
||||||
|
feature_extractor = torch.nn.Sequential(*model.blocks[:-1])
|
||||||
|
|
||||||
|
def preprocess_video(video_path, num_frames=32, size=224):
|
||||||
|
cap = cv2.VideoCapture(video_path)
|
||||||
|
frames = []
|
||||||
|
transform = transforms.Compose([
|
||||||
|
transforms.Resize((size, size)),
|
||||||
|
transforms.ToTensor(),
|
||||||
|
transforms.Normalize(mean=[0.45, 0.45, 0.45], std=[0.225, 0.225, 0.225])
|
||||||
|
])
|
||||||
|
|
||||||
|
total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
|
||||||
|
frame_indices = np.linspace(0, total_frames - 1, num_frames).astype(int)
|
||||||
|
|
||||||
|
for i in frame_indices:
|
||||||
|
cap.set(cv2.CAP_PROP_POS_FRAMES, i)
|
||||||
|
ret, frame = cap.read()
|
||||||
|
if not ret:
|
||||||
|
break
|
||||||
|
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
||||||
|
frame = Image.fromarray(frame)
|
||||||
|
frame = transform(frame)
|
||||||
|
frames.append(frame)
|
||||||
|
|
||||||
|
cap.release()
|
||||||
|
video_tensor = torch.stack(frames).permute(1, 0, 2, 3).unsqueeze(0)
|
||||||
|
return video_tensor
|
||||||
|
|
||||||
|
def extract_features(video_tensor):
|
||||||
|
with torch.no_grad():
|
||||||
|
features = feature_extractor(video_tensor)
|
||||||
|
features = F.adaptive_avg_pool3d(features, 1)
|
||||||
|
features = features.flatten()
|
||||||
|
return features.numpy()
|
||||||
|
|
||||||
|
def video_features(video_path):
|
||||||
|
video_tensor = preprocess_video(video_path)
|
||||||
|
features = extract_features(video_tensor)
|
||||||
|
return features
|
||||||
|
|
||||||
|
video_path = r'D:\DESKTOP\2025\44\a1\dataset\org\0.mp4'
|
||||||
|
video_f = video_features(video_path)
|
||||||
|
print(f"视频features: {video_f.shape}")
|
||||||
246
LBPTOP.ipynb
Normal file
246
LBPTOP.ipynb
Normal file
@@ -0,0 +1,246 @@
|
|||||||
|
{
|
||||||
|
"cells": [
|
||||||
|
{
|
||||||
|
"metadata": {
|
||||||
|
"ExecuteTime": {
|
||||||
|
"end_time": "2025-04-14T04:06:31.135934Z",
|
||||||
|
"start_time": "2025-04-14T04:06:30.845929Z"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"cell_type": "code",
|
||||||
|
"source": [
|
||||||
|
"import cv2\n",
|
||||||
|
"import numpy as np\n",
|
||||||
|
"from skimage.feature import local_binary_pattern\n"
|
||||||
|
],
|
||||||
|
"id": "9157e102c51206bb",
|
||||||
|
"outputs": [],
|
||||||
|
"execution_count": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"metadata": {
|
||||||
|
"ExecuteTime": {
|
||||||
|
"end_time": "2025-04-14T04:06:31.144988Z",
|
||||||
|
"start_time": "2025-04-14T04:06:31.138940Z"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"cell_type": "code",
|
||||||
|
"source": [
|
||||||
|
"def extract_lbp_top(video_path, radius=2, n_points=8, method='uniform', block_size=10):\n",
|
||||||
|
" cap = cv2.VideoCapture(video_path)\n",
|
||||||
|
" frames = []\n",
|
||||||
|
"\n",
|
||||||
|
" # 读取所有帧\n",
|
||||||
|
" while True:\n",
|
||||||
|
" ret, frame = cap.read()\n",
|
||||||
|
" if not ret:\n",
|
||||||
|
" break\n",
|
||||||
|
" gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)\n",
|
||||||
|
" frames.append(gray)\n",
|
||||||
|
" cap.release()\n",
|
||||||
|
"\n",
|
||||||
|
" frames = np.array(frames)\n",
|
||||||
|
" T, H, W = frames.shape # 时间、空间维度\n",
|
||||||
|
"\n",
|
||||||
|
" # 使用滑动窗口计算 XT, YT 平面\n",
|
||||||
|
" hist_xy = np.zeros((n_points + 2,))\n",
|
||||||
|
" hist_xt = np.zeros((n_points + 2,))\n",
|
||||||
|
" hist_yt = np.zeros((n_points + 2,))\n",
|
||||||
|
"\n",
|
||||||
|
" # LBP on XY plane\n",
|
||||||
|
" for t in range(0, T, block_size):\n",
|
||||||
|
" if t >= T:\n",
|
||||||
|
" break\n",
|
||||||
|
" lbp = local_binary_pattern(frames[t], n_points, radius, method)\n",
|
||||||
|
" hist, _ = np.histogram(lbp.ravel(), bins=np.arange(0, n_points + 3), density=True)\n",
|
||||||
|
" hist_xy += hist\n",
|
||||||
|
"\n",
|
||||||
|
" # LBP on XT plane\n",
|
||||||
|
" for y in range(0, H, block_size):\n",
|
||||||
|
" if y >= H:\n",
|
||||||
|
" break\n",
|
||||||
|
" xt_plane = frames[:, y, :]\n",
|
||||||
|
" lbp = local_binary_pattern(xt_plane, n_points, radius, method)\n",
|
||||||
|
" hist, _ = np.histogram(lbp.ravel(), bins=np.arange(0, n_points + 3), density=True)\n",
|
||||||
|
" hist_xt += hist\n",
|
||||||
|
"\n",
|
||||||
|
" # LBP on YT plane\n",
|
||||||
|
" for x in range(0, W, block_size):\n",
|
||||||
|
" if x >= W:\n",
|
||||||
|
" break\n",
|
||||||
|
" yt_plane = frames[:, :, x]\n",
|
||||||
|
" lbp = local_binary_pattern(yt_plane, n_points, radius, method)\n",
|
||||||
|
" hist, _ = np.histogram(lbp.ravel(), bins=np.arange(0, n_points + 3), density=True)\n",
|
||||||
|
" hist_yt += hist\n",
|
||||||
|
"\n",
|
||||||
|
" # 拼接三个平面的直方图作为最终特征向量\n",
|
||||||
|
" feature_vector = np.concatenate([hist_xy, hist_xt, hist_yt])\n",
|
||||||
|
" feature_vector /= np.linalg.norm(feature_vector) # 归一化\n",
|
||||||
|
"\n",
|
||||||
|
" return feature_vector"
|
||||||
|
],
|
||||||
|
"id": "d9d5bd6f6a9e114a",
|
||||||
|
"outputs": [],
|
||||||
|
"execution_count": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"metadata": {
|
||||||
|
"ExecuteTime": {
|
||||||
|
"end_time": "2025-04-14T04:06:31.297545Z",
|
||||||
|
"start_time": "2025-04-14T04:06:31.294247Z"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"cell_type": "code",
|
||||||
|
"source": [
|
||||||
|
"def getFeature(video_path = r\"D:\\DESKTOP\\2025\\44\\a1\\dataset\\org\\1.mp4\"):\n",
|
||||||
|
"\n",
|
||||||
|
" feature = extract_lbp_top(video_path)\n",
|
||||||
|
" # print(\"Video feature shape (for copyright):\", feature.shape)\n",
|
||||||
|
" return feature"
|
||||||
|
],
|
||||||
|
"id": "404b8b3562026f1f",
|
||||||
|
"outputs": [],
|
||||||
|
"execution_count": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"metadata": {
|
||||||
|
"ExecuteTime": {
|
||||||
|
"end_time": "2025-04-14T04:06:32.509232Z",
|
||||||
|
"start_time": "2025-04-14T04:06:31.302931Z"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"cell_type": "code",
|
||||||
|
"source": [
|
||||||
|
"import sqlite3\n",
|
||||||
|
"import io\n",
|
||||||
|
"import os\n",
|
||||||
|
"import tqdm\n",
|
||||||
|
"\n",
|
||||||
|
"# 注册适配器与转换器:numpy数组 <-> BLOB\n",
|
||||||
|
"def adapt_array(arr):\n",
|
||||||
|
" out = io.BytesIO()\n",
|
||||||
|
" np.save(out, arr)\n",
|
||||||
|
" out.seek(0)\n",
|
||||||
|
" return sqlite3.Binary(out.read())\n",
|
||||||
|
"\n",
|
||||||
|
"def convert_array(text):\n",
|
||||||
|
" out = io.BytesIO(text)\n",
|
||||||
|
" out.seek(0)\n",
|
||||||
|
" return np.load(out)\n",
|
||||||
|
"\n",
|
||||||
|
"# 注册自定义类型处理\n",
|
||||||
|
"sqlite3.register_adapter(np.ndarray, adapt_array)\n",
|
||||||
|
"sqlite3.register_converter(\"array\", convert_array)\n",
|
||||||
|
"\n",
|
||||||
|
"# 创建数据库连接(带类型检测)\n",
|
||||||
|
"conn = sqlite3.connect(\"LBPTOP.db\", detect_types=sqlite3.PARSE_DECLTYPES)\n",
|
||||||
|
"cursor = conn.cursor()\n",
|
||||||
|
"\n",
|
||||||
|
"# 创建表\n",
|
||||||
|
"cursor.execute(\"\"\"\n",
|
||||||
|
"CREATE TABLE IF NOT EXISTS data (\n",
|
||||||
|
" id INTEGER PRIMARY KEY,\n",
|
||||||
|
" array BLOB,\n",
|
||||||
|
" group_path TEXT,\n",
|
||||||
|
" full_path TEXT\n",
|
||||||
|
")\n",
|
||||||
|
"\"\"\")\n",
|
||||||
|
"\n",
|
||||||
|
"\n",
|
||||||
|
"def add_to_db(array_to_store,group_path,full_path):\n",
|
||||||
|
" cursor.execute(\"INSERT INTO data (array,group_path,full_path) VALUES (?,?,?)\", (array_to_store,group_path,full_path,))\n",
|
||||||
|
" conn.commit()\n",
|
||||||
|
"\n",
|
||||||
|
"# # 读取数组\n",
|
||||||
|
"# cursor.execute(\"SELECT array FROM data WHERE id=1\")\n",
|
||||||
|
"# fetched_array = cursor.fetchone()[0]\n",
|
||||||
|
"#\n",
|
||||||
|
"# print(\"原始数组:\\n\", array_to_store)\n",
|
||||||
|
"# print(\"读取的数组:\\n\", fetched_array)\n",
|
||||||
|
"\n",
|
||||||
|
"folder_path = r\"D:\\DESKTOP\\2025\\44\\a1\\dataset\"\n",
|
||||||
|
"\n",
|
||||||
|
"all_files = []\n",
|
||||||
|
"names = [str(x)+\".mp4\" for x in range(10)]\n",
|
||||||
|
"print(names)\n",
|
||||||
|
"\n",
|
||||||
|
"\n",
|
||||||
|
"# 遍历文件夹\n",
|
||||||
|
"for group_path in os.listdir(folder_path):\n",
|
||||||
|
" full_path = os.path.join(folder_path, group_path)\n",
|
||||||
|
" if os.path.isdir(full_path):\n",
|
||||||
|
" # 遍历子文件夹\n",
|
||||||
|
" for video_path in os.listdir(full_path):\n",
|
||||||
|
" if os.path.basename(video_path) in names:\n",
|
||||||
|
" video_full_path = os.path.join(full_path, video_path)\n",
|
||||||
|
" if os.path.isfile(video_full_path):\n",
|
||||||
|
" # 处理视频文件\n",
|
||||||
|
" all_files.append((group_path,video_full_path))\n",
|
||||||
|
"print(len(all_files))\n"
|
||||||
|
],
|
||||||
|
"id": "4dc69bad309cb6b1",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "stdout",
|
||||||
|
"output_type": "stream",
|
||||||
|
"text": [
|
||||||
|
"['0.mp4', '1.mp4', '2.mp4', '3.mp4', '4.mp4', '5.mp4', '6.mp4', '7.mp4', '8.mp4', '9.mp4']\n",
|
||||||
|
"70\n"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"execution_count": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"metadata": {
|
||||||
|
"ExecuteTime": {
|
||||||
|
"end_time": "2025-04-14T04:20:52.302187Z",
|
||||||
|
"start_time": "2025-04-14T04:06:32.521053Z"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"cell_type": "code",
|
||||||
|
"source": [
|
||||||
|
"for group_path, video_full_path in tqdm.tqdm(all_files):\n",
|
||||||
|
" # 读取视频特征\n",
|
||||||
|
" feature = getFeature(video_full_path)\n",
|
||||||
|
" # 将特征存储到数据库\n",
|
||||||
|
" add_to_db(feature,group_path,video_full_path)\n",
|
||||||
|
" # print(f\"已处理并存储: {video_full_path}\")\n",
|
||||||
|
"\n",
|
||||||
|
"conn.close()\n"
|
||||||
|
],
|
||||||
|
"id": "3cd83672f6901125",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "stderr",
|
||||||
|
"output_type": "stream",
|
||||||
|
"text": [
|
||||||
|
"100%|██████████| 70/70 [14:19<00:00, 12.28s/it]\n"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"execution_count": 5
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"metadata": {
|
||||||
|
"kernelspec": {
|
||||||
|
"display_name": "Python 3",
|
||||||
|
"language": "python",
|
||||||
|
"name": "python3"
|
||||||
|
},
|
||||||
|
"language_info": {
|
||||||
|
"codemirror_mode": {
|
||||||
|
"name": "ipython",
|
||||||
|
"version": 2
|
||||||
|
},
|
||||||
|
"file_extension": ".py",
|
||||||
|
"mimetype": "text/x-python",
|
||||||
|
"name": "python",
|
||||||
|
"nbconvert_exporter": "python",
|
||||||
|
"pygments_lexer": "ipython2",
|
||||||
|
"version": "2.7.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nbformat": 4,
|
||||||
|
"nbformat_minor": 5
|
||||||
|
}
|
||||||
61
LBPTOP.py
Normal file
61
LBPTOP.py
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
import cv2
|
||||||
|
import numpy as np
|
||||||
|
from skimage.feature import local_binary_pattern
|
||||||
|
|
||||||
|
|
||||||
|
def extract_lbp_top(video_path, radius=2, n_points=8, method='uniform', block_size=10):
|
||||||
|
cap = cv2.VideoCapture(video_path)
|
||||||
|
frames = []
|
||||||
|
|
||||||
|
# 读取所有帧
|
||||||
|
while True:
|
||||||
|
ret, frame = cap.read()
|
||||||
|
if not ret:
|
||||||
|
break
|
||||||
|
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
|
||||||
|
frames.append(gray)
|
||||||
|
cap.release()
|
||||||
|
|
||||||
|
frames = np.array(frames)
|
||||||
|
T, H, W = frames.shape # 时间、空间维度
|
||||||
|
|
||||||
|
# 使用滑动窗口计算 XT, YT 平面
|
||||||
|
hist_xy = np.zeros((n_points + 2,))
|
||||||
|
hist_xt = np.zeros((n_points + 2,))
|
||||||
|
hist_yt = np.zeros((n_points + 2,))
|
||||||
|
|
||||||
|
# LBP on XY plane
|
||||||
|
for t in range(0, T, block_size):
|
||||||
|
if t >= T:
|
||||||
|
break
|
||||||
|
lbp = local_binary_pattern(frames[t], n_points, radius, method)
|
||||||
|
hist, _ = np.histogram(lbp.ravel(), bins=np.arange(0, n_points + 3), density=True)
|
||||||
|
hist_xy += hist
|
||||||
|
|
||||||
|
# LBP on XT plane
|
||||||
|
for y in range(0, H, block_size):
|
||||||
|
if y >= H:
|
||||||
|
break
|
||||||
|
xt_plane = frames[:, y, :]
|
||||||
|
lbp = local_binary_pattern(xt_plane, n_points, radius, method)
|
||||||
|
hist, _ = np.histogram(lbp.ravel(), bins=np.arange(0, n_points + 3), density=True)
|
||||||
|
hist_xt += hist
|
||||||
|
|
||||||
|
# LBP on YT plane
|
||||||
|
for x in range(0, W, block_size):
|
||||||
|
if x >= W:
|
||||||
|
break
|
||||||
|
yt_plane = frames[:, :, x]
|
||||||
|
lbp = local_binary_pattern(yt_plane, n_points, radius, method)
|
||||||
|
hist, _ = np.histogram(lbp.ravel(), bins=np.arange(0, n_points + 3), density=True)
|
||||||
|
hist_yt += hist
|
||||||
|
|
||||||
|
# 拼接三个平面的直方图作为最终特征向量
|
||||||
|
feature_vector = np.concatenate([hist_xy, hist_xt, hist_yt])
|
||||||
|
feature_vector /= np.linalg.norm(feature_vector) # 归一化
|
||||||
|
|
||||||
|
return feature_vector
|
||||||
|
|
||||||
|
video_path = r'D:\DESKTOP\2025\44\a1\dataset\org\1.mp4'
|
||||||
|
features = extract_lbp_top(video_path)
|
||||||
|
print(f"特征向量维度: {features.shape}")
|
||||||
292
analy.ipynb
Normal file
292
analy.ipynb
Normal file
@@ -0,0 +1,292 @@
|
|||||||
|
{
|
||||||
|
"cells": [
|
||||||
|
{
|
||||||
|
"metadata": {
|
||||||
|
"ExecuteTime": {
|
||||||
|
"end_time": "2025-04-14T06:58:32.199713Z",
|
||||||
|
"start_time": "2025-04-14T06:58:32.134049Z"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"cell_type": "code",
|
||||||
|
"source": [
|
||||||
|
"import sqlite3\n",
|
||||||
|
"import numpy as np\n",
|
||||||
|
"import io\n",
|
||||||
|
"from numpy.linalg import norm\n",
|
||||||
|
"from collections import defaultdict"
|
||||||
|
],
|
||||||
|
"id": "6917288db44004ea",
|
||||||
|
"outputs": [],
|
||||||
|
"execution_count": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"metadata": {
|
||||||
|
"ExecuteTime": {
|
||||||
|
"end_time": "2025-04-14T06:58:34.129528Z",
|
||||||
|
"start_time": "2025-04-14T06:58:34.126022Z"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"cell_type": "code",
|
||||||
|
"source": [
|
||||||
|
"currdb = \"i3d.db\"\n",
|
||||||
|
"#currdb = \"LBPTOP.db\"\n",
|
||||||
|
"currdb = \"slowfast.db\""
|
||||||
|
],
|
||||||
|
"id": "dd9b84fa98c77e5a",
|
||||||
|
"outputs": [],
|
||||||
|
"execution_count": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"metadata": {
|
||||||
|
"ExecuteTime": {
|
||||||
|
"end_time": "2025-04-14T06:58:36.801611Z",
|
||||||
|
"start_time": "2025-04-14T06:58:36.798114Z"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"cell_type": "code",
|
||||||
|
"source": [
|
||||||
|
"# 注册适配器与转换器:numpy数组 <-> BLOB\n",
|
||||||
|
"def adapt_array(arr):\n",
|
||||||
|
" out = io.BytesIO()\n",
|
||||||
|
" np.save(out, arr)\n",
|
||||||
|
" out.seek(0)\n",
|
||||||
|
" return sqlite3.Binary(out.read())\n",
|
||||||
|
"\n",
|
||||||
|
"def convert_array(text):\n",
|
||||||
|
" out = io.BytesIO(text)\n",
|
||||||
|
" out.seek(0)\n",
|
||||||
|
" return np.load(out)"
|
||||||
|
],
|
||||||
|
"id": "fa2ab158cbe0aa98",
|
||||||
|
"outputs": [],
|
||||||
|
"execution_count": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"metadata": {
|
||||||
|
"ExecuteTime": {
|
||||||
|
"end_time": "2025-04-14T07:01:06.063185Z",
|
||||||
|
"start_time": "2025-04-14T07:01:06.060008Z"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"cell_type": "code",
|
||||||
|
"source": [
|
||||||
|
"\n",
|
||||||
|
"sqlite3.register_adapter(np.ndarray, adapt_array)\n",
|
||||||
|
"sqlite3.register_converter(\"BLOB\", convert_array)\n",
|
||||||
|
"\n",
|
||||||
|
"# 连接SQLite数据库\n",
|
||||||
|
"conn = sqlite3.connect(currdb, detect_types=sqlite3.PARSE_DECLTYPES)\n",
|
||||||
|
"cursor = conn.cursor()"
|
||||||
|
],
|
||||||
|
"id": "629eb156f332c0bc",
|
||||||
|
"outputs": [],
|
||||||
|
"execution_count": 12
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"metadata": {
|
||||||
|
"ExecuteTime": {
|
||||||
|
"end_time": "2025-04-14T07:01:06.372809Z",
|
||||||
|
"start_time": "2025-04-14T07:01:06.362911Z"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"cell_type": "code",
|
||||||
|
"source": [
|
||||||
|
"# 读取数据库所有数据\n",
|
||||||
|
"cursor.execute(\"SELECT id, array, group_path, full_path FROM data\")\n",
|
||||||
|
"all_data = cursor.fetchall()"
|
||||||
|
],
|
||||||
|
"id": "ba7902156f1b6117",
|
||||||
|
"outputs": [],
|
||||||
|
"execution_count": 13
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"metadata": {
|
||||||
|
"collapsed": true,
|
||||||
|
"ExecuteTime": {
|
||||||
|
"end_time": "2025-04-14T07:01:06.786016Z",
|
||||||
|
"start_time": "2025-04-14T07:01:06.779812Z"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"cell_type": "code",
|
||||||
|
"source": [
|
||||||
|
"# 整理特征\n",
|
||||||
|
"data_by_group = defaultdict(list)\n",
|
||||||
|
"for vid, arr, group, path in all_data:\n",
|
||||||
|
" data_by_group[group].append({'id': vid, 'feature': arr, 'path': path})\n",
|
||||||
|
"\n",
|
||||||
|
"# 相似度函数 (余弦相似度)\n",
|
||||||
|
"def cosine_similarity(a, b):\n",
|
||||||
|
" return np.dot(a, b) / (norm(a) * norm(b))\n",
|
||||||
|
"\n",
|
||||||
|
"# 计算指标函数\n",
|
||||||
|
"def compute_metrics(org_feats, query_feats, sim_feats, K=5):\n",
|
||||||
|
" precision_top1 = []\n",
|
||||||
|
" recall_at_k = []\n",
|
||||||
|
" AP_list = []\n",
|
||||||
|
"\n",
|
||||||
|
" # 构建搜索库 (原始视频 + 相似视频)\n",
|
||||||
|
" search_db = org_feats + sim_feats\n",
|
||||||
|
"\n",
|
||||||
|
" for query in query_feats:\n",
|
||||||
|
" similarities = []\n",
|
||||||
|
" query_feature = query['feature']\n",
|
||||||
|
"\n",
|
||||||
|
" # 计算query与所有库视频的相似度\n",
|
||||||
|
" for target in search_db:\n",
|
||||||
|
" sim = cosine_similarity(query_feature, target['feature'])\n",
|
||||||
|
" label = 1 if target in org_feats else 0 # 1代表匹配,0代表不匹配\n",
|
||||||
|
" similarities.append((sim, label))\n",
|
||||||
|
"\n",
|
||||||
|
" # 相似度降序排序\n",
|
||||||
|
" similarities.sort(key=lambda x: x[0], reverse=True)\n",
|
||||||
|
" labels_sorted = [label for _, label in similarities]\n",
|
||||||
|
"\n",
|
||||||
|
" # Top-1 precision\n",
|
||||||
|
" precision_top1.append(labels_sorted[0])\n",
|
||||||
|
"\n",
|
||||||
|
" # Recall@K\n",
|
||||||
|
" recall = sum(labels_sorted[:K]) / len(org_feats)\n",
|
||||||
|
" recall_at_k.append(recall)\n",
|
||||||
|
"\n",
|
||||||
|
" # Average Precision (AP)\n",
|
||||||
|
" hits, sum_precisions = 0, 0\n",
|
||||||
|
" for idx, label in enumerate(labels_sorted, start=1):\n",
|
||||||
|
" if label == 1:\n",
|
||||||
|
" hits += 1\n",
|
||||||
|
" sum_precisions += hits / idx\n",
|
||||||
|
" AP = sum_precisions / len(org_feats) if len(org_feats) else 0\n",
|
||||||
|
" AP_list.append(AP)\n",
|
||||||
|
"\n",
|
||||||
|
" # 返回指标均值\n",
|
||||||
|
" return {\n",
|
||||||
|
" 'Top-1 Precision': np.mean(precision_top1),\n",
|
||||||
|
" f'Recall@{K}': np.mean(recall_at_k),\n",
|
||||||
|
" 'MAP': np.mean(AP_list)\n",
|
||||||
|
" }"
|
||||||
|
],
|
||||||
|
"id": "initial_id",
|
||||||
|
"outputs": [],
|
||||||
|
"execution_count": 14
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"metadata": {
|
||||||
|
"ExecuteTime": {
|
||||||
|
"end_time": "2025-04-14T07:01:07.745386Z",
|
||||||
|
"start_time": "2025-04-14T07:01:07.740942Z"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"cell_type": "code",
|
||||||
|
"source": "data_by_group['org'][0]['feature'].shape",
|
||||||
|
"id": "55e57dc7ec56b732",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text/plain": [
|
||||||
|
"(2304,)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"execution_count": 15,
|
||||||
|
"metadata": {},
|
||||||
|
"output_type": "execute_result"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"execution_count": 15
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"metadata": {
|
||||||
|
"ExecuteTime": {
|
||||||
|
"end_time": "2025-04-14T06:00:12.392784Z",
|
||||||
|
"start_time": "2025-04-14T06:00:12.382725Z"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"cell_type": "code",
|
||||||
|
"source": [
|
||||||
|
"# 主函数,计算所有变形组的指标\n",
|
||||||
|
"def evaluate_all_variants(K=5):\n",
|
||||||
|
" org_feats = data_by_group['org']\n",
|
||||||
|
" sim_feats = data_by_group['sim']\n",
|
||||||
|
"\n",
|
||||||
|
" results = {}\n",
|
||||||
|
"\n",
|
||||||
|
" # 排除 'org' 和 'sim',其余都是变形组\n",
|
||||||
|
" variant_groups = [group for group in data_by_group if group not in ['org', 'sim']]\n",
|
||||||
|
"\n",
|
||||||
|
" for variant in variant_groups:\n",
|
||||||
|
" variant_feats = data_by_group[variant]\n",
|
||||||
|
" metrics = compute_metrics(org_feats, variant_feats, sim_feats, K)\n",
|
||||||
|
" results[variant] = metrics\n",
|
||||||
|
"\n",
|
||||||
|
" return results\n",
|
||||||
|
"\n",
|
||||||
|
"# 执行评估\n",
|
||||||
|
"results = evaluate_all_variants(K=3)\n",
|
||||||
|
"\n",
|
||||||
|
"# 输出结果\n",
|
||||||
|
"for variant, metrics in results.items():\n",
|
||||||
|
" print(f\"变形组: {variant}\")\n",
|
||||||
|
" for metric_name, value in metrics.items():\n",
|
||||||
|
" print(f\" {metric_name}: {value:.4f}\")\n",
|
||||||
|
" print(\"-\" * 40)\n",
|
||||||
|
"\n",
|
||||||
|
"# 关闭数据库连接\n",
|
||||||
|
"conn.close()"
|
||||||
|
],
|
||||||
|
"id": "d9a0103dbc3f1bef",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "stdout",
|
||||||
|
"output_type": "stream",
|
||||||
|
"text": [
|
||||||
|
"变形组: 动态水印2\n",
|
||||||
|
" Top-1 Precision: 1.0000\n",
|
||||||
|
" Recall@3: 0.1500\n",
|
||||||
|
" MAP: 0.5815\n",
|
||||||
|
"----------------------------------------\n",
|
||||||
|
"变形组: 水印1+2\n",
|
||||||
|
" Top-1 Precision: 0.8000\n",
|
||||||
|
" Recall@3: 0.1600\n",
|
||||||
|
" MAP: 0.5751\n",
|
||||||
|
"----------------------------------------\n",
|
||||||
|
"变形组: 水印1+2+滤镜\n",
|
||||||
|
" Top-1 Precision: 0.8000\n",
|
||||||
|
" Recall@3: 0.1500\n",
|
||||||
|
" MAP: 0.5685\n",
|
||||||
|
"----------------------------------------\n",
|
||||||
|
"变形组: 滤镜\n",
|
||||||
|
" Top-1 Precision: 0.9000\n",
|
||||||
|
" Recall@3: 0.1800\n",
|
||||||
|
" MAP: 0.6100\n",
|
||||||
|
"----------------------------------------\n",
|
||||||
|
"变形组: 静态水印1\n",
|
||||||
|
" Top-1 Precision: 0.9000\n",
|
||||||
|
" Recall@3: 0.1700\n",
|
||||||
|
" MAP: 0.6058\n",
|
||||||
|
"----------------------------------------\n"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"execution_count": 25
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"metadata": {
|
||||||
|
"kernelspec": {
|
||||||
|
"display_name": "Python 3",
|
||||||
|
"language": "python",
|
||||||
|
"name": "python3"
|
||||||
|
},
|
||||||
|
"language_info": {
|
||||||
|
"codemirror_mode": {
|
||||||
|
"name": "ipython",
|
||||||
|
"version": 2
|
||||||
|
},
|
||||||
|
"file_extension": ".py",
|
||||||
|
"mimetype": "text/x-python",
|
||||||
|
"name": "python",
|
||||||
|
"nbconvert_exporter": "python",
|
||||||
|
"pygments_lexer": "ipython2",
|
||||||
|
"version": "2.7.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nbformat": 4,
|
||||||
|
"nbformat_minor": 5
|
||||||
|
}
|
||||||
279
i3d.ipynb
Normal file
279
i3d.ipynb
Normal file
@@ -0,0 +1,279 @@
|
|||||||
|
{
|
||||||
|
"cells": [
|
||||||
|
{
|
||||||
|
"metadata": {
|
||||||
|
"ExecuteTime": {
|
||||||
|
"end_time": "2025-04-14T03:58:08.619189Z",
|
||||||
|
"start_time": "2025-04-14T03:58:08.616451Z"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"cell_type": "code",
|
||||||
|
"source": [
|
||||||
|
"import torch\n",
|
||||||
|
"import torch.nn.functional as F\n",
|
||||||
|
"import torchvision.transforms as transforms\n",
|
||||||
|
"from pytorchvideo.models.hub import i3d_r50\n",
|
||||||
|
"import cv2\n",
|
||||||
|
"import numpy as np\n",
|
||||||
|
"from PIL import Image"
|
||||||
|
],
|
||||||
|
"id": "79af3e0bb61c3290",
|
||||||
|
"outputs": [],
|
||||||
|
"execution_count": 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"metadata": {
|
||||||
|
"collapsed": true,
|
||||||
|
"ExecuteTime": {
|
||||||
|
"end_time": "2025-04-14T03:58:09.075199Z",
|
||||||
|
"start_time": "2025-04-14T03:58:08.635303Z"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"cell_type": "code",
|
||||||
|
"source": [
|
||||||
|
"# 初始化预训练I3D模型\n",
|
||||||
|
"model = i3d_r50(pretrained=True).eval()\n",
|
||||||
|
"feature_extractor = torch.nn.Sequential(*model.blocks[:-1])"
|
||||||
|
],
|
||||||
|
"id": "initial_id",
|
||||||
|
"outputs": [],
|
||||||
|
"execution_count": 6
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"metadata": {
|
||||||
|
"ExecuteTime": {
|
||||||
|
"end_time": "2025-04-14T03:58:09.118627Z",
|
||||||
|
"start_time": "2025-04-14T03:58:09.113363Z"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"cell_type": "code",
|
||||||
|
"source": [
|
||||||
|
"def preprocess_video(video_path, num_frames=32, size=224):\n",
|
||||||
|
" cap = cv2.VideoCapture(video_path)\n",
|
||||||
|
" frames = []\n",
|
||||||
|
" transform = transforms.Compose([\n",
|
||||||
|
" transforms.Resize((size, size)),\n",
|
||||||
|
" transforms.ToTensor(),\n",
|
||||||
|
" transforms.Normalize(mean=[0.45, 0.45, 0.45], std=[0.225, 0.225, 0.225])\n",
|
||||||
|
" ])\n",
|
||||||
|
"\n",
|
||||||
|
" total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))\n",
|
||||||
|
" frame_indices = np.linspace(0, total_frames - 1, num_frames).astype(int)\n",
|
||||||
|
"\n",
|
||||||
|
" for i in frame_indices:\n",
|
||||||
|
" cap.set(cv2.CAP_PROP_POS_FRAMES, i)\n",
|
||||||
|
" ret, frame = cap.read()\n",
|
||||||
|
" if not ret:\n",
|
||||||
|
" break\n",
|
||||||
|
" frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)\n",
|
||||||
|
" frame = Image.fromarray(frame)\n",
|
||||||
|
" frame = transform(frame)\n",
|
||||||
|
" frames.append(frame)\n",
|
||||||
|
"\n",
|
||||||
|
" cap.release()\n",
|
||||||
|
" video_tensor = torch.stack(frames).permute(1, 0, 2, 3).unsqueeze(0)\n",
|
||||||
|
" return video_tensor\n"
|
||||||
|
],
|
||||||
|
"id": "5fd2f80d5947967e",
|
||||||
|
"outputs": [],
|
||||||
|
"execution_count": 7
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"metadata": {
|
||||||
|
"ExecuteTime": {
|
||||||
|
"end_time": "2025-04-14T03:58:09.128752Z",
|
||||||
|
"start_time": "2025-04-14T03:58:09.125636Z"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"cell_type": "code",
|
||||||
|
"source": [
|
||||||
|
"def extract_features(video_tensor):\n",
|
||||||
|
" with torch.no_grad():\n",
|
||||||
|
" features = feature_extractor(video_tensor)\n",
|
||||||
|
" features = F.adaptive_avg_pool3d(features, 1)\n",
|
||||||
|
" features = features.flatten()\n",
|
||||||
|
" return features.numpy()"
|
||||||
|
],
|
||||||
|
"id": "728a0b9ece5bdc06",
|
||||||
|
"outputs": [],
|
||||||
|
"execution_count": 8
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"metadata": {
|
||||||
|
"ExecuteTime": {
|
||||||
|
"end_time": "2025-04-14T03:58:09.142606Z",
|
||||||
|
"start_time": "2025-04-14T03:58:09.138924Z"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"cell_type": "code",
|
||||||
|
"source": [
|
||||||
|
"def video_features(video_path):\n",
|
||||||
|
" video_tensor = preprocess_video(video_path)\n",
|
||||||
|
" features = extract_features(video_tensor)\n",
|
||||||
|
" return features"
|
||||||
|
],
|
||||||
|
"id": "60ca6ade121d00af",
|
||||||
|
"outputs": [],
|
||||||
|
"execution_count": 9
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"metadata": {
|
||||||
|
"ExecuteTime": {
|
||||||
|
"end_time": "2025-04-14T03:58:09.156458Z",
|
||||||
|
"start_time": "2025-04-14T03:58:09.152546Z"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"cell_type": "code",
|
||||||
|
"source": [
|
||||||
|
"def getFeature(video_path = r\"D:\\DESKTOP\\2025\\44\\a1\\dataset\\org\\1.mp4\"):\n",
|
||||||
|
"\n",
|
||||||
|
" feature = video_features(video_path)\n",
|
||||||
|
" # print(\"Video feature shape (for copyright):\", feature.shape)\n",
|
||||||
|
" return feature"
|
||||||
|
],
|
||||||
|
"id": "5c3f6ede68d0f22f",
|
||||||
|
"outputs": [],
|
||||||
|
"execution_count": 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"metadata": {
|
||||||
|
"ExecuteTime": {
|
||||||
|
"end_time": "2025-04-14T03:58:09.206798Z",
|
||||||
|
"start_time": "2025-04-14T03:58:09.166673Z"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"cell_type": "code",
|
||||||
|
"source": [
|
||||||
|
"import sqlite3\n",
|
||||||
|
"import io\n",
|
||||||
|
"import os\n",
|
||||||
|
"import tqdm\n",
|
||||||
|
"\n",
|
||||||
|
"# 注册适配器与转换器:numpy数组 <-> BLOB\n",
|
||||||
|
"def adapt_array(arr):\n",
|
||||||
|
" out = io.BytesIO()\n",
|
||||||
|
" np.save(out, arr)\n",
|
||||||
|
" out.seek(0)\n",
|
||||||
|
" return sqlite3.Binary(out.read())\n",
|
||||||
|
"\n",
|
||||||
|
"def convert_array(text):\n",
|
||||||
|
" out = io.BytesIO(text)\n",
|
||||||
|
" out.seek(0)\n",
|
||||||
|
" return np.load(out)\n",
|
||||||
|
"\n",
|
||||||
|
"# 注册自定义类型处理\n",
|
||||||
|
"sqlite3.register_adapter(np.ndarray, adapt_array)\n",
|
||||||
|
"sqlite3.register_converter(\"array\", convert_array)\n",
|
||||||
|
"\n",
|
||||||
|
"# 创建数据库连接(带类型检测)\n",
|
||||||
|
"conn = sqlite3.connect(\"i3d.db\", detect_types=sqlite3.PARSE_DECLTYPES)\n",
|
||||||
|
"cursor = conn.cursor()\n",
|
||||||
|
"\n",
|
||||||
|
"# 创建表\n",
|
||||||
|
"cursor.execute(\"\"\"\n",
|
||||||
|
"CREATE TABLE IF NOT EXISTS data (\n",
|
||||||
|
" id INTEGER PRIMARY KEY,\n",
|
||||||
|
" array BLOB,\n",
|
||||||
|
" group_path TEXT,\n",
|
||||||
|
" full_path TEXT\n",
|
||||||
|
")\n",
|
||||||
|
"\"\"\")\n",
|
||||||
|
"\n",
|
||||||
|
"\n",
|
||||||
|
"def add_to_db(array_to_store,group_path,full_path):\n",
|
||||||
|
" cursor.execute(\"INSERT INTO data (array,group_path,full_path) VALUES (?,?,?)\", (array_to_store,group_path,full_path,))\n",
|
||||||
|
" conn.commit()\n",
|
||||||
|
"\n",
|
||||||
|
"# # 读取数组\n",
|
||||||
|
"# cursor.execute(\"SELECT array FROM data WHERE id=1\")\n",
|
||||||
|
"# fetched_array = cursor.fetchone()[0]\n",
|
||||||
|
"#\n",
|
||||||
|
"# print(\"原始数组:\\n\", array_to_store)\n",
|
||||||
|
"# print(\"读取的数组:\\n\", fetched_array)\n",
|
||||||
|
"\n",
|
||||||
|
"folder_path = r\"D:\\DESKTOP\\2025\\44\\a1\\dataset\"\n",
|
||||||
|
"\n",
|
||||||
|
"all_files = []\n",
|
||||||
|
"names = [str(x)+\".mp4\" for x in range(10)]\n",
|
||||||
|
"print(names)\n",
|
||||||
|
"\n",
|
||||||
|
"\n",
|
||||||
|
"# 遍历文件夹\n",
|
||||||
|
"for group_path in os.listdir(folder_path):\n",
|
||||||
|
" full_path = os.path.join(folder_path, group_path)\n",
|
||||||
|
" if os.path.isdir(full_path):\n",
|
||||||
|
" # 遍历子文件夹\n",
|
||||||
|
" for video_path in os.listdir(full_path):\n",
|
||||||
|
" if os.path.basename(video_path) in names:\n",
|
||||||
|
" video_full_path = os.path.join(full_path, video_path)\n",
|
||||||
|
" if os.path.isfile(video_full_path):\n",
|
||||||
|
" # 处理视频文件\n",
|
||||||
|
" all_files.append((group_path,video_full_path))\n",
|
||||||
|
"print(len(all_files))\n"
|
||||||
|
],
|
||||||
|
"id": "517f4d3e7e8d4402",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "stdout",
|
||||||
|
"output_type": "stream",
|
||||||
|
"text": [
|
||||||
|
"['0.mp4', '1.mp4', '2.mp4', '3.mp4', '4.mp4', '5.mp4', '6.mp4', '7.mp4', '8.mp4', '9.mp4']\n",
|
||||||
|
"70\n"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"execution_count": 11
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"metadata": {
|
||||||
|
"ExecuteTime": {
|
||||||
|
"end_time": "2025-04-14T03:59:48.339352Z",
|
||||||
|
"start_time": "2025-04-14T03:58:09.217915Z"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"cell_type": "code",
|
||||||
|
"source": [
|
||||||
|
"for group_path, video_full_path in tqdm.tqdm(all_files):\n",
|
||||||
|
" # 读取视频特征\n",
|
||||||
|
" feature = getFeature(video_full_path)\n",
|
||||||
|
" # 将特征存储到数据库\n",
|
||||||
|
" add_to_db(feature,group_path,video_full_path)\n",
|
||||||
|
" # print(f\"已处理并存储: {video_full_path}\")\n",
|
||||||
|
"\n",
|
||||||
|
"conn.close()\n"
|
||||||
|
],
|
||||||
|
"id": "aa7bdb735dbc1e1e",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "stderr",
|
||||||
|
"output_type": "stream",
|
||||||
|
"text": [
|
||||||
|
"100%|██████████| 70/70 [01:39<00:00, 1.42s/it]\n"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"execution_count": 12
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"metadata": {
|
||||||
|
"kernelspec": {
|
||||||
|
"display_name": "Python 3",
|
||||||
|
"language": "python",
|
||||||
|
"name": "python3"
|
||||||
|
},
|
||||||
|
"language_info": {
|
||||||
|
"codemirror_mode": {
|
||||||
|
"name": "ipython",
|
||||||
|
"version": 2
|
||||||
|
},
|
||||||
|
"file_extension": ".py",
|
||||||
|
"mimetype": "text/x-python",
|
||||||
|
"name": "python",
|
||||||
|
"nbconvert_exporter": "python",
|
||||||
|
"pygments_lexer": "ipython2",
|
||||||
|
"version": "2.7.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nbformat": 4,
|
||||||
|
"nbformat_minor": 5
|
||||||
|
}
|
||||||
BIN
requirements.txt
Normal file
BIN
requirements.txt
Normal file
Binary file not shown.
357
slowFast.ipynb
Normal file
357
slowFast.ipynb
Normal file
@@ -0,0 +1,357 @@
|
|||||||
|
{
|
||||||
|
"cells": [
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"id": "initial_id",
|
||||||
|
"metadata": {
|
||||||
|
"collapsed": true,
|
||||||
|
"ExecuteTime": {
|
||||||
|
"end_time": "2025-04-14T03:41:10.176744Z",
|
||||||
|
"start_time": "2025-04-14T03:41:08.344955Z"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"source": [
|
||||||
|
"import torch\n",
|
||||||
|
"import numpy as np\n",
|
||||||
|
"import cv2\n",
|
||||||
|
"from decord import VideoReader, cpu"
|
||||||
|
],
|
||||||
|
"outputs": [],
|
||||||
|
"execution_count": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"metadata": {
|
||||||
|
"ExecuteTime": {
|
||||||
|
"end_time": "2025-04-14T03:41:10.726870Z",
|
||||||
|
"start_time": "2025-04-14T03:41:10.181751Z"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"cell_type": "code",
|
||||||
|
"source": [
|
||||||
|
"print(torch.__version__)\n",
|
||||||
|
"print(torch.cuda.is_available())"
|
||||||
|
],
|
||||||
|
"id": "31d50e0f9e4ea204",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "stdout",
|
||||||
|
"output_type": "stream",
|
||||||
|
"text": [
|
||||||
|
"2.6.0+cu124\n",
|
||||||
|
"True\n"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"execution_count": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"metadata": {
|
||||||
|
"ExecuteTime": {
|
||||||
|
"end_time": "2025-04-14T03:41:10.875039Z",
|
||||||
|
"start_time": "2025-04-14T03:41:10.871492Z"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"cell_type": "code",
|
||||||
|
"source": [
|
||||||
|
"def load_first_480_frames(video_path, resize=(224, 224)):\n",
|
||||||
|
" vr = VideoReader(video_path, ctx=cpu(0))\n",
|
||||||
|
" total_frames = len(vr)\n",
|
||||||
|
"\n",
|
||||||
|
" if total_frames < 480:\n",
|
||||||
|
" raise ValueError(f\"{video_path},视频帧数不足 480 帧\")\n",
|
||||||
|
"\n",
|
||||||
|
" indices = list(range(480))\n",
|
||||||
|
" frames = vr.get_batch(indices).asnumpy()\n",
|
||||||
|
"\n",
|
||||||
|
" if resize:\n",
|
||||||
|
" frames = np.array([cv2.resize(f, resize) for f in frames])\n",
|
||||||
|
" return frames"
|
||||||
|
],
|
||||||
|
"id": "e351cfd29d48331a",
|
||||||
|
"outputs": [],
|
||||||
|
"execution_count": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"metadata": {
|
||||||
|
"ExecuteTime": {
|
||||||
|
"end_time": "2025-04-14T03:41:10.884466Z",
|
||||||
|
"start_time": "2025-04-14T03:41:10.880516Z"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"cell_type": "code",
|
||||||
|
"source": [
|
||||||
|
"def preprocess_for_slowfast(frames, num_frames=32, alpha=4):\n",
|
||||||
|
" total = len(frames)\n",
|
||||||
|
" indices = np.linspace(0, total - 1, num=num_frames, dtype=int)\n",
|
||||||
|
" frames = frames[indices]\n",
|
||||||
|
"\n",
|
||||||
|
" frames = frames / 255.0\n",
|
||||||
|
" frames = (frames - [0.45, 0.45, 0.45]) / [0.225, 0.225, 0.225]\n",
|
||||||
|
" frames = frames.astype(np.float32)\n",
|
||||||
|
"\n",
|
||||||
|
" frames = torch.from_numpy(frames).permute(3, 0, 1, 2).unsqueeze(0)\n",
|
||||||
|
"\n",
|
||||||
|
" fast_pathway = frames\n",
|
||||||
|
" slow_pathway = frames[:, :, ::alpha, :, :]\n",
|
||||||
|
"\n",
|
||||||
|
" return [slow_pathway, fast_pathway]"
|
||||||
|
],
|
||||||
|
"id": "f8784f81a946176",
|
||||||
|
"outputs": [],
|
||||||
|
"execution_count": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"metadata": {
|
||||||
|
"ExecuteTime": {
|
||||||
|
"end_time": "2025-04-14T03:41:10.893723Z",
|
||||||
|
"start_time": "2025-04-14T03:41:10.890080Z"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"cell_type": "code",
|
||||||
|
"source": [
|
||||||
|
"# 定义特征提取模型 (SlowFast Backbone)\n",
|
||||||
|
"class SlowFastFeatureExtractor(torch.nn.Module):\n",
|
||||||
|
" def __init__(self):\n",
|
||||||
|
" super().__init__()\n",
|
||||||
|
" model = torch.hub.load(\"facebookresearch/pytorchvideo\", \"slowfast_r50\", pretrained=True)\n",
|
||||||
|
" # 移除分类头,仅保留backbone部分\n",
|
||||||
|
" self.blocks = model.blocks[:-1] # 去掉最后的分类器 head\n",
|
||||||
|
" self.pool = torch.nn.AdaptiveAvgPool3d(1) # 全局池化\n",
|
||||||
|
"\n",
|
||||||
|
" def forward(self, x):\n",
|
||||||
|
" for block in self.blocks:\n",
|
||||||
|
" x = block(x)\n",
|
||||||
|
" x = self.pool(x)\n",
|
||||||
|
" x = torch.flatten(x, 1) # [B, C]\n",
|
||||||
|
" x = torch.nn.functional.normalize(x, dim=1) # 特征归一化\n",
|
||||||
|
" return x"
|
||||||
|
],
|
||||||
|
"id": "6c52b60b3399c5b7",
|
||||||
|
"outputs": [],
|
||||||
|
"execution_count": 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"metadata": {
|
||||||
|
"ExecuteTime": {
|
||||||
|
"end_time": "2025-04-14T03:41:13.527271Z",
|
||||||
|
"start_time": "2025-04-14T03:41:10.899167Z"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"cell_type": "code",
|
||||||
|
"source": [
|
||||||
|
"\n",
|
||||||
|
"device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n",
|
||||||
|
"print(\"Loading SlowFast backbone for feature extraction...\")\n",
|
||||||
|
"model = SlowFastFeatureExtractor().to(device).eval()\n",
|
||||||
|
"\n",
|
||||||
|
"\n",
|
||||||
|
"def extract_video_feature(video_path):\n",
|
||||||
|
"\n",
|
||||||
|
"\n",
|
||||||
|
" frames = load_first_480_frames(video_path)\n",
|
||||||
|
" inputs = preprocess_for_slowfast(frames, num_frames=32, alpha=4)\n",
|
||||||
|
"\n",
|
||||||
|
" with torch.no_grad():\n",
|
||||||
|
" inputs = [x.to(device) for x in inputs]\n",
|
||||||
|
" features = model(inputs)\n",
|
||||||
|
"\n",
|
||||||
|
" features = features.cpu().numpy().squeeze()\n",
|
||||||
|
" return features"
|
||||||
|
],
|
||||||
|
"id": "d841190cdd5ee920",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "stdout",
|
||||||
|
"output_type": "stream",
|
||||||
|
"text": [
|
||||||
|
"Loading SlowFast backbone for feature extraction...\n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "stderr",
|
||||||
|
"output_type": "stream",
|
||||||
|
"text": [
|
||||||
|
"Using cache found in C:\\Users\\zikai/.cache\\torch\\hub\\facebookresearch_pytorchvideo_main\n"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"execution_count": 6
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"metadata": {
|
||||||
|
"ExecuteTime": {
|
||||||
|
"end_time": "2025-04-14T03:41:13.545015Z",
|
||||||
|
"start_time": "2025-04-14T03:41:13.541939Z"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"cell_type": "code",
|
||||||
|
"source": [
|
||||||
|
"def getFeature(video_path = r\"D:\\DESKTOP\\2025\\44\\a1\\dataset\\org\\1.mp4\"):\n",
|
||||||
|
"\n",
|
||||||
|
" feature = extract_video_feature(video_path)\n",
|
||||||
|
" # print(\"Video feature shape (for copyright):\", feature.shape)\n",
|
||||||
|
" return feature"
|
||||||
|
],
|
||||||
|
"id": "dce706080dfba5b6",
|
||||||
|
"outputs": [],
|
||||||
|
"execution_count": 7
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"metadata": {
|
||||||
|
"ExecuteTime": {
|
||||||
|
"end_time": "2025-04-14T03:41:13.607891Z",
|
||||||
|
"start_time": "2025-04-14T03:41:13.554129Z"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"cell_type": "code",
|
||||||
|
"source": [
|
||||||
|
"import sqlite3\n",
|
||||||
|
"import io\n",
|
||||||
|
"import os\n",
|
||||||
|
"import tqdm\n",
|
||||||
|
"\n",
|
||||||
|
"# 注册适配器与转换器:numpy数组 <-> BLOB\n",
|
||||||
|
"def adapt_array(arr):\n",
|
||||||
|
" out = io.BytesIO()\n",
|
||||||
|
" np.save(out, arr)\n",
|
||||||
|
" out.seek(0)\n",
|
||||||
|
" return sqlite3.Binary(out.read())\n",
|
||||||
|
"\n",
|
||||||
|
"def convert_array(text):\n",
|
||||||
|
" out = io.BytesIO(text)\n",
|
||||||
|
" out.seek(0)\n",
|
||||||
|
" return np.load(out)\n",
|
||||||
|
"\n",
|
||||||
|
"# 注册自定义类型处理\n",
|
||||||
|
"sqlite3.register_adapter(np.ndarray, adapt_array)\n",
|
||||||
|
"sqlite3.register_converter(\"array\", convert_array)\n",
|
||||||
|
"\n",
|
||||||
|
"# 创建数据库连接(带类型检测)\n",
|
||||||
|
"conn = sqlite3.connect(\"slowfast.db\", detect_types=sqlite3.PARSE_DECLTYPES)\n",
|
||||||
|
"cursor = conn.cursor()\n",
|
||||||
|
"\n",
|
||||||
|
"# 创建表\n",
|
||||||
|
"cursor.execute(\"\"\"\n",
|
||||||
|
"CREATE TABLE IF NOT EXISTS data (\n",
|
||||||
|
" id INTEGER PRIMARY KEY,\n",
|
||||||
|
" array BLOB,\n",
|
||||||
|
" group_path TEXT,\n",
|
||||||
|
" full_path TEXT\n",
|
||||||
|
")\n",
|
||||||
|
"\"\"\")\n",
|
||||||
|
"\n",
|
||||||
|
"\n",
|
||||||
|
"def add_to_db(array_to_store,group_path,full_path):\n",
|
||||||
|
" cursor.execute(\"INSERT INTO data (array,group_path,full_path) VALUES (?,?,?)\", (array_to_store,group_path,full_path,))\n",
|
||||||
|
" conn.commit()\n",
|
||||||
|
"\n",
|
||||||
|
"# # 读取数组\n",
|
||||||
|
"# cursor.execute(\"SELECT array FROM data WHERE id=1\")\n",
|
||||||
|
"# fetched_array = cursor.fetchone()[0]\n",
|
||||||
|
"#\n",
|
||||||
|
"# print(\"原始数组:\\n\", array_to_store)\n",
|
||||||
|
"# print(\"读取的数组:\\n\", fetched_array)\n",
|
||||||
|
"\n",
|
||||||
|
"folder_path = r\"D:\\DESKTOP\\2025\\44\\a1\\dataset\"\n",
|
||||||
|
"\n",
|
||||||
|
"all_files = []\n",
|
||||||
|
"names = [str(x)+\".mp4\" for x in range(10)]\n",
|
||||||
|
"print(names)\n",
|
||||||
|
"\n",
|
||||||
|
"\n",
|
||||||
|
"# 遍历文件夹\n",
|
||||||
|
"for group_path in os.listdir(folder_path):\n",
|
||||||
|
" full_path = os.path.join(folder_path, group_path)\n",
|
||||||
|
" if os.path.isdir(full_path):\n",
|
||||||
|
" # 遍历子文件夹\n",
|
||||||
|
" for video_path in os.listdir(full_path):\n",
|
||||||
|
" if os.path.basename(video_path) in names:\n",
|
||||||
|
" video_full_path = os.path.join(full_path, video_path)\n",
|
||||||
|
" if os.path.isfile(video_full_path):\n",
|
||||||
|
" # 处理视频文件\n",
|
||||||
|
" all_files.append((group_path,video_full_path))\n",
|
||||||
|
"print(len(all_files))\n"
|
||||||
|
],
|
||||||
|
"id": "dcf5af026d672b41",
|
||||||
|
"outputs": [],
|
||||||
|
"execution_count": 8
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"metadata": {
|
||||||
|
"ExecuteTime": {
|
||||||
|
"end_time": "2025-04-14T03:42:00.157934Z",
|
||||||
|
"start_time": "2025-04-14T03:41:13.633220Z"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"cell_type": "code",
|
||||||
|
"source": [
|
||||||
|
"for group_path, video_full_path in tqdm.tqdm(all_files):\n",
|
||||||
|
" # 读取视频特征\n",
|
||||||
|
" feature = getFeature(video_full_path)\n",
|
||||||
|
" # 将特征存储到数据库\n",
|
||||||
|
" add_to_db(feature,group_path,video_full_path)\n",
|
||||||
|
" # print(f\"已处理并存储: {video_full_path}\")\n",
|
||||||
|
"\n",
|
||||||
|
"conn.close()\n"
|
||||||
|
],
|
||||||
|
"id": "63eed21338e8f26c",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "stderr",
|
||||||
|
"output_type": "stream",
|
||||||
|
"text": [
|
||||||
|
"100%|██████████| 70/70 [00:46<00:00, 1.50it/s]\n"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"execution_count": 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"metadata": {
|
||||||
|
"ExecuteTime": {
|
||||||
|
"end_time": "2025-04-14T03:42:00.170765Z",
|
||||||
|
"start_time": "2025-04-14T03:42:00.167606Z"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"cell_type": "code",
|
||||||
|
"source": "",
|
||||||
|
"id": "d8a84ff72bc12b33",
|
||||||
|
"outputs": [],
|
||||||
|
"execution_count": 11
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"metadata": {
|
||||||
|
"ExecuteTime": {
|
||||||
|
"end_time": "2025-04-14T03:42:00.184252Z",
|
||||||
|
"start_time": "2025-04-14T03:42:00.181880Z"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"cell_type": "code",
|
||||||
|
"source": "",
|
||||||
|
"id": "7343d8b3fcea327c",
|
||||||
|
"outputs": [],
|
||||||
|
"execution_count": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"metadata": {
|
||||||
|
"kernelspec": {
|
||||||
|
"display_name": "Python 3",
|
||||||
|
"language": "python",
|
||||||
|
"name": "python3"
|
||||||
|
},
|
||||||
|
"language_info": {
|
||||||
|
"codemirror_mode": {
|
||||||
|
"name": "ipython",
|
||||||
|
"version": 2
|
||||||
|
},
|
||||||
|
"file_extension": ".py",
|
||||||
|
"mimetype": "text/x-python",
|
||||||
|
"name": "python",
|
||||||
|
"nbconvert_exporter": "python",
|
||||||
|
"pygments_lexer": "ipython2",
|
||||||
|
"version": "2.7.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nbformat": 4,
|
||||||
|
"nbformat_minor": 5
|
||||||
|
}
|
||||||
159
slowFast.py
Normal file
159
slowFast.py
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
#%%
|
||||||
|
import torch
|
||||||
|
import numpy as np
|
||||||
|
import cv2
|
||||||
|
from decord import VideoReader, cpu
|
||||||
|
#%%
|
||||||
|
print(torch.__version__)
|
||||||
|
print(torch.cuda.is_available())
|
||||||
|
#%%
|
||||||
|
def load_first_480_frames(video_path, resize=(224, 224)):
|
||||||
|
vr = VideoReader(video_path, ctx=cpu(0))
|
||||||
|
total_frames = len(vr)
|
||||||
|
|
||||||
|
if total_frames < 480:
|
||||||
|
raise ValueError(f"{video_path},视频帧数不足 480 帧")
|
||||||
|
|
||||||
|
indices = list(range(480))
|
||||||
|
frames = vr.get_batch(indices).asnumpy()
|
||||||
|
|
||||||
|
if resize:
|
||||||
|
frames = np.array([cv2.resize(f, resize) for f in frames])
|
||||||
|
return frames
|
||||||
|
#%%
|
||||||
|
def preprocess_for_slowfast(frames, num_frames=32, alpha=4):
|
||||||
|
total = len(frames)
|
||||||
|
indices = np.linspace(0, total - 1, num=num_frames, dtype=int)
|
||||||
|
frames = frames[indices]
|
||||||
|
|
||||||
|
frames = frames / 255.0
|
||||||
|
frames = (frames - [0.45, 0.45, 0.45]) / [0.225, 0.225, 0.225]
|
||||||
|
frames = frames.astype(np.float32)
|
||||||
|
|
||||||
|
frames = torch.from_numpy(frames).permute(3, 0, 1, 2).unsqueeze(0)
|
||||||
|
|
||||||
|
fast_pathway = frames
|
||||||
|
slow_pathway = frames[:, :, ::alpha, :, :]
|
||||||
|
|
||||||
|
return [slow_pathway, fast_pathway]
|
||||||
|
#%%
|
||||||
|
# 定义特征提取模型 (SlowFast Backbone)
|
||||||
|
class SlowFastFeatureExtractor(torch.nn.Module):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
model = torch.hub.load("facebookresearch/pytorchvideo", "slowfast_r50", pretrained=True)
|
||||||
|
# 移除分类头,仅保留backbone部分
|
||||||
|
self.blocks = model.blocks[:-1] # 去掉最后的分类器 head
|
||||||
|
self.pool = torch.nn.AdaptiveAvgPool3d(1) # 全局池化
|
||||||
|
|
||||||
|
def forward(self, x):
|
||||||
|
for block in self.blocks:
|
||||||
|
x = block(x)
|
||||||
|
x = self.pool(x)
|
||||||
|
x = torch.flatten(x, 1) # [B, C]
|
||||||
|
x = torch.nn.functional.normalize(x, dim=1) # 特征归一化
|
||||||
|
return x
|
||||||
|
#%%
|
||||||
|
|
||||||
|
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
|
||||||
|
print("Loading SlowFast backbone for feature extraction...")
|
||||||
|
model = SlowFastFeatureExtractor().to(device).eval()
|
||||||
|
|
||||||
|
|
||||||
|
def extract_video_feature(video_path):
|
||||||
|
|
||||||
|
|
||||||
|
frames = load_first_480_frames(video_path)
|
||||||
|
inputs = preprocess_for_slowfast(frames, num_frames=32, alpha=4)
|
||||||
|
|
||||||
|
with torch.no_grad():
|
||||||
|
inputs = [x.to(device) for x in inputs]
|
||||||
|
features = model(inputs)
|
||||||
|
|
||||||
|
features = features.cpu().numpy().squeeze()
|
||||||
|
return features
|
||||||
|
#%%
|
||||||
|
def getFeature(video_path = r"D:\DESKTOP\2025\44\a1\dataset\org\1.mp4"):
|
||||||
|
|
||||||
|
feature = extract_video_feature(video_path)
|
||||||
|
# print("Video feature shape (for copyright):", feature.shape)
|
||||||
|
return feature
|
||||||
|
#%%
|
||||||
|
import sqlite3
|
||||||
|
import io
|
||||||
|
import os
|
||||||
|
import tqdm
|
||||||
|
|
||||||
|
# 注册适配器与转换器:numpy数组 <-> BLOB
|
||||||
|
def adapt_array(arr):
|
||||||
|
out = io.BytesIO()
|
||||||
|
np.save(out, arr)
|
||||||
|
out.seek(0)
|
||||||
|
return sqlite3.Binary(out.read())
|
||||||
|
|
||||||
|
def convert_array(text):
|
||||||
|
out = io.BytesIO(text)
|
||||||
|
out.seek(0)
|
||||||
|
return np.load(out)
|
||||||
|
|
||||||
|
# 注册自定义类型处理
|
||||||
|
sqlite3.register_adapter(np.ndarray, adapt_array)
|
||||||
|
sqlite3.register_converter("array", convert_array)
|
||||||
|
|
||||||
|
# 创建数据库连接(带类型检测)
|
||||||
|
conn = sqlite3.connect("slowfast.db", detect_types=sqlite3.PARSE_DECLTYPES)
|
||||||
|
cursor = conn.cursor()
|
||||||
|
|
||||||
|
# 创建表
|
||||||
|
cursor.execute("""
|
||||||
|
CREATE TABLE IF NOT EXISTS data (
|
||||||
|
id INTEGER PRIMARY KEY,
|
||||||
|
array BLOB,
|
||||||
|
group_path TEXT,
|
||||||
|
full_path TEXT
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
|
|
||||||
|
def add_to_db(array_to_store,group_path,full_path):
|
||||||
|
cursor.execute("INSERT INTO data (array,group_path,full_path) VALUES (?,?,?)", (array_to_store,group_path,full_path,))
|
||||||
|
conn.commit()
|
||||||
|
|
||||||
|
# # 读取数组
|
||||||
|
# cursor.execute("SELECT array FROM data WHERE id=1")
|
||||||
|
# fetched_array = cursor.fetchone()[0]
|
||||||
|
#
|
||||||
|
# print("原始数组:\n", array_to_store)
|
||||||
|
# print("读取的数组:\n", fetched_array)
|
||||||
|
|
||||||
|
|
||||||
|
#%%
|
||||||
|
folder_path = r"D:\DESKTOP\2025\44\a1\dataset"
|
||||||
|
|
||||||
|
all_files = []
|
||||||
|
names = [str(x)+".mp4" for x in range(10)]
|
||||||
|
print(names)
|
||||||
|
|
||||||
|
|
||||||
|
# 遍历文件夹
|
||||||
|
for group_path in os.listdir(folder_path):
|
||||||
|
full_path = os.path.join(folder_path, group_path)
|
||||||
|
if os.path.isdir(full_path):
|
||||||
|
# 遍历子文件夹
|
||||||
|
for video_path in os.listdir(full_path):
|
||||||
|
if os.path.basename(video_path) in names:
|
||||||
|
video_full_path = os.path.join(full_path, video_path)
|
||||||
|
if os.path.isfile(video_full_path):
|
||||||
|
# 处理视频文件
|
||||||
|
all_files.append((group_path,video_full_path))
|
||||||
|
print(len(all_files))
|
||||||
|
#%%
|
||||||
|
for group_path, video_full_path in tqdm.tqdm(all_files):
|
||||||
|
# 读取视频特征
|
||||||
|
feature = getFeature(video_full_path)
|
||||||
|
# 将特征存储到数据库
|
||||||
|
add_to_db(feature,group_path,video_full_path)
|
||||||
|
# print(f"已处理并存储: {video_full_path}")
|
||||||
|
#%%
|
||||||
|
conn.close()
|
||||||
|
#%%
|
||||||
BIN
slowfast.db
Normal file
BIN
slowfast.db
Normal file
Binary file not shown.
Reference in New Issue
Block a user