自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

基于 OpenCV 和 Matplotlib 的物體移動(dòng)可視化

開(kāi)發(fā) 機(jī)器視覺(jué)
在本文中,我將向你展示如何結(jié)合OpenCV和Matplotlib的強(qiáng)大功能,創(chuàng)建此類(lèi)信號(hào)的實(shí)時(shí)動(dòng)畫(huà)可視化。

在計(jì)算機(jī)視覺(jué)中,一個(gè)基本目標(biāo)是從靜態(tài)圖像或視頻序列中提取有意義的信息。為了理解這些信號(hào),通常有助于對(duì)其進(jìn)行可視化。例如,在跟蹤高速公路上行駛的單個(gè)汽車(chē)時(shí),我們可以圍繞它們繪制邊界框,或者在檢測(cè)傳送帶上產(chǎn)品線(xiàn)中的問(wèn)題時(shí),我們可以使用不同的顏色來(lái)標(biāo)記異常。但是,如果提取的信息是更具數(shù)值性質(zhì)的,并且你希望可視化該信號(hào)的時(shí)間動(dòng)態(tài)呢?

僅僅在屏幕上顯示數(shù)值可能無(wú)法提供足夠的洞察力,尤其是當(dāng)信號(hào)變化迅速時(shí)。在這種情況下,可視化信號(hào)的一個(gè)好方法是帶有時(shí)間軸的圖表。在本文中,我將向你展示如何結(jié)合OpenCV和Matplotlib的強(qiáng)大功能,創(chuàng)建此類(lèi)信號(hào)的實(shí)時(shí)動(dòng)畫(huà)可視化。

繪制球的運(yùn)動(dòng)軌跡

讓我們從一個(gè)簡(jiǎn)單的示例問(wèn)題開(kāi)始,我錄制了一個(gè)球垂直向上拋出的視頻。目標(biāo)是跟蹤視頻中的球,并繪制其位置p(t)、速度v(t)和加速度a(t)隨時(shí)間的變化。

輸入視頻截圖

讓我們將參考坐標(biāo)系定義為攝像機(jī),為了簡(jiǎn)單起見(jiàn),我們只跟蹤圖像中球的垂直位置。我們期望位置呈拋物線(xiàn)形狀,速度線(xiàn)性減小,加速度保持恒定。

預(yù)期圖表的草圖

球體分割

首先,我們需要在視頻序列的每一幀中識(shí)別球體。由于攝像機(jī)保持靜止,檢測(cè)球的一個(gè)簡(jiǎn)單方法是使用背景減除模型,并結(jié)合顏色模型來(lái)去除畫(huà)面中的手。

首先,讓我們使用OpenCV的VideoCapture簡(jiǎn)單循環(huán)顯示視頻片段。我們只需在視頻片段結(jié)束時(shí)重新開(kāi)始播放。我們還通過(guò)根據(jù)視頻的FPS計(jì)算sleep_time(以毫秒為單位)來(lái)確保以原始幀速率播放視頻。最后,確保釋放資源并關(guān)閉窗口。

輸入視頻的可視化代碼:

import cv2

cap = cv2.VideoCapture("ball.mp4")
fps = int(cap.get(cv2.CAP_PROP_FPS))

while True:
    ret, frame = cap.read()
    if not ret:
        cap.set(cv2.CAP_PROP_POS_FRAMES, 0)
        continue

    cv2.imshow("Frame", frame)

    sleep_time = 1000 // fps
    key = cv2.waitKey(sleep_time) & 0xFF
    if key & 0xFF == ord("q"):
        break

cap.release()
cv2.destroyAllWindows()

讓我們先提取球的二值分割掩碼。這基本上意味著我們希望創(chuàng)建一個(gè)掩碼,該掩碼對(duì)球的像素激活,對(duì)所有其他像素不激活。為此,我將結(jié)合兩個(gè)掩碼:運(yùn)動(dòng)掩碼和顏色掩碼。運(yùn)動(dòng)掩碼提取移動(dòng)的部分,而顏色掩碼主要去除畫(huà)面中的手。對(duì)于顏色過(guò)濾器,我們可以將圖像轉(zhuǎn)換為HSV顏色空間,并選擇包含球體綠色但不含膚色色調(diào)的特定色調(diào)范圍(20–100)。我不對(duì)飽和度或亮度值進(jìn)行過(guò)濾,因此我們可以使用全范圍(0–255)。

hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
mask_color = cv2.inRange(hsv, (20, 0, 0), (100, 255, 255))

