使用 OpenCV 和 Python 在视频上应用热图
Apply heatmap on video with OpenCV and Python
我想编写一个代码,在视频中有运动的地方应用热图。
我写了一个检测运动的代码,有轮廓,但我不知道如何制作热图。
这是我的代码
import cv2
import numpy as np
# upload video
cap = cv2.VideoCapture('test_video.mp4')
#reading two frames
ret, frame1 = cap.read()
ret, frame2 = cap.read()
while cap.isOpened():
# get diference between two frames
diff = cv2.absdiff(frame1, frame2)
# convert diference in gray
gray = cv2.cvtColor(diff, cv2.COLOR_BGR2GRAY)
# bluring and treshold
blur = cv2.GaussianBlur(gray, (5,5), 0)
_, thresh = cv2.threshold(blur, 20, 255, cv2.THRESH_BINARY)
dilated = cv2.dilate(thresh, None, iterations = 3)
# define contours
contours, _ = cv2.findContours(dilated, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# draw contours
cv2.drawContours(frame1, contours, -1, (255,0,0), 1)
# show frames
cv2.imshow('frame', frame1)
frame1 = frame2
ret, frame2 = cap.read()
if cv2.waitKey(60) == 60:
break
cv2.destroyAllWindows()
cap.release()
我看过这个 link:Build a Motion Heatmap Video Using OpenCV With Python。而且我想重现代码,但是很多东西,比如fourcc
,image_folder
,和images
都没有定义,所以我试着用另一种方式来做。
你能帮我解决这个问题吗?基本上,我想将热图应用于有运动的视频。
这是一个想法。您知道如何使用 opencv 遍历视频的帧,对吗?那么,对于 while
循环所在的每一帧,将当前帧之后的帧存储在一个变量中,并比较当前帧和未来帧之间的差异。
通过两帧之间的差异,您可以检测到运动的轮廓。假设我们用绿色在图像上绘制轮廓。
在while
循环之前定义一个空白数组作为热图;循环的每次迭代,在帧上坐标为绿色的热图的每个坐标上添加一定量,并从图像上坐标不是绿色的热图中移除一定量。
- 导入必要的模块:
import cv2
import numpy as np
- 定义一个函数来处理两帧之间的差异,以便更好地检测我们案例的轮廓。这些值可以根据您的需要进行调整:
def process(img):
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
img_blur = cv2.GaussianBlur(img_gray, (5, 5), 25)
img_canny = cv2.Canny(img_blur, 5, 50)
kernel = np.ones((3, 3))
img_dilate = cv2.dilate(img_canny, kernel, iterations=4)
img_erode = cv2.erode(img_dilate, kernel, iterations=1)
return img_erode
- 定义一个函数,它将接收两帧之间差异的处理图像,以及要在其上绘制轮廓的图像。它将 return 上面绘制了轮廓(绿色)的图像:
def get_contours(img, img_original):
img_contours = img_original.copy()
contours, hierarchies = cv2.findContours(img, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
cv2.drawContours(img_contours, contours, -1, (0, 255, 0), -1)
return img_contours
- 定义你的捕获设备,并在
while
循环之前读取两帧;第一个是 while
循环每次迭代的当前帧,第二个是 while
循环每次迭代的未来帧。另外,为热图定义空白图像,heat_map
:
cap = cv2.VideoCapture("Bar fight security cam.mp4")
success, img1 = cap.read()
success, img2 = cap.read()
heat_map = np.zeros(img1.shape[:-1])
- 在
while
循环中,找出两帧之间的差异,并得到每个循环的当前帧,并根据差异绘制轮廓:
while success:
diff = cv2.absdiff(img1, img2)
img_contours = get_contours(process(diff), img1)
- 添加一个数字,比如
3
,到 heat_map
的每个坐标,在图像 return 之前定义的 get_contours
图像上它是绿色的,并从图像上不是绿色的 heat_map
的每个坐标中减去 3。为确保没有颜色导致通道值小于 0
和大于 255
,请将边界应用于热图:
heat_map[np.all(img_contours == [0, 255, 0], 2)] += 3
heat_map[np.any(img_contours != [0, 255, 0], 2)] -= 3
heat_map[heat_map < 0] = 0
heat_map[heat_map > 255] = 255
- 将
heat_map
数组转为灰度图,再转为热ma图:
img_mapped = cv2.applyColorMap(heat_map.astype('uint8'), cv2.COLORMAP_JET)
- 最后,显示帧并为下一次迭代检索帧:
cv2.imshow("Original", img1)
cv2.imshow("Heat Map", img_mapped)
img1 = img2
success, img2 = cap.read()
if cv2.waitKey(1) == ord('q'):
break
一共:
import cv2
import numpy as np
def process(img):
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
img_blur = cv2.GaussianBlur(img_gray, (5, 5), 25)
img_canny = cv2.Canny(img_blur, 5, 50)
kernel = np.ones((3, 3))
img_dilate = cv2.dilate(img_canny, kernel, iterations=4)
img_erode = cv2.erode(img_dilate, kernel, iterations=1)
return img_erode
def get_contours(img, img_original):
img_contours = img_original.copy()
contours, hierarchies = cv2.findContours(img, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
cv2.drawContours(img_contours, contours, -1, (0, 255, 0), -1)
# If you want to omit smaller contours, loop through the detected contours, and only draw them on the image if they are at least a specific area. Don't forget to remove the line above if you choose the below block of code.
# for cnt in contours:
# if cv2.contourArea(cnt) > 500:
# cv2.drawContours(img_contours, [cnt], -1, (0, 255, 0), -1)
return img_contours
cap = cv2.VideoCapture("Bar fight security cam.mp4")
success, img1 = cap.read()
success, img2 = cap.read()
heat_map = np.zeros(img1.shape[:-1])
while success:
diff = cv2.absdiff(img1, img2)
img_contours = get_contours(process(diff), img1)
heat_map[np.all(img_contours == [0, 255, 0], 2)] += 3 # The 3 can be tweaked depending on how fast you want the colors to respond
heat_map[np.any(img_contours != [0, 255, 0], 2)] -= 3
heat_map[heat_map < 0] = 0
heat_map[heat_map > 255] = 255
img_mapped = cv2.applyColorMap(heat_map.astype('uint8'), cv2.COLORMAP_JET)
# img1[heat_map > 160] = img_mapped[heat_map > 160] Use this line to draw the heat map on the original video at a specific temperature range. For this it's where ever the temperature is above 160 (min is 0 and max is 255)
cv2.imshow("Original", img1)
cv2.imshow("Heat Map", img_mapped)
img1 = img2
success, img2 = cap.read()
if cv2.waitKey(1) == ord('q'):
break
我想编写一个代码,在视频中有运动的地方应用热图。 我写了一个检测运动的代码,有轮廓,但我不知道如何制作热图。
这是我的代码
import cv2
import numpy as np
# upload video
cap = cv2.VideoCapture('test_video.mp4')
#reading two frames
ret, frame1 = cap.read()
ret, frame2 = cap.read()
while cap.isOpened():
# get diference between two frames
diff = cv2.absdiff(frame1, frame2)
# convert diference in gray
gray = cv2.cvtColor(diff, cv2.COLOR_BGR2GRAY)
# bluring and treshold
blur = cv2.GaussianBlur(gray, (5,5), 0)
_, thresh = cv2.threshold(blur, 20, 255, cv2.THRESH_BINARY)
dilated = cv2.dilate(thresh, None, iterations = 3)
# define contours
contours, _ = cv2.findContours(dilated, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# draw contours
cv2.drawContours(frame1, contours, -1, (255,0,0), 1)
# show frames
cv2.imshow('frame', frame1)
frame1 = frame2
ret, frame2 = cap.read()
if cv2.waitKey(60) == 60:
break
cv2.destroyAllWindows()
cap.release()
我看过这个 link:Build a Motion Heatmap Video Using OpenCV With Python。而且我想重现代码,但是很多东西,比如fourcc
,image_folder
,和images
都没有定义,所以我试着用另一种方式来做。
你能帮我解决这个问题吗?基本上,我想将热图应用于有运动的视频。
这是一个想法。您知道如何使用 opencv 遍历视频的帧,对吗?那么,对于 while
循环所在的每一帧,将当前帧之后的帧存储在一个变量中,并比较当前帧和未来帧之间的差异。
通过两帧之间的差异,您可以检测到运动的轮廓。假设我们用绿色在图像上绘制轮廓。
在while
循环之前定义一个空白数组作为热图;循环的每次迭代,在帧上坐标为绿色的热图的每个坐标上添加一定量,并从图像上坐标不是绿色的热图中移除一定量。
- 导入必要的模块:
import cv2
import numpy as np
- 定义一个函数来处理两帧之间的差异,以便更好地检测我们案例的轮廓。这些值可以根据您的需要进行调整:
def process(img):
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
img_blur = cv2.GaussianBlur(img_gray, (5, 5), 25)
img_canny = cv2.Canny(img_blur, 5, 50)
kernel = np.ones((3, 3))
img_dilate = cv2.dilate(img_canny, kernel, iterations=4)
img_erode = cv2.erode(img_dilate, kernel, iterations=1)
return img_erode
- 定义一个函数,它将接收两帧之间差异的处理图像,以及要在其上绘制轮廓的图像。它将 return 上面绘制了轮廓(绿色)的图像:
def get_contours(img, img_original):
img_contours = img_original.copy()
contours, hierarchies = cv2.findContours(img, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
cv2.drawContours(img_contours, contours, -1, (0, 255, 0), -1)
return img_contours
- 定义你的捕获设备,并在
while
循环之前读取两帧;第一个是while
循环每次迭代的当前帧,第二个是while
循环每次迭代的未来帧。另外,为热图定义空白图像,heat_map
:
cap = cv2.VideoCapture("Bar fight security cam.mp4")
success, img1 = cap.read()
success, img2 = cap.read()
heat_map = np.zeros(img1.shape[:-1])
- 在
while
循环中,找出两帧之间的差异,并得到每个循环的当前帧,并根据差异绘制轮廓:
while success:
diff = cv2.absdiff(img1, img2)
img_contours = get_contours(process(diff), img1)
- 添加一个数字,比如
3
,到heat_map
的每个坐标,在图像 return 之前定义的get_contours
图像上它是绿色的,并从图像上不是绿色的heat_map
的每个坐标中减去 3。为确保没有颜色导致通道值小于0
和大于255
,请将边界应用于热图:
heat_map[np.all(img_contours == [0, 255, 0], 2)] += 3
heat_map[np.any(img_contours != [0, 255, 0], 2)] -= 3
heat_map[heat_map < 0] = 0
heat_map[heat_map > 255] = 255
- 将
heat_map
数组转为灰度图,再转为热ma图:
img_mapped = cv2.applyColorMap(heat_map.astype('uint8'), cv2.COLORMAP_JET)
- 最后,显示帧并为下一次迭代检索帧:
cv2.imshow("Original", img1)
cv2.imshow("Heat Map", img_mapped)
img1 = img2
success, img2 = cap.read()
if cv2.waitKey(1) == ord('q'):
break
一共:
import cv2
import numpy as np
def process(img):
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
img_blur = cv2.GaussianBlur(img_gray, (5, 5), 25)
img_canny = cv2.Canny(img_blur, 5, 50)
kernel = np.ones((3, 3))
img_dilate = cv2.dilate(img_canny, kernel, iterations=4)
img_erode = cv2.erode(img_dilate, kernel, iterations=1)
return img_erode
def get_contours(img, img_original):
img_contours = img_original.copy()
contours, hierarchies = cv2.findContours(img, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
cv2.drawContours(img_contours, contours, -1, (0, 255, 0), -1)
# If you want to omit smaller contours, loop through the detected contours, and only draw them on the image if they are at least a specific area. Don't forget to remove the line above if you choose the below block of code.
# for cnt in contours:
# if cv2.contourArea(cnt) > 500:
# cv2.drawContours(img_contours, [cnt], -1, (0, 255, 0), -1)
return img_contours
cap = cv2.VideoCapture("Bar fight security cam.mp4")
success, img1 = cap.read()
success, img2 = cap.read()
heat_map = np.zeros(img1.shape[:-1])
while success:
diff = cv2.absdiff(img1, img2)
img_contours = get_contours(process(diff), img1)
heat_map[np.all(img_contours == [0, 255, 0], 2)] += 3 # The 3 can be tweaked depending on how fast you want the colors to respond
heat_map[np.any(img_contours != [0, 255, 0], 2)] -= 3
heat_map[heat_map < 0] = 0
heat_map[heat_map > 255] = 255
img_mapped = cv2.applyColorMap(heat_map.astype('uint8'), cv2.COLORMAP_JET)
# img1[heat_map > 160] = img_mapped[heat_map > 160] Use this line to draw the heat map on the original video at a specific temperature range. For this it's where ever the temperature is above 160 (min is 0 and max is 255)
cv2.imshow("Original", img1)
cv2.imshow("Heat Map", img_mapped)
img1 = img2
success, img2 = cap.read()
if cv2.waitKey(1) == ord('q'):
break