Beispiel #1
0
    def timeSIFT_orientation(self,
                             resolution=5000,
                             distortion_mode='Fraser',
                             display=False,
                             clahe=False,
                             tileGridSize_clahe=8):
        '''
        Function to initialize camera orientation of the reference set of images using the Micmac command Tapas

        :param resolution:
        '''
        # change from working dir to tmp dir
        os.chdir(self.tmp_path)

        # select the set of good pictures to estimate initial orientation

        for s in range(len(self.sorted_pictures)):
            if self.sorted_pictures[s, 1]:
                selected_line = self.sorted_pictures[s]

                for i in range(len(self.cam_folders)):
                    in_path = opj(self.cam_folders[i], selected_line[i + 2])
                    out_path = opj(self.tmp_path, selected_line[i + 2])
                    if clahe:
                        iu.process_clahe(in_path,
                                         tileGridSize_clahe,
                                         out_path=out_path)
                    else:
                        copyfile(in_path, out_path)

        # Execute mm3d command for orientation
        success, error = utils.exec_mm3d("mm3d Tapioca All {} {}".format(
            ".*" + self.ext, resolution),
                                         display=display)
        success, error = utils.exec_mm3d("mm3d Tapas {} {} Out={}".format(
            distortion_mode, ".*" + self.ext, Photo4d.ORI_FOLDER[4:]),
                                         display=display)

        ori_path = opj(self.project_path, Photo4d.ORI_FOLDER)
        if success == 0:
            # copy orientation file
            if os.path.exists(ori_path): rmtree(ori_path)
            copytree(opj(self.tmp_path, Photo4d.ORI_FOLDER), ori_path)
            self.in_ori = ori_path
        else:
            print("ERROR Orientation failed\nerror : " + str(error))

        os.chdir(self.project_path)
Beispiel #2
0
 def sort_picture(self, time_interval=600):
     self.sorted_pictures = iu.sort_pictures(self.cam_folders,
                                             opj(self.project_path,
                                                 Photo4d.SET_FILE),
                                             time_interval=time_interval,
                                             ext=self.ext)
     return self.sorted_pictures
Beispiel #3
0
    def initial_orientation(self, resolution=5000, distortion_mode='Fraser', display=True, clahe=False,
                            tileGridSize_clahe=8):
        '''
        Function to initialize camera orientation of the reference set of images using the Micmac command Tapas
        '''

        # add mkdir, and change dir
        tmp_path = opj(self.project_path, "tmp")
        if not os.path.exists(tmp_path): os.makedirs(tmp_path)
        os.chdir(tmp_path)

        # select the set of good pictures to estimate initial orientation
        selected_line = self.sorted_pictures[self.selected_picture_set]
        file_set = "("
        for i in range(len(self.cam_folders)):
            in_path = opj(self.cam_folders[i], selected_line[i + 1])
            out_path = opj(tmp_path, selected_line[i + 1])
            if clahe:
                iu.process_clahe(in_path, tileGridSize_clahe, out_path=out_path)
            else:
                copyfile(in_path, out_path)
            file_set += selected_line[i + 1] + "|"
        file_set = file_set[:-1] + ")"

        # Execute mm3d command for orientation
        success, error = utils.exec_mm3d("mm3d Tapioca All {} {}".format(file_set, resolution), display=display)
        success, error = utils.exec_mm3d(
            "mm3d Tapas {} {} Out={}".format(distortion_mode, file_set, Photo4d.ORI_FOLDER[4:]), display=display)

        ori_path = opj(self.project_path, Photo4d.ORI_FOLDER)
        if success == 0:
            # copy orientation file
            if os.path.exists(ori_path): rmtree(ori_path)
            copytree(opj(tmp_path, Photo4d.ORI_FOLDER), ori_path)
            self.in_ori = ori_path
        else:
            print("ERROR Orientation failed\nerror : " + str(error))

        os.chdir(self.project_path)
        # todo thisraise a permission error despite this chdir I don't know why
        try:
            rmtree(tmp_path)
        except PermissionError:
            print('WARNING Cannot delete temporary folder due to permission error')
