#!/usr/bin/env python
# -*- coding: utf-8 -*-

__author__ = 'Anette Eltner'
__contact__ = 'Anette.Eltner@tu-dresden.de'
__copyright__ = '(c) Anette Eltner 2018'
__license__ = 'MIT'
__date__ = '16 August 2018'
__version__ = '0.1'
__status__ = "initial release"
__url__ = "https://github.com/AnetteEltner/StageDetect"


"""
Name:           StageDetect_gui.py
Compatibility:  Python 2.7
Description:    This program detects water stage using image sequences. It includes
                camera orientation, template matching for GCP detection, master retrieval
                from image sequence, image co-registration, water line detection, and
                transforming 2D points into 3D coordinates. The program has been written in
                cooperation with Melanie Kröhnert and Hannes Sardemann.
URL:            https://github.com/AnetteEltner/StageDetect
Requires:       Tkinter, scipy, scikit-learn, scikit-image, shapely, statsmodels, seaborn,
                cv2 (openCV version 2.4.13)
AUTHOR:         Anette Eltner
ORGANIZATION:   TU Dresden
Contact:        Anette.Eltner@tu-dresden.de
Copyright:      (c) Anette Eltner 2018
Licence:        MIT
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in 
the Software without restriction, including without limitation the rights to 
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 
of the Software, and to permit persons to whom the Software is furnished to do 
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all 
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
SOFTWARE.
"""


import os, csv
import cv2
import numpy as np
import pandas as pd


from Tkinter import *
import tkFileDialog, ScrolledText
from ttk import *

import photogrammetry_classes as georef
import waterline_classes as wl_func
import templateMatching_classes as tmp_match