要?jiǎng)?chuàng)建運(yùn)動(dòng)掩碼,我們可以使用簡(jiǎn)單的背景減除模型。我們使用視頻的第一幀作為背景,將學(xué)習(xí)率設(shè)置為1。在循環(huán)中,我們應(yīng)用背景模型以獲取前景掩碼,但通過(guò)將學(xué)習(xí)率設(shè)置為0,不將新幀集成到其中。

bg_sub = cv2.createBackgroundSubtractorMOG2(varThreshold=50, detectShadows=False)
ret, frame0 = cap.read()
if not ret:
    print("Error: cannot read video file")
    exit(1)
bg_sub.apply(frame0, learningRate=1.0)

while True:
  ...
  mask_fg = bg_sub.apply(frame, learningRate=0)

接下來(lái),我們可以結(jié)合這兩個(gè)掩碼,并應(yīng)用開(kāi)運(yùn)算形態(tài)學(xué)操作以去除小噪聲,最終得到球的完美分割。

mask = cv2.bitwise_and(mask_color, mask_fg)
mask = cv2.morphologyEx(
    mask, cv2.MORPH_OPEN, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (13, 13))
)

跟蹤球體

現(xiàn)在我們只剩下掩碼中的球體。為了跟蹤球的中心,我首先提取球的輪廓,然后將其邊界框的中心作為參考點(diǎn)。如果某些噪聲通過(guò)了我們的掩碼,我通過(guò)大小過(guò)濾檢測(cè)到的輪廓,只關(guān)注最大的一個(gè)。

contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
if len(contours) > 0:
    largest_contour = max(contours, key=cv2.contourArea)
    x, y, w, h = cv2.boundingRect(largest_contour)
    center = (x + w // 2, y + h // 2)

我們還可以在幀中添加一些注釋以可視化檢測(cè)結(jié)果。我打算繪制兩個(gè)圓圈,一個(gè)用于中心,一個(gè)用于球的周長(zhǎng)。

cv2.circle(frame, center, 30, (255, 0, 0), 2)
cv2.circle(frame, center, 2, (255, 0, 0), 2)

為了跟蹤球的位置,我們可以使用一個(gè)列表。每當(dāng)檢測(cè)到球時(shí),我們只需將中心位置添加到列表中。我們還可以通過(guò)在跟蹤位置列表的每個(gè)段之間繪制線(xiàn)條來(lái)可視化軌跡。

tracked_pos = []


while True:
  ...

  if len(contours) > 0:
    ... 
    tracked_pos.append(center)


  # draw trajectory
  for i in range(1, len(tracked_pos)):
      cv2.line(frame, tracked_pos[i - 1], tracked_pos[i], (255, 0, 0), 1)

球體軌跡的可視化

創(chuàng)建圖表

現(xiàn)在我們可以跟蹤球了,讓我們開(kāi)始探索如何使用matplotlib繪制信號(hào)。首先,我們可以在視頻結(jié)束時(shí)創(chuàng)建最終圖表,然后在第二步中考慮如何實(shí)時(shí)動(dòng)畫(huà)化它。為了顯示位置、速度和加速度,我們可以使用三個(gè)水平對(duì)齊的子圖:

fig, axs = plt.subplots(nrows=1, ncols=3, figsize=(10, 2), dpi=100)

axs[0].set_title("Position")
axs[0].set_ylim(0, 700)
axs[1].set_title("Velocity")
axs[1].set_ylim(-200, 200)
axs[2].set_title("Acceleration")
axs[2].set_ylim(-30, 10)

for ax in axs:
    ax.set_xlim(0, 20)
    ax.grid(True)

我們只對(duì)圖像中的y位置(數(shù)組索引1)感興趣,為了獲得零偏移的位置圖,我們可以減去第一個(gè)位置。

pos0 = tracked_pos[0][1]
pos = np.array([pos0 - pos[1] for pos in tracked_pos])

對(duì)于速度,我們可以使用位置的差值作為近似值,對(duì)于加速度,我們可以使用速度的差值。

vel = np.diff(pos)
acc = np.diff(vel)

現(xiàn)在我們可以繪制這三個(gè)值:

位置、速度和加速度的靜態(tài)圖表

動(dòng)畫(huà)化圖表

現(xiàn)在進(jìn)入有趣的部分,我們希望使這個(gè)圖表動(dòng)態(tài)化!由于我們正在OpenCV的GUI循環(huán)中工作,我們不能直接使用matplotlib的show函數(shù),因?yàn)檫@會(huì)阻塞循環(huán)并且不會(huì)運(yùn)行我們的程序。相反,我們需要使用一些技巧。主要思想是將圖表繪制到內(nèi)存中的緩沖區(qū),然后在OpenCV窗口中顯示該緩沖區(qū)。通過(guò)手動(dòng)調(diào)用畫(huà)布的draw函數(shù),我們可以強(qiáng)制將圖形渲染到緩沖區(qū)。然后我們可以獲取該緩沖區(qū)并將其轉(zhuǎn)換為數(shù)組。由于緩沖區(qū)是RGB格式,而OpenCV使用BGR,我們需要轉(zhuǎn)換顏色順序。