Beispiel #4
0
 def check_picture_quality(self, luminosity_thresh=1, blur_thresh=6):
     '''
     Function to Check if pictures are not too dark and/or too blurry (e.g. fog)
     '''
     if self.sorted_pictures is None:
         print("ERROR You must launch the sort_pictures() method before check_pictures()")
         return
     self.sorted_pictures = iu.check_picture_quality(self.cam_folders, opj(self.project_path, Photo4d.SET_FILE),
                                                self.sorted_pictures,
                                                lum_inf=luminosity_thresh,
                                                blur_inf=blur_thresh)
     return self.sorted_pictures
Beispiel #5
0
def process_from_array(folders_list,
                       pictures_array,
                       output_folder,
                       incal=None,
                       inori=None,
                       pictures_ini=None,
                       gcp=None,
                       gcp_S2D=None,
                       clahe=False,
                       tileGridSize_clahe=8,
                       resol=-1,
                       distortion_model="Fraser",
                       re_estimate=False,
                       master_folder=0,
                       masq2D=None,
                       DefCor=0.0,
                       shift=None,
                       delete_temp=True,
                       display_micmac=True,
                       cond=None,
                       GNSS_PRECISION=0.2,
                       GCP_POINTING_PRECISION=5):
    """
    Do the 3D reconstruction of pictures using MicMac

    Mandatory arguments :
    :param folders_list: list of path to picture folders
            pictures are stored in a folder per camera
    :param pictures_array: array containing names of pictures to process
            each row is considered as a set, and pictures names must be in the same order as secondary_folder_list
    :param output_folder: where output file will be saved as well as where the temporary files will be created
    Reconstruction argument :
    :param resol: resolution for the research of TiePoints
            -1 stands for full resolution
    :param distortion_model: distortion model used in Tapas
            can be "Fraser", "FraserBasic", "RadialStd", "RadialBasic" and more
    :param incal: path to initial calibration folder (from MicMac), None if no initial calibration used
    :param inori: path to initial orientation folder (from MicMac), None if no initial orientation used
    :param pictures_ini: pictures of initial calibration, in the same order as secondary folder list
             None if the pictures are in pictures_array, they will be automatically detected
    :param re_estimate: -only if there is an initial orientation- if True, re estimate the orientation
    :param gcp: .xml file containing coordinates of GCPs, file from the MicMac command "GCPConvert"
    :param gcp_S2D: xml file containing image coordinates of the GCPs, result one of the "SaisieAppuis" command in MicMac

    :param master_folder: list index of the folder where "master images" for Malt reconstruction are stored
            by default it is the first folder
    :param masq2D:
    :param shift: shift for saving ply (if numbers are too big for 32 bit ply) [shiftE, shiftN, shiftZ]
    :param delete_temp: if False the temporary folder will not be deleted, but beware, MicMac files are quite heavy
    :param display_micmac: if False MicMac log will be hidden, may be useful as this may ba a bit messy sometimes
    :return:
    """
    # checking parameters :

    # it is assumed that all pictures have the same extension
    ext = pictures_array[0, 1].split('.')[-1].lower()

    nb_folders = len(folders_list)

    for i in range(nb_folders):
        if folders_list[i][-1] != "/": folders_list[i] += "/"
        if not os.path.exists(folders_list[i]):
            print(
                "WARNING the folder {} in folders_list does not exist".format(
                    folders_list[i]))

    if cond is None:

        def cond(datetime):
            return True

    if type(master_folder) != int or not (0 <= master_folder < nb_folders):
        print("Invalid value {} for parameter master folder, value set to 0".
              format(master_folder))
        print("must be one index of the array secondary_folder_list")
        master_folder = 0

    # if pictures_ini is not provided but there is an initial orientation, retrieve it from pictures array
    if inori is not None and pictures_ini is None:
        # find the name of one picture used in inori, using Orientation files
        flist = os.listdir(inori)
        image = ""
        for file in flist:
            if len(file) > 12 and file[:12] == "Orientation-":
                image = file[12:-4]  # todo qu'est ce que c'est moche
                break
        # find the row of this picture in pictures_array and use it as pictures_ini
        nb_sets, nb_pics = pictures_array.shape
        i = 0
        found = False
        while i < nb_sets and not found:
            j = 1
            while j < nb_pics and not found:
                if pictures_array[i, j] == image:
                    found = True
                j += 1
            i += 1
        if i == nb_sets - 1 and not found:
            raise ValueError(
                "Cannot find initial orientation pictures in pictures array\n"
                "Please fill parameter pictures_ini")
        pictures_ini = pictures_array[i - 1, 1:]

    if gcp is not None and gcp_S2D is not None:
        if type(gcp_S2D) == str:
            if gcp[-4:] != ".xml" or not os.path.exists(gcp_S2D):
                print(
                    "WARNING Param gcp must be an xml file from the micmac function GCPConvert"
                )
                return
            else:
                # retrieve gcp measures for all image in a dictionary
                all_gcp = XML_utils.read_S2D_xmlfile(gcp_S2D)
        elif type(gcp_S2D) == dict:
            # retrieve gcp measures for all image in a dictionary
            all_gcp = gcp_S2D
        else:
            print(
                'ERROR Param gcp_s2d must be either path to the xml or a dictionary'
            )
            return
        if not os.path.exists(gcp):
            print("WARNING Cannot open gcp file at " + gcp)
            return

    else:
        all_gcp = None

    if masq2D is not None:
        print("Collecting mask path")
        masqpath_list = ['' for i in range(pictures_array.shape[1] - 1)]
        flist = os.listdir(masq2D)
        for file in flist:
            if file[-9:] == "_Masq.tif":
                I, J = pictures_array.shape
                i = 0
                found = False
                while i < I and not found:
                    j = 1
                    while j < J and not found:

                        if pictures_array[
                                i, j].lower() == file[:-9].lower() + '.' + ext:
                            masqpath_list[j - 1] = os.path.join(masq2D, file)
                            found = True
                        j += 1
                    i += 1
        if '' in masqpath_list:
            print(
                "Cannot find pictures corresponding to mask in pictures array")
            return
    else:
        masqpath_list = None

    # launch the process
    for line in pictures_array:

        if line[0]:  # line[0] is a boolean, True if the set is correct
            list_path = []
            for i in range(1, len(folders_list) + 1):
                list_path.append(folders_list[i - 1] + str(line[i]))
            # determining which of the pictures is the master image for dense correlation (Malt)
            master_img = line[master_folder + 1]
            date = iu.load_date(list_path[0])

            if cond(date):
                info = "Processing pictures taken on " + str(date) + ":\n  "
                for img in line[1:]:
                    info += img + "  "

                print(info)

                if all_gcp is not None:
                    # create a dictionary with gcp image coordinates of this picture set
                    try:
                        set_gcp = dict([(k, all_gcp.get(k)) for k in line[1:]])
                    except AttributeError:
                        print(
                            "Couldn't find gcp measures for this set of pictures in S2D xml\nSet ignored"
                        )
                        continue
                else:
                    set_gcp = None

                copy_and_process(list_path,
                                 output_folder=output_folder,
                                 incal=incal,
                                 inori=inori,
                                 pictures_ini=pictures_ini,
                                 abs_coord_gcp=gcp,
                                 img_coord_gcp=set_gcp,
                                 re_estimate=re_estimate,
                                 master_img=master_img,
                                 masqpath_list=masqpath_list,
                                 resol=resol,
                                 distortion_model=distortion_model,
                                 DefCor=DefCor,
                                 clahe=clahe,
                                 tileGridSize_clahe=tileGridSize_clahe,
                                 shift=shift,
                                 delete_temp=delete_temp,
                                 display_micmac=display_micmac,
                                 GNSS_PRECISION=GNSS_PRECISION,
                                 GCP_POINTING_PRECISION=GCP_POINTING_PRECISION)
