PaliGemma模型以其较小的规模(三十亿参数)、商业使用条款的支持以及微调能力,成为计算机视觉任务中令人兴奋的模型。作为一名计算机视觉应用开发者,对这款模型在实际应用中可能带来的改进充满好奇。让通过构建一个应用来一探究竟。
为了展示PaliGemma模型的优势,将构建一个车辆分析应用。该应用将检测车辆,分析车辆信息(包括品牌、颜色和款式),读取车牌号,并将这些信息保存到电子表格中以供历史查看。以下是运行中的应用程序的一个小预览。
为了构建这个应用,需要将问题分解为几个较小的步骤,并讨论系统的一些要求。
希望应用能够实时运行,并能够在硬件上自行托管。
在这个应用中,将使用一个微调过的Yolov8模型来检测车牌和车辆。使用Roboflow自动标记数据,并在30分钟内训练了一个模型。然后,使用推理来在模型上运行视频流。还将使用Supervision包作为计算机视觉瑞士军刀,以显示边界框并使用cv2显示帧。
from inference import InferencePipeline
import supervision as sv
import cv2
bb = sv.BoundingBoxAnnotator()
def call_back(results, frame):
detections = sv.Detections.from_inference(results)
annotated_frame = bb.annotate(
scene=frame.image.copy(),
detections=detections,
)
cv2.imshow("Vehicle Analytics", annotated_frame)
cv2.waitKey(1)
pipeline = InferencePipeline.init(
model_id="vehicle-recognition-z5mpj/4",
api_key="ROBOFLOW_API_KEY",
video_reference=["output.MOV"],
on_prediction=call_back,
)
pipeline.start()
pipeline.join()
这部分应用是最复杂的,因此让一步一步地进行。首先,需要一个机制来跟踪独特车辆,并在这些特定检测上触发分类和OCR任务。为了给PaliGemma一个更高的机会进行准确的OCR和分类任务,希望在车辆清晰可见时抓住车辆的一帧。为此,将使用ByteTrack在车辆进入视频最右侧的多边形区域时保存独特车辆。
import numpy as np
import threading
...
tracker = sv.ByteTrack()
detection_polygon = np.array([[717, 6], [717, 1270], [681, 1271], [683, 9], [714, 9]])
detection_zone = sv.PolygonZone(polygon=detection_polygon, triggering_anchors=(sv.Position.BOTTOM_RIGHT,))
unique_cars = set()
def background_task(results, frame):
print(results, frame)
def call_back(results, frame):
...
tracked_detections = tracker.update_with_detections(detections)
detected_cars = tracked_detections[tracked_detections.class_id == 2]
cars_in_zone = detected_cars[detection_zone.trigger(detected_cars)]
global unique_cars
for car in cars_in_zone.tracker_id:
if not car in unique_cars:
unique_cars.add(car)
background_thread = threading.Thread(target=backgroud_task, args=(results, frame))
...
现在到了有趣的部分!将使用推理来加载PaliGemma权重,并利用该模型进行分类和OCR任务!首先,让确保已经安装了正确的依赖项,按照Roboflow PaliGemma训练笔记本中的设置步骤进行。由于这个模型是一个VLM,可以通过传递一个图像和一个提示来与之交互。注意,在初次运行时,下载权重需要几分钟。
from inference.models.paligemma.paligemma import PaliGemma
...
pg = PaliGemma(api_key="ROBOFLOW_API_KEY")
def call_pali(prompt, image):
global pg
response = pg.predict(image, prompt)
return response[0]
...
现在已经有一个使用PaliGemma的机制,让看看分类和OCR任务是什么样子的。只需将车辆和车牌裁剪传递给函数`call_pali`,并提出具体的问题。在这里,可以尝试调整提示,但发现下面的方法对这种用例效果很好。
def background_task(results, frame):
... # 之前的代码
color = call_pali("What color is the car?", vehicle_img)
brand = call_pali("car make", vehicle_img)
car_type = call_pali("car;van;suv;truck", vehicle_img)
plate = call_pali("read", plate_img)
print(color, brand, car_type)
最后,将裁剪结果保存到一个名为vehicles的目录中。还将创建一个CSV文件来保存数据。
import csv
report = "path_to_csv.csv"
with open(report, mode="w", newline='') as f:
fieldnames = ["Color", "Brand", "Car Type", "Plate"]
writer = csv.DictWriter(f, fieldnames=fieldnames)
writer.writeheader()
def background_task(results, frame):
... # 之前的代码
with open(report, mode="a", newline='') as f:
fieldnames = ["Color", "Brand", "Car Type", "Plate"]
data = [{"Color": color, "Brand":brand, "Car Type": car_type, "Plate": plate}]
writer = csv.DictWriter(f, fieldnames=fieldnames)
writer.writerows(data)
file_name = f"./vehicles/{color}-{brand}-{car_type}-{plate}.jpg"
combined_img.save(file_name)
做到了!一个本地托管的实时车辆分析应用。在PaliGemma之前,可能会选择使用CLIP来完成分类任务,以及使用众多OCR模型之一来读取车牌。有了PaliGemma,可以减少使用的模型数量,同时也简化了逻辑。还认为,这个演示完全在硬件上以近乎实时的速度运行,使用Nvidia RTX 3090,这是相当不可思议的。预测,这些VLM将随着时间的推移不断变得更好,硬件也会变得更便宜,这将解锁今天略有难度的企业级和业余爱好者应用。