Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update vid2xlsx.py #2

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
145 changes: 81 additions & 64 deletions vid2xlsx.py
Original file line number Diff line number Diff line change
@@ -1,78 +1,95 @@
#!/usr/bin/env python3

from imutils.video import FileVideoStream
from loguru import logger
from sklearn.cluster import MiniBatchKMeans

import argparse
import cv2
import imutils
import numpy as np
import sys
import xlsxwriter

ap = argparse.ArgumentParser()
ap.add_argument("-i", "--input", required = True, help = "path to input video file")
ap.add_argument("-o", "--output", required = True, help = "path to output xlsx file")
ap.add_argument("-v", "--verbose", action = "store_true", help = "show detailed output")
ap.add_argument("-d", "--debug", action = "store_true", help = "show debug and troubleshooting information")
ap.add_argument("-c", "--colors", required = True, type = int, help = "number of colors per frame")
ap.add_argument("-f", "--frame", required = True, type = int, help = "how often a frame should be generated")
args = vars(ap.parse_args())
from imutils.video import FileVideoStream
from loguru import logger
from sklearn.cluster import MiniBatchKMeans

cap = FileVideoStream(args["input"]).start()
if args["verbose"]: logger.info("Opened FileVideoStream from {}", args["input"])
length = int(cv2.VideoCapture(args["input"]).get(7))
if args["debug"]: logger.debug("File contains {} frames, expect {} frames in output", length, length // args["frame"])
if args["debug"]: logger.debug("Projected maximum color usage: {}", length // args["frame"] * args["colors"])
if length // args["frame"] * args["colors"] > 64000: logger.warning("Current settings may exceed the maximum number of colors permitted in an XLSX file (64000)")
width = 640
height = 360
count = 0

workbook = xlsxwriter.Workbook(args["output"], {'constant_memory': True})
def process_video(input_path, output_path, colors, frame_rate, verbose=False, debug=False):
cap = FileVideoStream(input_path).start()
length = int(cv2.VideoCapture(input_path).get(cv2.CAP_PROP_FRAME_COUNT))

palette = {}
clt = None
labels = None
quant = None
if debug:
logger.debug("File contains {} frames, expecting {} frames in output", length, length // frame_rate)

if length // frame_rate * colors > 64000:
logger.warning("Current settings may exceed the maximum number of colors permitted in an XLSX file (64000)")

width, height = 640, 360
count = 0
workbook = xlsxwriter.Workbook(output_path, {'constant_memory': True})
palette = {}

while cap.more():
frame = cap.read()

if frame is None:
break

if count % frame_rate == 0:
current = workbook.add_worksheet(str(count))
current.set_zoom(10)

if verbose:
logger.info("Processing frame {}", count)

if debug:
logger.debug("Palette dictionary size: {}", len(palette))

frame = cv2.resize(frame, (width, height), interpolation=cv2.INTER_LINEAR)
(h, w) = frame.shape[:2]
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2LAB)
frame = frame.reshape((frame.shape[0] * frame.shape[1], 3))

clt = MiniBatchKMeans(n_clusters=colors)
labels = clt.fit_predict(frame)
quant = clt.cluster_centers_.astype("uint8")[labels]
quant = quant.reshape((h, w, 3))
frame = cv2.cvtColor(quant, cv2.COLOR_LAB2BGR)

cv2.imshow("Preview", frame)
cv2.waitKey(1)

current.set_column(0, width - 1, 3.17)

for row in range(height):
current.set_row(row, 18.75)

for col in range(width):
blue, green, red = frame[row][col]
color = f'{red:02x}{green:02x}{blue:02x}'

if color not in palette:
palette[color] = workbook.add_format({'bg_color': f'#{color}'})

cell_format = palette[color]
current.write_blank(row, col, None, cell_format)

count += 1

if len(palette) > 64000:
logger.warning("""
Palette size ({}) exceeds the maximum permitted under the XLSX specification (64000).
The resulting file may not be recognized as a valid XLSX file.""", len(palette))

if verbose:
logger.info("Writing XLSX file: {}", output_path)

workbook.close()
cap.stop()
cv2.destroyAllWindows()

while cap.more():
frame = cap.read()
if frame is None:
break
if count % args["frame"] == 0:
current = workbook.add_worksheet(str(count))
current.set_zoom(10)
if args["verbose"]: logger.info("Processing frame {}", count)
if args["debug"]: logger.debug("Palette dictionary size: {}", len(palette))
frame = cv2.resize(frame, (width, height), interpolation = cv2.INTER_CUBIC)
(h, w) = frame.shape[:2]
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2LAB)
frame = frame.reshape((frame.shape[0] * frame.shape[1], 3))
clt = MiniBatchKMeans(n_clusters = args["colors"])
labels = clt.fit_predict(frame)
quant = clt.cluster_centers_.astype("uint8")[labels]
quant = quant.reshape((h, w, 3))
frame = cv2.cvtColor(quant, cv2.COLOR_LAB2BGR)
cv2.imshow("Preview", frame)
cv2.waitKey(1)
current.set_column(0, width - 1, 3.17)
for row in range(0, height):
current.set_row(row, 18.75)
for col in range(0, width):
blue, green, red = frame[row][col]
color = f'{red:02x}{green:02x}{blue:02x}'
if color not in palette:
palette[color] = workbook.add_format({'bg_color': f'#{color}'})
cell_format = palette[color]
current.write_blank(row, col, None, cell_format)
count = count + 1

if len(palette) > 64000: logger.warning("""
Palette size ({}) exceeds the maximum permitted under the XLSX specification (64000).
The resulting file may not be recognized as a valid XLSX file.""", len(palette))
if args["verbose"]: logger.info("Writing xlsx file: {}", args["output"])
workbook.close()
cap.stop()
cv2.destroyAllWindows()
def main():
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--input", required=True, help="path to input video file")
ap.add_argument("-o", "--output", required=True, help="path to output XLSX file")
ap.add_argument("-v", "--verbose", action="store_true", help="show detailed output")
ap.add_argument("-d",