Beispiel #6
0
def copy_and_process(filepath_list,
                     output_folder,
                     tmp_folder_name="TMP_MicMac",
                     ply_name="",
                     clahe=False,
                     tileGridSize_clahe=8,
                     resol=-1,
                     distortion_model="RadialStd",
                     incal=None,
                     inori=None,
                     abs_coord_gcp=None,
                     img_coord_gcp=None,
                     pictures_ini=None,
                     re_estimate=False,
                     master_img=None,
                     masqpath_list=None,
                     DefCor=0.0,
                     shift=None,
                     delete_temp=True,
                     display_micmac=True,
                     GNSS_PRECISION=0.2,
                     GCP_POINTING_PRECISION=5):
    """
    copy needed files and process micmac for a set of given pictures (filepath_list)
    It is advised to give only absolute path in parameters


    :param filepath_list: list of absolute path of pictures to process
    :param output_folder: directory for saving results and process pictures
    :param tmp_folder_name: name of the temporary folder where processing pictures
            date is automatically added to the name
    :param ply_name: first part of the name of the output point-cloud, date and extension will be added automatically
    :param clahe: if True, apply a "contrast limited adaptive histogram equalization" on the pictures before processing

    MicMac parameters: (see more documentation on official github and wiki (hopefully))
    :param resol: resolution for the research of TiePoints todo demander à luc pour les racourcis
            -1 stands for full resolution
    :param distortion_model: distortion model used in Tapas
            can be "Fraser", "FraserBasic", "RadialStd", "RadialBasic" and more
    :param incal: path to initial calibration folder (from MicMac), None if no initial calibration used
    :param inori: path to initial orientation folder (from MicMac), None if no initial orientation used
    :param pictures_ini: pictures of initial calibration, in the same order as secondary folder list
    :param re_estimate: -only if there is an initial orientation- if True, re estimate the orientation
    :param abs_coord_gcp: xml file containing absolute coordinates of GCPs, file from the MicMac command GCPConvert
    :param img_coord_gcp: xml file containing image coordinates of the GCPs, result one of the SaisieAppuis command in MicMac

    :param master_img:
    :param masqpath_list: list of mask, each mask file in this list correspond to the picture of the same indice in filepath list
            list of path to .tif files from MicMac
    :param DefCor:
    :param shift: shift for saving ply (if numbers are too big for 32 bit ply) [shiftE, shiftN, shiftZ]
    :param delete_temp: if False the temporary folder will not be deleted, but beware, MicMac files are quite heavy
    :param display_micmac: if False MicMac log will be hidden, may be useful as this may ba a bit messy sometimes
    :return:
    """
    # ==================================================================================================================
    # checking path and parameters :

    # check output folder
    if not os.path.exists(output_folder): os.makedirs(output_folder)

    # check processing folder, name it according to the date of the first picture
    date = iu.load_date(filepath_list[0])
    if date is not None:
        date_str = date.strftime("%Y_%m_%d-%H_%M")
        folder_path = os.path.join(output_folder,
                                   tmp_folder_name + "_" + date_str)
    else:
        folder_path = os.path.join(
            output_folder, tmp_folder_name + filepath_list[0].split('/')[-1])
        date_str = filepath_list[0].split(
            '/'
        )[-1]  # if we can't find a date, put the name of the first picture...
    if not os.path.exists(folder_path): os.mkdir(folder_path)

    # check masks
    if masqpath_list is not None:
        if type(masqpath_list) != list or len(masqpath_list) != len(
                filepath_list):
            print("Invalid value {} for parameter masqpath_list".format(
                masqpath_list))
            print("Mask ignored")
            masqpath_list = None

    # ==================================================================================================================
    # copy pictures into the temporary folder
    pictures_pattern = "("  # pattern of pictures telling MicMac which one to process
    for i in range(len(filepath_list)):

        filepath = filepath_list[i]
        filename = os.path.basename(filepath)
        pictures_pattern += filename + "|"

        if not clahe:
            copyfile(filepath, os.path.join(folder_path, filename))

        else:
            # apply the CLAHE method, used for the orientation
            iu.process_clahe(filepath,
                             tileGridSize_clahe,
                             out_path=os.path.join(folder_path, filename),
                             grey=True)

        # copy mask corresponding to the picture
        if masqpath_list is not None:
            # copy the mask and gave it the default name of a mask created by MicMac
            copyfile(
                masqpath_list[i],
                os.path.join(folder_path,
                             '.'.join(filename.split('.')[:-1]) + "_Masq.tif"))
            # MicMac needs a xml file with the tiff file, if it doesn't exist, it is created
            if os.path.exists('.'.join(masqpath_list[i].split('.')[:-1]) +
                              '.xml'):
                copyfile(
                    '.'.join(masqpath_list[i].split('.')[:-1]) + '.xml',
                    os.path.join(
                        folder_path,
                        '.'.join(filename.split('.')[:-1]) + "_Masq.xml"))
            else:
                XML_utils.write_masq_xml(
                    masqpath_list[i], folder_path +
                    '.'.join(filename.split('.')[:-1]) + "_Masq.xml")

    pictures_pattern = pictures_pattern[:-1] + ")"

    # launching MicMac reconstruction
    # ==================================================================================================================

    # detection of Tie points
    # ===================================================
    os.chdir(folder_path)
    print(folder_path)
    # first detection of Tie points with the option ExpTxt=1 to make a report with txt
    command = 'mm3d Tapioca All {} {} ExpTxt=1'.format(pictures_pattern, resol)
    print("\033[0;33" + command + "\033[0m")
    exec_mm3d(command, display_micmac)
    # second detection of Tie points at a lower resolution, without ExpTxt=1, just to avoid a stupid MicMac bug in C3DC
    # MicMac will just convert txt to binary
    command = 'mm3d Tapioca All {} {}'.format(pictures_pattern, resol)
    print("\033[0;33" + command + "\033[0m")
    exec_mm3d(command, display_micmac)

    # Orientation of cameras
    # ===================================================

    # list picture names, used to transform orientation and calibration
    final_pictures = []
    for filepath in filepath_list:
        final_pictures.append(filepath.split("/")[-1])

    ori = distortion_model  # name of orientation, it is the distortion model by default
    # if there is an initial orientation
    print("ICIIII", inori)
    if inori is not None:

        print(os.path.basename(inori))
        # copy the initial orientation file
        new_Ori_path = os.path.join(folder_path, os.path.basename(inori))
        print("OIRIIIII", new_Ori_path)
        if not os.path.exists(new_Ori_path):
            print("COPYTREE", inori, new_Ori_path)
            copytree(
                inori, new_Ori_path
            )  # We assume that the path is correctly written ( "/Root/folder/Ori-Truc/")
        # swap pictures names to mock MicMac computed orientation files
        print(pictures_ini)
        print(final_pictures)
        XML_utils.change_Ori(pictures_ini, final_pictures, new_Ori_path)

        # if re_estimate, MicMac recompute the orientation
        if re_estimate:
            ori += "_R"
            command = 'mm3d Tapas {} {} InOri={} Out={}'.format(
                distortion_model, pictures_pattern, os.path.basename(inori),
                ori)
            print("\033[0;33" + command + "\033[0m")
            success, error = exec_mm3d(command, display_micmac)
        else:
            ori = os.path.basename(
                inori)  # name of the new ori is the same as the initial one
            success, error = 0, None
    # if there is no initial orientation but an initial calibration
    # it assumed that the calibration is the same for every picture
    elif incal is not None:
        if incal[-1] != "/": incal += "/"
        new_Cal_path = folder_path + incal.split('/')[-2] + "/"
        if not os.path.exists(new_Cal_path):
            copytree(
                incal, new_Cal_path
            )  # We assume that the path is correctly written ( "/fgg/Ori-Truc/")
        command = 'mm3d Tapas {} {} InCal={}'.format(distortion_model,
                                                     pictures_pattern,
                                                     incal.split('/')[-2])
        print("\033[0;33" + command + "\033[0m")
        success, error = exec_mm3d(command, display_micmac)

    # if no initial parameters, classic orientation computation
    else:
        command = 'mm3d Tapas {} {}'.format(distortion_model, pictures_pattern)
        print("\033[0;33" + command + "\033[0m")
        success, error = exec_mm3d(command, display_micmac)

    # if GCP are provided for Bascule (Absolute orientation)
    if abs_coord_gcp is not None and img_coord_gcp is not None:
        # copy GCP absolute coordinates
        gcp_name = os.path.basename(abs_coord_gcp)
        if abs_coord_gcp != os.path.join(folder_path, gcp_name):
            copyfile(abs_coord_gcp, os.path.join(folder_path, gcp_name))
        # create S2D xml file with images positions of gcp
        XML_utils.write_S2D_xmlfile(img_coord_gcp,
                                    os.path.join(folder_path, "GCP-S2D.xml"))

        command = 'mm3d GCPBascule {} {} Bascule_ini {} {}'.format(
            pictures_pattern, ori, gcp_name, "GCP-S2D.xml")
        print(command)
        exec_mm3d(command, display_micmac)

        command = 'mm3d Campari {} Bascule_ini Bascule GCP=[{},{},{},{}] AllFree=1'.format(
            pictures_pattern, gcp_name, GNSS_PRECISION, "GCP-S2D.xml",
            GCP_POINTING_PRECISION)
        success, error = exec_mm3d(command, display_micmac)

        ori = 'Bascule'

    # dense correlation
    # ===================================================
    if clahe:
        # clahe images were used for orientation, but we need JPG for dense correlation
        for i in range(len(filepath_list)):
            filepath = filepath_list[i]
            filename = os.path.basename(filepath)
            copyfile(filepath, os.path.join(folder_path, filename))

    ply_name += date_str + ".ply"
    command = 'mm3d Malt GeomImage {} {} Master={} DefCor={} MasqIm=Masq'.format(
        pictures_pattern, ori, master_img, DefCor)
    print("\033[0;33" + command + "\033[0m")
    success, error = exec_mm3d(command, display_micmac)

    # creation of the final point cloud file
    # ===================================================

    # create the point cloud
    if shift is None:
        command = 'mm3d Nuage2Ply MM-Malt-Img-{}/NuageImProf_STD-MALT_Etape_8.xml Attr={} Out={}'.format(
            '.'.join(master_img.split('.')[:-1]), master_img, ply_name)
    else:
        command = 'mm3d Nuage2Ply MM-Malt-Img-{}/NuageImProf_STD-MALT_Etape_8.xml Attr={} Out={} Offs={}'.format(
            '.'.join(master_img.split('.')[:-1]), master_img, ply_name,
            str(shift).replace(" ", ""))

    print("\033[0;33" + command + "\033[0m")
    success, error = exec_mm3d(command, display_micmac)

    # ==================================================================================================================
    # Make stats about the reconstruction
    with open(date_str + '_recap.txt', 'w') as recap:
        recap.write("Summary of MicMac 3D reconstruction for " + date_str +
                    "\n")
        string = "\nNumber of Tie Points : "
        df, tot = XML_utils.count_tiepoints_from_txt(folder_path)
        string += str(tot) + "\n\nFiles used :\n"
        for i in df.index.values:
            string += "  - {} taken on {} : {} tie points\n".format(
                i, iu.load_date(folder_path + i), df.loc())
        recap.write(string)

        if os.path.exists(os.path.join(folder_path, ply_name)):
            copyfile(os.path.join(folder_path, ply_name),
                     os.path.join(output_folder, ply_name))
            recap.write("\nStatus  : Success\n")
        else:
            recap.write("\nStatus  : Failure\n")

        if inori is not None:
            recap.write("\n Initial orientation used  : " + inori + "\n")
        elif incal is not None:
            recap.write("\n Initial calibration used  : " + incal + "\n")

        # write a .txt with residuals
        if ori[:4] == "Ori-":
            ori_path = folder_path + ori + "/"
        else:
            ori_path = folder_path + "Ori-" + ori + "/"
        if os.path.exists(ori_path):  # if Tapas command worked
            dict = XML_utils.extract_res(ori_path)
            recap.write(
                "\nNumber of iterations : {}   Average Residual : {}\n".format(
                    dict['nb_iters'], "%.4f" % dict['AverageResidual']))
            recap.write(
                "\nName           Residual     PercOk        Number of Tie Points\n"
            )
            for i in df.index.values:
                recap.write("{} : {}       {}       {}\n".format(
                    i, "%.4f" % float(dict[i][0]), "%.4f" % float(dict[i][1]),
                    dict[i][2]))
    copyfile(os.path.join(folder_path, date_str + '_recap.txt'),
             os.path.join(output_folder, date_str + '_recap.txt'))

    # try to delete temporary folder
    if delete_temp:
        try:
            rmtree(folder_path)
        except FileNotFoundError:
            pass
        except PermissionError:
            print("Permission Denied, cannot delete " + folder_path)
        except OSError:
            pass
    else:
        # only delete some heavy micmac files
        try:
            rmtree(folder_path + "Pastis")
            rmtree(folder_path + "Tmp-MM-Dir")
            rmtree(folder_path + "Pyram")
        except PermissionError:
            print("Permission Denied, cannot delete some MicMac files")
