Hướng dẫn thực chiến VideoAgentTrek-ScreenFilter: Phân tích kết quả JSON thành DataFrame Pandas
1. Giới thiệu: Từ kết quả phát hiện đến phân tích dữ liệu
Khi bạn sử dụng VideoAgentTrek-ScreenFilter để phát hiện nội dung màn hình trong hình ảnh hoặc video, bạn sẽ nhận được một kết quả JSON có cấu trúc. Tệp JSON này chứa thông tin chi tiết về tất cả các đối tượng được phát hiện - loại, độ tin cậy, tọa độ vị trí, v.v. Nhưng vấn đề là: đối mặt với hàng chục thậm chí hàng trăm bản ghi phát hiện, làm thế nào để phân tích nhanh các dữ liệu này? Làm thế nào để thống kê tần suất xuất hiện của từng loại? Làm thế nào để lọc các đối tượng có độ tin cậy cao?
Đây chính là vấn đề chúng ta sẽ giải quyết hôm nay: Chuyển đổi kết quả JSON từ VideoAgentTrek-ScreenFilter thành DataFrame Pandas.
Thông qua hướng dẫn này, bạn sẽ học được:
- Cách đọc và phân tích đầu ra JSON của VideoAgentTrek-ScreenFilter
- Cách chuyển đổi dữ liệu JSON thành DataFrame có cấu trúc
- Cách thực hiện phân tích dữ liệu cơ bản và trực quan hóa
- Cách áp dụng kết quả phân tích vào các tình huống kinh doanh thực tế
Dù bạn là nhà phân tích dữ liệu, kỹ sư AI, hay nhân viên kinh doanh cần xử lý lượng lớn kết quả phát hiện, việc nắm vững kỹ năng này sẽ giúp nâng cao hiệu suất công việc của bạn.
2. Chuẩn bị: Môi trường và dữ liệu
2.1 Cài đặt các thư viện Python cần thiết
Trước khi bắt đầu, hãy đảm bảo môi trường Python của bạn đã cài đặt các thư viện sau:
pip install pandas numpy matplotlib seaborn
Nếu bạn chưa cài đặt các thư viện này, bạn có thể thực thi lệnh trên trong terminal hoặc command line. Các thư viện này có chức năng tương ứng:
- pandas: Thư viện cốt lõi cho xử lý và phân tích dữ liệu
- numpy: Thư viện cơ sở cho tính toán số học
- matplotlib: Thư viện trực quan hóa dữ liệu
- seaborn: Thư viện biểu đồ thống kê dựa trên matplotlib, có kiểu dáng đẹp hơn
2.2 Lấy kết quả JSON từ VideoAgentTrek-ScreenFilter
Đầu tiên, bạn cần chạy VideoAgentTrek-ScreenFilter để lấy kết quả phát hiện. Dưới đây là các bước tóm tắt:
- Chế độ phát hiện hình ảnh:
- Tải lên tệp hình ảnh (định dạng JPG/PNG)
- Đặt ngưỡng độ tin cậy (khuyến nghị mặc định 0.25)
- Đặt ngưỡng IOU NMS (khuyến nghị mặc định 0.45)
- Nhấp "Bắt đầu phát hiện hình ảnh"
- Tải xuống tệp JSON kết quả được tạo
- Chế độ phát hiện video:
- Tải lên tệp video (khuyến nghị 10-30 giây cho lần thử đầu tiên)
- Điều chỉnh các tham số ngưỡng (theo nhu cầu thực tế)
- Nhấp "Bắt đầu phát hiện video"
- Tải xuống tệp JSON kết quả được tạo
Cả hai chế độ đều tạo ra một tệp JSON, có cấu trúc tương tự nhưng hơi khác nhau. Chúng ta sẽ xử lý từng trường hợp riêng biệt.
3. Phân tích kết quả JSON phát hiện hình ảnh
3.1 Hiểu cấu trúc JSON phát hiện hình ảnh
Hãy xem một ví dụ JSON phát hiện hình ảnh (để rõ ràng, tôi đã đơn giản hóa):
{
"model_path": "/root/ai-models/xlangai/VideoAgentTrek-ScreenFilter/best.pt",
"type": "image",
"count": 3,
"class_count": {
"screen": 2,
"monitor": 1
},
"boxes": [
{
"frame": 0,
"class_id": 0,
"class_name": "screen",
"confidence": 0.87,
"xyxy": [120, 80, 450, 320]
},
{
"frame": 0,
"class_id": 0,
"class_name": "screen",
"confidence": 0.92,
"xyxy": [500, 150, 800, 400]
},
{
"frame": 0,
"class_id": 1,
"class_name": "monitor",
"confidence": 0.78,
"xyxy": [300, 400, 600, 550]
}
]
}
Giải thích các trường chính:
- type: Loại phát hiện, ở đây là "image"
- count: Tổng số đối tượng được phát hiện
- class_count: Số lượng theo loại
- boxes: Danh sách thông tin chi tiết của hộp phát hiện
3.2 Chuyển đổi JSON thành DataFrame
Bây giờ, hãy dùng mã Python để chuyển đổi tệp JSON này thành DataFrame:
import json
import pandas as pd
def doc_json_hinh_anh_vao_dataframe(duong_dan_json):
"""
Tải tệp JSON phát hiện hình ảnh và chuyển đổi thành DataFrame
Tham số:
duong_dan_json: Đường dẫn đến tệp JSON
Trả về:
DataFrame pandas chứa thông tin chi tiết của tất cả các hộp phát hiện
"""
# 1. Đọc tệp JSON
with open(duong_dan_json, 'r', encoding='utf-8') as f:
du_lieu = json.load(f)
# 2. Trích xuất danh sách boxes
du_lieu_boxes = du_lieu.get('boxes', [])
# 3. Chuyển đổi thành DataFrame
df = pd.DataFrame(du_lieu_boxes)
# 4. Thêm một số cột tính toán hữu ích
if not df.empty:
# Tính chiều rộng và chiều cao của hộp phát hiện
df['chieu_rong'] = df['xyxy'].apply(lambda x: x[2] - x[0])
df['chieu_cao'] = df['xyxy'].apply(lambda x: x[3] - x[1])
# Tính diện tích hộp phát hiện
df['dien_tich'] = df['chieu_rong'] * df['chieu_cao']
# Tính tọa độ trung tâm của hộp phát hiện
df['trung_tam_x'] = df['xyxy'].apply(lambda x: (x[0] + x[2]) / 2)
df['trung_tam_y'] = df['xyxy'].apply(lambda x: (x[1] + x[3]) / 2)
return df, du_lieu
# Ví dụ sử dụng
duong_dan_tep_json = "path/to/your/image_detection_result.json"
df_hinh_anh, thong_tin_phu = doc_json_hinh_anh_vao_dataframe(duong_dan_tep_json)
# Xem vài dòng đầu của DataFrame
print("DataFrame kết quả phát hiện hình ảnh:")
print(df_hinh_anh.head())
print(f"\nTổng số phát hiện: {len(df_hinh_anh)}")
print(f"Loại phát hiện: {df_hinh_anh['class_name'].unique()}")
Sau khi chạy mã này, bạn sẽ nhận được một DataFrame chứa các cột sau:
- frame: Số khung (luôn là 0 trong chế độ hình ảnh)
- class_id: ID loại
- class_name: Tên loại
- confidence: Điểm độ tin cậy
- xyxy: Tọa độ hộp giới hạn [x1, y1, x2, y2]
- chieu_rong: Chiều rộng hộp phát hiện
- chieu_cao: Chiều cao hộp phát hiện
- dien_tich: Diện tích hộp phát hiện
- trung_tam_x: Tọa độ X của trung tâm hộp phát hiện
- trung_tam_y: Tọa độ Y của trung tâm hộp phát hiện
3.3 Phân tích cơ bản kết quả phát hiện hình ảnh
Với DataFrame, chúng ta có thể dễ dàng thực hiện các phân tích khác nhau:
def phan_tich_ket_qua_hinh_anh(df):
"""
Phân tích kết quả phát hiện hình ảnh
Tham số:
df: DataFrame chứa kết quả phát hiện
"""
print("=== Phân tích kết quả phát hiện hình ảnh ===")
# 1. Thống kê theo loại
print("\n1. Thống kê theo loại:")
thong_ke_loai = df['class_name'].value_counts()
print(thong_ke_loai)
# 2. Phân tích độ tin cậy
print("\n2. Phân tích độ tin cậy:")
print(f"Độ tin cậy trung bình: {df['confidence'].mean():.3f}")
print(f"Độ tin cậy cao nhất: {df['confidence'].max():.3f}")
print(f"Độ tin cậy thấp nhất: {df['confidence'].min():.3f}")
# 3. Phân tích kích thước hộp phát hiện
print("\n3. Phân tích kích thước hộp phát hiện:")
print(f"Chiều rộng trung bình: {df['chieu_rong'].mean():.1f} pixel")
print(f"Chiều cao trung bình: {df['chieu_cao'].mean():.1f} pixel")
print(f"Diện tích trung bình: {df['dien_tich'].mean():.1f} pixel²")
# 4. Lọc các đối tượng có độ tin cậy cao
print("\n4. Đối tượng có độ tin cậy cao (>=0.8):")
cao_tin_cay = df[df['confidence'] >= 0.8]
print(f"Số lượng: {len(cao_tin_cay)}")
if not cao_tin_cay.empty:
print(cao_tin_cay[['class_name', 'confidence', 'chieu_rong', 'chieu_cao']])
return {
'thong_ke_loai': thong_ke_loai,
'do_tin_cay_trung_binh': df['confidence'].mean(),
'dien_tich_trung_binh': df['dien_tich'].mean(),
'so_luong_cao_tin_cay': len(cao_tin_cay)
}
# Thực hiện phân tích
ket_qua_phan_tich = phan_tich_ket_qua_hinh_anh(df_hinh_anh)
4. Phân tích kết quả JSON phát hiện video
4.1 Hiểu cấu trúc JSON phát hiện video
Cấu trúc JSON phát hiện video phức tạp hơn phát hiện hình ảnh vì nó chứa thông tin phát hiện theo từng khung:
{
"model_path": "/root/ai-models/xlangai/VideoAgentTrek-ScreenFilter/best.pt",
"type": "video",
"count": 45,
"class_count": {
"screen": 30,
"monitor": 10,
"tv": 5
},
"boxes": [
{
"frame": 0,
"class_id": 0,
"class_name": "screen",
"confidence": 0.85,
"xyxy": [100, 50, 400, 300]
},
{
"frame": 0,
"class_id": 1,
"class_name": "monitor",
"confidence": 0.72,
"xyxy": [450, 200, 700, 450]
},
{
"frame": 1,
"class_id": 0,
"class_name": "screen",
"confidence": 0.88,
"xyxy": [105, 55, 405, 305]
},
// ... nhiều kết quả phát hiện hơn
],
"video_info": {
"total_frames": 60,
"processed_frames": 60,
"fps": 30,
"duration_seconds": 2.0
}
}
Các trường mới quan trọng:
- video_info: Thông tin siêu dữ liệu của video
- frame trong boxes: Bây giờ biểu thị số khung của video
4.2 Chuyển đổi JSON video thành DataFrame
Mã xử lý JSON video tương tự như hình ảnh, nhưng cần xử lý thêm thông tin khung:
def doc_json_video_vao_dataframe(duong_dan_json):
"""
Tải tệp JSON phát hiện video và chuyển đổi thành DataFrame
Tham số:
duong_dan_json: Đường dẫn đến tệp JSON
Trả về:
DataFrame pandas chứa thông tin hộp phát hiện của tất cả các khung
"""
# 1. Đọc tệp JSON
with open(duong_dan_json, 'r', encoding='utf-8') as f:
du_lieu = json.load(f)
# 2. Trích xuất danh sách boxes
du_lieu_boxes = du_lieu.get('boxes', [])
# 3. Chuyển đổi thành DataFrame
df = pd.DataFrame(du_lieu_boxes)
# 4. Thêm cột tính toán
if not df.empty:
# Tính các thuộc tính hình học của hộp phát hiện
df['chieu_rong'] = df['xyxy'].apply(lambda x: x[2] - x[0])
df['chieu_cao'] = df['xyxy'].apply(lambda x: x[3] - x[1])
df['dien_tich'] = df['chieu_rong'] * df['chieu_cao']
df['trung_tam_x'] = df['xyxy'].apply(lambda x: (x[0] + x[2]) / 2)
df['trung_tam_y'] = df['xyxy'].apply(lambda x: (x[1] + x[3]) / 2)
# Tính thông tin thời gian (nếu có video_info)
if 'video_info' in du_lieu:
fps = du_lieu['video_info'].get('fps', 30)
df['thoi_gian_giay'] = df['frame'] / fps
df['thoi_gian_dinh_dang'] = df['thoi_gian_giay'].apply(
lambda x: f"{int(x//60):02d}:{int(x%60):02d}.{int((x%1)*100):02d}"
)
return df, du_lieu
# Ví dụ sử dụng
duong_dan_json_video = "path/to/your/video_detection_result.json"
df_video, thong_tin_video = doc_json_video_vao_dataframe(duong_dan_json_video)
print("DataFrame kết quả phát hiện video:")
print(df_video.head())
print(f"\nTổng số phát hiện: {len(df_video)}")
print(f"Tổng số khung: {df_video['frame'].nunique()}")
print(f"Loại phát hiện: {df_video['class_name'].unique()}")
4.3 Phân tích chuỗi thời gian kết quả phát hiện video
Đặc điểm lớn nhất của dữ liệu phát hiện video là có chiều thời gian, chúng ta có thể thực hiện phân tích chuỗi thời gian:
def phan_tich_ket_qua_video(df, thong_tin_phu):
"""
Phân tích kết quả phát hiện video
Tham số:
df: DataFrame chứa kết quả phát hiện
thong_tin_phu: Siêu dữ liệu JSON
"""
print("=== Phân tích kết quả phát hiện video ===")
# 1. Thống kê tổng thể
print("\n1. Thống kê tổng thể:")
print(f"Tổng số lần phát hiện: {len(df)}")
print(f"Tổng số khung video: {thong_tin_phu.get('video_info', {}).get('total_frames', 'không xác định')}")
print(f"Số khung đã xử lý: {thong_tin_phu.get('video_info', {}).get('processed_frames', 'không xác định')}")
# 2. Thống kê theo loại
print("\n2. Thống kê theo loại:")
thong_ke_loai = df['class_name'].value_counts()
print(thong_ke_loai)
# 3. Phân tích chiều thời gian
print("\n3. Phân tích chiều thời gian:")
# Phân tích tần suất phát hiện (số lượng phát hiện mỗi khung)
phat_hien_tren_khung = df.groupby('frame').size()
print(f"Số phát hiện trung bình mỗi khung: {phat_hien_tren_khung.mean():.2f}")
print(f"Khung có nhiều phát hiện nhất: Khung thứ {phat_hien_tren_khung.idxmax()} ({phat_hien_tren_khung.max()} phát hiện)")
# 4. Độ tin cậy theo thời gian thay đổi
if 'thoi_gian_giay' in df.columns:
print("\n4. Độ tin cậy theo thời gian thay đổi:")
# Tính độ tin cậy trung bình theo cửa sổ thời gian
cua_so_thoi_gian = pd.cut(df['thoi_gian_giay'], bins=5)
do_tin_cay_theo_thoi_gian = df.groupby(cua_so_thoi_gian)['confidence'].mean()
print("Độ tin cậy trung bình theo cửa sổ thời gian:")
print(do_tin_cay_theo_thoi_gian)
# 5. Phân tích mẫu xuất hiện của đối tượng phát hiện
print("\n5. Phân tích mẫu xuất hiện của đối tượng phát hiện:")
# Tìm các đối tượng phát hiện liên tục (phiên bản đơn giản)
# Ở đây giả sử các đối tượng gần nhau về vị trí, cùng loại có thể là cùng một vật thể
if len(df) > 0:
# Sắp xếp theo loại và số khung
df_sap_xep = df.sort_values(['class_name', 'frame'])
# Phân tích tính liên tục đơn giản
for ten_loai in df['class_name'].unique():
df_loai = df_sap_xep[df_sap_xep['class_name'] == ten_loai]
cac_khung = df_loai['frame'].values
# Tính khoảng cách khung
if len(cac_khung) > 1:
khoang_cach = np.diff(cac_khung)
khoang_cach_trung_binh = khoang_cach.mean() if len(khoang_cach) > 0 else 0
print(f"{ten_loai}: Xuất hiện trung bình mỗi {khoang_cach_trung_binh:.1f} khung")
return {
'tong_so_phat_hien': len(df),
'thong_ke_loai': thong_ke_loai.to_dict(),
'so_phat_hien_trung_binh_tren_khung': phat_hien_tren_khung.mean() if len(phat_hien_tren_khung) > 0 else 0
}
# Thực hiện phân tích
ket_qua_phan_tich_video = phan_tich_ket_qua_video(df_video, thong_tin_video)
5. Phân tích dữ liệu nâng cao và trực quan hóa
5.1 Tạo bảng điều khiển phân tích dữ liệu tương tác
Chúng ta có thể tạo một bảng điều khiển phân tích dữ liệu đơn giản để giúp người dùng hiểu rõ hơn về kết quả phát hiện:
import matplotlib.pyplot as plt
import seaborn as sns
def tao_bang_dieu_khien_phat_hien(df, tieu_de="Phân tích kết quả phát hiện"):
"""
Tạo bảng điều khiển trực quan hóa kết quả phát hiện
Tham số:
df: DataFrame chứa kết quả phát hiện
tieu_de: Tiêu đề biểu đồ
"""
# Thiết lập kiểu biểu đồ
plt.style.use('seaborn-v0_8-darkgrid')
fig = plt.figure(figsize=(16, 10))
fig.suptitle(tieu_de, fontsize=16, fontweight='bold')
# 1. Biểu đồ tròn phân bố loại
ax1 = plt.subplot(2, 3, 1)
so_luong_loai = df['class_name'].value_counts()
colors = plt.cm.Set3(np.linspace(0, 1, len(so_luong_loai)))
ax1.pie(so_luong_loai.values, labels=so_luong_loai.index, autopct='%1.1f%%',
colors=colors, startangle=90)
ax1.set_title('Phân bố loại phát hiện', fontweight='bold')
# 2. Biểu đồ histogram phân bố độ tin cậy
ax2 = plt.subplot(2, 3, 2)
ax2.hist(df['confidence'], bins=20, edgecolor='black', alpha=0.7)
ax2.set_xlabel('Độ tin cậy')
ax2.set_ylabel('Tần suất')
ax2.set_title('Phân bố độ tin cậy', fontweight='bold')
ax2.axvline(df['confidence'].mean(), color='red', linestyle='--',
label=f'Trung bình: {df["confidence"].mean():.3f}')
ax2.legend()
# 3. Phân bố kích thước hộp phát hiện
ax3 = plt.subplot(2, 3, 3)
ax3.scatter(df['chieu_rong'], df['chieu_cao'], alpha=0.6,
c=df['confidence'], cmap='viridis')
ax3.set_xlabel('Chiều rộng (pixel)')
ax3.set_ylabel('Chiều cao (pixel)')
ax3.set_title('Phân bố kích thước hộp phát hiện', fontweight='bold')
# Thêm thanh màu biểu thị độ tin cậy
plt.colorbar(ax3.collections[0], ax=ax3, label='Độ tin cậy')
# 4. Mối quan hệ giữa loại và độ tin cậy
ax4 = plt.subplot(2, 3, 4)
sns.boxplot(x='class_name', y='confidence', data=df, ax=ax4)
ax4.set_title('Phân bố độ tin cậy theo loại', fontweight='bold')
ax4.set_xlabel('Loại')
ax4.set_ylabel('Độ tin cậy')
ax4.tick_params(axis='x', rotation=45)
# 5. Phân tích chuỗi thời gian (nếu là dữ liệu video)
if 'frame' in df.columns and df['frame'].nunique() > 1:
ax5 = plt.subplot(2, 3, 5)
# Thống kê số lượng phát hiện theo khung
phat_hien_tren_khung = df.groupby('frame').size()
ax5.plot(phat_hien_tren_khung.index, phat_hien_tren_khung.values,
marker='o', linestyle='-', linewidth=2)
ax5.set_xlabel('Số khung')
ax5.set_ylabel('Số lượng phát hiện')
ax5.set_title('Số lượng phát hiện theo thời gian', fontweight='bold')
ax5.grid(True, alpha=0.3)
# 6. Bản đồ nhiệt vị trí hộp phát hiện
ax6 = plt.subplot(2, 3, 6)
if 'trung_tam_x' in df.columns and 'trung_tam_y' in df.columns:
# Tạo biểu đồ 2D histogram (bản đồ nhiệt)
h = ax6.hist2d(df['trung_tam_x'], df['trung_tam_y'], bins=20, cmap='hot')
ax6.set_xlabel('Tọa độ X')
ax6.set_ylabel('Tọa độ Y')
ax6.set_title('Bản đồ nhiệt vị trí hộp phát hiện', fontweight='bold')
plt.colorbar(h[3], ax=ax6, label='Tần suất')
plt.tight_layout()
plt.show()
# Lưu biểu đồ
duong_dan_xuat = f"{tieu_de.replace(' ', '_')}_bang_dieu_khien.png"
fig.savefig(duong_dan_xuat, dpi=300, bbox_inches='tight')
print(f"Bảng điều khiển đã được lưu: {duong_dan_xuat}")
# Ví dụ sử dụng
tao_bang_dieu_khien_phat_hien(df_hinh_anh, tieu_de="Phân tích kết quả phát hiện hình ảnh")
# Nếu là dữ liệu video
if 'frame' in df_video.columns:
tao_bang_dieu_khien_phat_hien(df_video, tieu_de="Phân tích kết quả phát hiện video")
5.2 Tạo báo cáo phân tích chi tiết
Ngoài trực quan hóa, chúng ta còn có thể tạo báo cáo phân tích văn bản chi tiết:
def tao_bao_cao_phan_tich(df, thong_tin_phu, duong_dan_xuat="bao_cao_phan_tich_phat_hien.txt"):
"""
Tạo báo cáo phân tích phát hiện chi tiết
Tham số:
df: DataFrame chứa kết quả phát hiện
thong_tin_phu: Siêu dữ liệu JSON
duong_dan_xuat: Đường dẫn lưu báo cáo
"""
dong_bao_cao = []
# Phần đầu báo cáo
dong_bao_cao.append("=" * 60)
dong_bao_cao.append("Báo cáo phân tích kết quả phát hiện VideoAgentTrek-ScreenFilter")
dong_bao_cao.append("=" * 60)
dong_bao_cao.append(f"Thời gian tạo: {pd.Timestamp.now().strftime('%Y-%m-%d %H:%M:%S')}")
dong_bao_cao.append(f"Loại phát hiện: {thong_tin_phu.get('type', 'không xác định')}")
dong_bao_cao.append(f"Đường dẫn mô hình: {thong_tin_phu.get('model_path', 'không xác định')}")
dong_bao_cao.append("")
# Thông tin thống kê cơ bản
dong_bao_cao.append("1. Thông tin thống kê cơ bản")
dong_bao_cao.append("-" * 40)
dong_bao_cao.append(f"Tổng số đối tượng phát hiện: {len(df)}")
dong_bao_cao.append(f"Số loại phát hiện: {df['class_name'].nunique()}")
dong_bao_cao.append(f"Loại phát hiện: {', '.join(df['class_name'].unique())}")
if thong_tin_phu.get('type') == 'video' and 'video_info' in thong_tin_phu:
thong_tin_video = thong_tin_phu['video_info']
dong_bao_cao.append(f"Tổng số khung video: {thong_tin_video.get('total_frames', 'không xác định')}")
dong_bao_cao.append(f"Số khung đã xử lý: {thong_tin_video.get('processed_frames', 'không xác định')}")
dong_bao_cao.append(f"Tần số khung: {thong_tin_video.get('fps', 'không xác định')} FPS")
dong_bao_cao.append(f"Thời lượng: {thong_tin_video.get('duration_seconds', 'không xác định')} giây")
dong_bao_cao.append("")
# Thống kê chi tiết theo loại
dong_bao_cao.append("2. Thống kê chi tiết theo loại")
dong_bao_cao.append("-" * 40)
thong_ke_loai = df['class_name'].value_counts()
for loai, so_luong in thong_ke_loai.items():
phan_tram = so_luong / len(df) * 100
df_loai = df[df['class_name'] == loai]
do_tin_cay_trung_binh = df_loai['confidence'].mean()
dong_bao_cao.append(f"{loai}:")
dong_bao_cao.append(f" Số lượng: {so_luong} ({phan_tram:.1f}%)")
dong_bao_cao.append(f" Độ tin cậy trung bình: {do_tin_cay_trung_binh:.3f}")
dong_bao_cao.append(f" Độ tin cậy từ: {df_loai['confidence'].min():.3f} - {df_loai['confidence'].max():.3f}")
if 'chieu_rong' in df_loai.columns:
chieu_rong_trung_binh = df_loai['chieu_rong'].mean()
chieu_cao_trung_binh = df_loai['chieu_cao'].mean()
dong_bao_cao.append(f" Kích thước trung bình: {chieu_rong_trung_binh:.1f} × {chieu_cao_trung_binh:.1f} pixel")
dong_bao_cao.append("")
# Phân tích độ tin cậy
dong_bao_cao.append("3. Phân tích độ tin cậy")
dong_bao_cao.append("-" * 40)
dong_bao_cao.append(f"Độ tin cậy trung bình tổng thể: {df['confidence'].mean():.3f}")
dong_bao_cao.append(f"Độ tin cậy trung vị: {df['confidence'].median():.3f}")
dong_bao_cao.append(f"Độ lệch chuẩn độ tin cậy: {df['confidence'].std():.3f}")
# Phân bố độ tin cậy
khoang_do_tin_cay = [0, 0.3, 0.5, 0.7, 0.9, 1.0]
nhan_khoang = ['Thấp(0-0.3)', 'Trung thấp(0.3-0.5)', 'Trung bình(0.5-0.7)', 'Trung cao(0.7-0.9)', 'Cao(0.9-1.0)']
df['muc_do_tin_cay'] = pd.cut(df['confidence'], bins=khoang_do_tin_cay, labels=nhan_khoang)
phan_bo = df['muc_do_tin_cay'].value_counts().sort_index()
dong_bao_cao.append("\nPhân bố độ tin cậy:")
for muc_do, so_luong in phan_bo.items():
phan_tram = so_luong / len(df) * 100
dong_bao_cao.append(f" {muc_do}: {so_luong} ({phan_tram:.1f}%)")
dong_bao_cao.append("")
# Phân tích kích thước hộp phát hiện
if 'chieu_rong' in df.columns:
dong_bao_cao.append("4. Phân tích kích thước hộp phát hiện")
dong_bao_cao.append("-" * 40)
dong_bao_cao.append(f"Chiều rộng trung bình: {df['chieu_rong'].mean():.1f} pixel")
dong_bao_cao.append(f"Chiều cao trung bình: {df['chieu_cao'].mean():.1f} pixel")
dong_bao_cao.append(f"Diện tích trung bình: {df['dien_tich'].mean():.1f} pixel²")
dong_bao_cao.append(f"Hộp phát hiện lớn nhất: {df['dien_tich'].max():.1f} pixel²")
dong_bao_cao.append(f"Hộp phát hiện nhỏ nhất: {df['dien_tich'].min():.1f} pixel²")
dong_bao_cao.append("")
# Phân tích chuỗi thời gian (nếu là video)
if 'frame' in df.columns and df['frame'].nunique() > 1:
dong_bao_cao.append("5. Phân tích chuỗi thời gian")
dong_bao_cao.append("-" * 40)
# Thống kê theo khung
so_khung_co_phat_hien = df['frame'].nunique()
tong_so_khung = df['frame'].max() + 1 # Giả sử khung bắt đầu từ 0
ty_le_phat_hien = so_khung_co_phat_hien / tong_so_khung * 100
dong_bao_cao.append(f"Số khung có phát hiện: {so_khung_co_phat_hien}/{tong_so_khung} ({ty_le_phat_hien:.1f}%)")
dong_bao_cao.append(f"Số phát hiện trung bình mỗi khung: {len(df)/tong_so_khung:.2f}")
# Phân tích mật độ phát hiện
phat_hien_tren_khung = df.groupby('frame').size()
dong_bao_cao.append(f"Mật độ phát hiện cao nhất: Khung thứ {phat_hien_tren_khung.idxmax()} ({phat_hien_tren_khung.max()} phát hiện)")
dong_bao_cao.append(f"Mật độ phát hiện thấp nhất: Khung thứ {phat_hien_tren_khung.idxmin()} ({phat_hien_tren_khung.min()} phát hiện)")
dong_bao_cao.append("")
dong_bao_cao.append("=" * 60)
dong_bao_cao.append("Kết thúc báo cáo")
dong_bao_cao.append("=" * 60)
# Ghi vào tệp
with open(duong_dan_xuat, 'w', encoding='utf-8') as f:
f.write('\n'.join(dong_bao_cao))
print(f"Báo cáo phân tích đã được tạo: {duong_dan_xuat}")
# Đồng thời xuất ra console
print('\n'.join(dong_bao_cao[:50])) # Chỉ xuất 50 dòng đầu tiên để xem trước
return duong_dan_xuat
# Ví dụ sử dụng
ten_tep_bao_cao = tao_bao_cao_phan_tich(df_hinh_anh, thong_tin_phu)
6. Tình huống ứng dụng thực tế
6.1 Tình huống 1: Giám sát chất lượng và phát hiện bất thường
Giả sử bạn đang giám sát một hệ thống hội nghị video, cần đảm bảo tất cả màn hình của người tham gia đều được phát hiện chính xác:
def giam_sat_chat_luong_phat_hien_man_hinh(df, so_man_hinh_ky_vong=4, nguong_do_tin_cay=0.7):
"""
Giám sát chất lượng phát hiện màn hình
Tham số:
df: DataFrame chứa kết quả phát hiện
so_man_hinh_ky_vong: Số màn hình mong đợi
nguong_do_tin_cay: Ngưỡng độ tin cậy
Trả về:
Báo cáo chất lượng dưới dạng dictionary
"""
bao_cao = {
'trang_thai': 'PASS',
'van_de': [],
'chi_so': {}
}
# 1. Kiểm tra tổng số phát hiện
tong_so_phat_hien = len(df)
bao_cao['chi_so']['tong_so_phat_hien'] = tong_so_phat_hien
if tong_so_phat_hien == 0:
bao_cao['trang_thai'] = 'FAIL'
bao_cao['van_de'].append('Không phát hiện được màn hình nào')
return bao_cao
# 2. Kiểm tra phát hiện có độ tin cậy cao
phat_hien_cao_tin_cay = df[df['confidence'] >= nguong_do_tin_cay]
so_luong_cao_tin_cay = len(phat_hien_cao_tin_cay)
bao_cao['chi_so']['so_luong_cao_tin_cay'] = so_luong_cao_tin_cay
bao_cao['chi_so']['ty_le_cao_tin_cay'] = so_luong_cao_tin_cay / tong_so_phat_hien
if so_luong_cao_tin_cay < so_man_hinh_ky_vong:
bao_cao['trang_thai'] = 'WARNING'
bao_cao['van_de'].append(f'Số phát hiện có độ tin cậy cao({so_luong_cao_tin_cay}) thấp hơn giá trị mong đợi({so_man_hinh_ky_vong})')
# 3. Kiểm tra tính nhất quán kích thước hộp phát hiện
if 'dien_tich' in df.columns:
do_lech_chuan = df['dien_tich'].std()
trung_binh = df['dien_tich'].mean()
bao_cao['chi_so']['trung_binh'] = trung_binh
bao_cao['chi_so']['do_lech_chuan'] = do_lech_chuan
# Nếu sự khác biệt kích thước quá lớn, có thể có vấn đề
if do_lech_chuan > trung_binh * 0.5: # Độ lệch chuẩn vượt quá 50% trung bình
bao_cao['trang_thai'] = 'WARNING'
bao_cao['van_de'].append('Sự khác biệt kích thước hộp phát hiện quá lớn, có thể phát hiện sai')
# 4. Kiểm tra phân bố vị trí hộp phát hiện
if 'trung_tam_x' in df.columns and 'trung_tam_y' in df.columns:
# Tính phân bố tọa độ trung tâm
do_lech_x = df['trung_tam_x'].std()
do_lech_y = df['trung_tam_y'].std()
bao_cao['chi_so']['do_lech_x'] = do_lech_x
bao_cao['chi_so']['do_lech_y'] = do_lech_y
# Nếu tất cả hộp phát hiện tập trung ở một khu vực, có thể có vấn đề
if do_lech_x < 50 or do_lech_y < 50: # Độ lệch chuẩn quá nhỏ, có thể phát hiện cùng một khu vực
bao_cao['trang_thai'] = 'WARNING'
bao_cao['van_de'].append('Vị trí hộp phát hiện quá tập trung, có thể phát hiện lặp lại cùng một đối tượng')
# 5. Tạo đề xuất
if bao_cao['trang_thai'] == 'PASS':
bao_cao['de_xuat'] = ['Chất lượng phát hiện tốt, không cần điều chỉnh']
else:
de_xuat = []
if so_luong_cao_tin_cay < so_man_hinh_ky_vong:
de_xuat.append('Nên giảm ngưỡng độ tin cậy để tăng độ bao phủ')
if 'do_lech_chuan' in bao_cao['chi_so'] and bao_cao['chi_so']['do_lech_chuan'] > bao_cao['chi_so']['trung_binh'] * 0.5:
de_xuat.append('Nên kiểm tra chất lượng video đầu vào, đảm bảo hình ảnh rõ nét')
bao_cao['de_xuat'] = de_xuat
return bao_cao
# Ví dụ sử dụng
bao_cao_chat_luong = giam_sat_chat_luong_phat_hien_man_hinh(df_video, so_man_hinh_ky_vong=2)
print("Báo cáo giám sát chất lượng:")
print(f"Trạng thái: {bao_cao_chat_luong['trang_thai']}")
print(f"Vấn đề: {bao_cao_chat_luong['van_de']}")
print(f"Đề xuất: {bao_cao_chat_luong.get('de_xuat', [])}")
6.2 Tình huống 2: Xử lý hàng loạt và xuất dữ liệu
Khi bạn cần xử lý nhiều tệp kết quả:
import os
import glob
def xu_ly_hang_loat_tep_json(Thu_muc_nhap, Thu_muc_xuat):
"""
Xử lý hàng loạt tệp JSON
Tham số:
Thu_muc_nhap: Thư mục chứa tệp JSON đầu vào
Thu_muc_xuat: Thư mục đầu ra
"""
# Đảm bảo thư mục đầu ra tồn tại
os.makedirs(Thu_muc_xuat, exist_ok=True)
# Tìm tất cả các tệp JSON
tep_json = glob.glob(os.path.join(Thu_muc_nhap, "*.json"))
print(f"Tìm thấy {len(tep_json)} tệp JSON")
tat_ca_ket_qua = []
for tep_json in tep_json:
try:
# Trích xuất tên tệp
ten_tep = os.path.basename(tep_json)
print(f"Đang xử lý tệp: {ten_tep}")
# Đọc tệp JSON
with open(tep_json, 'r', encoding='utf-8') as f:
du_lieu = json.load(f)
# Chọn hàm xử lý theo loại
if du_lieu.get('type') == 'image':
df, thong_tin_phu = doc_json_hinh_anh_vao_dataframe(tep_json)
elif du_lieu.get('type') == 'video':
df, thong_tin_phu = doc_json_video_vao_dataframe(tep_json)
else:
print(f" Loại không xác định: {du_lieu.get('type')}")
continue
# Thêm thông tin tên tệp
df['ten_tep_nguon'] = ten_tep
# Lưu dưới dạng CSV
ten_tep_csv = ten_tep.replace('.json', '.csv')
duong_dan_csv = os.path.join(Thu_muc_xuat, ten_tep_csv)
df.to_csv(duong_dan_csv, index=False, encoding='utf-8-sig')
print(f" Đã lưu thành: {ten_tep_csv}")
# Tạo báo cáo phân tích
ten_tep_bao_cao = ten_tep.replace('.json', '_bao_cao.txt')
duong_dan_bao_cao = os.path.join(Thu_muc_xuat, ten_tep_bao_cao)
tao_bao_cao_phan_tich(df, thong_tin_phu, duong_dan_bao_cao)
# Thu thập thông tin tổng hợp
thong_tin_tong_hop = {
'ten_tep': ten_tep,
'loai': du_lieu.get('type'),
'tong_so_phat_hien': len(df),
'loai_phat_hien': list(df['class_name'].unique()),
'do_tin_cay_trung_binh': df['confidence'].mean(),
'duong_dan_csv': duong_dan_csv,
'duong_dan_bao_cao': duong_dan_bao_cao
}
tat_ca_ket_qua.append(thong_tin_tong_hop)
except Exception as e:
print(f" Xử lý thất bại: {str(e)}")
# Tạo báo cáo tổng hợp
if tat_ca_ket_qua:
df_tong_hop = pd.DataFrame(tat_ca_ket_qua)
duong_dan_tong_hop = os.path.join(Thu_muc_xuat, "tong_hop.csv")
df_tong_hop.to_csv(duong_dan_tong_hop, index=False, encoding='utf-8-sig')
print(f"\nHoàn thành xử lý hàng loạt!")
print(f"Số tệp đã xử lý: {len(tat_ca_ket_qua)}")
print(f"Báo cáo tổng hợp: {duong_dan_tong_hop}")
# In thống kê tổng hợp
print("\nThống kê tổng hợp:")
print(f"Tổng số phát hiện: {df_tong_hop['tong_so_phat_hien'].sum()}")
print(f"Độ tin cậy trung bình: {df_tong_hop['do_tin_cay_trung_binh'].mean():.3f}")
# Thống kê theo loại
thong_ke_loai = df_tong_hop['loai'].value_counts()
print("\nThống kê theo loại:")
for ten_loai, so_luong in thong_ke_loai.items():
print(f" {ten_loai}: {so_luong} tệp")
return tat_ca_ket_qua
# Ví dụ sử dụng
# ket_qua_xu_ly = xu_ly_hang_loat_tep_json("Thu_muc_json_nhap", "Thu_muc_csv_xuat")
6.3 Tình huống 3: Tích hợp với hệ thống kinh doanh
Tích hợp kết quả phát hiện vào hệ thống kinh doanh hiện có:
class Xu_ly_ket_qua_phat_hien:
"""Xử lý kết quả phát hiện, dùng cho tích hợp hệ thống kinh doanh"""
def __init__(self, duong_dan_cau_hinh=None):
"""
Khởi tạo bộ xử lý
Tham số:
duong_dan_cau_hinh: Đường dẫn tệp cấu hình
"""
self.cau_hinh = self._tai_cau_hinh(duong_dan_cau_hinh)
self.lich_su_phat_hien = []
def _tai_cau_hinh(self, duong_dan_cau_hinh):
"""Tải cấu hình"""
cau_hinh_mac_dinh = {
'nguong_do_tin_cay': 0.5,
'dien_tich_nho_nhat': 1000,
'dien_tich_lon_nhat': 100000,
'canh_bao_khi_do_tin_cay_thap': True,
'nguong_canh_bao': 0.3,
'dinh_dang_xuat': 'csv', # csv, json, database
'cau_hinh_co_so_du_lieu': None
}
if duong_dan_cau_hinh and os.path.exists(duong_dan_cau_hinh):
with open(duong_dan_cau_hinh, 'r') as f:
cau_hinh_nguoi_dung = json.load(f)
cau_hinh_mac_dinh.update(cau_hinh_nguoi_dung)
return cau_hinh_mac_dinh
def xu_ly_ket_qua_phat_hien(self, du_lieu_json, thong_tin_nguon=None):
"""
Xử lý kết quả phát hiện
Tham số:
du_lieu_json: Dữ liệu JSON hoặc đường dẫn tệp
thong_tin_nguon: Thông tin nguồn (như ID video, timestamp, v.v.)
Trả về:
Kết quả đã xử lý
"""
# Nếu là đường dẫn tệp, đọc tệp
if isinstance(du_lieu_json, str) and os.path.exists(du_lieu_json):
with open(du_lieu_json, 'r', encoding='utf-8') as f:
du_lieu = json.load(f)
else:
du_lieu = du_lieu_json
# Chuyển đổi thành DataFrame
if du_lieu.get('type') == 'image':
df, thong_tin_phu = self._xu_ly_du_lieu_hinh_anh(du_lieu)
elif du_lieu.get('type') == 'video':
df, thong_tin_phu = self._xu_ly_du_lieu_video(du_lieu)
else:
raise ValueError(f"Loại phát hiện không xác định: {du_lieu.get('type')}")
# Áp dụng bộ lọc
df_da_loc = self._ap_dung_bo_loc(df)
# Tính toán chỉ số kinh doanh
chi_so = self._tinh_toan_chi_so(df_da_loc, thong_tin_phu)
# Kiểm tra cần cảnh báo không
canh_bao = self._kiem_tra_canh_bao(df_da_loc, chi_so)
# Ghi vào lịch sử
ban_ghi_ket_qua = {
'thoi_gian': pd.Timestamp.now(),
'nguon': thong_tin_nguon,
'loai': du_lieu.get('type'),
'tong_so_phat_hien': len(df),
'so_phat_hien_da_loc': len(df_da_loc),
'chi_so': chi_so,
'canh_bao': canh_bao,
'dataframe': df,
'dataframe_da_loc': df_da_loc
}
self.lich_su_phat_hien.append(ban_ghi_ket_qua)
# Xuất kết quả
ket_qua_xuat = self._tao_ket_qua_xuat(ban_ghi_ket_qua)
return ket_qua_xuat
def _xu_ly_du_lieu_hinh_anh(self, du_lieu):
"""Xử lý dữ liệu hình ảnh"""
df = pd.DataFrame(du_lieu.get('boxes', []))
# Thêm cột tính toán
if not df.empty:
df['chieu_rong'] = df['xyxy'].apply(lambda x: x[2] - x[0])
df['chieu_cao'] = df['xyxy'].apply(lambda x: x[3] - x[1])
df['dien_tich'] = df['chieu_rong'] * df['chieu_cao']
return df, du_lieu
def _xu_ly_du_lieu_video(self, du_lieu):
"""Xử lý dữ liệu video"""
df = pd.DataFrame(du_lieu.get('boxes', []))
# Thêm cột tính toán
if not df.empty:
df['chieu_rong'] = df['xyxy'].apply(lambda x: x[2] - x[0])
df['chieu_cao'] = df['xyxy'].apply(lambda x: x[3] - x[1])
df['dien_tich'] = df['chieu_rong'] * df['chieu_cao']
# Thêm thông tin thời gian
if 'video_info' in du_lieu:
fps = du_lieu['video_info'].get('fps', 30)
df['thoi_gian_giay'] = df['frame'] / fps
return df, du_lieu
def _ap_dung_bo_loc(self, df):
"""Áp dụng bộ lọc"""
df_da_loc = df.copy()
# Bộ lọc độ tin cậy
nguong = self.cau_hinh['nguong_do_tin_cay']
df_da_loc = df_da_loc[df_da_loc['confidence'] >= nguong]
# Bộ lọc kích thước hộp phát hiện
if 'dien_tich' in df_da_loc.columns:
nho_nhat = self.cau_hinh['dien_tich_nho_nhat']
lon_nhat = self.cau_hinh['dien_tich_lon_nhat']
df_da_loc = df_da_loc[
(df_da_loc['dien_tich'] >= nho_nhat) &
(df_da_loc['dien_tich'] <= lon_nhat)
]
return df_da_loc
def _tinh_toan_chi_so(self, df, thong_tin_phu):
"""Tính toán chỉ số kinh doanh"""
chi_so = {
'tong_so_phat_hien': len(df),
'so_loai_khac_nhau': df['class_name'].nunique() if not df.empty else 0,
'do_tin_cay_trung_binh': df['confidence'].mean() if not df.empty else 0,
'ty_le_phat_hien': 0
}
if thong_tin_phu.get('type') == 'video' and 'video_info' in thong_tin_phu:
tong_so_khung = thong_tin_phu['video_info'].get('processed_frames', 1)
so_khung_co_phat_hien = df['frame'].nunique() if not df.empty else 0
chi_so['ty_le_phat_hien'] = so_khung_co_phat_hien / tong_so_khung
return chi_so
def _kiem_tra_canh_bao(self, df, chi_so):
"""Kiểm tra điều kiện cảnh báo"""
canh_bao = []
# Cảnh báo độ tin cậy thấp
if self.cau_hinh['canh_bao_khi_do_tin_cay_thap'] and not df.empty:
so_thap = len(df[df['confidence'] < self.cau_hinh['nguong_canh_bao']])
if so_thap > 0:
canh_bao.append({
'loai': 'DO_TIN_CAY_THAP',
'thong_bao': f'Phát hiện {so_thap} phát hiện có độ tin cậy thấp',
'muc_do': 'WARNING'
})
# Cảnh báo không phát hiện được
if len(df) == 0:
canh_bao.append({
'loai': 'KHONG_PHAT_HIEN',
'thong_bao': 'Không phát hiện được đối tượng hợp lệ',
'muc_do': 'ERROR'
})
return canh_bao
def _tao_ket_qua_xuat(self, ban_ghi_ket_qua):
"""Tạo kết quả xuất"""
dinh_dang_xuat = self.cau_hinh['dinh_dang_xuat']
if dinh_dang_xuat == 'csv':
# Lưu dưới dạng CSV
thoi_gian_str = ban_ghi_ket_qua['thoi_gian'].strftime('%Y%m%d_%H%M%S')
ten_tep = f"phat_hien_{thoi_gian_str}.csv"
ban_ghi_ket_qua['dataframe_da_loc'].to_csv(ten_tep, index=False)
return {'ten_tep': ten_tep, 'dinh_dang': 'csv'}
elif dinh_dang_xuat == 'json':
# Chuyển đổi thành định dạng JSON
du_lieu_xuat = {
'thoi_gian': ban_ghi_ket_qua['thoi_gian'].isoformat(),
'nguon': ban_ghi_ket_qua['nguon'],
'chi_so': ban_ghi_ket_qua['chi_so'],
'canh_bao': ban_ghi_ket_qua['canh_bao'],
'phat_hien': ban_ghi_ket_qua['dataframe_da_loc'].to_dict('records')
}
return du_lieu_xuat
elif dinh_dang_xuat == 'database' and self.cau_hinh['cau_hinh_co_so_du_lieu']:
# Lưu vào cơ sở dữ liệu (đây chỉ là ví dụ, cần triển khai cụ thể theo loại cơ sở dữ liệu)
# Bỏ qua mã cụ thể của cơ sở dữ liệu ở đây
return {'trang_thai': 'da_luu_vao_co_so_du_lieu'}
else:
return ban_ghi_ket_qua
def lay_thong_ke(self):
"""Lấy thông tin thống kê lịch sử"""
if not self.lich_su_phat_hien:
return None
df_thong_ke = pd.DataFrame([
{
'thoi_gian': ban_ghi['thoi_gian'],
'loai': ban_ghi['loai'],
'tong': ban_ghi['tong_so_phat_hien'],
'da_loc': ban_ghi['so_phat_hien_da_loc'],
'do_tin_cay_trung_binh': ban_ghi['chi_so']['do_tin_cay_trung_binh']
}
for ban_ghi in self.lich_su_phat_hien
])
return df_thong_ke
# Ví dụ sử dụng
bo_xu_ly = Xu_ly_ket_qua_phat_hien()
# Xử lý một kết quả phát hiện
ket_qua = bo_xu_ly.xu_ly_ket_qua_phat_hien(
du_lieu_json="path/to/detection_result.json",
thong_tin_nguon={"video_id": "test_001", "timestamp": "2024-01-15 10:30:00"}
)
print("Kết quả xử lý:", ket_qua)
# Lấy thông tin thống kê
thong_ke = bo_xu_ly.lay_thong_ke()
if thong_ke is not None:
print("\nThống kê xử lý:")
print(thong_ke)