Skip to content

Commit c7589d1

Browse files
authored
Updated the program
Fixed the program (it breaks when the input file perfectly matches (or is a multiple of) the amount of bits each frame contains) Cleaned up the excessive comments
1 parent f69d339 commit c7589d1

File tree

2 files changed

+101
-82
lines changed

2 files changed

+101
-82
lines changed

Dec.py

Lines changed: 33 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,44 @@
1-
import cv2 #imports opencv, make sure that you have opencv installed
2-
import numpy as np #imports numpy and makes it callable with np cus lazy
1+
import cv2
2+
import numpy as np
33

44
def decode_video(video_path, output_file_path, width=1280, height=720, pix=5): #set this exactly like how you set the encoding, otherwise it breaks
5-
video_reader = cv2.VideoCapture(video_path) #initialize the video reader
6-
binary_data = '' #declares binary_data
7-
index = 0 #declares index, it
8-
add = int(width * height / (pix * pix)) #declares add and makes it the amount that needs to be added for each time a frame is completed
9-
m = True #declares m to check if the 1st frame has been read, m=True = no, m=False = yes
5+
video_reader = cv2.VideoCapture(video_path)
6+
binary_data = ''
7+
index = 0 #counter of the bits already converted
8+
add = int(width * height / (pix * pix))
9+
m = 1 #declares m to check if the 1st frame has been read, m=1 = no, m=0 = yes
1010
with open(output_file_path, 'ab') as output_file: #declares output_file as the output file, and makes every write function append data
11-
while True: #loop forever
11+
while True:
1212
ret, frame = video_reader.read() #ret = if the frame exsists or not, frame = the frame data itself
13-
if not ret: #if the frame doesn't exsist break
14-
print("a") #prints a if the condition is true, so if you see an a the video may be fried of you just reached the end (the latter is 100000000000 times more likely)
15-
break #breaks if the condition is true
16-
frame = cv2.resize(frame, (int(width / pix), int(height / pix)), interpolation=cv2.INTER_NEAREST) #resize the frame so that each bit is 1 pixel wide
13+
if not ret:
14+
print("finished") #prints this if it finished going through the video
15+
break
16+
frame = cv2.resize(frame, (int(width / pix), int(height / pix)), interpolation=cv2.INTER_NEAREST) #resize the frame so that each bit is 1 pixel wide, in the encoder each pixel is much wider to resist compression
1717
if frame.size == 0: #if the frame is corrupt it breaks
18-
break #it breaks if the frame is corrupt
18+
break
1919
intensity = np.mean(frame, axis=(2 if len(frame.shape) == 3 else 0))
20-
index += add #adds the amount of bits it has already converted
21-
print(index) #prints the amount of bits it has converted in the 1st frame
22-
if m == False: #checks if the 1st frame has already been done
20+
index += add
21+
print(index)
22+
if m == 0:
2323
binary_data = ''.join(np.where(intensity.flatten() > 127, '1', '0').astype(str)) #writes the data in the frame into a variable
2424
binary_array = np.array([int(bit) for bit in binary_data]) #transforms the data into an array
2525
bytes_array = np.packbits(binary_array) #transforms the binary array into a bytes array
26-
output_file.write(bytes_array) #appends the bytes array (the data itself)
27-
if m == True: #checks if the 1st frame has not been done
28-
binary_data = ''.join(np.where(intensity.flatten() > 127, '1', '0').astype(str)) #writes the data in the frame into a variable
29-
first_one_index = binary_data.find('1') #checks where the 1st 1 is in the 1st frame
30-
binary_data = binary_data[first_one_index + 1:] #scraps all the data including the extra 1
31-
binary_array = np.array([int(bit) for bit in binary_data]) #transforms the data into an array
32-
bytes_array = np.packbits(binary_array) #transforms the binary array into a bytes array
33-
output_file.write(bytes_array)#appends the bytes array (the data itself)
34-
m = False #sets the 1st frame check to false (1st frame has already been done)
35-
print(f"file decoded and written to {output_file}") #tells the user where the file is, useless since it can be found down a few lines from here
26+
output_file.write(bytes_array)
27+
else:
28+
binary_data = ''.join(np.where(intensity.flatten() > 127, '1', '0').astype(str))
29+
first_one_index = binary_data.find('1')
30+
binary_data = binary_data[first_one_index + 1:] #scraps all the data including the extra 1, all of this is because it needs to scrap the gap left by files that don't perfectly fit into the video without leaving some gaps (the gap is at the beginning for efficiency reasons)
31+
if binary_data == "": #scraps the 1st frame if the 1st frame is empty, happens when the file perfectly fits into the video without leaving any gap
32+
m = 0
33+
else:
34+
binary_array = np.array([int(bit) for bit in binary_data]) #transforms the data into an array
35+
bytes_array = np.packbits(binary_array) #transforms the binary array into a bytes array
36+
output_file.write(bytes_array)
37+
m = 0
38+
print("file decoded and written to" + output_file_path)
3639

