import numpy as np
import cv2 as cv
import csv

import tkinter as tkinter
from tkinter import filedialog
import os
# import time

from detectors import sift_algorithm
from detectors import surf_algorithm
from detectors import akaze_algorithm



#SIFT, SURF avaliable at version 3.2.16


root = tkinter.Tk()
root.withdraw()  # withdraw hides empty GUI window

global file_path
file_path = filedialog.askdirectory()  # opens 'select folder' dialog



# **********************************************************************************************************************
# PARAMETERS SIFT

print('SET THE INPUTS FOR THE SIFT ALGORITHM')
nfeatures = input("Enter a number of features <0;500> : ")
nfeatures = int(nfeatures)
# The number of best features to retain. The features are ranked by their scores (measured in SIFT algorithm as the local contrast)
# (default = 0)



nOctaveLayers_sift = input("Enter a number of octave layers <1;9>: ")
nOctaveLayers_sift = int(nOctaveLayers_sift)
# The number of layers in each octave. 3 is the value used in D. Lowe paper. The number of octaves is computed automatically
# from the image resolution. (default = 3)



contrastThreshold = input("Enter a value of contrast threshold <0.0001;0.5>: ")
contrastThreshold = float(contrastThreshold)
# The contrast threshold used to filter out weak features in semi-uniform (low-contrast) regions. The larger the threshold,
# the less features are produced by the detector. (default = 0.03)

edgeThreshold = input("Enter a value of the edge threshold <1; 500>: ")
edgeThreshold = int(edgeThreshold)
# The threshold used to filter out edge-like features. Note that the its meaning is different from the contrastThreshold,
# i.e. the larger the edgeThreshold, the less features are filtered out (more features are retained). (default = 10)




sigma = input("Enter a vaule of the sigma <1;3.5>: ")
sigma = float(sigma)
# The sigma of the Gaussian applied to the input image at the octave #0. If your image is captured with a weak camera
# with soft lenses, you might want to reduce the number. (default = 1.6)



method_name1 = '_sift_nOctLay_' + str(nOctaveLayers_sift) + '_nFeat_' + str(nfeatures) + '_contThr_' + str(contrastThreshold) + '_edgThr_' + str(edgeThreshold) + '_sig_' + str(sigma)


# **********************************************************************************************************************
# PARAMETERS SURF
print('SET THE INPUTS FOR THE SURF ALGORITHM')


hessianThreshold = input("Enter a value of Hessian threshold <10;950>: ")
hessianThreshold = int(hessianThreshold)
# Threshold for hessian keypoint detector used in SURF. The larger the threshold, the less keypoints get. (default = 300-500)




nOctaves_surf = input("Enter a number of octaves <1;9>: ")
nOctaves_surf = int(nOctaves_surf)
# Number of pyramid octaves the keypoint detector will use. If you want to get very large features, use the larger value.
# If you want just small features, decrease it. (default = 4)



nOctaveLayers_surf = input("Enter a number of the octave layers <1;9>: ")
nOctaveLayers_surf = int(nOctaveLayers_surf)
# Number of octave layers within each octave. The number of images within each octave of a gaussian pyramid. (default = 2)


extended = input("Enter the extened descriptor flag ((1 for True - 128-element descriptors; 0 for False - 64-element descriptors): ")
extended = int(extended)
# Extended descriptor flag (true - use extended 128-element descriptors; false - use 64-element descriptors)
# (default = False)



upright = input("Enter orientation of feature flags (1 for True - do not compute the orientation, 0 for False - compute the orientation): ")
upright = int(upright)
# Up-right or rotated features flag (true - do not compute orientation of features; false - compute orientation).
# (default = False)




method_name2 = '_surf_nOctLay_' + str(nOctaveLayers_surf) + '_nOct_' + str(nOctaves_surf) + '_hessThr_' + str(hessianThreshold) + '_upr_' + str(upright) + '_ext_' + str(extended)



# **********************************************************************************************************************
# PARAMETERS AKAZE
print('SET THE INPUTS FOR THE AKAZE ALGORITHM')


