This is a Python script that I wrote completely by myself. Basically it scans a giant picture to make a video.
They say one picture is worth more than a thousand words. Since a video contains thousands of pictures, a video is worth more than millions of words, so I will let the video outputs do the descriptions for me (because I am not a native speaker of English and I can't even describe the process in my native language or any natural language for that matter, but I can describe it in code).
Vertical video (Google Drive)
Horizontal video Output (Google Drive)
For more context, see this question.
The code:
import cv2
import numpy as np
from fractions import Fraction
from pathlib import Path
def resize_guide(image_size, target_area):
aspect_ratio = Fraction(*image_size).limit_denominator()
horizontal = aspect_ratio.numerator
vertical = aspect_ratio.denominator
unit_length = (target_area/(horizontal*vertical))**.5
return (int(horizontal*unit_length), int(vertical*unit_length))
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
FRAME = np.zeros((1080, 1920, 3), dtype=np.uint8)
def new_frame():
return np.ndarray.copy(FRAME)
def center(image):
frame = new_frame()
h, w = image.shape[:2]
yoff = round((1080-h)/2)
xoff = round((1920-w)/2)
frame[yoff:yoff+h, xoff:xoff+w] = image
return frame
def image_scanning(file, fps=60, pan_increment=64, horizontal_increment=8, vertical_increment=24):
image = cv2.imread(file)
height, width = image.shape[:2]
if width < 1920:
frame = np.zeros([height, 1920, 3], dtype=np.uint8)
frame[0:height, 0:width] = image
image = frame
width = 1920
assert width*height >= 1920*1080
video_writer = cv2.VideoWriter(file+'.mp4', fourcc, fps, (1920, 1080))
fit_height = True
if height < 1080:
width = width*1080/height
image = cv2.resize(image, (width, 1080), interpolation = cv2.INTER_AREA)
aspect_ratio = width / height
not_thin = False
if 4/9 <= aspect_ratio <= 16/9:
new_width = round(width*1080/height)
fit = cv2.resize(image, (new_width, 1080), interpolation = cv2.INTER_AREA)
not_thin = True
elif 16/9 < aspect_ratio <= 32/9:
new_height = round(height*1920/width)
fit = cv2.resize(image, (1920, new_height), interpolation = cv2.INTER_AREA)
fit_height = False
not_thin = True
if not_thin:
centered = center(fit)
for i in range(fps):
video_writer.write(centered)
if fit_height:
xoff = round((1920 - new_width)/2)
while xoff:
if xoff - pan_increment >= 0:
xoff -= pan_increment
else:
xoff = 0
frame = new_frame()
frame[0:1080, xoff:xoff+new_width] = fit
video_writer.write(frame)
else:
yoff = round((1080 - new_height)/2)
while yoff:
if yoff - pan_increment >= 0:
yoff -= pan_increment
else:
yoff = 0
frame = new_frame()
frame[yoff:yoff+new_height, 0:1920] = fit
video_writer.write(frame)
if not_thin:
if fit_height:
width_1, height_1 = new_width, 1080
else:
width_1, height_1 = 1920, new_height
new_area = width_1 * height_1
original_area = width * height
area_diff = original_area - new_area
unit_diff = area_diff / fps
for i in range(1, fps+1):
zoomed = cv2.resize(image, resize_guide((width_1, height_1), new_area+unit_diff*i), interpolation=cv2.INTER_AREA)
zheight, zwidth = zoomed.shape[:2]
zheight = min(zheight, 1080)
zwidth = min(zwidth, 1920)
frame = new_frame()
frame[0:zheight, 0:zwidth] = zoomed[0:zheight, 0:zwidth]
video_writer.write(frame)
if (width - 1920) % horizontal_increment:
new_width = ((width - 1920) // horizontal_increment + 1) * horizontal_increment + 1920
frame = np.zeros([height, new_width, 3], dtype=np.uint8)
frame[0:height, 0:width] = image
width = new_width
image = frame
if not_thin:
if height % 1080:
new_height = (height // 1080 + 1) * 1080 + 8
frame = np.zeros([new_height, width, 3], dtype=np.uint8)
frame[0:height, 0:width] = image
height = new_height - 8
image = frame
y, x = 0, 0
for y in range(0, height, 1080):
for x in range(0, width-1920, horizontal_increment):
frame = image[y:y+1080, x:x+1920]
video_writer.write(frame)
x = width - 1920
frame = image[y:y+1080, x:x+1920]
for i in range(round(fps/3)):
video_writer.write(frame)
else:
if (height - 1080) % vertical_increment:
new_height = ((height - 1080) // vertical_increment + 1) * vertical_increment + 1088
frame = np.zeros([new_height, width, 3], dtype=np.uint8)
frame[0:height, 0:width] = image
height = new_height - 8
image = frame
y, x = 0, 0
for y in range(0, height-1080, vertical_increment):
for x in range(0, width-1920, vertical_increment):
frame = image[y:y+1080, x:x+1920]
video_writer.write(frame)
x = width - 1920
frame = image[y:y+1080, x:x+1920]
for i in range(round(fps/3)):
video_writer.write(frame)
y = height - 1080
for x in range(0, width-1920, vertical_increment):
frame = image[y:y+1080, x:x+1920]
video_writer.write(frame)
x = width - 1920
frame = image[y:y+1080, x:x+1920]
for i in range(round(fps/3)):
video_writer.write(frame)
cv2.destroyAllWindows()
video_writer.release()
del video_writer
It is in need of refactoring.