class WaterlineTool:
    
    def __init__(self, master):
        
        master_frame = Frame(master, name='master_frame')
        master.title('StageDetect: Image-based water level detection')
        note = Notebook(master_frame, name='note')
        master_frame.grid()
        
        #text box for display output
        self.textbox = ScrolledText.ScrolledText(master, height=10, width=20)
        self.textbox.place(x=470, y=30, width=350, height=350)
                                
        
        '''----------------frame waterline in image-------------------'''
        frame = Frame(note)  
        note.add(frame, text="waterline image")
        note.grid(row=0, column=0, ipadx=350, ipady=200)
        
        self.xButton = 370
        self.xText = 250
        self.yAddText = 10
        Style().configure("RB.TButton", foreground='blue', font=('helvetica', 10))
                
        #prepare text box to read parameters
        Label(frame, text="Buffer Size: ").place(x=10, y=self.yAddText)
        self.buff_size_waterlineSearch = IntVar()
        self.buff_size_waterlineSearch_Param = Entry(frame, textvariable=self.buff_size_waterlineSearch)
        self.buff_size_waterlineSearch_Param.place(x=self.xText, y=self.yAddText, width=100, height=20)
        self.buff_size_waterlineSearch.set(250)                
        self.OK_ParBuff1 = Button(frame, text="Get", command= lambda: self.getValuesFromTxtBox(self.buff_size_waterlineSearch))
        self.OK_ParBuff1.place(x=self.xButton, y=self.yAddText, height=20)
        
        self.yAddText = self.yAddText + 30
        Label(frame, text="Threshold histogram: ").place(x=10, y=self.yAddText)  
        self.thresh_hist_waterlineSearch = DoubleVar()
        self.thresh_hist_waterlineSearch_Param = Entry(frame, textvariable=self.thresh_hist_waterlineSearch)
        self.thresh_hist_waterlineSearch_Param.place(x=self.xText, y=self.yAddText, width=100, height=20)
        self.thresh_hist_waterlineSearch.set(0.94)                
        self.OK_ParBuff2 = Button(frame, text="Get", command= lambda: self.getValuesFromTxtBox(self.thresh_hist_waterlineSearch))
        self.OK_ParBuff2.place(x=self.xButton, y=self.yAddText, height=20)
         
        self.yAddText = self.yAddText + 30 
        Label(frame, text="Add value to grey value thresh: ").place(x=10, y=self.yAddText)
        self.add_thresh_grey = IntVar()
        self.add_thresh_grey_Param = Entry(frame, textvariable=self.add_thresh_grey)
        self.add_thresh_grey_Param.place(x=self.xText, y=self.yAddText, width=100, height=20)
        self.add_thresh_grey.set(15)                
        self.OK_ParBuff3 = Button(frame, text="Get", command= lambda: self.getValuesFromTxtBox(self.add_thresh_grey))
        self.OK_ParBuff3.place(x=self.xButton, y=self.yAddText, height=20)
         
        self.yAddText = self.yAddText + 30
        Label(frame, text="Add value to temp texture thresh: ").place(x=10, y=self.yAddText)
        self.add_thresh_tempText = IntVar()
        self.add_thresh_tempText_Param = Entry(frame, textvariable=self.add_thresh_tempText)
        self.add_thresh_tempText_Param.place(x=self.xText, y=self.yAddText, width=100, height=20)
        self.add_thresh_tempText.set(55)                
        self.OK_ParBuff4 = Button(frame, text="Get", command= lambda: self.getValuesFromTxtBox(self.add_thresh_tempText))
        self.OK_ParBuff4.place(x=self.xButton, y=self.yAddText, height=20)
         
        self.yAddText = self.yAddText + 30 
        Label(frame, text="Kernel size bilateral filter: ").place(x=10, y=self.yAddText)
        self.bilat_kernelStr = StringVar()
        self.bilat_kernel_Param = Entry(frame, textvariable=self.bilat_kernelStr)
        self.bilat_kernel_Param.place(x=self.xText, y=self.yAddText, width=100, height=20)
        self.bilat_kernelStr.set("7:3")                
        self.OK_ParBuff5 = Button(frame, text="Get", command= lambda: self.getValuesFromTxtBox(self.bilat_kernelStr))
        self.OK_ParBuff5.place(x=self.xButton, y=self.yAddText, height=20)
        
        self.yAddText = self.yAddText + 30 
        Label(frame, text="Kernel size canny filter: ").place(x=10, y=self.yAddText)
        self.canny_kernel = IntVar()
        self.canny_kernel_Param = Entry(frame, textvariable=self.canny_kernel)
        self.canny_kernel_Param.place(x=self.xText, y=self.yAddText, width=100, height=20)
        self.canny_kernel.set(3)                
        self.OK_ParBuff6 = Button(frame, text="Get", command= lambda: self.getValuesFromTxtBox(self.canny_kernel))
        self.OK_ParBuff6.place(x=self.xButton, y=self.yAddText, height=20)
                
        self.yAddText = self.yAddText + 30
        Label(frame, text="Clip size NaN values: ").place(x=10, y=self.yAddText)
        self.nan_clip_size = IntVar()
        self.nan_clip_size_Param = Entry(frame, textvariable=self.nan_clip_size)
        self.nan_clip_size_Param.place(x=self.xText, y=self.yAddText, width=100, height=20)
        self.nan_clip_size.set(10)                
        self.OK_ParBuff7 = Button(frame, text="Get", command= lambda: self.getValuesFromTxtBox(self.nan_clip_size))
        self.OK_ParBuff7.place(x=self.xButton, y=self.yAddText, height=20)     
        
        self.yAddText = self.yAddText + 30
        Label(frame, text="Start at image: ").place(x=10, y=self.yAddText)
        self.video_value = StringVar()
        self.video_value_Param = Entry(frame, textvariable=self.video_value)
        self.video_value_Param.place(x=self.xText, y=self.yAddText, width=100, height=20)
        self.video_value.set(" ")                
        self.OK_ParBuff8 = Button(frame, text="Get", command= lambda: self.getValuesFromTxtBox(self.video_value))
        self.OK_ParBuff8.place(x=self.xButton, y=self.yAddText, height=20) 


        #check waterside
        self.yAddText = self.yAddText + 30
        Label(frame, text="Waterside: ").place(x=10, y=self.yAddText)
        self.watersideInt = IntVar()
        self.watersideInt.set(0)
        self.watersideBut = Radiobutton(frame, text = "Left", variable=self.watersideInt, value=0)
        self.watersideBut.place(x=80, y=self.yAddText, height=20)
        self.watersideBut = Radiobutton(frame, text = "Right", variable=self.watersideInt, value=1)
        self.watersideBut.place(x=130, y=self.yAddText, height=20)
         
        #check if Canny should be used, else region growing depending on color is used
        self.yAddText = self.yAddText + 20
        self.use_canny = BooleanVar()
        self.use_canny.set(True)
        self.checkCannyBut = Checkbutton(frame, text = "Use Canny filter", variable=self.use_canny)
        self.checkCannyBut.place(x=10, y=self.yAddText)          
          
        #check if results should be illustrated
        self.plot_results = BooleanVar()
        self.plot_results.set(False)
        self.plot_resultsBut = Checkbutton(frame, text = "Plot results", variable=self.plot_results)
        self.plot_resultsBut.place(x=180, y=self.yAddText)
          
        #check if co-registration should be performed
        self.yAddText = self.yAddText + 20
        self.perform_coregist = BooleanVar()
        self.perform_coregist.set(True)
        self.perform_coregistBut = Checkbutton(frame, text = "Perform co-registration", variable=self.perform_coregist)
        self.perform_coregistBut.place(x=10, y=self.yAddText)
                    
        #check if start from specific video
        self.do_continue = BooleanVar()
        self.do_continue.set(False)
        self.do_continueBut = Checkbutton(frame, text = "Start from specific image", variable=self.do_continue)
        self.do_continueBut.place(x=180, y=self.yAddText)          
          
        #check whether approximation only one file or list of files
        self.yAddText = self.yAddText + 20
        self.waterline_approx_steady = BooleanVar()
        self.waterline_approx_steady.set(False)
        self.checkWaterlineApproxNbr = Checkbutton(frame, text = "Waterline approx: single file", variable=self.waterline_approx_steady)
        self.checkWaterlineApproxNbr.place(x=10, y=self.yAddText)
        
        #check whether processing only for one waterline
        self.yAddText = self.yAddText + 20
        self.waterline_single = BooleanVar()
        self.waterline_single.set(False)
        self.checkWaterlineSingle = Checkbutton(frame, text = "Waterline detection: single case", variable=self.waterline_single)
        self.checkWaterlineSingle.place(x=10, y=self.yAddText)
          
          
        #prepare starting waterline detection button
        self.waterlineDetection = Button(frame, text="Detect waterline", style="RB.TButton", command=self.waterlineDetection)
        self.waterlineDetection.place(x=10, y=self.yAddText+30)

                        
        
        '''----------------get GCP coordinates in image-------------------'''
        frame2 = Frame(note)  
        note.add(frame2, text="get GCP image coordinates")
        note.grid(row=0, column=0, ipadx=350, ipady=200)
        
        self.yAddText = 10     
        self.xButton = 250
        self.xText = 180

        #prepare image list with masters        
        Label(frame2, text="Variable folder search: ").place(x=10, y=self.yAddText)
        self.varDirSearch = StringVar()
        self.varDirSearch_Param = Entry(frame2, textvariable=self.varDirSearch)
        self.varDirSearch_Param.place(x=self.xText, y=self.yAddText, width=60, height=20)
        self.varDirSearch.set('2017')                
        self.OK_ParBuff18 = Button(frame2, text="Get", command= lambda: self.getValuesFromTxtBox(self.varDirSearch))
        self.OK_ParBuff18.place(x=self.xButton, y=self.yAddText, height=20, width=50)
        
        self.yAddText = self.yAddText + 30
        Label(frame2, text="Variable sub folder search: ").place(x=10, y=self.yAddText)
        self.varSubDirSearch = StringVar()
        self.varSubDirSearch_Param = Entry(frame2, textvariable=self.varSubDirSearch)
        self.varSubDirSearch_Param.place(x=self.xText, y=self.yAddText, width=60, height=20)
        self.varSubDirSearch.set('_0.jpg')                
        self.OK_ParBuff17 = Button(frame2, text="Get", command= lambda: self.getValuesFromTxtBox(self.varSubDirSearch))
        self.OK_ParBuff17.place(x=self.xButton, y=self.yAddText, height=20, width=50)
             
        self.yAddText = self.yAddText + 30
        self.imgList = Button(frame2, text="Image master list", style="RB.TButton", command=self.getImgList)
        self.imgList.place(x=10, y=self.yAddText)
                
                
        #set parameters for template matching
        self.yAddText = self.yAddText + 70
        Label(frame2, text="Template size x: ").place(x=10, y=self.yAddText)
        self.template_size_x = IntVar()
        self.template_size_x_Param = Entry(frame2, textvariable=self.template_size_x)
        self.template_size_x_Param.place(x=self.xText, y=self.yAddText, width=60, height=20)
        self.template_size_x.set(300)                
        self.OK_ParBuff11 = Button(frame2, text="Get", command= lambda: self.getValuesFromTxtBox(self.template_size_x))
        self.OK_ParBuff11.place(x=self.xButton, y=self.yAddText, height=20, width=50)
        
        self.yAddText = self.yAddText + 30
        Label(frame2, text="Template size y: ").place(x=10, y=self.yAddText)
        self.template_size_y = IntVar()
        self.template_size_y_Param = Entry(frame2, textvariable=self.template_size_y)
        self.template_size_y_Param.place(x=self.xText, y=self.yAddText, width=60, height=20)
        self.template_size_y.set(300)                
        self.OK_ParBuff12 = Button(frame2, text="Get", command= lambda: self.getValuesFromTxtBox(self.template_size_y))
        self.OK_ParBuff12.place(x=self.xButton, y=self.yAddText, height=20, width=50)       
        
        self.yAddText = self.yAddText + 30
        Label(frame2, text="Search area x: ").place(x=10, y=self.yAddText)
        self.search_area_x = IntVar()
        self.search_area_x_Param = Entry(frame2, textvariable=self.search_area_x)
        self.search_area_x_Param.place(x=self.xText, y=self.yAddText, width=60, height=20)
        self.search_area_x.set(500)                
        self.OK_ParBuff13 = Button(frame2, text="Get", command= lambda: self.getValuesFromTxtBox(self.search_area_x))
        self.OK_ParBuff13.place(x=self.xButton, y=self.yAddText, height=20, width=50)
        
        self.yAddText = self.yAddText + 30
        Label(frame2, text="Search area y: ").place(x=10, y=self.yAddText)
        self.search_area_y = IntVar()
        self.search_area_y_Param = Entry(frame2, textvariable=self.search_area_y)
        self.search_area_y_Param.place(x=self.xText, y=self.yAddText, width=60, height=20)
        self.search_area_y.set(500)                
        self.OK_ParBuff14 = Button(frame2, text="Get", command= lambda: self.getValuesFromTxtBox(self.search_area_y))
        self.OK_ParBuff14.place(x=self.xButton, y=self.yAddText, height=20, width=50)
        
        self.yAddText = self.yAddText + 30
        Label(frame2, text="Error threshold (%): ").place(x=10, y=self.yAddText)
        self.error_accpt = DoubleVar()
        self.error_accpt_Param = Entry(frame2, textvariable=self.error_accpt)
        self.error_accpt_Param.place(x=self.xText, y=self.yAddText, width=60, height=20)
        self.error_accpt.set(0.01)                
        self.OK_ParBuff15 = Button(frame2, text="Get", command= lambda: self.getValuesFromTxtBox(self.error_accpt))
        self.OK_ParBuff15.place(x=self.xButton, y=self.yAddText, height=20, width=50)
        
        self.yAddText = self.yAddText + 30
        Label(frame2, text="Maximum points skip able: ").place(x=10, y=self.yAddText)
        self.max_ptsToSkip = IntVar()
        self.max_ptsToSkip_Param = Entry(frame2, textvariable=self.max_ptsToSkip)
        self.max_ptsToSkip_Param.place(x=self.xText, y=self.yAddText, width=60, height=20)
        self.max_ptsToSkip.set(5)                
        self.OK_ParBuff16 = Button(frame2, text="Get", command= lambda: self.getValuesFromTxtBox(self.max_ptsToSkip))
        self.OK_ParBuff16.place(x=self.xButton, y=self.yAddText, height=20, width=50)
        
        #check if results should be illustrated
        self.yAddText = self.yAddText + 30
        self.plot_results2 = BooleanVar()
        self.plot_results2.set(False)
        self.plot_resultsBut2 = Checkbutton(frame2, text = "Plot results", variable=self.plot_results2)
        self.plot_resultsBut2.place(x=10, y=self.yAddText)
                    
        #check if save images with matched points
        self.save_img = BooleanVar()
        self.save_img.set(False)
        self.save_imgBut = Checkbutton(frame2, text = "Save image with matches", variable=self.save_img)
        self.save_imgBut.place(x=180, y=self.yAddText)
        
        self.templateMatch = Button(frame2, text="Template matching", style="RB.TButton", command=self.performTemplateMatching)
        self.templateMatch.place(x=10, y=self.yAddText+30)
        
        
        '''----------------get location approximated waterlines (account for camera movement)-------------------'''
        frame3 = Frame(note)  
        note.add(frame3, text="2D to 3D (and again 2D)")
        note.grid(row=0, column=0, ipadx=350, ipady=200)
        
        self.yAddText = 10     
        self.xButton = 390
        self.xText = 290
        
        Label(frame3, text="Exterior orientation (estimates): ").place(x=10, y=self.yAddText)
        self.yAddText = self.yAddText + 20
        self.exterior_approx_raw = StringVar()
        self.exterior_approx_raw_Param = Entry(frame3, textvariable=self.exterior_approx_raw)
        self.exterior_approx_raw_Param.place(x=10, y=self.yAddText, width=300, height=20)
        self.exterior_approx_raw.set('281, 4288, 2255, -0.053, -0.857, -1.908')                
        self.OK_ParBuff31 = Button(frame3, text="Get", command= lambda: self.getValuesFromTxtBox(self.exterior_approx_raw))
        self.OK_ParBuff31.place(x=320, y=self.yAddText, height=20, width=50)
        
        self.yAddText = self.yAddText + 30
        Label(frame3, text="Unit GCP (mm): ").place(x=10, y=self.yAddText)  
        self.unit_gcp = IntVar()
        self.unit_gcp_Param = Entry(frame3, textvariable=self.unit_gcp)
        self.unit_gcp_Param.place(x=self.xText, y=self.yAddText, width=100, height=20)
        self.unit_gcp.set(1000)                
        self.OK_ParBuff32 = Button(frame3, text="Get", command= lambda: self.getValuesFromTxtBox(self.unit_gcp))
        self.OK_ParBuff32.place(x=self.xButton, y=self.yAddText, height=20, width=50)
         
        self.yAddText = self.yAddText + 30 
        Label(frame3, text="Minimum sigma 0 (resection): ").place(x=10, y=self.yAddText)
        self.min_s0 = DoubleVar()
        self.min_s0_Param = Entry(frame3, textvariable=self.min_s0)
        self.min_s0_Param.place(x=self.xText, y=self.yAddText, width=100, height=20)
        self.min_s0.set(0.1)                
        self.OK_ParBuff33 = Button(frame3, text="Get", command= lambda: self.getValuesFromTxtBox(self.min_s0))
        self.OK_ParBuff33.place(x=self.xButton, y=self.yAddText, height=20, width=50)
         
        self.yAddText = self.yAddText + 30
        Label(frame3, text="Skip value (prior starting): ").place(x=10, y=self.yAddText)
        self.skip_val = IntVar()
        self.skip_val_Param = Entry(frame3, textvariable=self.skip_val)
        self.skip_val_Param.place(x=self.xText, y=self.yAddText, width=100, height=20)
        self.skip_val.set(0)                
        self.OK_ParBuff34 = Button(frame3, text="Get", command= lambda: self.getValuesFromTxtBox(self.skip_val))
        self.OK_ParBuff34.place(x=self.xButton, y=self.yAddText, height=20, width=50)
         
        self.yAddText = self.yAddText + 30 
        Label(frame3, text="Maximum distance NN search (pix): ").place(x=10, y=self.yAddText)
        self.max_NN_dist = IntVar()
        self.max_NN_dist_Param = Entry(frame3, textvariable=self.max_NN_dist)
        self.max_NN_dist_Param.place(x=self.xText, y=self.yAddText, width=100, height=20)
        self.max_NN_dist.set(1)                
        self.OK_ParBuff35 = Button(frame3, text="Get", command= lambda: self.getValuesFromTxtBox(self.max_NN_dist))
        self.OK_ParBuff35.place(x=self.xButton, y=self.yAddText, height=20, width=50)
        
        self.yAddText = self.yAddText + 30 
        Label(frame3, text="Maximum orientation difference to estimates: ").place(x=10, y=self.yAddText)
        self.max_orient_diff = DoubleVar()
        self.max_orient_diff_Param = Entry(frame3, textvariable=self.max_orient_diff)
        self.max_orient_diff_Param.place(x=self.xText, y=self.yAddText, width=100, height=20)
        self.max_orient_diff.set(0.1)                
        self.OK_ParBuff36 = Button(frame3, text="Get", command= lambda: self.getValuesFromTxtBox(self.max_orient_diff))
        self.OK_ParBuff36.place(x=self.xButton, y=self.yAddText, height=20, width=50)

                
        #check if results should be illustrated
        self.yAddText = self.yAddText + 30
        self.plot_results3 = BooleanVar()
        self.plot_results3.set(False)
        self.plot_resultsBut3 = Checkbutton(frame3, text = "Plot results", variable=self.plot_results3)
        self.plot_resultsBut3.place(x=10, y=self.yAddText)
                    
        #check if RANSAC used for approximation values
        self.use_ransac_for_approx = BooleanVar()
        self.use_ransac_for_approx.set(False)
        self.use_ransac_for_approxBut = Checkbutton(frame3, text = "RANSAC for estimates", variable=self.use_ransac_for_approx)
        self.use_ransac_for_approxBut.place(x=100, y=self.yAddText)
               
        
        self.yAddText = self.yAddText + 30
        Label(frame3, text="Waterline approximation or water level retrieval: ").place(x=10, y=self.yAddText)
        self.waterlineApprox3D = IntVar()
        self.waterlineApprox3D.set(0)
        self.yAddText = self.yAddText + 20
        self.waterlineApprox3DBut = Radiobutton(frame3, text = "Water line Approx", variable=self.waterlineApprox3D, value=1)
        self.waterlineApprox3DBut.place(x=10, y=self.yAddText, height=20)
        self.waterlineApprox3DBut = Radiobutton(frame3, text = "Water level Retrieval", variable=self.waterlineApprox3D, value=0)
        self.waterlineApprox3DBut.place(x=150, y=self.yAddText, height=20)        
        
        
        self.templateMatch = Button(frame3, text="Get 3D from 2D", style="RB.TButton", command=self.get3Dfrom2D)
        self.templateMatch.place(x=10, y=self.yAddText+30)
             
        
    def get3Dfrom2D(self):
        
        '''----read input----'''
        #read parameters from GUI
        try:
            use_ransac_for_approx = self.use_ransac_for_approx.get()
            plot_results = self.plot_results3.get()
            
            exterior_approx_rawStr = self.exterior_approx_raw.get()
            exterior_approx_raw = exterior_approx_rawStr.split(',')
            exterior_approx_raw = np.asarray([float(x) for x in exterior_approx_raw]).reshape(6,1)
            unit_gcp = self.unit_gcp.get()
            min_s0 = self.min_s0.get()
            skip_val = self.skip_val.get()
            max_NN_dist = self.max_NN_dist.get()
            max_orient_diff = self.max_orient_diff.get()
        
        except Exception as e:
            print(e)
            exc_type, exc_obj, exc_tb = sys.exc_info()
            fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
            print(exc_type, fname, exc_tb.tb_lineno)            
            self.printTxt('retrieving parameters failed\n')        
        
        
        #read parameters from directories
        failing = True
        while failing:
            try:
                dir_output = tkFileDialog.askdirectory(title='Output directory')
                dir_output = dir_output + '/'
                dir_imgCooGCP = tkFileDialog.askdirectory(title='Directory of GCP image coordinates')
                dir_imgCooGCP = dir_imgCooGCP + '/'
                
                if self.waterlineApprox3D.get() == 1:
                    waterline_file = tkFileDialog.askopenfilename(title='File with initial waterline', 
                                                                  filetypes=[('Text file (*.txt)', '*.txt')],initialdir=os.getcwd())
                else:
                    directory_waterline = tkFileDialog.askdirectory(title='Directory of waterlines') + '/'
                    
                GPC_coo_file = tkFileDialog.askopenfilename(title='File with GCP coordinates (3D)', 
                                                            filetypes=[('Text file (*.txt)', '*.txt')],initialdir=os.getcwd())
                ior_file = tkFileDialog.askopenfilename(title='Read interior orientation file', 
                                                        filetypes=[('Text file (*.txt)', '*.txt')],initialdir=os.getcwd())
                model_3Dpts = tkFileDialog.askopenfilename(title='Read 3D point cloud (XYZ)', 
                                                           filetypes=[('Text file (*.txt)', '*.txt')],initialdir=os.getcwd())

                failing = False
            
            except Exception as e:
                print(e)
                exc_type, exc_obj, exc_tb = sys.exc_info()
                fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
                print(exc_type, fname, exc_tb.tb_lineno)
                self.printTxt('failed reading directories, please try again\n')
                self.dummy()


        '''----start processing----'''
        try:
            '''prepare output'''
            #write files ransac result
            if use_ransac_for_approx:
                ransac_result_file = open(dir_output + 'ransac_result.txt', 'wb')
                writer = csv.writer(ransac_result_file, delimiter=' ')
                writer.writerow(['datetime', 'X', 'Y', 'Z', 'nbr_inliers', 'outliers'])

            #write files orientation result
            calib_results_output = ['image', 's0', 'X','stdX', 'Y', 'stdY', 'Z', 'stdZ',
                                    'omega', 'stdomega', 'phi', 'stdphi', 'kappa', 'stdkappa']
            calib_results_output = pd.DataFrame(calib_results_output).T
            calib_results_output.to_csv(dir_output + 'AccuracyCamOrient.txt', sep='\t', index=False, header=False)
            
            #write files water level result
            ouput_waterlevel_file = open(dir_output + 'waterlevel.txt', 'wb')
            writer_waterlevel =  csv.writer(ouput_waterlevel_file, delimiter=' ')
            
            #write output 3D measurement
            if self.waterlineApprox3D.get() == 1:                  
                file_3D = open(dir_output + 'Waterline_Approx_3D.txt', 'wb')
            else:
                file_3D = open(dir_output + 'Waterline_3D.txt', 'wb')            
            
            
            '''read measurements'''
            if self.waterlineApprox3D.get() == 1:
                #read waterline file
                waterline_table = pd.read_table(waterline_file, header=None, delimiter=',')
                waterline = np.asarray(waterline_table)            
            
            #read interior orientation from file (aicon)
            interior_orient = georef.camera_interior()
            interior_orient.read_aicon_ior(ior_file)
            
            #convert camera parameters to pixel value for opencv
            pixel_size = interior_orient.sensor_size_x / interior_orient.resolution_x
            ck = -1 * interior_orient.ck / pixel_size
            xh = interior_orient.resolution_x / 2
            yh = interior_orient.resolution_y / 2
            cam_file_forOpenCV = [ck, xh, yh, 0, 0, 0, 0, 0]            
            
            #read point cloud
            pt_cloud_table = pd.read_csv(model_3Dpts, header=None, index_col=False, delimiter=',')
            ptCloud = np.asarray(pt_cloud_table,dtype=np.float)
            del pt_cloud_table
                        
            #read object coordinates of GCP (including point ID)
            gcp_table = pd.read_csv(GPC_coo_file, header=None, index_col=False, delimiter='\t')
            gcp_table = np.asarray(gcp_table,dtype=np.float)
            gcp_table[:,1:4] = gcp_table[:,1:4] * unit_gcp

            
            '''prepare water line data'''                   
            #get water line dates
            waterline_dates = []
            for imgGCPCoo_file in os.listdir(dir_imgCooGCP):
                if 'imgPtsGCP_' in imgGCPCoo_file:
                    waterline_date = imgGCPCoo_file[10:-4]
                    waterline_dates.append(waterline_date)
            waterline_dates = sorted(waterline_dates)
                
            #search for waterline files
            if self.waterlineApprox3D.get() == 0:
                #undistort image measurements of waterline            
                waterline_files = []
                if os.path.isdir(directory_waterline):
                    for file_line in os.listdir(directory_waterline):
                        if 'wasserlinie' in file_line:
                            waterline_files.append(file_line)
                waterline_files =  sorted(waterline_files, key=lambda waterline_order: waterline_order)
 
 
            '''start 3D retrieval'''
            position_ref = 0
            nbr_img = 0   
            XYZ_estim = False
            waterline_3D_approx_given = False
            skip_val = skip_val - 1        
            waterline_found = False
            
            img_measures = georef.image_measures()
            waterline_pt_cl = georef.PtImg()
            pts_to_undist_cl = georef.PtImg()
            cl_2D_3D = georef.TwoD_to_ThreeD()
            conversionMat = georef.conversions()
            pt3D = georef.Pt3D()
            waterline_xy = georef.PtImg()
            
            while nbr_img < len(waterline_dates): 
                
                waterline_date = str(waterline_dates[nbr_img])    #str(waterline[0])    in case of longer date name
                
                '''read data for each iteration'''
                #read water line if list of water lines
                if self.waterlineApprox3D.get() == 0:
                    for waterline_file in waterline_files:
                        if waterline_date == waterline_file[12:-4]:
                            waterline_table = pd.read_table(directory_waterline + waterline_file, header=None, delimiter=',')
                            waterline = np.asarray(waterline_table)
                            waterline_found = True
                            break
                    if not waterline_found:
                        nbr_img = nbr_img + 1
                        skip_val = skip_val + 1
                        print('no waterline file given')          
                        continue    
                
                #read pixel coordinates from corresponding files of template matching results    
                pts_table = pd.read_csv(dir_imgCooGCP + 'imgPtsGCP_' + str(waterline_dates[nbr_img] + '.txt'),
                                        header=None, index_col=False, delimiter='\t') #'_ellipse' +
                pts_table = np.asarray(pts_table, dtype=np.float)
                pts_ids = pts_table[:,0]
                pts_ids = pts_ids.reshape(pts_ids.shape[0],1)
                pts_to_undist = pts_table[:,1:3]
             
                self.printTxt('process ' + waterline_date + '\n')
                self.dummy()
                 
                 
                '''undistort image measurements'''
                #undistort waterline measurement
                waterline_pt = waterline[:,:]
                waterline_pt_cl.read_imgPts(waterline_pt)
                
                waterline_pts_undist = img_measures.undistort_img_coos(waterline_pt_cl, interior_orient)
                waterline_pts_undist_px = img_measures.metric_to_pixel(waterline_pts_undist, interior_orient)
                 
                #undistort image measurements of GCP measurements
                pts_to_undist_cl.read_imgPts(pts_to_undist)
                img_pts_undist_metric = img_measures.undistort_img_coos(pts_to_undist_cl, interior_orient, False)               
             
             
                '''re-organise coordinates to numpy matrix with assigned pt ids'''
                img_pts_undist_metric_id = np.hstack((pts_ids, img_pts_undist_metric.x.reshape(img_pts_undist_metric.x.shape[0],1)))
                img_pts_undist_metric_id = np.hstack((img_pts_undist_metric_id, img_pts_undist_metric.y.reshape(img_pts_undist_metric.y.shape[0],1)))
                ImgGCPCoo, _ = cl_2D_3D.assign_ImgToObj_Measurement(gcp_table, img_pts_undist_metric_id)     
                  
              
                '''get exterior camera geometry''' 
                if use_ransac_for_approx: 
                    '''using RANSAC in OpenCV'''
                    #convert image measurements into pixels for opencv
                    img_pts_undist = img_measures.metric_to_pixel(img_pts_undist_metric, interior_orient)
                    img_pts_undist = np.hstack((pts_ids, img_pts_undist))
                    ImgGCPCoo_pix, _ = cl_2D_3D.assign_ImgToObj_Measurement(gcp_table, img_pts_undist)
                   
                    #get camera position with OpenCV
                    rot_mat, position, inliers = cl_2D_3D.image_orientation_RANSAC(ImgGCPCoo_pix, cam_file_forOpenCV)   #True, img_to_read
                     
                    #convert rot_mat into angles
                    conversionMat = georef.conversions()
                    exterior_approx = conversionMat.rotMat_to_angle(rot_mat, position)
                    self.printTxt(exterior_approx)
                    self.dummy()
                    
                    if inliers == None:
                        inliers = [-999]
                        writer.writerow([waterline_date, position[0,0], position[1,0], position[2,0], '-'])
                    else:
                        writer.writerow([waterline_date, position[0,0], position[1,0], position[2,0], len(inliers)])
                    ransac_result_file.flush()
                
                 
                '''using resection with adjustment'''
                cam_file_forResection = [interior_orient.ck, interior_orient.xh, interior_orient.yh,    #note that ck is negative (used unchanged from aicon)
                                         0, 0, 0, 0, 0, 0, 0, 0]
                if not use_ransac_for_approx:
                    exterior_approx = np.zeros((exterior_approx_raw.shape[0],1))
                    exterior_approx[:] = exterior_approx_raw[:]
                
                resection = georef.resection()
                    
                calib_results, s0 = resection.resection(cam_file_forResection, exterior_approx, ImgGCPCoo, 0.00001, plot_results)
                if not calib_results[0,0] == -9999:
                    #print(calib_results)
                        
                    position = calib_results[0:3,0] / unit_gcp
                        
                    # rotation = calib_results[3:6,0]        
                    #convert angles into rotation matrix
                    rot_mat = conversionMat.rot_Matrix(calib_results[3,0], calib_results[4,0], calib_results[5,0], 'radians').T
                    multipl_array = np.array([[-1,-1,-1],[1,1,1],[-1,-1,-1]])
                    rot_mat = rot_mat * multipl_array
                    
                    accuracyCamOrient_output = [waterline_date] + [s0[0,0]] + calib_results.flatten().tolist()
                    accuracyCamOrient_output = pd.DataFrame(accuracyCamOrient_output).T
                    accuracyCamOrient_output.to_csv(dir_output + 'AccuracyCamOrient.txt', mode='a', sep='\t', index=False, header=False)

                else:
                    self.printTxt('referencing skipped\n')
                    nbr_img = nbr_img + 1
                    skip_val = skip_val + 1
                    calib_results_output = [waterline_date, -9999]
                    calib_results_output = pd.DataFrame(calib_results_output).T
                    calib_results_output.to_csv(dir_output + 'AccuracyCamOrient.txt', mode='a', sep='\t', index=False) 
                    continue
            
                #process only waterlines where referencing at least within 90% of good registration
                if nbr_img == skip_val:
                    position_ref_neg = position - max_orient_diff * position   
                    position_ref_pos = position + max_orient_diff * position   
                    position_ref = 1
                    print('orient range: ' + str(position_ref_neg) + str(position_ref_pos))
                if position_ref == 1 and nbr_img > skip_val:
                    if (position_ref_neg[0] > position[0] or position_ref_pos[0] < position[0] or
                        position_ref_neg[1] > position[1] or position_ref_pos[1] < position[1] or
                        position_ref_neg[2] > position[2] or position_ref_pos[2] < position[2]):        
                        print('orientation too large deviations')
                        nbr_img = nbr_img + 1 
                        continue
                 
                eor_mat = np.hstack((rot_mat.T, position.reshape(position.shape[0],1))) #if rotation matrix received from opencv transpose rot_mat
                eor_mat = np.vstack((eor_mat, [0,0,0,1]))
                 
                if position[0] < 0 or position[1] < 0 or position[2] < 0:   #projection center needs to be positive
                    print('failed image referencing')
                    nbr_img = nbr_img + 1 
                    continue
                 
                print('image referenced: ' + str(position))
                
                 
                '''project into image space'''
                if self.waterlineApprox3D.get() == 0:
                    waterline_3D_approx_given = False
                
                if not waterline_3D_approx_given:  
                    if nbr_img > skip_val and s0 < min_s0:  #minimum quality of resection needed        
                        #project points into depth image
                        if ptCloud.shape[1] > 3:
                            pt3D.rgb = True
                        
                        pt3D.read_imgPts_3D(ptCloud)
                        
                        try: 
                            xyd_rgb_map = cl_2D_3D.project_pts_into_img(eor_mat, interior_orient, pt3D, plot_results,False)
                        except Exception as e:
                            print(e)
                            print('registration image erroneous')
                            nbr_img = nbr_img + 1 
                            continue
                             
                        print('point cloud projected into img')  
                         
                        #find nearest depth value to waterline in depth image
                        waterline_xyz = cl_2D_3D.NN_pts(xyd_rgb_map, waterline_pts_undist_px, max_NN_dist, False)
                        if waterline_xyz == None:
                            print('no NN for waterlevel')
                            nbr_img = nbr_img + 1 
                            continue
                        print('nearest neighbours found')
                                                
                        
                        '''project into object space again'''  
                        #transform image measurement into object space
                        try:
                            waterline_xy.x = waterline_xyz.X
                            waterline_xy.y = waterline_xyz.Y
                            imgPts_mm = img_measures.pixel_to_metric(waterline_xy, interior_orient)
                        except Exception as e:
                            print(e)
                            nbr_img = nbr_img + 1 
                            continue    
                        
                        waterline_xyz.X = imgPts_mm.x
                        waterline_xyz.Y = imgPts_mm.y
            
                        xyd_map_mm = cl_2D_3D.imgDepthPts_to_objSpace(waterline_xyz, eor_mat, interior_orient)
                          
                        #write output
                        xyd_map_mm_write = np.hstack((xyd_map_mm.X.reshape(xyd_map_mm.X.shape[0],1), xyd_map_mm.Y.reshape(xyd_map_mm.Y.shape[0],1)))
                        xyd_map_mm_write = np.hstack((xyd_map_mm_write, xyd_map_mm.Z.reshape(xyd_map_mm.Z.shape[0],1))) 
                        writer = csv.writer(file_3D, delimiter=' ')
                        writer.writerows(xyd_map_mm_write)
                        file_3D.flush()
                        
                        XYZ_estim = True
                        waterline_3D_approx_given = True
                    
                    if nbr_img == skip_val and s0 >= min_s0:
                        skip_val = skip_val + 1
                        nbr_img = nbr_img + 1
                        continue
                    
                elif skip_val > nbr_img:
                    nbr_img = nbr_img + 1
                    continue
                
                
                '''re-project found approx-waterline 3D coordinates into image space of each frame to account for camera movements and get adopted approx position'''
                if self.waterlineApprox3D.get() == 1:
                    if nbr_img > skip_val and s0 < min_s0 and XYZ_estim == True:  #minimum quality of resection needed 
                        #project points into image
                        try:
                            xy_waterline_approx = cl_2D_3D.project_pts_into_img(eor_mat, interior_orient, xyd_map_mm, plot_results)
                            # xy_waterline_approx_xy = np.hstack((xy_waterline_approx.X, xy_waterline_approx.Y))
                        except:
                            print('registration image erroneous. waterline approx 3D not projectable into image space.')
                            nbr_img = nbr_img + 1 
                            continue
                         
                        print('waterline approx 3D projected into img')
                        
                        #write output
                        log_file_temp = open(dir_output + waterline_date + 'waterline_approx.txt', 'wb')
                        writer2 = csv.writer(log_file_temp, delimiter=',')
                        xy_waterline_approx_write = np.hstack((xy_waterline_approx.X.reshape(xy_waterline_approx.X.shape[0],1), 
                                                               xy_waterline_approx.Y.reshape(xy_waterline_approx.Y.shape[0],1)))                        
                        writer2.writerows(xy_waterline_approx_write)
                        log_file_temp.flush()
                        log_file_temp.close()
                    
                    else:
                        nbr_img = nbr_img + 1
                        continue            
                
                else:
                    '''calculate median of all height values to get one waterlevel measurement'''
                    waterlevel_mean = np.mean(xyd_map_mm.Z)
                    waterlevel_median = np.median(xyd_map_mm.Z)
                    waterlevel_std = np.std(xyd_map_mm.Z)
                    waterlevel_min = np.min(xyd_map_mm.Z)
                    waterlevel_max = np.max(xyd_map_mm.Z)
                    writer_waterlevel.writerow([waterline_date, waterlevel_mean, waterlevel_median, waterlevel_std, waterlevel_min, waterlevel_max, s0[0,0]])
                    ouput_waterlevel_file.flush()
                
                nbr_img = nbr_img + 1   
        
            self.printTxt('getting waterline approxmation finisched successfully\n') 
        
        except Exception as e:
            print(e)
            exc_type, exc_obj, exc_tb = sys.exc_info()
            fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
            print(exc_type, fname, exc_tb.tb_lineno)
            self.printTxt('getting waterline approxmation failed\n')  
            

    def printTxt(self, txt):
        self.textbox.insert(END, txt)
        return

    def dummy(self):
        self.textbox.insert(END, ' ')
        return

    def getImgList(self):
        
        failing = True
        while failing:
            try:
                directory_folders = tkFileDialog.askdirectory(title='Directory to search in') 
