-
Notifications
You must be signed in to change notification settings - Fork 2
/
decode_video.py
executable file
·194 lines (169 loc) · 7.51 KB
/
decode_video.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
import cv2
from pyzbar.pyzbar import decode
import numpy as np
import base64
import random
QRCODE_NUMBER = 28
VIDEO_FILE = "20231007_220623.mp4"
current_frame = 0
total_frame = -1
cap = cv2.VideoCapture(VIDEO_FILE)
current_frame_data = {}
all_chunks = {}
Found_All_QR_in_Frame = False
lazy_frame = False
lazy_frame_pts = None
def bytes_with_length_prefix_to_int(b):
# Convert bytes with length prefix (Which is generated by the func [int_to_bytes_with_length_prefix()]) to int
length = b[0]
n_bytes = b[1:1+length]
n = int.from_bytes(n_bytes, 'big')
return n
def end_of_file():
#Proces last frame
for i in range(QRCODE_NUMBER - 1):
if i not in current_frame_data:
print(f"Error: Missing QR code {i} for frame {current_frame}")
exit()
print(f"------Last frame {frame_index} OK------")
for key, value in current_frame_data.items():
if key not in all_chunks:
all_chunks[key] = value
else:
all_chunks[key] += value
final_bytes = bytes()
for i in range(QRCODE_NUMBER - 1):
final_bytes += all_chunks[i]
with open('output.bin', 'wb') as f:
f.write(final_bytes)
f.close()
print("Done. The file is saved to output.bin")
cap.release()
cv2.destroyAllWindows()
exit()
pass
reset_alpha=1.5
binary_thresh=120
current_qr_start_frame_index=0
def set_random_image_parameters():
global reset_alpha
global binary_thresh
reset_alpha=random.uniform(1, 2)
binary_thresh=random.randint(90, 150)
def set_retry():
set_random_image_parameters()
cap.set(cv2.CAP_PROP_POS_FRAMES, current_qr_start_frame_index)
while True:
# Read one video frame from opencv
ret, frame = cap.read()
# frame = cv2.medianBlur(frame, 1)
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
frame = cv2.convertScaleAbs(frame, alpha=reset_alpha, beta=0)
_, frame = cv2.threshold(frame, binary_thresh, 255, cv2.THRESH_BINARY)
if not ret:
print("Error: Video reached end but end of file is not found")
break
if lazy_frame == True:
frame = frame[lazy_frame_pts[0][0][1]:lazy_frame_pts[2][0][1], lazy_frame_pts[0][0][0]:lazy_frame_pts[2][0][0]]
decoded_objects = decode(frame)
if len(decoded_objects) == 0:
set_random_image_parameters()
for obj in decoded_objects:
# Get the bytes data from the QR code
byte_data = obj.data
try:
byte_data = base64.b64decode(byte_data)
except:
continue
if(len(byte_data) < 1):
continue
hex_representation = " ".join(f"{byte:02x} " for byte in byte_data)
if(byte_data == b"EndOfData"):
print("Found end of file QR code")
end_of_file()
qr_count = int(byte_data[0])
if(int(byte_data[0]) == (QRCODE_NUMBER - 1)):
frame_index = bytes_with_length_prefix_to_int(byte_data[1:])
frame_index_len = byte_data[1]
if (total_frame == -1):
total_frame = bytes_with_length_prefix_to_int(byte_data[2 + frame_index_len:])
print(f"Sync QR: Frame index: {frame_index}/{total_frame}")
if(frame_index > current_frame):
lazy_frame = False
# New frame detected, check data for last frame
if (frame_index != current_frame + 1):
print(f"Error: Lost frame {current_frame + 1}. Current frame: {frame_index}, last frame: {current_frame}")
set_retry()
print(f"Retry from frame {current_frame} with image arg: Binary_Thresh={binary_thresh}, Alpha={reset_alpha}")
frame_ok = True
for i in range(QRCODE_NUMBER - 1):
if i not in current_frame_data:
print(f"Error: Missing QR code {i} for frame {current_frame}, will retry")
frame_ok = False
if frame_ok == True:
current_qr_start_frame_index = int(cap.get(cv2.CAP_PROP_POS_FRAMES))
print(f"------Frame {current_frame} OK------")
for key, value in current_frame_data.items():
if key not in all_chunks:
all_chunks[key] = value
else:
all_chunks[key] += value
current_frame_data = {}
current_frame = frame_index
print(f"New frame index {frame_index} detected. Set current_frame={frame_index}.")
Found_All_QR_in_Frame = False
if lazy_frame == True: # If current frame is lazy frame, go back to the last frame and redetect the current frame for the data QR codes.
cap.set(cv2.CAP_PROP_POS_FRAMES, int(cap.get(cv2.CAP_PROP_POS_FRAMES)) - 1)
else:
# Go back to the start frame
set_retry()
print(f"Retry from frame {current_frame} with image arg: Binary_Thresh={binary_thresh}, Alpha={reset_alpha}")
if(frame_index == total_frame):
print("Reached the last frame.")
else:
if(total_frame == -1):
continue # Wait for sync QR firstly
if len(current_frame_data) == QRCODE_NUMBER - 1:
Found_All_QR_in_Frame = True
continue # We already got all the QR codes for this frame
chunk_index = int(byte_data[0])
chunk_frame = bytes_with_length_prefix_to_int(byte_data[1:])
if (chunk_frame == current_frame):
if chunk_index not in current_frame_data:
prefix_len = 2 + int(byte_data[1])
chunk_data = byte_data[prefix_len:]
chunk_data_len = chunk_data[0]
chunk_data = chunk_data[1:1+chunk_data_len]
if chunk_index == 12 and chunk_frame == 125:
pass
if chunk_index == 12 and chunk_frame == 126:
pass
if(len(chunk_data) != chunk_data_len):
print(f"Error: Wrong chunk data length: {len(chunk_data)} != {chunk_data_len} in QR code {chunk_index} for frame {current_frame}")
exit()
current_frame_data[chunk_index] = chunk_data
print(f"Adding QR code {chunk_index} for frame:{current_frame}/{total_frame}, QR:{len(current_frame_data)}/{QRCODE_NUMBER - 1}, chunk size: {chunk_data_len}")
else:
print(f"Warning: Wrong frame index: {chunk_frame} != {current_frame} in QR code {chunk_index}, ignored!")
# Draw the bounding box
pts = obj.polygon
if len(pts) == 4: # If found 4 corners of QR code
pts = np.array(pts, dtype=np.int32)
pts = pts.reshape((-1, 1, 2))
color = (0, 0, 255)
if(Found_All_QR_in_Frame):
color = (0, 255, 0)
if(lazy_frame == False):
lazy_frame_pts = pts.copy()
lazy_frame_pts[0][0][1] -= 100
lazy_frame_pts[2][0][1] += 100
lazy_frame_pts[0][0][0] -= 100
lazy_frame_pts[2][0][0] += 100
lazy_frame = True
cv2.polylines(frame, [pts], True, color, 2)
cv2.imshow('Frame', frame)
# Press q on keyboard to exit
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()