蚕茧视频识别AI程序关键代码(不包含资源、模型、转换库)
This commit is contained in:
@@ -0,0 +1 @@
|
||||
LOCAL_IP = "10.10.12.101"
|
||||
@@ -0,0 +1,78 @@
|
||||
from utils.pgDb import pg_pool
|
||||
import json
|
||||
|
||||
def insert_sca_video(
|
||||
name,
|
||||
raw_object_name,
|
||||
ai_object_name,
|
||||
duration,
|
||||
size,
|
||||
video_codec,
|
||||
audio_codec,
|
||||
overall_bit_rate,
|
||||
resolution,
|
||||
sc_analysis_time,
|
||||
sc_analysis_total_count,
|
||||
sc_analysis_max_count,
|
||||
sc_analysis_primary_type,
|
||||
sc_analysis_secondary_type,
|
||||
other_info,
|
||||
):
|
||||
with pg_pool.getConn() as conn:
|
||||
with conn.cursor() as cursor:
|
||||
other_info = json.dumps(other_info, ensure_ascii=False)
|
||||
cursor.execute(
|
||||
"""
|
||||
INSERT INTO sca_videos (
|
||||
name, raw_object_name, ai_object_name, duration, size, video_codec, audio_codec,
|
||||
overall_bit_rate, resolution, sc_analysis_time, sc_analysis_total_count, sc_analysis_max_count,
|
||||
sc_analysis_primary_type, sc_analysis_secondary_type, other_info, created_at
|
||||
)
|
||||
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, NOW())
|
||||
RETURNING id
|
||||
""",
|
||||
(
|
||||
name,
|
||||
raw_object_name,
|
||||
ai_object_name,
|
||||
duration,
|
||||
size,
|
||||
video_codec,
|
||||
audio_codec,
|
||||
overall_bit_rate,
|
||||
resolution,
|
||||
sc_analysis_time,
|
||||
sc_analysis_total_count,
|
||||
sc_analysis_max_count,
|
||||
sc_analysis_primary_type,
|
||||
sc_analysis_secondary_type,
|
||||
other_info,
|
||||
),
|
||||
)
|
||||
|
||||
new_id = cursor.fetchone()[0]
|
||||
conn.commit()
|
||||
return new_id
|
||||
|
||||
def insert_sca_video_details(
|
||||
v_id,
|
||||
time_stamp,
|
||||
other_info,
|
||||
):
|
||||
with pg_pool.getConn() as conn:
|
||||
with conn.cursor() as cursor:
|
||||
other_info = json.dumps(other_info, ensure_ascii=False)
|
||||
cursor.execute(
|
||||
"""
|
||||
INSERT INTO sca_video_details (
|
||||
v_id, time_stamp, other_info
|
||||
)
|
||||
VALUES (%s, %s, %s)
|
||||
""",
|
||||
(
|
||||
v_id,
|
||||
time_stamp,
|
||||
other_info,
|
||||
),
|
||||
)
|
||||
conn.commit()
|
||||
@@ -0,0 +1,97 @@
|
||||
|
||||
from pymediainfo import MediaInfo
|
||||
from datetime import datetime
|
||||
import json
|
||||
from utils.db import insert_sca_video,insert_sca_video_details
|
||||
from collections import Counter
|
||||
|
||||
def getVideoResolution(file_path):
|
||||
media_info = MediaInfo.parse(file_path) # 解析视频文件
|
||||
|
||||
for track in media_info.tracks:
|
||||
if track.track_type == 'Video':
|
||||
return track.width,track.height
|
||||
|
||||
def get_type_name_by_id(id):
|
||||
type_dict = {
|
||||
0: "正茧",
|
||||
1: "双宫茧",
|
||||
2: "黄斑茧",
|
||||
3: "毛茧",
|
||||
4: "蛆壳茧",
|
||||
}
|
||||
return type_dict.get(id, "未知类型")
|
||||
|
||||
# 将视频信息保存至数据库
|
||||
def save_sca_results(file_path, out_put_file_name,tracker_dict,
|
||||
analysis_time,statics =[]):
|
||||
media_info = MediaInfo.parse(file_path) # 解析视频文件
|
||||
video_data = {} # 用于存储视频信息
|
||||
|
||||
for track in media_info.tracks:
|
||||
if track.track_type == 'General':
|
||||
video_data.update({
|
||||
"v_file_name": track.file_name_extension,
|
||||
"v_duration": round(track.duration / 1000),
|
||||
"v_size": round(track.file_size/1024,2),
|
||||
"v_video_codec": track.video_format_list,
|
||||
"v_audio_codec": track.audio_codecs,
|
||||
"v_overall_bit_rate": track.overall_bit_rate,
|
||||
})
|
||||
if track.track_type == 'Video':
|
||||
video_data.update({
|
||||
"v_resolution": f"{track.width}x{track.height}"
|
||||
})
|
||||
|
||||
# 分析 得出数量最多的种类 以及 出现次多的种类
|
||||
counter = Counter(tracker_dict.values()) # 统计所有 value 的出现次数
|
||||
most_common = counter.most_common(2) # 取出现次数前两名(返回列表)
|
||||
primary_type = get_type_name_by_id(most_common[0][0]) if most_common else ""
|
||||
secondary_type = get_type_name_by_id(most_common[1][0]) if len(most_common) > 1 else ""
|
||||
|
||||
# 1️⃣ 统计 { value: count }
|
||||
count_map = {}
|
||||
for k, v in tracker_dict.items():
|
||||
v_int = int(v)
|
||||
count_map[v_int] = count_map.get(v_int, 0) + 1
|
||||
|
||||
# 2️⃣ 替换成类型名称
|
||||
result = {}
|
||||
for type_value, count in count_map.items():
|
||||
type_name = get_type_name_by_id(type_value)
|
||||
result[type_name] = count
|
||||
|
||||
other_info = result
|
||||
|
||||
# 分析结果进行统计 得出 单帧最大蚕茧数量
|
||||
max_count_in_same_frame = 0
|
||||
for timestamp_in_video,json in statics.items():
|
||||
count_in_frame = sum(json.values())
|
||||
if count_in_frame > max_count_in_same_frame:
|
||||
max_count_in_same_frame = count_in_frame
|
||||
|
||||
# 保存至数据库
|
||||
video_id = insert_sca_video(
|
||||
# 取后八位
|
||||
name=out_put_file_name.split('/')[-1].split('.')[0].replace('-','')[-8:],
|
||||
raw_object_name=video_data.get("v_file_name", "").split('/')[-1],
|
||||
ai_object_name=out_put_file_name.split('/')[-1],
|
||||
duration=video_data.get("v_duration", 0),
|
||||
size=video_data.get("v_size", 0),
|
||||
video_codec=video_data.get("v_video_codec", ""),
|
||||
audio_codec=video_data.get("v_audio_codec", ""),
|
||||
overall_bit_rate=video_data.get("v_overall_bit_rate", 0),
|
||||
resolution=video_data.get("v_resolution", ""),
|
||||
sc_analysis_time= analysis_time,
|
||||
sc_analysis_total_count=len(tracker_dict),
|
||||
sc_analysis_max_count=max_count_in_same_frame,
|
||||
sc_analysis_primary_type= primary_type,
|
||||
sc_analysis_secondary_type= secondary_type,
|
||||
other_info= other_info,
|
||||
)
|
||||
|
||||
# 将细则存入数据库
|
||||
counter = Counter()
|
||||
|
||||
for timestamp_in_video, json in statics.items():
|
||||
insert_sca_video_details(video_id,timestamp_in_video, json)
|
||||
@@ -0,0 +1,72 @@
|
||||
import logging
|
||||
import time
|
||||
from contextlib import contextmanager
|
||||
|
||||
import psycopg
|
||||
from psycopg_pool import ConnectionPool
|
||||
from utils.GlobalVariable import LOCAL_IP
|
||||
|
||||
logger = logging.getLogger("PGPool")
|
||||
logger.setLevel(logging.INFO)
|
||||
|
||||
class PGPool:
|
||||
"""
|
||||
PostgreSQL 连接池封装
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
uri: str,
|
||||
min_size: int = 1,
|
||||
max_size: int = 20,
|
||||
max_idle: int = 30,
|
||||
max_lifetime: int = 300,
|
||||
timeout: int = 10,
|
||||
check: bool = False,
|
||||
):
|
||||
"""
|
||||
:param uri: PostgreSQL 连接 URI
|
||||
"""
|
||||
self.uri = uri
|
||||
self.pool = ConnectionPool(
|
||||
self.uri,
|
||||
min_size=min_size,
|
||||
max_size=max_size,
|
||||
max_idle=max_idle,
|
||||
max_lifetime=max_lifetime,
|
||||
timeout=timeout,
|
||||
check=check,
|
||||
)
|
||||
|
||||
@contextmanager
|
||||
def getConn(self, retries: int = 2, delay: float = 1.0):
|
||||
"""
|
||||
获取数据库连接,带重试机制,自动健康检查。
|
||||
使用方式:
|
||||
with pg_pool.get_conn() as conn:
|
||||
with conn.cursor() as cur:
|
||||
cur.execute(...)
|
||||
"""
|
||||
attempt = 0
|
||||
while attempt <= retries:
|
||||
try:
|
||||
with self.pool.connection() as conn:
|
||||
conn.autocommit = True
|
||||
yield conn
|
||||
return
|
||||
except psycopg.OperationalError as e:
|
||||
logger.warning(f"数据库连接异常: {e}. 尝试重试 ({attempt+1}/{retries})")
|
||||
self.pool.check() # 丢掉坏连接,重新建
|
||||
attempt += 1
|
||||
time.sleep(delay)
|
||||
except Exception as e:
|
||||
logger.error(f"SQL执行异常: {e}")
|
||||
raise
|
||||
raise psycopg.OperationalError("无法获取数据库连接,多次重试失败")
|
||||
|
||||
|
||||
pg_pool = PGPool(
|
||||
uri="postgresql://postgres:123456@" + LOCAL_IP + "/ktor2",
|
||||
min_size=1,
|
||||
max_size=20,
|
||||
)
|
||||
@@ -0,0 +1,7 @@
|
||||
from utils.GlobalVariable import LOCAL_IP
|
||||
|
||||
RABBIT_HOST = LOCAL_IP
|
||||
RABBIT_VHOST = "bbit_ai"
|
||||
RABBIT_USER = "ai_lab"
|
||||
RABBIT_PASSWORD = "123456"
|
||||
QUEUE_NAME = "analysis_queue"
|
||||
Reference in New Issue
Block a user