"""
*************************************************************************
// Example program using OpenCV library
//      python >3.7 - OpenCV 4.5
// @file	e4c.py
// @author Luis M. Jimenez
// @date 2022
//
// @brief Course: Computer Vision (1782)
// Dept. of Systems Engineering and Automation
// Automation, Robotics and Computer Vision Lab (ARVC)
// http://arvc.umh.es
// University Miguel Hernandez
//
// @note Description:
//	- Capture images from a camera
//	- Detects edges (Canny detector)
//	- Extract contours
//	- Search for rectangular contours
//	- Draw detected points over captured image
//	- Save contours in a JSON file
//
*************************************************************************
"""

# Import libraries
import cv2 as cv
import numpy as np
import argparse
import json

# -----------------------------------------
# Global variables
# -----------------------------------------

WINDOW_CAMERA1 = '(W1) Camera 1'   # window id
CAMERA_ID = 0	                   # default camera

# check command line parameters (camera id)
parser = argparse.ArgumentParser(description='OpenCV example: captures and filter images from a camera')
parser.add_argument('-c', dest='cameraID', type=int, default=CAMERA_ID, metavar='id', help='camera id')
CAMERA_ID = parser.parse_args().cameraID

# -----------------------------------------
# Put here the code to Initialize objets
# -----------------------------------------

# Open camera object
camera = cv.VideoCapture(CAMERA_ID)
if not camera.isOpened():
    print("you need to connect a camera, sorry.")
    exit()

# Getting camera resolution
cameraWidth = int(camera.get(cv.CAP_PROP_FRAME_WIDTH))
cameraHeight = int(camera.get(cv.CAP_PROP_FRAME_HEIGHT))

# Creating visualization windows
cv.namedWindow(WINDOW_CAMERA1, cv.WINDOW_AUTOSIZE)

print(f"Capturing images from camera {CAMERA_ID} ({cameraWidth},{cameraHeight})")
print("...Hit q/Q/Esc to exit.")

# -----------------------------------------
# Main Loop
# while there are images ...
# -----------------------------------------
while True:
    # Capture frame-by-frame
    ret, capture = camera.read()

    # if frame is read correctly ret is True
    if not ret:
        print("Can't receive frame (stream end?). Exiting ...")
        break
    # -----------------------------------------
    # Put your image processing code here
    # -----------------------------------------

    #  transform to gray level
    gray_image = cv.cvtColor(capture, cv.COLOR_BGR2GRAY);

    # Apply filter to image
    edge_image = cv.Canny(gray_image, threshold1=80, threshold2=150)  # Canny border detector

    # find contours
    contours, hierarchy = cv.findContours(edge_image, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_NONE)

    # Filter out non rectangular contours
    contours_filtered = list()      # empty list (remember tuples are immutable)
    for cnt in contours:
        # approximate to a polygon (epsilon 5% of perimeter)
        approxCurve = cv.approxPolyDP(cnt, cv.arcLength(cnt, True)*0.05, True)

        # check that the polygon has 4 points, and is convex and big enough
        if (approxCurve.shape[0] == 4 and cv.isContourConvex(approxCurve)
                and cv.contourArea(approxCurve) > 200):
            contours_filtered.append(approxCurve)


    # -----------------------------------------
    # Put your visualization code here
    # -----------------------------------------
    # Draw  contours
    for idx in range(len(contours_filtered)):
        color = np.random.randint(low=0, high=256, size=3).tolist()
        cv.drawContours(capture, contours_filtered, idx, color, thickness=2, lineType=cv.LINE_8)

    cv.imshow(WINDOW_CAMERA1, capture)     # Display the resulting frame

    # check keystroke to exit (image window must be on focus)
    key = cv.pollKey()
    if key == ord('q') or key == ord('Q') or key == 27:
        break

# End while (main loop)

# -------------------------------------------
# Put your File Storage code here
#-------------------------------------------

# Only base types  list/tuple/set/dict  are supported,  so ndarray must be converted
contours_json = list()      # empty list (remember tuples are immutable)
for cnt in contours_filtered:
    contours_json.append(cnt.tolist())

# Writing contours to the file
with open('contours.json', 'w') as file:
    json.dump({'size': len(contours_json), 'contours': contours_json}, file)

# Reading contours from file
try:
    with open('contours.json') as file:
        data = json.load(file)
    print("Num. Contours:", data['size'])
    print(data['contours'])
except:
    print("File not valid")

# -----------------------------------------
# free windows and camera resources
# -----------------------------------------
cv.destroyAllWindows()
if camera.isOpened():  camera.release()
