You want to display an interactive graph while receiving webcam frames.
-
- You can use
plt.ion(). The ion() method updates the graph while receiving inputs.
-
- How to get frames for each second?
We can calculate the fps (frame-per-second) value. For instance, if the fps value is 5, then 5 frames duration is equal to the 1 second.
We can count the frames using a variable and check whether the variable equals the fps. Then we add the frames.
-
if frame_count % fps == 0:
b, g, r = cv2.split(frame)
line = [line for line in zip(b, g, r) if len(line)]
xs.append(second)
blue.append(np.mean(line[0]))
green.append(np.mean(line[1]))
red.append(np.mean(line[2]))
You may ask Why not using time.time for calculating the seconds?
I think using fps is more reliable than using time.time. I wanted to guarantee to get frames for each second.
Result:

I've obtained the result from the command prompt. If you debug it, you may get multiple images instead of one updated image.
Update-1
If you want to separate the channels you can multiply the each calculated variance with a different coefficient:
blue.append(np.var(line[0])*0.02)
green.append(np.var(line[1])*0.03)
red.append(np.var(line[2])*0.04)
Result:

blue.append(np.mean(line[0])*0.02)
green.append(np.mean(line[1])*0.03)
red.append(np.mean(line[2])*0.04)
Result:

Update-2
If you want to write the output data to the excel, you can use the xlsxwriter library.
You can install:
- pip environment:
pip install xlsxwriter
- anaconda environment:
conda install -c anaconda xlsxwriter
Three-steps:
Output:

Update-3
We were using red, green, blue, xs list structures for storing frames and seconds for both displaying and writing to the excel file.
As frame data increases the list structures become a burden for real-time processing. Therefore one solution is dividing the displaying and writing operations.
For displaying: b_frame, g_frame, r_frame, and s_frame are used.
For writing to excel: blue, green, red, and xs are used.
The main advantage is now we can reduce the storage for displaying frames. Since we are storing in blue, green, red, and xs.
For instance: after two seconds delete the first frames.
del b_frame[0]
del g_frame[0]
del r_frame[0]
del s_frame[0]
Since the b_frame, g_frame, r_frame, and s_frame are no longer containing all the frames. The system speeds-up.
Update-4
VideoCapture blocks the application while the next frame is read, decode, and returned. Most probably this is the reason for the frozen camera.
One option is using VideoStream which process read, decode, and return actions concurrently by using queue structure.
To install imutils
- For pip:
pip install imutils
- For anaconda:
conda install -c conda-forge imutils
Example:
from imutils.video import VideoStream
vs = VideoStream().start()
while True:
frame = vs.read()
if frame is None:
break
.
.
vs.stop()
I tested VideoStream and there were no frozen frames or pause during the application.
Code:
import cv2
import numpy as np
import matplotlib.pyplot as plt
from imutils.video import VideoStream
from xlsxwriter import Workbook
fig = plt.figure()
plt.ion() # Set interactive mode on
xs = []
blue = []
red = []
green = []
b_frame = []
g_frame = []
r_frame = []
s_frame = []
# We will be using Video-capture to get the fps value.
capture = cv2.VideoCapture(0)
fps = capture.get(cv2.CAP_PROP_FPS)
capture.release()
# New module: VideoStream
vs = VideoStream().start()
frame_count = 0
second = 1
is_new_frame = False
while True:
frame = vs.read()
if frame is None:
break
if frame_count % int(fps) == 0:
b, g, r = cv2.split(frame)
is_new_frame = True # New frame has come
line = [line for line in zip(b, g, r) if len(line)]
s_frame.append(second)
b_frame.append(np.mean(line[0]) * 0.02)
g_frame.append(np.mean(line[1]) * 0.03)
r_frame.append(np.mean(line[2]) * 0.04)
plt.plot(s_frame, b_frame, 'b', label='blue', lw=7)
plt.plot(s_frame, g_frame, 'g', label='green', lw=4)
plt.plot(s_frame, r_frame, 'r', label='red')
plt.xlabel('seconds')
plt.ylabel('mean')
if frame_count == 0:
plt.legend()
plt.show()
second += 1
elif second > 2:
if is_new_frame:
if second == 3:
blue.extend(b_frame)
green.extend(g_frame)
red.extend(r_frame)
xs.extend(s_frame)
else:
blue.append(b_frame[len(b_frame)-1])
green.append(g_frame[len(g_frame)-1])
red.append(r_frame[len(r_frame)-1])
xs.append(s_frame[len(s_frame)-1])
del b_frame[0]
del g_frame[0]
del r_frame[0]
del s_frame[0]
is_new_frame = False # we added the new frame to our list structure
cv2.imshow('Frame', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
frame_count += 1
cv2.destroyAllWindows()
capture.release()
vs.stop()
book = Workbook('Channel.xlsx')
sheet = book.add_worksheet()
row = 0
col = 0
sheet.write(row, col, 'Seconds')
sheet.write(row + 1, col, 'Blue mean')
sheet.write(row + 2, col, 'Green mean')
sheet.write(row + 3, col, 'Red mean')
col += 1
for s, b, g, r in zip(xs, blue, green, red):
sheet.write(row, col, s)
sheet.write(row + 1, col, b)
sheet.write(row + 2, col, g)
sheet.write(row + 3, col, r)
col += 1
book.close()