Based on the code, you can answer the following questions: 1. Go through the code and write steps (bullet points) on how the SfM system works, you must write steps that include each function call and data IO
2. What is the assumption for the principal points in this system? Under what condition willthis assumption get violated?
3. Graph is a data structure that we used in the code for bundle adjustment. It has 5 majorfields. What are their names? What is the data in each field? How the data is organized?Why we need these 5 fields?
4. What is bundle adjustment? Explain why we need it
5. How is the fundamental matrix estimated? Explain the 8 point algorithm

Here is the code : import os
import cv2
import numpy as np
from utils.bundleAjust import bundleAdjustment
from utils.dense import denseMatch, denseReconstruction, outputPly
from utils.fundamental import default, ransacimplementation
from utils.getPose import getPose
from utils.graph import createGraph, triangulateGraph, showGraph, visualizeDense
from utils.mergeGraph import mergeG, removeOutlierPts
from utils.paresDescript import getPairSIFT

#Credits SFMedu: Structrue From Motion for Education Purpose
# % Written by Jianxiong Xiao (MIT License)


def mergeAllGraph(gL,imsize):
    graphMerged = gL[0]
    # merge partial views
    for i in range(len(gL) - 1):
        graphMerged = updateMerged(graphMerged, gL[i+1],imageSize)
    return graphMerged
def updateMerged(gA,gB,imsize):
    gt = mergeG(gA, gB)
    gt = triangulateGraph(gt, imsize)
    gt = bundleAdjustment(gt, False)
    gt = removeOutlierPts(gt, 10)
    gt = bundleAdjustment(gt)
    return gt

if __name__ == "__main__":

    #---------------------------SET PARAMETERS
    maxSize = 640 #maximum image resolution
    carpetaImagenes = 'C:\\Users\Sweta Mukkollu\Downloads\PA5\Captured_Images\\'
    debug = False
    outName = 'pc2' # ouput name for ply file (open with mesh lab to see pointcloud)
    validFile = ['jpg','png','JPG'] #valid image types
    f = 2082.7179 # Find this from the image metadata (EXIF)

    # ---------------------------SET PARAMETERS


    algoMatrizFundamental = ransacimplementation

    graphList = []

    #Upload images
    listaArchivos = os.listdir(carpetaImagenes)
    listaArchivos = sorted(listaArchivos, reverse=False)
    print(listaArchivos)
    listaImages = filter(lambda x : x.split('.')[-1] in validFile,listaArchivos )

    #Load the images
    listaImages = []
    for fname in listaArchivos:
        listaImages.append(cv2.imread(carpetaImagenes+fname))

    imageSize = listaImages[0].shape
    print ("original dimensions ",imageSize)
    #todo Scale the image if it goes over maxSize
    if imageSize[0] > maxSize:
        print ("Scaling")
        print ("Size image ",imageSize," max size ",maxSize)
        #480 640 function
        listaImages = list(map(lambda x: np.transpose(cv2.resize(x,(1280,720)),axes=[1,0,2]), listaImages))
        imageSize = listaImages[0].shape
        print ("Result size ",imageSize)

    #Calculate K
    K = np.eye(3)
    K[0][0] = f
    K[1][1] = f

    graphList = [0 for i in range(len(listaImages)-1)]
    #calculate pairs from SIFT or other local descriptor
    #calculated as successive images
    print ("Start calculating SIFT pairs")
    for i in range(len(listaImages)-1):
        keypointsA,keypointsB = getPairSIFT(listaImages[i],listaImages[i+1],show=debug)


        #Calculate the fundamental matrix or the essential matrix
        #TODO get the essentials
        if type(keypointsA[0]) == np.ndarray:
            assert(len(keypointsA.shape) == 2)
            assert (len(keypointsB.shape) == 2)
            pointsA = keypointsA
            pointsB = keypointsB
        else:
            pointsA = np.array([(keypointsA[idx].pt) for idx in range(len(keypointsA))]).reshape(-1, 1, 2)
            pointsB = np.array([(keypointsB[idx].pt) for idx in range(len(keypointsB))]).reshape(-1, 1, 2)
        pointsA = pointsA[:,[1,0]]
        pointsB = pointsB[:, [1, 0]]

        F = np.array(algoMatrizFundamental(pointsA,pointsB))
        Fmat = F[0]
        K = np.array(K)
        E = np.dot(np.transpose(K),np.dot(Fmat,K))

        # get camera pose
        Rtbest = getPose(E,K, np.hstack([pointsA,pointsB]),imageSize)

        #create graph
        graphList[i] = createGraph(i,i+1,K, pointsA, pointsB, Rtbest, f)

        #Triangular
        graphList[i] = triangulateGraph(graphList[i],imageSize)

        #visualize graph
        # showGraph(graphList[i],imageSize)

        #Bundle ajustement
        graphList[i]=bundleAdjustment(graphList[i])

        #Visualize with improvements
        # showGraph(graphList[i], imageSize)

    gM = mergeAllGraph(graphList,imageSize)
    print ("Graph merge finished")
    #View partial result
    showGraph(gM,imageSize)
    #Dense matching
    for i in range(len(listaImages)-1):
        graphList[i] = denseMatch(graphList[i],listaImages[i],
                                  listaImages[i+1], imageSize, imageSize)

    print ("Dense match ended")
    print ("Initializing dense Triangulation")
    #Dense reconstruction
    for i in range(len(listaImages) - 1):
        print (i)
        graphList[i] = denseReconstruction(graphList[i], gM,K,imageSize)
    print ("Dense rebuild finished")
    data = visualizeDense(graphList, gM, imageSize)

    outputPly(data,outName)