### Run SurfRCaT Application Source: https://github.com/conlin-matt/surfrcat/blob/master/docs/download.md Invoke the SurfRCaT tool after installation and setup by running this command. ```bash fbs run ``` -------------------------------- ### Install Python Packages with Pip Source: https://github.com/conlin-matt/surfrcat/blob/master/docs/download.md Install the fbs, pptk, and reverse_geocoder Python packages using pip. ```bash pip install fbs pptk reverse_geocoder ``` -------------------------------- ### Create Conda Environment and Install Packages Source: https://github.com/conlin-matt/surfrcat/blob/master/docs/download.md Use these commands in an Anaconda prompt to create a new environment named 'SurfRCaT_env' with Python 3.6 and necessary packages, then activate it. ```bash conda config --set channel_priority strict conda create -n SurfRCaT_env -c conda-forge python=3.6 python-pdal pyqt numpy pandas matplotlib opencv requests pyshp utm lxml ``` ```bash conda activate SurfRCaT_env ``` -------------------------------- ### Get GCP Coordinates Source: https://github.com/conlin-matt/surfrcat/blob/master/src/main/SurfRCaT_demo.ipynb Extracts Ground Control Points (GCPs) from lidar data and sorts them by their Z-coordinate. ```python GCPs_lidar = np.empty([0,3]) for i in sorted(iGCPs_lidar): GCPs_lidar = np.vstack((GCPs_lidar,pc.iloc[i,:])) iss = np.argsort(GCPs_lidar[:,2]) GCPs_lidar = np.flipud(GCPs_lidar[iss,:]) print(GCPs_lidar) ``` -------------------------------- ### Initialize Environment and Imports Source: https://github.com/conlin-matt/surfrcat/blob/master/src/main/SurfRCaT_demo.ipynb Sets up the necessary Python modules and defines the working directory for the project. ```python # Import modules # import copy import cv2 import ftplib import matplotlib matplotlib.use('TkAgg') import matplotlib.pyplot as plt import numpy as np import os import pickle import pptk import SurfRCaT import time # Create a working directory # pth = os.path.realpath('../../../') ``` -------------------------------- ### Prepare Calibration Image Source: https://github.com/conlin-matt/surfrcat/blob/master/src/main/SurfRCaT_demo.ipynb Selects a specific frame from the extracted imagery and saves it to a products directory for calibration. ```python frameNum = 20 # Can choose any of the extracted frames # img = cv2.imread(os.path.realpath(pth+os.sep+'_frames'+os.sep+'frame'+str(frameNum)+'.png')) os.mkdir(pth+os.sep+'_products') cv2.imwrite(pth+os.sep+'_products/calibrationImage.png',img) ``` -------------------------------- ### Navigate to Project Directory Source: https://github.com/conlin-matt/surfrcat/blob/master/docs/download.md Change the current directory to the location where the SurfRCaT repository contents were extracted. ```bash cd \SurfRCaT-master ``` -------------------------------- ### Complete Calibration Workflow Source: https://context7.com/conlin-matt/surfrcat/llms.txt Executes the full SurfRCaT pipeline, including frame extraction, lidar data acquisition, GCP-based calibration, and image rectification. ```python import SurfRCaT import numpy as np import cv2 import pickle import matplotlib.pyplot as plt import ftplib # === STEP 1: Set up camera parameters === camera_lat = 26.93846 camera_lon = -80.07054 camera_elevation = 49.5 camera_azimuth = 350 camera_name = "JupiterInlet" # === STEP 2: Extract frames from video === video_path = '/path/to/video.mp4' output_path = '/path/to/output/' cap = cv2.VideoCapture(video_path) fps = cap.get(5) vid_len = int(cap.get(7) / fps) SurfRCaT.getImagery_GetStills(video_path, 10, None, vid_len, fps, output_path) # Select calibration frame frame_num = 20 calibration_image = cv2.imread(f'{output_path}_frames/frame{frame_num}.png') # === STEP 3: Find and download lidar data === possible_ids = SurfRCaT.getLidar_FindPossibleIDs(camera_lat, camera_lon) dataset_id = 6330 # Choose appropriate dataset sf = SurfRCaT.getLidar_GetShapefile(dataset_id) poly = SurfRCaT.getLidar_CalcViewArea(camera_azimuth, 40, 1000, camera_lat, camera_lon) tiles = [] for i in range(len(sf)): tile = SurfRCaT.getLidar_SearchTiles(sf, poly, i, camera_lat, camera_lon) if tile: tiles.append(tile) lidar_data = np.empty([0, 3]) for tile in tiles: xyz = SurfRCaT.getLidar_Download(tile, dataset_id, camera_lat, camera_lon) lidar_data = np.append(lidar_data, xyz, axis=0) point_cloud = SurfRCaT.getLidar_CreatePC(lidar_data, camera_lat, camera_lon) # === STEP 4: Pick GCPs (interactive - shown as example values) === # In practice, use pptk viewer for lidar and matplotlib.ginput for image gcps_image = np.array([ [512.3, 284.7], [789.2, 301.5], [445.8, 412.3], [623.1, 398.9] ]) gcps_lidar = np.array([ [-45.2, 156.7, 8.3], [23.8, 178.4, 7.9], [-67.3, 245.2, 2.1], [-12.5, 231.8, 3.4] ]) # === STEP 5: Perform calibration === f, x0, y0 = SurfRCaT.calibrate_GetInitialApprox_IOPs(calibration_image) omega, phi, kappa = SurfRCaT.calibrate_GetInitialApprox_ats2opk(camera_azimuth, 80, 180) init_approx = np.array([omega, phi, kappa, 0, 0, camera_elevation, f, x0, y0]) # Two-step optimization calib_step1, _ = SurfRCaT.calibrate_PerformCalibration( init_approx, np.array([0,0,0,1,1,1,0,0,0]), gcps_image, gcps_lidar ) calib_final, _ = SurfRCaT.calibrate_PerformCalibration( calib_step1, np.array([1,1,1,0,0,0,1,1,1]), gcps_image, gcps_lidar ) # Check calibration quality u_proj, v_proj = SurfRCaT.calibrate_CalcReprojPos(gcps_lidar, calib_final) residuals = gcps_image - np.hstack([u_proj, v_proj]) rms_error = np.sqrt(np.mean(residuals**2)) print(f"Calibration RMS error: {rms_error:.2f} pixels") # Save calibration with open(f'{output_path}calibVals.pkl', 'wb') as f: pickle.dump(calib_final, f) # === STEP 6: Rectify images === grid = [-200, 200, 0.5, 250, 900, 0.5, 0.1] # At tide level 0.1m NAVD88 rectified, extents = SurfRCaT.rectify_RectifyImage( calib_final, cv2.cvtColor(calibration_image, cv2.COLOR_BGR2RGB), grid ) # Save and display plt.figure(figsize=(12, 10)) plt.imshow(rectified, extent=extents) plt.xlabel('East of camera (m)') plt.ylabel('North of camera (m)') plt.title('Rectified Coastal Image') plt.savefig(f'{output_path}rectified.png', dpi=150) plt.show() ``` -------------------------------- ### Import .pkl file in Python Source: https://github.com/conlin-matt/surfrcat/blob/master/docs/extensions.md Load rectified image data saved as a compressed Python dictionary in .pkl format. The dictionary structure mirrors the Matlab struct. ```python import pickle f = open('/_rectif.pkl','rb') frameRect = pickle.load(f) ``` -------------------------------- ### Estimate Initial Camera Parameters Source: https://context7.com/conlin-matt/surfrcat/llms.txt Estimates intrinsic camera parameters from image dimensions. ```python import SurfRCaT import cv2 # Load calibration image img = cv2.imread('/path/to/calibration_image.png') # Get initial approximations for intrinsic parameters focal_length, x0, y0 = SurfRCaT.calibrate_GetInitialApprox_IOPs(img) print(f"Estimated focal length: {focal_length:.2f} pixels") print(f"Principal point: ({x0:.2f}, {y0:.2f})") ``` -------------------------------- ### Estimate Initial Camera Intrinsic Parameters Source: https://github.com/conlin-matt/surfrcat/blob/master/src/main/SurfRCaT_demo.ipynb Estimates initial intrinsic camera parameters (focal length, principal point) from a calibration image. ```python # Estimate instrinsic parmeters from the image characteristics # cam_f,cam_x0,cam_y0 = SurfRCaT.calibrate_GetInitialApprox_IOPs(cv2.imread(pth+os.sep+'_products/calibrationImage.png')) ``` -------------------------------- ### Create Local Point Cloud Source: https://context7.com/conlin-matt/surfrcat/llms.txt Converts downloaded lidar data into a pandas DataFrame with coordinates relative to the camera. ```python import SurfRCaT import pickle camera_lat = 26.93846 camera_lon = -80.07054 # Assuming lidar_data was downloaded previously # lidar_data is an Nx3 numpy array with UTM X, Y, Z coordinates # Convert to local coordinate system (camera at origin) point_cloud = SurfRCaT.getLidar_CreatePC( lidarDat=lidar_data, cameraLoc_lat=camera_lat, cameraLoc_lon=camera_lon ) print(point_cloud.head()) # Save point cloud for later use with open('lidarPC.pkl', 'wb') as f: pickle.dump(point_cloud, f) ``` -------------------------------- ### Assess and download airborne lidar datasets programmatically in Python Source: https://github.com/conlin-matt/surfrcat/blob/master/docs/extensions.md Programmatically determine and download airborne lidar datasets for a given geographic location. This involves finding nearby datasets, checking coverage, and downloading relevant tiles. Requires ftplib and numpy. ```python import SurfRCaT import ftplib import numpy as np camera_latitude = camera_longitude = # Get the IDs of datasets that are near this location (same state and/or coast) # closeIDs = SurfRCaT.getLidar_FindPossibleIDs(camera_latitude,camera_longitude) # Search these close datasets to find those that cover this location # ftp = ftplib.FTP('ftp.coast.noaa.gov',timeout=1000000) ftp.login('anonymous','anonymous') ftp.cwd('/pub/DigitalCoast') dirs = [i for i in ftp.nlst() if 'lidar' in i] alldirs = [] for ii in dirs: ftp.cwd(ii) alldirs.append([ii+'/'+i for i in ftp.nlst() if 'geoid' in i]) ftp.cwd('../') appropID = list() # Initiate list of IDs that contain the camera location # i = 0 for ID in IDs: i = i+=1 check = SurfRCaT.getLidar_TryID(ftp,alldirs,ID,camera_latitude,camera_longitude) ftp.cwd('../../../../') if check: if len(check)>0: appropID.append(ID) # Choose a dataset # IDToDownload = appropID[] # Determine the tiles that are close enough to the camera to download # sf = SurfRCaT.getLidar_GetShapefile(IDToDownload) poly = SurfRCaT.getLidar_CalcViewArea(30,20,1000,camera_latitude,camera_longitude) tilesKeep = list() for shapeNum in range(0,len(sf)): out = SurfRCaT.getLidar_SearchTiles(sf,poly,shapeNum,camera_latitude,camera_longitude) if out: tilesKeep.append(out) # Download the portion of the dataset close to the camera # lidarDat = np.empty([0,3]) for thisFile in tilesKeep: lidarXYZsmall = SurfRCaT.getLidar_Download(thisFile,IDToDownload,camera_latitude,camera_longitude) lidarDat = np.append(lidarDat,lidarXYZsmall,axis=0) # Format the point cloud as a Pandas DataFrame (coordinates relative to input location) # pc = SurfRCaT.getLidar_CreatePC(lidarDat,camera_latitude,camera_longitude) ``` -------------------------------- ### Identify and Filter Lidar Datasets Source: https://github.com/conlin-matt/surfrcat/blob/master/src/main/SurfRCaT_demo.ipynb Finds potential NOAA lidar datasets and verifies coverage for the camera location via FTP. ```python # Find NOAA lidar datasets that cover the correct state or coast # possibleIDs = SurfRCaT.getLidar_FindPossibleIDs(cam_lat,cam_lon) print(possibleIDs) ``` ```python # Check all possibleIDs to find datasets that cover the camera location - appropIDs # # NOAA FTP login # ftp = ftplib.FTP('ftp.coast.noaa.gov',timeout=1000000) ftp.login('anonymous','anonymous') # Get a list of all lidar directories in the NOAA FTP. # ftp.cwd('/pub/DigitalCoast') dirs = [i for i in ftp.nlst() if 'lidar' in i] alldirs = [] for ii in dirs: ftp.cwd(ii) alldirs.append([ii+'/'+i for i in ftp.nlst() if 'geoid' in i]) ftp.cwd('../') # Check each of the possibleIDs to see if it covers the location of the camera # appropIDs = list() i = 0 for ID in possibleIDs: i = i+1 perDone = i/len(possibleIDs) print(str(perDone*100)+'% done') check = SurfRCaT.getLidar_TryID(ftp,alldirs,ID,cam_lat,cam_lon) ftp.cwd('/pub/DigitalCoast') if check: if len(check)>0: appropIDs.append(ID) print(appropIDs) ``` ```python # Establish the ID of the dataset to use # useID = 6330 ``` -------------------------------- ### Download WebCAT Video with SurfRCaT Source: https://context7.com/conlin-matt/surfrcat/llms.txt Downloads a 10-minute video clip from the WebCAT archive using camera name and timestamp parameters. ```python import SurfRCaT # Download a video from a WebCAT camera save_path = '/path/to/save/' camera_name = 'follypiersouthcam' # Options: follypiernorthcam, follypiersouthcam, staugustinecam, miami40thcam # Download video for January 1, 2019 at 4:00 PM video_file = SurfRCaT.getImagery_GetVideo( pth=save_path, camToInput=camera_name, year=2019, month=1, day=1, hour=1600 ) print(f"Downloaded: {video_file}") # Output: Downloaded: follypiersouthcam.2019-01-01_1600.mp4 ``` -------------------------------- ### Perform Two-Step Calibration Optimization Source: https://github.com/conlin-matt/surfrcat/blob/master/src/main/SurfRCaT_demo.ipynb Performs camera calibration in two optimization steps. The first step optimizes rotation and translation, while the second optimizes intrinsic parameters. ```python # Perform the calibration in a two-step optimization # initApprox = np.array([cam_omega,cam_phi,cam_kappa,0,0,cam_elev,cam_f,cam_x0,cam_y0]) freeVec1 = np.array([0,0,0,1,1,1,0,0,0]) freeVec2 = np.array([1,1,1,0,0,0,1,1,1]) calibVals1,se1 = SurfRCaT.calibrate_PerformCalibration(initApprox,freeVec1,GCPs_im,GCPs_lidar) updatedApprox = copy.copy(calibVals1) calibVals2,se2 = SurfRCaT.calibrate_PerformCalibration(updatedApprox,freeVec2,GCPs_im,GCPs_lidar) ``` -------------------------------- ### Define Camera Parameters Source: https://github.com/conlin-matt/surfrcat/blob/master/src/main/SurfRCaT_demo.ipynb Sets the required geographic coordinates and orientation for the camera. ```python # Required user inputs # # NOTE: Can get all of these from Google Earth # cam_lat = 26.93846 cam_lon = -80.07054 cam_elev = 49.5 cam_az = 350 ``` -------------------------------- ### Select Ground Control Points (GCPs) Source: https://github.com/conlin-matt/surfrcat/blob/master/src/main/SurfRCaT_demo.ipynb Interactively selects GCPs from the calibration image and the lidar point cloud viewer. ```python im = plt.imread(pth+os.sep+'_products/calibrationImage.png') plt.imshow(im) GCPs_im = plt.ginput(4) GCPs_im = np.array(np.array(GCPs_im)) print(GCPs_im) ``` ```python # Launch the point cloud viewer v = pptk.viewer(pc,pc.iloc[:,2]) v.set(point_size=0.1,theta=-25,phi=0,lookat=[0,0,20],color_map_scale=[-1,10],r=0) ``` ```python # Do the GCP picking # iGCPs_lidar = np.empty([0,1]) while 1<2: # Continuously test to see if viewer window is open # try: test = v.get('curr_attribute_id') a = v.get('selected') if len(a)>0: a = int(a) iGCPs_lidar = np.vstack([iGCPs_lidar,a]) else: a = 0 del a time.sleep(2) except ConnectionRefusedError: break iGCPs_lidar = np.unique(iGCPs_lidar).astype(int) print(iGCPs_lidar) ``` -------------------------------- ### Verify Lidar Dataset Coverage with SurfRCaT Source: https://context7.com/conlin-matt/surfrcat/llms.txt Checks if a specific lidar dataset covers a camera location by inspecting minmax extent files on the NOAA FTP server. ```python import SurfRCaT import ftplib camera_lat = 26.93846 camera_lon = -80.07054 # Connect to NOAA FTP ftp = ftplib.FTP('ftp.coast.noaa.gov', timeout=1000000) ftp.login('anonymous', 'anonymous') # Get list of all lidar directories ftp.cwd('/pub/DigitalCoast') dirs = [i for i in ftp.nlst() if 'lidar' in i] alldirs = [] for d in dirs: ftp.cwd(d) alldirs.append([d + '/' + i for i in ftp.nlst() if 'geoid' in i]) ftp.cwd('../') # Check if dataset 6330 covers the camera location dataset_id = 6330 check = SurfRCaT.getLidar_TryID(ftp, alldirs, dataset_id, camera_lat, camera_lon) if check and len(check) > 0: print(f"Dataset {dataset_id} covers the camera location!") else: print(f"Dataset {dataset_id} does not cover this location") ``` -------------------------------- ### Convert Camera Angle Systems Source: https://context7.com/conlin-matt/surfrcat/llms.txt Converts camera orientation from azimuth-tilt-swing to omega-phi-kappa conventions. ```python import SurfRCaT import numpy as np # Camera orientation in azimuth-tilt-swing (degrees) azimuth = 350 # Direction camera faces (degrees from north) tilt = 80 # Angle from vertical (80° = looking mostly horizontal) swing = 180 # Roll angle (180° = no roll) # Convert to omega-phi-kappa (radians) omega, phi, kappa = SurfRCaT.calibrate_GetInitialApprox_ats2opk(azimuth, tilt, swing) print(f"Omega: {np.degrees(omega):.2f}°") print(f"Phi: {np.degrees(phi):.2f}°") print(f"Kappa: {np.degrees(kappa):.2f}°") ``` -------------------------------- ### Retrieve Lidar Dataset Metadata with SurfRCaT Source: https://context7.com/conlin-matt/surfrcat/llms.txt Fetches metadata such as name and collection year for a list of lidar dataset IDs. ```python import SurfRCaT ``` -------------------------------- ### Download and Process Lidar Data Source: https://github.com/conlin-matt/surfrcat/blob/master/src/main/SurfRCaT_demo.ipynb Retrieves lidar shapefiles, calculates the camera view area, filters tiles, and loads the point cloud data. ```python # Get the geographic info of the dataset, contained in a shapefile # sf = SurfRCaT.getLidar_GetShapefile(useID) print(sf) ``` ```python # Calculate the view area of the camera poly = SurfRCaT.getLidar_CalcViewArea(cam_az,40,1000,cam_lat,cam_lon) print(poly) ``` ```python # Get the dataset tiles that cover the camera area # tilesKeep = list() i = 0 for shapeNum in range(0,len(sf)): out = SurfRCaT.getLidar_SearchTiles(sf,poly,shapeNum,cam_lat,cam_lon) if out: tilesKeep.append(out) i = i+1 perDone = i/len(sf) print(str(perDone*100)+'% done') print(tilesKeep) ``` ```python # Use pre-downloaded lidar data # with open(pth+os.sep+'demoLidarFile.pkl','rb') as f: lidarDat = pickle.load(f) ``` ```python # Create a point cloud with local coordinates relative to the camera location # pc = SurfRCaT.getLidar_CreatePC(lidarDat,cam_lat,cam_lon) print(pc) ``` -------------------------------- ### Convert Rotation Systems Source: https://github.com/conlin-matt/surfrcat/blob/master/src/main/SurfRCaT_demo.ipynb Converts rotation system from azimuth, tilt, swing to omega, phi, kappa. Assumes tilt=80 and swing=180. ```python # Convert rotation systems from azimuth, tilt, swing to omega, phi, kappa # # Note the following assumptions: tilt = 80, swing = 180 # cam_omega,cam_phi,cam_kappa = SurfRCaT.calibrate_GetInitialApprox_ats2opk(cam_az,80,180) ``` -------------------------------- ### Check Calibration by Reprojecting GCPs Source: https://github.com/conlin-matt/surfrcat/blob/master/src/main/SurfRCaT_demo.ipynb Checks the calibration by reprojecting GCPs onto the image and plotting the original and reprojected points. ```python # Check the calibration by reprojecting the GCPs onto the image # u_reproj,v_reproj = SurfRCaT.calibrate_CalcReprojPos(GCPs_lidar,calibVals2) fig,ax = plt.subplots(1) ax.imshow(im) cols = ['r','g','b','c'] for i in range(len(GCPs_im)): ax.plot(GCPs_im[i,0],GCPs_im[i,1],'o',markeredgecolor=cols[i],markerfacecolor='w') ax.plot(u_reproj[i],v_reproj[i],'x',color=cols[i]) fig.show() ``` -------------------------------- ### Find Potential Lidar Datasets with SurfRCaT Source: https://context7.com/conlin-matt/surfrcat/llms.txt Queries the NOAA lidar repository to identify datasets that may cover a specific geographic location. ```python import SurfRCaT # Camera location (WGS84 coordinates) camera_lat = 26.93846 # Jupiter Inlet, FL camera_lon = -80.07054 # Find lidar dataset IDs that may cover this location possible_ids = SurfRCaT.getLidar_FindPossibleIDs(camera_lat, camera_lon) print(f"Found {len(possible_ids)} potential datasets") print(f"Dataset IDs: {possible_ids}") # Output: Found 15 potential datasets # Dataset IDs: [6330, 5185, 5184, 8698, 1070, 1119, 34, 37, 100, 19, 8, ...] ``` -------------------------------- ### Establish Real-World Rectification Grid Source: https://github.com/conlin-matt/surfrcat/blob/master/src/main/SurfRCaT_demo.ipynb Defines the parameters for the real-world rectification grid, including spatial extents and resolution. ```python # Establsih the real-world rectification grid # xmin = -200 xmax = 200 dx = 0.5 ymin = 250 ymax = 900 dy = 0.5 z = 0.1 # Tide level, can get from NOAA # grid = [xmin,xmax,dx,ymin,ymax,dy,z] ``` -------------------------------- ### Import .mat file in Matlab Source: https://github.com/conlin-matt/surfrcat/blob/master/docs/extensions.md Load rectified image data saved in .mat format into Matlab. This structure is compatible with CIRN routines. ```matlab load('/_rectif.mat'); frameRect.x = x; frameRect.y = y; frameRect.I = I; ``` -------------------------------- ### Download Lidar Tiles Source: https://context7.com/conlin-matt/surfrcat/llms.txt Retrieves lidar data tiles that intersect with a defined camera view area. ```python import SurfRCaT import numpy as np camera_lat = 26.93846 camera_lon = -80.07054 azimuth = 350 dataset_id = 6330 # Get shapefile describing all tiles in the dataset sf = SurfRCaT.getLidar_GetShapefile(dataset_id) print(f"Dataset has {len(sf)} tiles") # Calculate camera view polygon poly = SurfRCaT.getLidar_CalcViewArea(azimuth, 40, 1000, camera_lat, camera_lon) # Find tiles that intersect with view polygon tiles_to_download = [] for shape_num in range(len(sf)): tile_name = SurfRCaT.getLidar_SearchTiles( sf=sf, poly=poly, shapeNum=shape_num, cameraLoc_lat=camera_lat, cameraLoc_lon=camera_lon ) if tile_name: tiles_to_download.append(tile_name) print(f"Found {len(tiles_to_download)} tiles in view area") # Download lidar data from selected tiles lidar_data = np.empty([0, 3]) for tile_file in tiles_to_download: xyz = SurfRCaT.getLidar_Download( thisFile=tile_file, IDToDownload=dataset_id, cameraLoc_lat=camera_lat, cameraLoc_lon=camera_lon ) lidar_data = np.append(lidar_data, xyz, axis=0) print(f"Downloaded {len(lidar_data)} lidar points") ``` -------------------------------- ### Perform Camera Calibration Source: https://context7.com/conlin-matt/surfrcat/llms.txt Uses least-squares space resection to optimize camera parameters. The process is typically performed in two steps: first optimizing angles and internal orientation parameters, then optimizing camera position. ```python import SurfRCaT import numpy as np import cv2 # Load image and get initial IOPs img = cv2.imread('/path/to/calibration_image.png') f, x0, y0 = SurfRCaT.calibrate_GetInitialApprox_IOPs(img) # Camera position and orientation estimates camera_elevation = 49.5 # meters NAVD88 azimuth = 350 # Convert angles omega, phi, kappa = SurfRCaT.calibrate_GetInitialApprox_ats2opk(azimuth, 80, 180) # Initial approximations: [omega, phi, kappa, XL, YL, ZL, f, x0, y0] # XL, YL = 0 because lidar coordinates are relative to camera init_approx = np.array([omega, phi, kappa, 0, 0, camera_elevation, f, x0, y0]) # GCPs picked from image (pixel coordinates) gcps_image = np.array([ [512.3, 284.7], [789.2, 301.5], [445.8, 412.3], [623.1, 398.9] ]) # Corresponding GCPs from lidar (local meters, relative to camera) gcps_lidar = np.array([ [-45.2, 156.7, 8.3], [23.8, 178.4, 7.9], [-67.3, 245.2, 2.1], [-12.5, 231.8, 3.4] ]) # Free vector: 0 = optimize, 1 = hold fixed # Two-step optimization: first angles and IOPs, then position free_vec_step1 = np.array([0, 0, 0, 1, 1, 1, 0, 0, 0]) # Optimize angles & IOPs calib_vals_1, se_1 = SurfRCaT.calibrate_PerformCalibration( init_approx, free_vec_step1, gcps_image, gcps_lidar ) # Second step: optimize position with fixed angles/IOPs free_vec_step2 = np.array([1, 1, 1, 0, 0, 0, 1, 1, 1]) # Optimize XL, YL, ZL calib_vals_final, se_final = SurfRCaT.calibrate_PerformCalibration( calib_vals_1, free_vec_step2, gcps_image, gcps_lidar ) print("Final calibration parameters:") print(f" Omega: {np.degrees(calib_vals_final[0]):.4f}°") print(f" Phi: {np.degrees(calib_vals_final[1]):.4f}°") print(f" Kappa: {np.degrees(calib_vals_final[2]):.4f}°") print(f" Camera X: {calib_vals_final[3]:.2f} m") print(f" Camera Y: {calib_vals_final[4]:.2f} m") print(f" Camera Z: {calib_vals_final[5]:.2f} m") print(f" Focal length: {calib_vals_final[6]:.2f} pixels") print(f" Principal point: ({calib_vals_final[7]:.2f}, {calib_vals_final[8]:.2f})") ``` -------------------------------- ### Extract Frames from Video with SurfRCaT Source: https://context7.com/conlin-matt/surfrcat/llms.txt Extracts frames from a video file and saves them as PNGs. Supports extraction at a fixed rate or by specifying a total number of evenly-spaced frames. ```python import SurfRCaT import cv2 # Load video and get properties vid = '/path/to/video.mp4' save_dir = '/path/to/output/' cap = cv2.VideoCapture(vid) num_frames = int(cap.get(7)) fps = cap.get(5) vid_len = int(num_frames / fps) # Option 1: Extract at a specific rate (e.g., 2 frames per second) seconds_per_frame = 1 # Set to 1 when using rate rate = 2 # frames per second SurfRCaT.getImagery_GetStills( vid=vid, secondsPerFrame=seconds_per_frame, rate=rate, vidLen=vid_len, fps=fps, saveBasePth=save_dir ) # Option 2: Extract a specific number of evenly-spaced frames total_frames_wanted = 25 seconds_per_frame = int(round(vid_len / total_frames_wanted)) SurfRCaT.getImagery_GetStills( vid=vid, secondsPerFrame=seconds_per_frame, rate=None, vidLen=vid_len, fps=fps, saveBasePth=save_dir ) # Frames saved to: /path/to/output/_frames/frame0.png, frame10.png, etc. ``` -------------------------------- ### Extract frames from video programmatically in Python Source: https://github.com/conlin-matt/surfrcat/blob/master/docs/extensions.md Use SurfRCaT to extract frames from a video file at a specified rate (frames per second). Requires OpenCV and SurfRCaT libraries. ```python import SurfRCaT import cv2 vid = 'C:/path/to/video.mp4' saveDir = 'C:/directory/to/save/frames/to' cap = cv2.VideoCapture(vid) numFrames = int(cap.get(7)) fps = cap.get(5) vidLen = int(numFrames/fps) secondsPerFrame = 1 # Leave as 1 to ignore this parameter # rate = 2 # 2 frames/second # SurfRCaT.getImagery_GetStills(vid,secondsPerFrame,rate,vidLen,saveDir) ``` -------------------------------- ### Extract Video Stills for Calibration Source: https://github.com/conlin-matt/surfrcat/blob/master/src/main/SurfRCaT_demo.ipynb Extracts frames from a video file based on a specified time interval to be used for camera calibration. ```python # Establish the video file # vid = os.path.realpath(pth+os.sep+'JupiterTutorial1.mp4') # Extract video properties cap = cv2.VideoCapture(vid) numFrames = int(cap.get(7)) fps = cap.get(5) vidLen = int(numFrames/fps) # Establish desired extraction parameters # secondsPerFrame = 10 rate = None # Don't need if using a secondsPerFrame # # Run the frame extraction # SurfRCaT.getImagery_GetStills(vid,secondsPerFrame,rate,vidLen,fps,pth+os.sep) ``` -------------------------------- ### Rectify Images Source: https://context7.com/conlin-matt/surfrcat/llms.txt Transforms camera images into real-world coordinates based on a defined grid and elevation. Requires previously computed calibration values. ```python import SurfRCaT import numpy as np import matplotlib.pyplot as plt import matplotlib.image as mpimg import pickle # Load calibration values with open('calibVals.pkl', 'rb') as f: calib_vals = pickle.load(f) # Load image to rectify img = mpimg.imread('/path/to/image_to_rectify.png') # Define real-world grid (meters relative to camera location) # x = east of camera, y = north of camera grid = [ -200, # xmin (200m west of camera) 200, # xmax (200m east of camera) 0.5, # dx (0.5m resolution) 250, # ymin (250m north of camera) 900, # ymax (900m north of camera) 0.5, # dy (0.5m resolution) 0.1 # z (rectification elevation - tide level in meters NAVD88) ] # Perform rectification rectified_image, extents = SurfRCaT.rectify_RectifyImage( calibVals=calib_vals, img=img, grd=grid ) ``` -------------------------------- ### Display and Save Rectified Image Source: https://context7.com/conlin-matt/surfrcat/llms.txt Visualizes a rectified image using matplotlib and saves the data to a pickle file for later analysis. ```python fig, ax = plt.subplots(1, figsize=(10, 12)) ax.imshow(rectified_image, extent=extents, interpolation='bilinear') ax.set_xlabel('Local x (m) - East of camera') ax.set_ylabel('Local y (m) - North of camera') ax.set_title('Rectified Image') ax.axis('equal') plt.show() # Save rectified image data for further analysis with open('rectified_image.pkl', 'wb') as f: pickle.dump({'I': rectified_image, 'x': extents[:2], 'y': extents[2:]}, f) ``` -------------------------------- ### Retrieve Lidar Dataset Metadata Source: https://context7.com/conlin-matt/surfrcat/llms.txt Fetches metadata for specific lidar datasets using their IDs. ```python appropriate_ids = [6330, 5185, 5184] matching_table = SurfRCaT.getLidar_GetDatasetNames(appropriate_ids) print(matching_table) ``` -------------------------------- ### Perform Image Rectification Source: https://github.com/conlin-matt/surfrcat/blob/master/src/main/SurfRCaT_demo.ipynb Rectifies the input image using the calculated calibration values and the defined grid. ```python # Perform the rectification # im_rectif,extents = SurfRCaT.rectify_RectifyImage(calibVals2,im,grid) ``` -------------------------------- ### Calculate Reprojection Error Source: https://context7.com/conlin-matt/surfrcat/llms.txt Calculates the accuracy of calibration by comparing reprojected GCP positions against original image coordinates. Includes visualization of the residuals. ```python import SurfRCaT import numpy as np import matplotlib.pyplot as plt import matplotlib.image as mpimg # Load calibration results and GCPs # calib_vals_final from previous calibration # gcps_image, gcps_lidar from GCP picking # Calculate reprojected positions u_proj, v_proj = SurfRCaT.calibrate_CalcReprojPos(gcps_lidar, calib_vals_final) # Calculate reprojection error uv_projected = np.hstack([u_proj, v_proj]) residuals = gcps_image - uv_projected rms_error = np.sqrt(np.mean(residuals**2)) print(f"RMS reprojection error: {rms_error:.2f} pixels") # Visualize GCPs and reprojections img = mpimg.imread('/path/to/calibration_image.png') fig, ax = plt.subplots(1, figsize=(12, 8)) ax.imshow(img) colors = ['red', 'green', 'blue', 'cyan'] for i in range(len(gcps_image)): # Original GCP location (circle) ax.plot(gcps_image[i, 0], gcps_image[i, 1], 'o', markeredgecolor=colors[i], markerfacecolor='white', markersize=10) # Reprojected location (X) ax.plot(u_proj[i], v_proj[i], 'x', color=colors[i], markersize=10, mew=2) ax.set_title(f'GCP Reprojection (RMS error: {rms_error:.2f} px)') plt.show() ``` -------------------------------- ### Plot Rectified Image Source: https://github.com/conlin-matt/surfrcat/blob/master/src/main/SurfRCaT_demo.ipynb Displays the rectified image with appropriate axis labels and equal aspect ratio. ```python # Plot the rectified image # fig,ax = plt.subplots(1) ax.imshow(im_rectif,extent=extents,interpolation='bilinear') ax.set_xlabel('Local x (m)') ax.set_ylabel('Local y (m)') ax.axis('equal') fig.show() ``` -------------------------------- ### Calculate Camera View Area Source: https://context7.com/conlin-matt/surfrcat/llms.txt Generates a polygon representing the camera's field of view for filtering lidar tiles. ```python import SurfRCaT # Camera parameters camera_lat = 26.93846 camera_lon = -80.07054 azimuth = 350 # Degrees from north (camera looking NNW) window = 40 # Angular tolerance in degrees max_distance = 1000 # Maximum view distance in meters # Calculate view polygon poly = SurfRCaT.getLidar_CalcViewArea( az=azimuth, window=window, dmax=max_distance, lat=camera_lat, lon=camera_lon ) print(f"View polygon created with {len(poly.vertices)} vertices") ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.