fig.canvas.draw()

buf = fig.canvas.buffer_rgba()
plot = np.asarray(buf)
plot = cv2.cvtColor(plot, cv2.COLOR_RGB2BGR)

確保axs.plot調(diào)用現(xiàn)在位于幀循環(huán)內(nèi):

while True:
  ...

  axs[0].plot(range(len(pos)), pos, c="b")
  axs[1].plot(range(len(vel)), vel, c="b")
  axs[2].plot(range(len(acc)), acc, c="b")

  ...

現(xiàn)在我們可以使用OpenCV的imshow函數(shù)簡(jiǎn)單地顯示圖表。

cv2.imshow("Plot", plot)

為了提高性能,我們需要使用blitting技術(shù)。這是一種高級(jí)渲染技術(shù),將圖表的靜態(tài)部分繪制到背景圖像中,只重新繪制變化的動(dòng)態(tài)元素。要設(shè)置此功能,我們首先需要在幀循環(huán)之前為每個(gè)圖表定義一個(gè)引用。

pl_pos = axs[0].plot([], [], c="b")[0]
pl_vel = axs[1].plot([], [], c="b")[0]
pl_acc = axs[2].plot([], [], c="b")[0]

然后,我們需要在循環(huán)之前繪制一次圖形的背景,并獲取每個(gè)軸的背景。

fig.canvas.draw()
bg_axs = [fig.canvas.copy_from_bbox(ax.bbox) for ax in axs]

在循環(huán)中,我們現(xiàn)在可以更改每個(gè)圖表的數(shù)據(jù),然后對(duì)于每個(gè)子圖,我們需要恢復(fù)區(qū)域的背景,繪制新圖表,然后調(diào)用blit函數(shù)以應(yīng)用更改。

# Update plot data
pl_pos.set_data(range(len(pos)), pos)
pl_vel.set_data(range(len(vel)), vel)
pl_acc.set_data(range(len(acc)), acc)

# Blit Pos
fig.canvas.restore_region(bg_axs[0])
axs[0].draw_artist(pl_pos)
fig.canvas.blit(axs[0].bbox)

# Blit Vel
fig.canvas.restore_region(bg_axs[1])
axs[1].draw_artist(pl_vel)
fig.canvas.blit(axs[1].bbox)

# Blit Acc
fig.canvas.restore_region(bg_axs[2])
axs[2].draw_artist(pl_acc)
fig.canvas.blit(axs[2].bbox)

完整代碼:https://github.com/trflorian/ball-tracking-live-plot/blob/main/src/tracker.py

責(zé)任編輯:趙寧寧 來(lái)源: 小白玩轉(zhuǎn)Python
相關(guān)推薦

2024-12-24 12:00:00

Matplotlib可視化分析Python

2022-07-13 15:54:14

Matplotlib圖表

2017-10-31 09:38:53

大數(shù)據(jù)數(shù)據(jù)可視化Python

2020-03-11 14:39:26

數(shù)據(jù)可視化地圖可視化地理信息

2024-10-24 16:43:15

2018-03-15 09:57:00

PythonMatplotlib數(shù)據(jù)可視化

2015-10-29 09:36:48

2023-04-04 08:10:45

SQL數(shù)據(jù)可視化

2017-07-27 09:49:37

Python工具Matplotlib

2017-07-04 16:00:16

PythonMatplotlib可視化工具

2017-10-14 13:54:26

數(shù)據(jù)可視化數(shù)據(jù)信息可視化

2022-08-26 09:15:58

Python可視化plotly

2009-04-21 14:26:41

可視化監(jiān)控IT管理摩卡

2017-07-25 14:50:50

Rshinydashbo可視化

2013-07-31 10:14:15

炎黃盈動(dòng)BPM

2020-12-17 09:40:01

Matplotlib數(shù)據(jù)可視化命令

2020-07-16 15:20:37

MatplotlibPython可視化

2019-06-23 15:44:24

Matplotlib可視化圖表

2015-11-06 14:04:54

數(shù)據(jù)可視化信息圖

2024-02-16 08:00:00

機(jī)器學(xué)習(xí)ML-data預(yù)訓(xùn)練模型
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)