Beispiel #7
0
                                 display_micmac=display_micmac,
                                 GNSS_PRECISION=GNSS_PRECISION,
                                 GCP_POINTING_PRECISION=GCP_POINTING_PRECISION)


if __name__ == "__main__":
    tic = time.time()
    print("process launched")

    main_GCP_estim(
        "C:/Users/Alexis/Documents/Travail/Stage_Oslo/Test_scene_blindern/Pictures/ByCam/Cam2/",
        "DSC00918_11h30.JPG",
        points='selection-S2D.xml')
    iu.sort_pictures([
        "L:\Finse\Photo4D\Test_V1_2019/cam_east/",
        "L:\Finse\Photo4D\Test_V1_2019/cam_west/",
        "L:\Finse\Photo4D\Test_V1_2019/cam_middle/"
    ])

    array = pictures_array_from_file(
        "C:/Users/Alexis/Documents/Travail/Stage_Oslo/Grandeurnature/Pictures/linked_files.txt"
    )
    main_folder = "C:/Users/Alexis/Documents/Travail/Stage_Oslo/Grandeurnature/Pictures/"
    folders = [
        main_folder + "cam_est/", main_folder + "cam_ouest/",
        main_folder + "cam_mid/"
    ]
    output_folder = "C:/Users/Alexis/Documents/Travail/Stage_Oslo/Grandeurnature/Pictures/TestdelaMortquitue/Results/"
    masq2D = "C:/Users/Alexis/Documents/Travail/Stage_Oslo/Grandeurnature/Pictures/TestdelaMortquitue/Mask/"
    inori = "C:/Users/Alexis/Documents/Travail/Stage_Oslo/Grandeurnature/Pictures/TestdelaMortquitue/Ori-Fraser/"
    S2D = "C:/Users/Alexis/Documents/Travail/Stage_Oslo/photo4D/python_script/Stats/All_points-S2D.xml"