3740

38-
if __name__ == "__main__": #checks if the program has already been run
39-
video_path = "/home/ema/Desktop/Out1.avi" #input the video file
40-
output_file_path = "/home/ema/Desktop/bk foot lettuce2.txt" #input the file output
41-
decode_video(video_path, output_file_path) #calls decode video
41+
if __name__ == "__main__":
42+
video_path = "input.avi" #input the video file
43+
output_file_path = "output.txt" #input the file output
44+
decode_video(video_path, output_file_path)

Enc.py

Lines changed: 68 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,66 +1,82 @@
1-
import cv2 #imports opencv, make sure that you have opencv installed
2-
import numpy as np #imports numpy and makes it be called with np because lazy
3-
import os #imports os, needed for reading file size
1+
import cv2
2+
import numpy as np
3+
import os
44

5-
def create_video(output_video_path, inputf, width=1280, height=720, frame_rate=12, pix=5): #change the width and height however you like, width is the width, height is the height and pix is the bit size in pixels (you need to check if your desired height and width can be divided with pix, if not change pix or height and width)
6-
with open(inputf, 'rb') as file: #declares file as the input file
5+
def create_video(output_video_path, inputf, width=1280, height=720, frame_rate=12, pix=5): #change the width and height however you like, pix is the size of each bit in pixels (to resist compression, 5 means each bit is 5x5)
6+
with open(inputf, 'rb') as file:
77
size = os.path.getsize(inputf) #gets the size of the file
8-
print(size) #prints the size
9-
chunk = int(width*height/(pix*pix)) #get the chunk, or in better terms how many bits a single frame can contain
8+
print(size)
9+
chunk = int(width*height/(pix*pix)) #get the chunk, basically how many bits a single frame can contain
1010
width1 = width #i could just divide height1 and width1 directly, but it breaks compatibility since i need to swap all the var names and im lazy
11-
height1 = height #i could just divide height1 and width1 directly, but it breaks compatibility since i need to swap all the var names and im lazy
12-
width = int(width / pix) #i could just divide height1 and width1 directly, but it breaks compatibility since i need to swap all the var names and im lazy
13-
height = int(height / pix) #i could just divide height1 and width1 directly, but it breaks compatibility since i need to swap all the var names and im lazy
14-
add = height * width #declares add so that basically i dont need to multiply height and width over and over when trying to add the elapsed bits
11+
height1 = height
12+
width = int(width / pix)
13+
height = int(height / pix)
14+
add = height * width
1515
total_bits = size * 8 #gets the total bits
16-
print(total_bits) #prints the total bits amount
17-
if total_bits <= chunk: #if the file fits in one frame or less, then set the bits amount to the chunk
18-
total_bits = chunk #sets bit length as the chunk if previous condition is true
19-
print(total_bits) #prints bit length if the condition is true, for debugging purposes (kinda useless)
16+
print(total_bits)
17+
if total_bits < chunk: #if the file fits in less than one frame, set the bits amount to the chunk
18+
total_bits = chunk
19+
print(total_bits)
2020
total_frames = int(np.ceil(total_bits / (width * height))) #gets the total frames amount
21-
print(total_frames) #prints the total frames
21+
if (size*8) % (width*height) == 0: #if the file does NOT leave a gap then it makes an empty 1st frame
22+
total_frames += 1
23+
print(total_frames)
2224
fourcc = cv2.VideoWriter_fourcc(*'png ') #codec (fourcc)
23-
index = 0 #this number is totally useless except for the fact that it prints how many buts it has converted, updates each frame
24-
video_writer = cv2.VideoWriter(output_video_path, fourcc, frame_rate, (width1, height1), isColor=False) #DONT SWAP WIDTH1 AND HEIGHT1, OTHERWISE OPENCV GETS REAL MAD AND IT WILL MURDER YOUR HOPES AND DREAMS BY NOT CREATING THE VIDEO (empty video file) AND TELL YOU NOTHING ABOUT WHY IT HAPPENED
25+
index = 0
26+
video_writer = cv2.VideoWriter(output_video_path, fourcc, frame_rate, (width1, height1), isColor=False) #DONT SWAP WIDTH1 AND HEIGHT1, OTHERWISE OPENCV GETS REAL MAD
2527
m = 1 #just an indicator to check if the first frame has been done, m=1 = no, m=0 = yes
26-
for _ in range(total_frames): #do the frames after the 1st
27-
if m == 0: #checks if the 1st frame is done, it is important
28-
frame = np.zeros((height, width), dtype=np.uint8) #create the frame
28+
for _ in range(total_frames):
29+
if m == 0:
30+
frame = np.zeros((height, width), dtype=np.uint8)
2931
content = file.read(int(chunk / 8)) #read the portion of the file needed to fill 1 frame (resulting in less ram usage), the divide by 8 is there since chunk represents of the bits that can fit in one frame, and this converts it into bytes
30-
content = ''.join(format(byte, '08b') for byte in content) #converts content into a string otherwise the program will get pretty mad
32+
content = ''.join(format(byte, '08b') for byte in content)
3133
values = np.array([int(content[bit2]) * 255 for bit2 in range (chunk)]) #basically if it is reading a 1 it will multiply it by 255, resulting in 255 (white), otherwise it'll multiply 0 by 255 resulting in 0 (black)
32-
values = values.reshape(-1) #idk what it does honestly, afaik it reshapes values into a 1d array
33-
index += add #increments index by the amount of bits it has converted
34-
print(f"{index} 1") #prints the bits it has converted in total, if you get the bits amount of the file and compare it with the output you can get a pseudo progress percentage
35-
frame.flat = values #writes the bits to the frame right after flattening the frame into a 1d picture
34+
values = values.reshape(-1) #vectoring stuff, efficiency reasons
35+
index += add
36+
print(f"{index} 1")
37+
frame.flat = values
3638
frame = frame.reshape((height, width)) #converts the frame back into 2d
37-
frame = cv2.resize(frame, (width1, height1), interpolation=cv2.INTER_NEAREST) #enlargens the frame back into the original resolution, instead of writing each bit (it will take longer if i do the latter)
38-
video_writer.write(frame) #writes the frame instead of caching it in ram, resulting in less ram usage
39-
else: #PRETTY SMART STUFF, I SUGGEST TO NOT EDIT (except the one that declares size2, but it still works as it is tho, so maybe dont change it)
40-
frame = np.zeros((height, width), dtype=np.uint8) #create the frame
41-
size2 = size * 8 #converts the total bytes amount into bits, didnt want to use the other variable because uhh idk feel free to change it i did not test it
42-
size3 = size2 % chunk #gets the bits it needs to write
43-
temp = chunk - size3 #gets the padding bits it will write at the beginning of the 1st frame, this is basically why i split the stuff that makes the 1st frame from the others
44-
print(temp)
45-
content = file.read(int(size3 / 8)) #read the bits needed for the 1st frame
46-
binary_data = '0' * (temp - 1) #creates the padding 0s (except for the last 0 where it is swapped for a 1, for decoding purposes)
47-
binary_data += '1' #puts the 1 at the end of the padding, i made room specifically for that
48-
content = ''.join(format(byte, '08b') for byte in content) #converts content into a string otherwise the program will get pretty mad
49-
binary_data += content #appends at the end the data itself
50-
values = np.array([int(binary_data[bit]) * 255 for bit in range(chunk)]) #basically if it is reading a 1 it will multiply it by 255, resulting in 255 (white), otherwise it'll multiply 0 by 255 resulting in 0 (black)
51-
values = values.reshape(-1) #idk what it does honestly, afaik it reshapes values into a 1d array
52-
index += add #increments index by the amount of bits it has converted
53-
print(f"{index} 0") #prints the bits it has converted in the 1st frame
54-
frame.flat = values #writes the bits to the frame right after flattening the frame into a 1d picture
55-
frame = frame.reshape((height, width)) #converts the frame back into 2d
56-
frame = cv2.resize(frame, (width1, height1), interpolation=cv2.INTER_NEAREST) #enlargens the frame back into the original resolution
57-
video_writer.write(frame) #writes the frame instead of caching it in ram, resulting in less ram usage
58-
m = 0 #changes the indicator to say that the 1st frame has been done
39+
frame = cv2.resize(frame, (width1, height1), interpolation=cv2.INTER_NEAREST) #enlargens the frame back into the original resolution, instead of writing each bit, this is to resist compression
40+
video_writer.write(frame)
41+
else:
42+
if (size*8) % (width*height) == 0: #if the file does NOT leave a gap then i'm making an empty 1st frame
43+
temp = chunk
44+
frame = np.zeros((height, width), dtype=np.uint8)
45+
binary_data = '0' * (temp - 1)
46+
binary_data += '1'
47+
print(temp)
48+
values = np.array([int(binary_data[bit]) * 255 for bit in range(chunk)])
49+
values = values.reshape(-1)
50+
frame.flat = values
51+
frame = frame.reshape((height, width))
52+
frame = cv2.resize(frame, (width1, height1), interpolation=cv2.INTER_NEAREST)
53+
video_writer.write(frame)
54+
m = 0
55+
else:
56+
frame = np.zeros((height, width), dtype=np.uint8)
57+
size2 = size * 8
58+
size3 = size2 % chunk #gets the bits it needs to write
59+
temp = chunk - size3 #gets the padding bits it will write at the beginning of the 1st frame
60+
print(temp)
61+
content = file.read(int(size3 / 8)) #read the bits needed for the 1st frame
62+
binary_data = '0' * (temp - 1) #creates the padding 0s (except for the last 0 where it is swapped for a 1, for decoding purposes)
63+
binary_data += '1'
64+
content = ''.join(format(byte, '08b') for byte in content)
65+
binary_data += content
66+
values = np.array([int(binary_data[bit]) * 255 for bit in range(chunk)])
67+
values = values.reshape(-1) #vectoring stuff, efficiency reasons
68+
index += add
69+
print(f"{index} 0")
70+
frame.flat = values #writes the bits to the frame right after flattening the frame into a 1d picture
71+
frame = frame.reshape((height, width)) #converts the frame back into 2d
72+
frame = cv2.resize(frame, (width1, height1), interpolation=cv2.INTER_NEAREST) #enlargens the frame back into the original resolution, it's to resist compression
73+
video_writer.write(frame)
74+
m = 0
5975
video_writer.release()
6076

61-
if __name__ == "__main__": #checks if the program has already been run
62-
input_file_path = "/home/ema/Desktop/bk foot lettuce2.txt" #replace with the path to your input file
63-
output_video_path = "/home/ema/Desktop/Out1.avi" #replace with the desired output video path
64-
create_video(output_video_path, input_file_path) #calls create_video function
77+
if __name__ == "__main__":
78+
input_file_path = "input.txt" #replace with the path to your input file
79+
output_video_path = "output.avi" #replace with the desired output video path
80+
create_video(output_video_path, input_file_path)
6581

6682

0 commit comments

Comments
 (0)