descriptor_type = input("Enter a type of descriptor (4 for AKAZE_DESCRIPTOR_MLDB_UPRIGHT, 5 for AKAZE_DESCRIPTOR_MLDB): ")
descriptor_type = int(descriptor_type)
# Type of the extracted descriptor: DESCRIPTOR_KAZE, DESCRIPTOR_KAZE_UPRIGHT, DESCRIPTOR_MLDB or DESCRIPTOR_MLDB_UPRIGHT.
# (default = cv.AKAZE_DESCRIPTOR_MLDB)




descriptor_size = input("Enter a size of descriptor <0,7,8,9,10,12,16,22>: ")
descriptor_size = int(descriptor_size)
# Size of the descriptor in bits. 0 -> Full size (0,7,8,9,10,12,13,14,16... vyskusat)
# (default = 0)



descriptor_channels	= 3
# Number of channels in the descriptor (default = 3)


threshold_akaze = 0.0001
# Detector response threshold to accept point (default = 0.0001)



nOctaves_akaze = input("Enter a number of octaves <1;9>: ")
nOctaves_akaze = int(nOctaves_akaze)
# Maximum octave evolution of the image (1,4,10)
# (default = 4)


nOctaveLayers_akaze = input("Enter a number of octave layers <1;9>: ")
nOctaveLayers_akaze = int(nOctaveLayers_akaze)
# Default number of sublevels per scale level
# (default = 4)



diffusivity = input("Enter a diffusivity type(0 for PM_G1, 1 for PM_G2, 3 for CHARBONNIER): ")
diffusivity = int(diffusivity)
# Diffusivity type. DIFF_PM_G1, DIFF_PM_G2, DIFF_WEICKERT or DIFF_CHARBONNIER
# DIFF_PM_G1 - 0, KAZE_DIFF_PM_G2 - 1, DIFF_CHARBONNIER - 3
# (default = cv.KAZE_DIFF_PM_G2)



method_name3 = '_akaze_nOctLay_' + str(nOctaveLayers_akaze) + '_nOct_' + str(nOctaves_akaze) + '_diff_' + str(diffusivity) + '_desSize_' + str(descriptor_size) + '_desType_' + str(descriptor_type)




for dir_, dirnames, filenames in os.walk(file_path):

    with open(str(dir_) + '_results' + method_name1 + '.csv', 'a', newline='') as f:
        thewriter = csv.writer(f)
        thewriter.writerow(['Image', 'Matches', 'Good Matches', 'Threshold', 'Time [sec]', 'Diff X', 'Diff Y',
                            'nfeatures', 'nOctaveLayers', 'contrastThreshold', 'edgeThreshold', 'sigma'])


    with open(str(dir_) + '_results' + method_name2 + '.csv', 'a', newline='') as f:
        thewriter = csv.writer(f)
        thewriter.writerow(['Image', 'Matches', 'Good Matches', 'Threshold', 'Time [sec]', 'Diff X', 'Diff Y',
                            'hessianThreshold', 'nOctaves', 'nOctaveLayers', 'extended', 'upright'])


    with open(str(dir_) + '_results' + method_name3 + '.csv', 'a', newline='') as f:
        thewriter = csv.writer(f)
        thewriter.writerow(['Image', 'Matches', 'Good Matches', 'Threshold', 'Time [sec]', 'Diff X', 'Diff Y',
                            'descriptor_type', 'descriptor_size', 'descriptor_channels', 'threshold', 'nOctaves',
                            'nOctaveLayers', 'diffusivity'])

    for filename in filenames:
        if filename.endswith("a.tif"):
            filename_b = os.path.join(dir_, filename[:-5] + "b.tif")
        # elif filename.endswith("a.png"):
        #     filename_b = os.path.join(dir_, filename[:-5] + "b.png")

            if os.path.exists(filename_b):
                filename_a = os.path.join(dir_, filename)

                sift_algorithm(filename_a, filename_b, dir_, method_name1, nfeatures, nOctaveLayers_sift, contrastThreshold, edgeThreshold, sigma)


                surf_algorithm(filename_a, filename_b, dir_, method_name2, hessianThreshold, nOctaves_surf, nOctaveLayers_surf,
                               extended, upright)

                akaze_algorithm(filename_a, filename_b, dir_, method_name3, descriptor_type, descriptor_size, descriptor_channels,
                                threshold_akaze, nOctaves_akaze, nOctaveLayers_akaze, diffusivity)

