计算机视觉是一个跨学科的科学领域,致力于从数字图像或视频中理解高层次的信息并获得理解能力。从工程角度看,它致力于理解和自动化人类视觉系统能够完成的任务,如识别、分类等。
来源:网
如今,分类、目标检测、分割和关键点识别是实时计算机视觉应用中的主要任务。大家觉得这些技术是怎么发展起来的呢?
首先,我们将简短地讨论一些计算机视觉的主要问题。
来源:在线
你看过上面的图片后,应该已经对所有与计算机视觉相关的关键术语有了清晰的理解。
在我看来,这是一个严重的问题,虽然这主要取决于问题的表述。不过,这种困难通常会困扰每个2D计算机视觉工程师。
六年前,我开始从事图像处理,后来逐渐过渡到计算机视觉领域,在深度学习模型流行之前,我学到了许多基础概念。例如,我会仔细研究许多数学概念,比如resnet、vgg19、unet和efficientnet等。然而,当我最近和很多学生讨论早期的计算机视觉时,他们只说“YOLO”。大多数人对YOLO的内部工作原理并不了解,YOLO的内部架构借鉴了VGG的设计。YOLO的普及和相比其他模型异常高的准确性,这才是真的重要。
大家想要现成的解决方案,仅需安装包然后让其自动运行,不需要理解后端操作。这个解决方案就是 YOLO(由 Ultralytics 提供)
来源:网络
我将聊聊Yolov10,以及我做的视频分析演示项目,该项目通过图形来展示从商业角度看,物体的数量、速度和距离。
什么 YOLO ?
(YOLO 指 "活在当下")
基于CNN的对象检测器主要用于推荐系统。YOLO(You Only Look Once)模型用于高效率的对象检测。YOLO将图像划分为网格系统,每个网格检测其内部的对象。它们可以基于数据流进行实时对象检测,并且只需要很少的计算资源。
大家来看看 YoloV10 刚刚发布!它的主要特点有哪些?
实时目标检测旨在以最小的延迟,准确地识别图像中的对象类别和位置。YOLO系列在性能和效率之间找到了良好的平衡,但仍然存在依赖NMS和架构效率低的问题。YOLOv10通过引入无NMS训练和采用注重效率与准确性的模型设计策略来解决这些问题。
建筑设计
YOLOv10 通过几项创新提升了之前的 YOLO 版本:
- 骨干网络:采用改进的CSPNet来优化梯度流动并减少计算冗余。
- 颈部结构:引入PAN层,实现多尺度特征融合,聚合来自不同尺度的特征信息。
- 一对多头:在训练过程中为每个对象生成多个预测,从而丰富监督信号并提高学习精度。
- 一对一头:在推理过程中为每个对象输出一个最佳预测,从而消除NMS的需求并减少延迟。
主要特点:
- 无需NMS的训练:利用一致的双分配去除NMS需求,减少推断延迟时间。
- 整体设计的模型:优化各组件以提高效率和准确性,包括轻量级分类头、空间-通道解耦的下采样以及基于秩的模块设计。
- 增强模型能力:采用大核卷积和部分自注意力机制来提升性能且不会显著增加计算成本。
❓️YOLOV10的特别之处在哪里
YOLOv10 引入了一种突破性的实时物体检测方法,这种方法不需要非极大值抑制(NMS),并通过利用一致的双重分配策略和一种整体效率和准确性驱动的设计,实现了业界领先的精度,同时减少了计算开销。其架构包括增强的骨干网和颈部组件,以及创新的一对多和一对一头部。通过提供适用于不同应用场景的模型变体,YOLOv10 在准确性和效率方面设立了新的标准,超越了之前的 YOLO 版本和其他现代检测器。例如,YOLOv10-S 在 COCO 数据集上与 RT-DETR-R18 具有相似的 AP 时速度快了 1.8 倍,而 YOLOv10-B 在具有相同性能的情况下,延迟降低了 46%,参数减少了 25%,比 YOLOv9-C 更优秀。
如果你想深入了解YOLOV8,请看下面的文章。
YoloV8架构介绍及使用YoloV8进行基于区域拖拽的奶牛计数计算机视觉是一个跨学科领域,主要涉及如何让计算机理解和处理图像及视频等视觉信息。
视频分析技术:计数、测速、估距,带图形展示:
在这个项目中,我开发了一个系统,用户可以即时获得特定对象的计数、速度和距离估算值,以及图形化的视图。这为企业的决策提供了即时且可操作的洞察,带来了显著的好处。
我使用了来自Ultralytics的模型,特别是YOLOv8s和YOLOv8n,这些模型因其在目标检测方面的高精度、高效性和低延迟而闻名。这些模型在简化最终阶段分析方面至关重要,使整个流程更为顺畅和有效。
开发过程非常愉快,并展示了这种类型的解决方案在通过先进技术解决业务挑战方面的重要潜力。虽然YoloV8和YoloV10也表现良好,但YoloV10在准确性和延迟方面表现更优。
'''
最终代码:视频分析特定对象
指导
1. 用户输入:特定对象
2. 特定对象检测,速度估计和距离计算
3. 图表分析:饼图,面积图,多类线图
!pip install ultralytics
'''
# 辅助函数
def create_pie_chart(data):
fig, ax = plt.subplots(figsize=(4, 3)) # 宽高比为 4:3
ax.pie(data.values(), labels=data.keys(), autopct='%1.1f%%')
ax.legend()
ax.set_title("每个类别的总百分比")
plt.close(fig)
return fig
def create_area_plot(class_counts_over_time):
fig, ax = plt.subplots(figsize=(4, 3)) # 宽高比为 4:3
sorted_keys = sorted(class_counts_over_time.keys())
for cls in sorted_keys:
ax.fill_between(range(len(class_counts_over_time[cls])), class_counts_over_time[cls], label=cls, alpha=0.6)
ax.legend()
ax.set_title("随时间变化的每个类别分布")
ax.set_xlabel("帧数")
ax.set_ylabel("数量")
plt.close(fig)
return fig
def create_multiple_line_plot(speed_data, distance_data, frame_count):
fig, ax = plt.subplots(figsize=(4, 3)) # 宽高比为 4:3
for track_id in speed_data.keys():
ax.plot(range(frame_count), speed_data[track_id], label=f"速度 {track_id}")
for track_id in distance_data.keys():
ax.plot(range(frame_count), distance_data[track_id], label=f"距离 {track_id}")
ax.legend()
ax.set_title("每个类别的速度和距离识别")
ax.set_xlabel("帧数")
ax.set_ylabel("值")
plt.close(fig)
return fig
def create_scatter_plot(data):
fig, ax = plt.subplots(figsize=(4, 3)) # 宽高比为 4:3
x = list(data.keys())
y = list(data.values())
ax.scatter(x, y)
ax.set_title("类别分布散点图")
ax.set_xlabel("类别")
ax.set_ylabel("数量")
plt.close(fig)
return fig
def fig_to_img(fig):
fig.canvas.draw()
img = np.frombuffer(fig.canvas.tostring_rgb(), dtype=np.uint8)
img = img.reshape(fig.canvas.get_width_height()[::-1] + (3,))
return img
def resize_and_place_image(base_image, overlay_image, position):
overlay_image_resized = cv2.resize(overlay_image, (w // 3, h // 3))
x, y = position
base_image[y:y + overlay_image_resized.shape[0], x:x + overlay_image_resized.shape[1]] = overlay_image_resized
return base_image
def draw_visualizations(frame, data, labels, speed_data, distance_data, class_counts_over_time, frame_count):
vis_frame = np.zeros((h, w // 3, 3), dtype=np.uint8)
# 创建饼图
if data:
pie_chart = create_pie_chart(data)
pie_chart_img = fig_to_img(pie_chart)
vis_frame = resize_and_place_image(vis_frame, pie_chart_img, (0, 0))
# 创建面积图
if class_counts_over_time:
area_plot = create_area_plot(class_counts_over_time)
area_plot_img = fig_to_img(area_plot)
vis_frame = resize_and_place_image(vis_frame, area_plot_img, (0, h // 3))
# 创建多条线图
if speed_data or distance_data:
line_plot = create_multiple_line_plot(speed_data, distance_data, frame_count)
line_plot_img = fig_to_img(line_plot)
vis_frame = resize_and_place_image(vis_frame, line_plot_img, (0, 2 * (h // 3)))
combined_frame = np.hstack((frame, vis_frame))
return combined_frame
def pad_lists_to_length(data_dict, length, default_value=0):
for key in data_dict.keys():
if len(data_dict[key]) < length:
data_dict[key] += [default_value] * (length - len(data_dict[key]))
'''
主函数:
特定输入的视频分析
(对象计数,速度,距离估计等)
'''
import cv2
import math
import numpy as np
import matplotlib.pyplot as plt
from ultralytics import YOLO
from ultralytics.utils.plotting import Annotator
from ultralytics.solutions import speed_estimation
# 初始化YOLO模型
object_detection_model = YOLO("yolov8s.pt")
speed_estimation_model = YOLO("yolov8n.pt")
names = speed_estimation_model.model.names
# 打开视频文件
cap = cv2.VideoCapture("/content/drive/MyDrive/yolo/race.mp4")
assert cap.isOpened(), "视频文件读取失败"
# 获取视频属性
w, h, fps = (int(cap.get(x)) for x in (cv2.CAP_PROP_FRAME_WIDTH, cv2.CAP_PROP_FRAME_HEIGHT, cv2.CAP_PROP_FPS))
# 初始化视频写入
out = cv2.VideoWriter("Distribution_speed_distance_visual_scatter_unique1hor_car_overall.avi", cv2.VideoWriter_fourcc(*"MJPG"),15, (w + w // 3, h))
frame_count = 0
data = {}
labels = []
class_counts_over_time = {}
speed_over_time = {}
distance_over_time = {}
# 中心点和每像素米数用于距离计算
center_point = (0, h)
pixel_per_meter = 10
# 速度估计的线点
line_pts = [(0, 360), (1280, 360)]
# 初始化速度估计对象
speed_obj = speed_estimation.SpeedEstimator(names=names, reg_pts=line_pts, view_img=False)
# 文本和边界框颜色
txt_color, txt_background, bbox_clr = ((0, 0, 0), (255, 255, 255), (255, 0, 255))
print('示例输入:马:17, 人:0,车:2, 面包车:8,公共汽车:5,树:62')
# 允许用户输入所需的类
user_input = input("请输入所需的类别及其ID(格式:'类别1:ID1,类别2:ID2,...'):")
# 示例输入:"人:0,车:2,马:17"
desired_classes = {}
for item in user_input.split(','):
cls, cls_id = item.split(':')
desired_classes[cls.strip()] = int(cls_id.strip())
print("所需类别:", desired_classes)
while cap.isOpened():
success, frame = cap.read()
if not success:
break
frame_count += 1
# 速度估计的对象检测
speed_tracks = speed_estimation_model.track(frame, persist=True, show=False)
frame = speed_obj.estimate_speed(frame, speed_tracks)
# 距离计算的对象检测
annotator = Annotator(frame, line_width=2)
results = object_detection_model.track(frame, persist=True)
if results[0].boxes.id is not None:
boxes = results[0].boxes.xyxy.cpu()
track_ids = results[0].boxes.id.int().cpu().tolist()
clss = results[0].boxes.cls.cpu().tolist()
for box, track_id, cls in zip(boxes, track_ids, clss):
cls_name = object_detection_model.names[int(cls)]
if cls_name in desired_classes and desired_classes[cls_name] == cls: # 过滤所需的类和ID
if cls_name not in labels:
labels.append(cls_name)
if cls_name in data:
data[cls_name] += 1
else:
data[cls_name] = 1
annotator.box_label(box, label=str(track_id), color=bbox_clr)
annotator.visioneye(box, center_point)
x1, y1 = int((box[0] + box[2]) // 2), int((box[1] + box[3]) // 2) # 中心点
distance = (math.sqrt((x1 - center_point[0]) ** 2 + (y1 - center_point[1]) ** 2)) / pixel_per_meter
text_size, _ = cv2.getTextSize(f"{distance:.2f} 米", cv2.FONT_HERSHEY_SIMPLEX, 1.2, 3)
cv2.rectangle(frame, (x1, y1 - text_size[1] - 10), (x1 + text_size[0] + 10, y1), txt_background, -1)
cv2.putText(frame, f"{distance:.2f} 米", (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 1.2, txt_color, 3)
if track_id not in distance_over_time:
distance_over_time[track_id] = [0] * (frame_count - 1)
distance_over_time[track_id].append(distance)
speed = speed_obj.speeds.get(track_id, 0) if hasattr(speed_obj, 'speeds') else 0
if track_id not in speed_over_time:
speed_over_time[track_id] = [0] * (frame_count - 1)
speed_over_time[track_id].append(speed)
if cls_name not in class_counts_over_time:
class_counts_over_time[cls_name] = [0] * frame_count
if len(class_counts_over_time[cls_name]) < frame_count:
class_counts_over_time[cls_name].extend([0] * (frame_count - len(class_counts_over_time[cls_name])))
class_counts_over_time[cls_name][-1] += 1
# 将列表填充到当前帧数以确保长度一致
pad_lists_to_length(distance_over_time, frame_count)
pad_lists_to_length(speed_over_time, frame_count)
# 在帧上绘制组合可视化
combined_frame = draw_visualizations(frame, data, labels, speed_over_time, distance_over_time, class_counts_over_time, frame_count)
# 写入带有可视化效果的帧
out.write(combined_frame)
# 清除计数以准备下一帧
data = {}
if cv2.waitKey(1) & 0xFF == ord("q"):
break
# 在最终图片上生成和叠加散点图
final_frame = np.zeros((h, w, 3), dtype=np.uint8)
scatter_plot = create_scatter_plot(class_counts_over_time)
scatter_plot_img = fig_to_img(scatter_plot)
final_frame = resize_and_place_image(final_frame, scatter_plot_img, (0, 0))
# 保存带有散点图的最终图片
cv2.imwrite("final_frame_with_scatter_plot.png", final_frame)
cap.release()
out.release()
cv2.destroyAllWindows()
# 打印总体分析
total_counts = sum(sum(counts) for counts in class_counts_over_time.values())
print(f"总体总数:{total_counts}")
for cls, counts in class_counts_over_time.items():
print(f"{cls} 的总数:{sum(counts)}")
best_speed = max((max(speeds) for speeds in speed_over_time.values()), default=0)
print(f"总体最佳速度:{best_speed} 米/秒")
best_distance = max((max(distances) for distances in distance_over_time.values()), default=0)
print(f"总体最佳距离:{best_distance} 米")
O输出:
计算机视觉探索/用户输入特定对象的视频分析.ipynb 在 main · …Eye 探索。通过在 GitHub 上创建一个帐户来参与 VK-Ant/计算机视觉探索的开发贡献。在我看来,这个模型非常适合识别物品,而且可以很容易地调整以适应特定对象。即使是对于AI或深度学习不太了解的人,这个程序也非常易于上手并且很受欢迎。
一个经常出现的重要问题是,为什么AI、深度学习和计算机视觉工程师热衷于开发这样的项目。原因多方面。这些项目为推动领域进步和解决真实世界的问题提供了非常重要的机会。我建议大家尽快开始这项任务。在这个领域的发展遵循一个共同的路径,但在物体识别和分割项目中,仍然面临许多挑战。
这些挑战包括以下:.
- 光照:光照条件的变化,例如夜间与白天的差异,会显著影响物体检测的准确性。
- 环境:不同的背景和环境会使得识别过程变得更加复杂。
3. 问题定义:正确地识别和解决正确的难题对于这些项目的成功来说至关重要。
4. 田野工作:实际在真实条件下的实施和测试十分关键,但要妥善处理却可能比较棘手。
来自网上的
只有有相关领域经验的工程师和技术开发人员才能搞定这类问题。
👀计算机视觉 | 🤔端到端计算机视觉项目💡计算机视觉是研究如何让计算机理解并处理图像和视频的学科…medium.com谢谢大家来。如果这篇文章有任何问题或错误,请留言评论。或者可以通过Kaggle上的消息或LinkedIn联系我。
参考如下:
共同学习,写下你的评论
评论加载中...
作者其他优质文章