#                 if type(directory_folders) == unicode:
#                     directory_folders = directory_folders.encode('ascii','ignore')
                directory_results = tkFileDialog.askdirectory(title='Output Directory')
                failing = False
            except Exception as e:
                print(e)
                self.printTxt('failed reading directories, please try again\n')
        
        #search through directory for sub-directories
        try:
            self.printTxt('start image retrieval\n')
            
            dir_folders = []
            var_dirsearch = self.varDirSearch.get()
            var_subdirsearch = self.varSubDirSearch.get()
            if os.path.isdir(directory_folders):
                for dirpath, dirsubpaths, dirfiles in os.walk(directory_folders):                    
                    for folder in dirsubpaths:                        
                        if var_dirsearch in folder:   #'2017', 'coreg'
            #                 dir_folders.append(folder)
                            
                            for files in os.listdir(dirpath + '/' + folder + '/'):    #
                                if var_subdirsearch in files:      #'0_coreg.jpg'
                                    if type(files) == unicode:
                                        files = files.encode('ascii','ignore')
                                    dir_folders.append(files[:-4]) #files[:-13], files[:-12]
                                    
                                    # os.system('cp -r -f ' + dirpath + '/coreg/' + files + ' ' + directory_results)
                                    os.system('cp -r -f ' + dirpath + '/' + folder + '/' + files + ' ' + directory_results)
            
            folder_list =  sorted(dir_folders, key=lambda folder_order: folder_order)
            
            img_file_write = open(directory_results + 'img_list.txt', 'wb')
            writer_img = csv.writer(img_file_write, delimiter=' ', quoting=csv.QUOTE_MINIMAL)
            writer_img.writerow(folder_list)
            img_file_write.flush()
            
            self.printTxt('finished image retrieval\n')
        
        except Exception as e:
            print(e)
            self.printTxt('searching through directory failed\n')    
        
      
    def performTemplateMatching(self):
        
        try:
            #read parameters from entry
            plot_results = self.plot_results2.get()
            save_img = self.save_img.get()
            template_size_x = self.template_size_x.get()
            template_size_y = self.template_size_y.get()
            search_area_x = self.search_area_x.get()
            search_area_y = self.search_area_y.get()
            error_accpt = self.error_accpt.get()
            max_ptsToSkip = self.max_ptsToSkip.get()

        except Exception as e:
            print(e)
            exc_type, exc_obj, exc_tb = sys.exc_info()
            fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
            print(exc_type, fname, exc_tb.tb_lineno)            
            self.printTxt('retrieving parameters failed\n')               
            
            
        failing = True
        while failing:  
            try:   
                directory_output = tkFileDialog.askdirectory(title='Output Directory') + '/'
                
                directory_img = tkFileDialog.askdirectory(title='Directory images for template matching') + '/'
                
                if self.save_img.get():
                    directory_output_img = tkFileDialog.askdirectory(title='Output directory images TM result')+ '/'
                
                img_start = tkFileDialog.askopenfilename(title='Open 1st template image', 
                                                         filetypes=[('Image file (*.jpg)', '*.jpg')],initialdir=os.getcwd())
                
                imgCooGCP_file_start = tkFileDialog.askopenfilename(title='Open GCP img coordinates of 1st template', 
                                                         filetypes=[('Txt file (*.txt)', '*.txt')],initialdir=os.getcwd())
                
                failing = False
                
            except Exception as e:
                print(e)
                exc_type, exc_obj, exc_tb = sys.exc_info()
                fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
                print(exc_type, fname, exc_tb.tb_lineno)
                self.printTxt('loading data for template matching failed, please try again\n')
        
        try:   
            #print parameters   
            self.printTxt('-----Parameter settings template matching-----\n')
            self.printTxt('-----Parameter settings template matching-----\n')
            self.printTxt('Template size x: ' + str(template_size_x) + '\n')
            self.printTxt('Template size y: ' + str(template_size_y) + '\n')
            self.printTxt('Search area size x: ' + str(search_area_x) + '\n')
            self.printTxt('Search area size y: ' + str(search_area_y) + '\n')
            self.printTxt('Error threshold: ' + str(error_accpt) + '\n')
            self.printTxt('Maximum points to skip: ' + str(max_ptsToSkip) + '\n')
            if save_img:   
                self.printTxt('Save images matching results\n')
            if plot_results:   
                self.printTxt('Plot results\n')     
 
 
            self.printTxt('-----start template matching-----\n')
 
            '''prepare master (template)'''
            #read image point coordinates of GCPs of template
            pts_table = pd.read_csv(imgCooGCP_file_start, header=None, index_col=False, delimiter='\t')
            pts_table = np.asarray(pts_table, dtype=np.float)
            img_pts = pts_table[:,1:3]
            
            pt_ids = pts_table[:,0]
            pt_ids = pt_ids.reshape(pt_ids.shape[0],1)
            
            #read template image 
            imgTemplate = cv2.imread(img_start, 0)     
            
            tmpMatch = tmp_match.templateMatch(template_size_x, template_size_y, search_area_x, search_area_y, plot_results)
            
            '''prepare quality control template matching'''
            img_pts_CooID = np.hstack((pt_ids, img_pts.reshape(img_pts.shape[0],2)))
            #calculate distances in image space between all points 
            pt_distances_template = np.asarray(tmpMatch.pt_distances(img_pts_CooID))            
            
            '''perform template matching for each image in dir'''
            for img_file in os.listdir(directory_img):                
                if '.jpg' in img_file:                    
                    self.printTxt('processing ' + img_file[:20] + '\n')
                    
                    #read search image 
                    imgSearch = cv2.imread(directory_img + img_file, 0)
            
                    #perform template matching
                    matched_points = tmpMatch.templateMatching(img_pts, imgTemplate, imgSearch)
                    try:
                        matched_points = np.hstack((pt_ids, matched_points.reshape(matched_points.shape[0],2)))
                    except Exception as e:
                        print(e)
                        exc_type, exc_obj, exc_tb = sys.exc_info()
                        fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
                        print(exc_type, fname, exc_tb.tb_lineno)                        
                        continue
                    
                    pt_distances_search = np.asarray(tmpMatch.pt_distances(matched_points))
                    pt_distances_search = np.hstack((matched_points, pt_distances_search[:,1].reshape(pt_distances_search.shape[0],1)))
                    pt_distances_merged = np.hstack((pt_distances_search, pt_distances_template[:,1].reshape(pt_distances_template.shape[0],1)))
                    correct_matched_pts = pt_distances_merged[pt_distances_merged[:,3] < (pt_distances_merged[:,4] + pt_distances_merged[:,4] * error_accpt)]
                    correct_matched_pts = correct_matched_pts[correct_matched_pts[:,3] > (correct_matched_pts[:,4] - correct_matched_pts[:,4] * error_accpt)]
                    
                    if correct_matched_pts.shape[0] < matched_points.shape[0]:
                        self.printTxt('skipped ' + str(correct_matched_pts.shape[0] - matched_points.shape[0]) + ' points\n')
                    
                    
                    if (np.abs(correct_matched_pts.shape[0] - matched_points.shape[0])) <= max_ptsToSkip: 
                        #write output
                        write_file = open(directory_output + 'imgPtsGCP_' + img_file[:20] + '.txt', 'wb')
                        writer = csv.writer(write_file, delimiter='\t')
                        writer.writerows(correct_matched_pts[:,0:3])
                        write_file.flush()
                        write_file.close()
                                        
                        tmpMatch.plot_pts(imgSearch, correct_matched_pts[:,1:3], switchColRow=False, plt_title='', output_save=True,
                                          output_img=os.path.join(directory_output_img, 'templates_' + img_file[:20] + '.jpg'))
                    
                    else: 
                        tmpMatch.plot_pts(imgSearch, correct_matched_pts[:,1:3], switchColRow=False, plt_title='', output_save=True, 
                                          output_img=os.path.join(directory_output_img, 'templates_' + img_file[:20] + '.jpg'), edgecolor='red')
                        self.printTxt('no img coo of GCP\n')
            
            self.printTxt('-----finished template matching-----\n')
                        
        except Exception as e:
            exc_type, exc_obj, exc_tb = sys.exc_info()
            fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
            print(exc_type, fname, exc_tb.tb_lineno)
            self.printTxt('template matching failed\n')
                            
        
    def getValuesFromTxtBox(self, parameter):
        try:
            paramRead = parameter.get()
            self.printTxt('Parameter set to: ' + str(paramRead) + '\n')
            
            return paramRead
        
        except Exception as e:
            print(e)
            self.printTxt('reading parameter failed, please try again\n')
  
  
    def loadData_images(self):

        failing = True
        while failing:
            directory_image_folders = tkFileDialog.askdirectory(title='Open Images Directory') + '/'
            
            try:
                '''search through directory for sub-directories'''
                if os.path.isdir(directory_image_folders):
                    for dirpath, dirsubpaths, dirfiles in os.walk(directory_image_folders):
                        if len(dirsubpaths) >= 1:
                            folders = dirsubpaths
                            break
                        else:
                            self.printTxt('empty directory: ' + dirpath + '\n')
                            sys.exit()
                else: 
                    self.printTxt('directory ' + directory_image_folders + ' not found\n')
                    sys.exit()
                    
                '''search through sub-directories for master file'''
                masterImg_list = []
                for video_folder in folders:
                    directory_video = directory_image_folders + video_folder + '/' + video_folder + '/'
                    for video_file in os.listdir(directory_video):
                        if '_0.jpg' in video_file:
                            masterImg_list.append([directory_video, video_file])
                masterImg_list = sorted(masterImg_list, key=lambda video: (video[0], video[1]))
                        
                '''search through sub-directories for image files'''
                image_all_list = []
                for image_folder in folders:
                    directory_image = directory_image_folders + image_folder + '/' + image_folder + '/'
                    for image_file in os.listdir(directory_image):
                        if 'jpg' in image_file or 'png' in image_file:
                            image_all_list.append([directory_image, image_file])
                image_all_list = sorted(image_all_list, key=lambda image: (image[0], image[1]))
                
                self.printTxt(str(len(image_all_list)) + ' images are loaded\n')
                
                failing = False
                
                return image_all_list, masterImg_list
            
            except Exception as e:
                print(e)
                self.printTxt('reading images failed, please try again\n')

            
    def loadData_waterlineApprox(self):      
        
        failing = True
        while failing:
            '''read water line approx files'''
            try:
                if self.waterline_approx_steady.get():
                    
                    #read file
                    waterlines_approx = tkFileDialog.askopenfilename(title='Open waterline approximated', filetypes=[('Txt files (*.txt)',
                                                                                                                      '*.txt')],initialdir=os.getcwd())
                    
                    self.printTxt(waterlines_approx + ' water line file loaded\n')
            
                    return waterlines_approx
                
                else:
                    #read directory
                    directory_waterline_approx = tkFileDialog.askdirectory(title='Open waterlines approximated directory') + '/'
                    
                    #get files in directory
                    waterlines_approx = []
                    for waterline_approx_file in os.listdir(directory_waterline_approx):
                        if '_waterline_approx.txt' in waterline_approx_file:
                            waterlines_approx.append([directory_waterline_approx, waterline_approx_file])
                    waterlines_approx = sorted(waterlines_approx)
        
                    self.printTxt(str(len(waterlines_approx)) +  ' waterlines (approximated) loaded\n')
        
                    failing = True
        
                    return waterlines_approx
                
            except Exception as e:
                print(e)
                self.printTxt('reading waterlines approximated failed, please try again\n')            
            
               
    def waterlineDetection(self):
        
        kp_nbr = 3000
        nbr_good_matches = 40        

        try:
            #get values from textbox entry
            bilat_kernelStr = self.bilat_kernelStr.get()
            bilat_kernel = bilat_kernelStr.split(':')
            bilat_kernel = [int(bilat_kernel[0]), int(bilat_kernel[1])]                    
            if self.watersideInt.get() == 0:
                waterside = "right"
            else:
                waterside = "left"                         
            buff_size_waterlineSearch = self.buff_size_waterlineSearch.get()            
            thresh_hist_waterlineSearch = self.thresh_hist_waterlineSearch.get()            
            add_thresh_grey = self.add_thresh_grey.get()              
            add_thresh_tempText = self.add_thresh_tempText.get()
            canny_kernel = self.canny_kernel.get()            
            nan_clip_size = self.nan_clip_size.get()            
            use_canny = self.use_canny.get()            
            plot_results = self.plot_results.get()
            perform_coregist = self.perform_coregist.get()
            do_continue = self.do_continue.get()
            if do_continue:
                video_value = self.video_value.get()
             
            #print parameters   
            self.printTxt('-----Parameter settings water line detection-----\n')
            self.printTxt('Buffer size: ' + str(buff_size_waterlineSearch) + '\n')
            self.printTxt('Threshold histogram: ' + str(thresh_hist_waterlineSearch) + '\n')
            self.printTxt('Add value to grey value thresh: ' + str(add_thresh_grey) + '\n')
            self.printTxt('Add value to temp texture thresh: ' + str(add_thresh_tempText) + '\n')
            self.printTxt('Kernel size bilateral filter: ' + str(bilat_kernel) + '\n')
            self.printTxt('Kernel size canny filter: ' + str(canny_kernel) + '\n')
            self.printTxt('Clip size NaN values: ' + str(nan_clip_size) + '\n')
            self.printTxt('Waterside: ' + waterside + '\n')
            if do_continue:            
                self.printTxt('Start at image: ' + video_value + '\n')            
            if self.waterline_approx_steady.get():
                self.printTxt('Waterline approx: single file\n')
            if use_canny:   
                self.printTxt('Use Canny filter\n')
            if plot_results:   
                self.printTxt('Plot results\n')            
            if perform_coregist:   
                self.printTxt('Perform co-registration\n')                 
            
            
            #load images and waterlines           
            image_all_list, masterImg_list = self.loadData_images()
            waterlines_approx = self.loadData_waterlineApprox()           

            #set output location
            failing = True
            while failing:
                try:
                    directory_results = tkFileDialog.askdirectory(title='Open Output Directory') + '/'
                    failing = False
                except Exception as e:
                    exc_type, exc_obj, exc_tb = sys.exc_info()
                    fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
                    print(exc_type, fname, exc_tb.tb_lineno)                       
                    print(e)
                    self.printTxt('reading output directory failed, please try again\n')
            
            self.printTxt('Output Directory: ' + directory_results + '\n')
            self.dummy()

        except Exception as e:
            exc_type, exc_obj, exc_tb = sys.exc_info()
            fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
            print(exc_type, fname, exc_tb.tb_lineno)   
            print(e)
            self.printTxt('water line detection failed, please try again\n')
            
        try:
            #prepare logfile
            logfile = open(directory_results + 'logfile_.txt', 'wb')
            writer = csv.writer(logfile, delimiter=' ', quoting=csv.QUOTE_MINIMAL)
            writer.writerow(['water line detection'])
            writer.writerow(['buffer size'] + [str(buff_size_waterlineSearch)])
            writer.writerow(['correlation threshold'] + [str(thresh_hist_waterlineSearch)])
            writer.writerow(['---------------------------------------------------'])
            logfile.flush()
                       
            '''------------------------------------------------------------------------------------------------------------------------------------------
            start processing
            ---------------------------------------------------------------------------------------------------------------------------------------------'''            
            #processing per master image file (and thus hour)
            coreg = wl_func.Coregsitration() 
            imgProc = wl_func.ImageProcess()
            wlEstim = wl_func.WaterlineEstimation()
            
            only_once = False
            print(masterImg_list)
            for masterImg in masterImg_list:
                if only_once:
                    continue

                if self.waterline_single.get():
                    only_once = True
                     
                if do_continue: 
                    if str((masterImg[1])[:-6]) == video_value:
                        do_continue = False
                    if do_continue:
                        continue               
            
                try:
                    self.printTxt('---------------------------------------------------------------------------\n')
                    self.printTxt('processing: ' + masterImg[0] + ' ' + masterImg[1] + '\n')
                    self.printTxt('---------------------------------------------------------------------------\n')
                    self.dummy()
                    
                    masterImg_name = (masterImg[1])[11:-6]
                    
                    temporary_folder = masterImg[0] + 'temp_' + masterImg_name + '/'
                    if not os.path.exists(temporary_folder):     #open directory for temporary saving of video frames
                        os.makedirs(temporary_folder)  
                    
                    output_folder = directory_results + masterImg[1][0:-6] + '/'
                    if not os.path.exists(output_folder):
                        os.makedirs(output_folder)

                    output_dir_coreg = output_folder + 'coreg/'
                    if not os.path.exists(output_dir_coreg):
                        os.makedirs(output_dir_coreg)
                        perform_coregist = True
                    else:
                        perform_coregist = False
                    
                    output_results_dir =  output_dir_coreg + 'results/'
                    if not os.path.exists(output_results_dir):
                        os.makedirs(output_results_dir)      
                                           
                    '''----------------------------------------------------------------------------------------------------'''   
                    '''get images from corresponding master image (and thus time/hour)'''
                    image_list = []
                    for image in image_all_list:
                        if masterImg[1][:-6] == image[1][:-6]:
                            if masterImg_name in image[1]:
                                image_list.append(image)
                                
                except Exception as e:
                    exc_type, exc_obj, exc_tb = sys.exc_info()
                    fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
                    print(exc_type, fname, exc_tb.tb_lineno)   
                    print(e)
                    print('data preparation failed')
                    continue
                                    
           
                '''----------------------------------------------------------------------------------------------------'''   
                '''co-register images of varying sources'''
                try:
                    if perform_coregist:     
                        #co-register images and frames                 
                        coreg.coregistration(image_list, output_dir_coreg, kp_nbr, False, 
                                             True, nbr_good_matches, 
                                             False, True, False)  #[video_list[0][0],  (video_list[0][1])[0:-5] + '_0.jpg']       
                        
                        #read co-registered images in directory into image list                                        
                        print(masterImg[1][0:5])
                        
                        image_list = wl_func.read_files_in_dir(output_dir_coreg, masterImg[1] + ' images coreg', masterImg[1][0:5])
                    
                except Exception as e:
                    exc_type, exc_obj, exc_tb = sys.exc_info()
                    fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
                    print(exc_type, fname, exc_tb.tb_lineno)   
                    print(e)
                    print('coregistration failed')
                    continue
              
                '''----------------------------------------------------------------------------------------------------'''   
                '''start WaterLineDetection'''
                try:        
                    #calculate and filter temporal texture        
                    border_mask_file = os.path.join(output_dir_coreg, 'mask_border.txt')
                    mean_stills, tempText_stills  = imgProc.tempTexture(image_list, output_results_dir, border_mask_file, False)
                    
                    #estimate waterline
                    if not self.waterline_approx_steady.get():
                        waterlineApproxRead = None
                        for waterline_approx_file in waterlines_approx:
                            if waterline_approx_file[1][:-21] == masterImg[1][:-6]:        
                                waterlineApproxRead = waterline_approx_file[0] + '/' + waterline_approx_file[1]
                        if waterlineApproxRead == None:
                            print('no waterline approximatio given')
                            continue
                                
                    waterline_stills, BB, corr_hist = wlEstim.waterline_estimate(tempText_stills, mean_stills, output_results_dir, waterlineApproxRead, 
                                                                                 plot_results, thresh_hist_waterlineSearch, buff_size_waterlineSearch, waterside, 
                                                                                 add_thresh_tempText, add_thresh_grey, bilat_kernel, canny_kernel, use_canny, nan_clip_size)
                        
                    print('waterline tool executed')
                
                except Exception as e:
                    
                    exc_type, exc_obj, exc_tb = sys.exc_info()
                    del exc_type, exc_obj

                    cv2.imwrite(directory_results + 'waterline_' + (masterImg[1])[:-6] + '.jpg', mean_stills)
                    
                    print(e, exc_tb.tb_lineno)
                    print('waterline detection failed')
                    continue
            
                
                '''----------------------------------------------------------------------------------------------------'''   
                '''create new waterline approximation'''
                try:
                    #log report
                    log_file_temp = open(output_results_dir + 'logfile.txt', 'rb')
                    reader = csv.reader(log_file_temp, delimiter=' ', quoting=csv.QUOTE_MINIMAL)        
                    writer.writerow(['___________________'])
                    writer.writerow([str((masterImg[1])[:-6])])
                    for row in reader:
                        writer.writerows([row])
                    logfile.flush()
                    log_file_temp.close()                         
                    
                    '''----------------------------------------------------------------------------------------------------'''   
                    '''save results'''                                  
                    #copy to result folder:
                    os.system('cp -r -f ' + output_results_dir + 'wasserlinie.txt ' + directory_results)
                    os.system('mv '+ directory_results + 'wasserlinie.txt ' + directory_results + 'wasserlinie_' + (masterImg[1])[:-5] + '.txt')  
                    os.system('cp -r -f ' + output_results_dir + 'waterline.jpg ' + directory_results)
                    os.system('mv '+ directory_results + 'waterline.jpg ' + directory_results + 'waterline_' + (masterImg[1])[:-5] + '.jpg')
                                          
                except Exception as e:
                    exc_type, exc_obj, exc_tb = sys.exc_info()
                    fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
                    print(exc_type, fname, exc_tb.tb_lineno)   
                    print(e)
                    print('waterline approximation failed') 
            
            
                #remove temporary directory of video frames and waterline
                os.system('rm -r -f ' + temporary_folder)           
            
            logfile.close()
        
        except Exception as e:
            exc_type, exc_obj, exc_tb = sys.exc_info()
            fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
            print(exc_type, fname, exc_tb.tb_lineno)   
            print(e)
            

def main():        

    print('openCV version: ' + cv2.__version__)
    
    root = Tk()
    
    app = WaterlineTool(root)   
    
    root.mainloop()   
    
    #root.destroy() # optional; see description below        



if __name__ == "__main__":
    main()  