Python OpenCV 视频图像熵的奇怪结果

Python OpenCV Strange result for image entropy on video

我正在从事一个项目,旨在使用不同的概念从 mp4 视频中提取“有趣”的序列。

其中一个应该是图像熵,现在,我有点卡住了。

我已经按照本教程从视频中获取了一些选定屏幕截图的熵: https://scikit-image.org/docs/dev/auto_examples/filters/plot_entropy.html

为此,我得到了如下结果 this one 这就是我想要的。

为了将其应用于我的测试视频,我执行了以下操作:

import cv2
from skimage.filters.rank import entropy
from skimage.morphology import disk

# Creating a VideoCapture object to read the video
video = cv2.VideoCapture('mypath/samplevideo.mp4')

if not video.isOpened():
    print("Error reading video file")

width = int(video.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(video.get(cv2.CAP_PROP_FRAME_HEIGHT))
size = (width, height)
fourcc = cv2.VideoWriter_fourcc(*'XVID')

result = cv2.VideoWriter('filename.avi', cv2.VideoWriter_fourcc(*'VIDX'), 30, size)
# Loop until the end of the video
while video.isOpened():
    # Capture frame-by-frame
    ret, frame = video.read()

    # Display the resulting frame
    cv2.imshow('Frame', frame)

    # apply the entropy to each frame
    img = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    entropy_frame = entropy(img, disk(5))
    cv2.imshow('Entropy', entropy_frame)

    result.write(entropy_frame)
    # define q as the exit button
    if cv2.waitKey(25) & 0xFF == ord('q'):
        break

# release the video capture object
video.release()
result.release()
# Closes all the windows currently opened.
cv2.destroyAllWindows()

此代码生成两个 windows,一个包含原始视频(根据需要),另一个应该显示相同的视频但应用了图像熵。最后,它应该保存熵视频。我现在在“熵 window”中得到的是 something like this (left is the original video, right the entropy),它看起来根本不像我想要的结果。

我可以修正什么以获得我想要的结果? 提前致谢

你得到了奇怪的结果,因为 entropy_frame 的范围大约是 [0, 6.0]。
您需要将范围转换为 [0, 255] 并将结果从 float 转换为 uint8.

进行范围转换的一种简单方法是乘以 (255/max(entropy_mat)):

entropy_frame = (entropy_mat * 255/np.max(entropy_mat)).astype(np.uint8)

注:
example使用matplotlib方法ax1.imshow,自动进行线性拉伸显示,所以显示正确(但不能作为视频帧使用)。


这里是一个单帧的例子:

import numpy as np
import cv2
from skimage.filters.rank import entropy
from skimage.morphology import disk

frame = cv2.imread('frame.png')

# Display the resulting frame
cv2.imshow('Frame', frame)

# apply the entropy to each frame
img = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
entropy_mat = entropy(img, disk(5))  # Range is about [0, 6]

# Apply linear stretching - lower 1% goes to 0, and maximum 1% goes to 255
# lo_val, up_val = np.percentile(entropy_mat, (1, 99))  # Get the value of lower and upper 1% of all pixels [0, 5.48]
# 
# entropy_frame = np.clip((entropy_mat - lo_val)*(255/(up_val - lo_val)), 0, 255).astype(np.uint8)

# Or simply multiply by 255/np.max(entropy_mat)
entropy_frame = (entropy_mat * 255/np.max(entropy_mat)).astype(np.uint8)

cv2.imshow('Entropy', entropy_frame)

cv2.imwrite('entropy_frame.png', entropy_frame)

cv2.waitKey()
cv2.destroyAllWindows()

备注:

  • 修改cv2.VideoWriter_fourcc(*'VIDX')cv2.VideoWriter_fourcc(*'XVID')('VIDX'显示错误信息)

  • entropy_frame 是灰度图像。
    您需要将 VideoWriter isColor 参数设置为 False:

     result = cv2.VideoWriter('filename.avi', cv2.VideoWriter_fourcc(*'VIDX'), 30, size, isColor=False)
    
  • 如果 retFalse,您需要打破循环:

     if not ret:
         break
    

结果:


完整代码:

import numpy as np
import cv2
from skimage.filters.rank import entropy
from skimage.morphology import disk

# Creating a VideoCapture object to read the video
video = cv2.VideoCapture('mypath/samplevideo.mp4')

if not video.isOpened():
    print("Error reading video file")

width = int(video.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(video.get(cv2.CAP_PROP_FRAME_HEIGHT))
size = (width, height)
fourcc = cv2.VideoWriter_fourcc(*'XVID')

result = cv2.VideoWriter('filename.avi', cv2.VideoWriter_fourcc(*'XVID'), 30, size, isColor=False)
# Loop until the end of the video
while video.isOpened():
    # Capture frame-by-frame
    ret, frame = video.read()

    if not ret:
        break  # Break the loop if ret is false (last video frame).

    # Display the resulting frame
    cv2.imshow('Frame', frame)

    # apply the entropy to each frame
    img = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    entropy_mat = entropy(img, disk(5))
    entropy_frame = (entropy_mat * 255/np.max(entropy_mat)).astype(np.uint8)
    cv2.imshow('Entropy', entropy_frame)

    result.write(entropy_frame)
    # define q as the exit button
    if cv2.waitKey(25) & 0xFF == ord('q'):
        break

# release the video capture object
video.release()
result.release()
# Closes all the windows currently opened.
cv2.destroyAllWindows()