I'm currently working on a project that takes in a video file, reads individual frames as grayscale, normalizes them, thresholds them, and then outputs them as individual .jpg files. Below I have two functions, frameCapture()
and frameCaptureMulti()
. The former uses cv2.threshold
and cv2.THRESH_OTSU
and works as intended. The latter uses threshold_multiotsu()
from skimage.filters
and outputs completely black frames.
import cv2
import numpy as np
from skimage.filters import threshold_multiotsu
def frameCapture(fc_path):
fc_vidObj = cv2.VideoCapture(fc_path) # Path to video file
fc_count = 0 # Used as counter variable
fc_success = 1 # Checks if the frames were extracted
while fc_success:
# vidObj object calls read
fc_success, fc_image = fc_vidObj.read()
fc_image = cv2.cvtColor(fc_image, cv2.COLOR_BGR2GRAY) # Convert the image to grayscale
fc_image = cv2.GaussianBlur(fc_image,(5,5),0) # Gaussian noise filtering
(threshold, fc_image) = cv2.threshold(fc_image, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU) # Normalize & Segment
cv2.imwrite("frame%d.jpg" % fc_count, fc_image) # Saves the frames
fc_count += 1
def frameCaptureMulti(fc_path):
fc_vidObj = cv2.VideoCapture(fc_path) # Path to video file
fc_count = 0 # Used as counter variable
fc_success = 1 # Checks if the frames were extracted
while fc_success:
# vidObj object calls read
fc_success, fc_image = fc_vidObj.read()
fc_image = cv2.cvtColor(fc_image, cv2.COLOR_BGR2GRAY) # Convert the image to grayscale
fc_image = cv2.GaussianBlur(fc_image,(5,5),0) # Gaussian noise filtering
fc_thresholds = threshold_multiotsu(fc_image)
fc_regions = np.digitize(fc_image, bins=fc_thresholds)
cv2.imwrite("frame%d.jpg" % fc_count, fc_regions) # Saves the frames
fc_count += 1
The driver code simply runs frameCaptureMulti() on a .mp4 file on my computer.
Here's what the frames look like:
frameCapture()
output
I am not sure why frameCaptureMulti()
produces pure black frames. I only have a few weeks experience with Python (outside of learning about ten years ago) and even less with these particular libraries, so any help as to why my code isn't producing expected output is welcome.
Pages referenced for portions of code in frameCapture and frameCaptureMulti:
https://scikit-image.org/docs/dev/auto_examples/segmentation/plot_multiotsu.html
https://www.geeksforgeeks.org/python-program-extract-frames-using-opencv/
I think what's happening is that CV2 gives you a binary image that is correctly saved as a frame with 0 under the threshold and 255 (white) above it. Meanwhile, threshold_multiotsu
and np.digitize
return an image with values 0, 1, 2, all of which look black in the 0-255 range supported by jpeg. You could use skimage.exposure.rescale_intensity
to map those values to e.g. 0, 127, 255.