From 6dacec96754a493171d1d45dd4f5b7b683de6ccb Mon Sep 17 00:00:00 2001 From: Anthony Wang Date: Sun, 28 Apr 2024 21:35:46 -0400 Subject: Use cv2.warpPerspective instead of dumb interpolation https://docs.opencv.org/4.9.0/da/d6e/tutorial_py_geometric_transformations.html --- README.md | 4 ++-- decoder.py | 51 ++++++++++++--------------------------------------- encoder.py | 4 ++-- 3 files changed, 16 insertions(+), 43 deletions(-) diff --git a/README.md b/README.md index 9857d2a..d465263 100644 --- a/README.md +++ b/README.md @@ -10,11 +10,11 @@ pip install --upgrade reedsolo --no-binary "reedsolo" --no-cache --config-settin ## Usage -Encode: `python encoder.py -i in -o vid.mkv` +Encode: `python encoder.py -i in` Play video: `mpv --scale=nearest --fullscreen --loop --no-keepaspect vid.mkv` -Copy the flags printed by the encoder and pass them to the decoder: `python decoder.py -o out FLAGS` +Copy the flags printed by the encoder and pass them to the decoder: `python decoder.py FLAGS` Formatting: `black -l 120 *.py` diff --git a/decoder.py b/decoder.py index d541d6e..2fb0183 100644 --- a/decoder.py +++ b/decoder.py @@ -1,15 +1,14 @@ import argparse -import sys import traceback import cv2 -import matplotlib.pyplot as plt +# import matplotlib.pyplot as plt import numpy as np from creedsolo import RSCodec from raptorq import Decoder parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument("-i", "--input", help="camera device index or input video file", default=0) -parser.add_argument("-o", "--output", help="output file for decoded data") +parser.add_argument("-o", "--output", help="output file for decoded data", default="out") parser.add_argument("-x", "--height", help="grid height", default=100, type=int) parser.add_argument("-y", "--width", help="grid width", default=100, type=int) parser.add_argument("-f", "--fps", help="frame rate", default=30, type=int) @@ -38,7 +37,7 @@ def find_corner(A, f): mask = cv2.floodFill( A, np.empty(0), - tuple(reversed(guess)), + tuple(np.flip(guess)), 0, (100, 100, 100), (100, 100, 100), @@ -83,42 +82,16 @@ while data is None: bcol -= origin F = 255 * np.linalg.inv(np.stack((rcol, gcol, bcol)).T) - # Dumb perspective transform - xv = np.linspace( - -(cheight / 2 - 1) / (args.height - cheight + 1), - 1 + (cheight / 2 - 1) / (args.height - cheight + 1), - args.height, + cch = cheight / 2 - 1 + ccw = cwidth / 2 - 1 + M = cv2.getPerspectiveTransform( + np.float32([np.flip(widx), np.flip(ridx), np.flip(gidx), np.flip(bidx)]), + np.float32([[ccw, cch], [args.width - ccw - 1, cch], [ccw, args.height - ccw - 1], [args.width - ccw - 1, args.height - cch - 1]]), ) - yv = np.linspace( - -(cwidth / 2 - 1) / (args.width - cwidth + 1), - 1 + (cwidth / 2 - 1) / (args.width - cwidth + 1), - args.width, - ) - xp = ( - np.outer(1 - xv, 1 - yv) * widx[0] - + np.outer(1 - xv, yv) * ridx[0] - + np.outer(xv, 1 - yv) * gidx[0] - + np.outer(xv, yv) * bidx[0] - ) - yp = ( - np.outer(1 - xv, 1 - yv) * widx[1] - + np.outer(1 - xv, yv) * ridx[1] - + np.outer(xv, 1 - yv) * gidx[1] - + np.outer(xv, yv) * bidx[1] - ) - - # plt.scatter(widx[1], widx[0]) - # plt.scatter(ridx[1], ridx[0]) - # plt.scatter(gidx[1], gidx[0]) - # plt.scatter(bidx[1], bidx[0]) - # plt.scatter(yp, xp) - # plt.imshow(raw_frame.astype(np.uint8)) - # plt.show() - - frame = raw_frame[ - np.clip(np.round(xp).astype(np.int64), 0, X - 1), np.clip(np.round(yp).astype(np.int64), 0, Y - 1), : - ] + frame = cv2.warpPerspective(raw_frame, M, (args.width, args.height)) frame = (np.squeeze(F @ (frame - origin)[..., np.newaxis]) >= 128).astype(np.uint8) + # plt.imshow(frame * 255) + # plt.show() frame = np.concatenate( ( frame[:cheight, cwidth : args.width - cwidth].flatten(), @@ -130,7 +103,7 @@ while data is None: data = decoder.decode(bytes(rsc.decode(bytearray(np.packbits(frame) ^ frame_xor))[0][: args.psize])) print("Decoded frame") except KeyboardInterrupt: - sys.exit() + break except: traceback.print_exc() with open(args.output, "wb") as f: diff --git a/encoder.py b/encoder.py index c510b18..d80beae 100644 --- a/encoder.py +++ b/encoder.py @@ -6,7 +6,7 @@ from raptorq import Encoder parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument("-i", "--input", help="input file") -parser.add_argument("-o", "--output", help="output video file") +parser.add_argument("-o", "--output", help="output video file", default="vid.mkv") parser.add_argument("-x", "--height", help="grid height", default=100, type=int) parser.add_argument("-y", "--width", help="grid width", default=100, type=int) parser.add_argument("-f", "--fps", help="frame rate", default=30, type=int) @@ -39,7 +39,7 @@ rcorner = np.pad(np.dstack((ones, zeros, zeros)), ((0, 1), (1, 0), (0, 0))) gcorner = np.pad(np.dstack((zeros, ones, zeros)), ((1, 0), (0, 1), (0, 0))) bcorner = np.pad(np.dstack((zeros, zeros, ones)), ((1, 0), (1, 0), (0, 0))) -print(f"-x {args.height} -y {args.width} -l {args.level} -s {len(data)} -p {len(packets[0])}") +print(f"-x {args.height} -y {args.width} -l {args.level} -s {len(data)} -p {len(packets[0])}", end="") def frame(packet): -- cgit v1.2.3-70-g09d2