1919# ' translates the image with GCPs then warps to the target CRS using
2020# ' bilinear resampling.
2121# '
22+ # ' **Nodata handling:** Band count is read from each file header. RGB
23+ # ' thumbnails (3+ bands) get an alpha band (`-dstalpha`) for clean masking
24+ # ' in mosaics. Grayscale thumbnails (1 band) use nodata=0 — some shadow
25+ # ' detail is lost but black borders are eliminated.
26+ # '
2227# ' **Accuracy:** footprints assume flat terrain and nadir camera angle.
2328# ' The georeferenced thumbnails are approximate — useful for visual context,
2429# ' not survey-grade positioning. See [fly_footprint()] for details on
@@ -96,14 +101,18 @@ georef_one <- function(src, fp, out_file) {
96101 # fly_footprint builds: BL, BR, TR, TL, BL (closing)
97102 coords <- sf :: st_coordinates(fp )[1 : 4 , , drop = FALSE ]
98103
99- # Read image dimensions via GDAL
104+ # Read image dimensions and band count via GDAL
100105 info <- sf :: gdal_utils(" info" , source = src , quiet = TRUE )
101106 dims <- regmatches(info , regexpr(" Size is \\ d+, \\ d+" , info ))
102107 if (length(dims ) == 0 ) return (FALSE )
103108 px <- as.integer(strsplit(sub(" Size is " , " " , dims ), " , " )[[1 ]])
104109 ncol_px <- px [1 ]
105110 nrow_px <- px [2 ]
106111
112+ # Count bands from "Band N" lines
113+ n_bands <- length(gregexpr(" Band \\ d+" , info )[[1 ]])
114+ is_rgb <- n_bands > = 3
115+
107116 # Map pixel corners to footprint corners
108117 # Pixel: TL=(0,0), TR=(ncol,0), BR=(ncol,nrow), BL=(0,nrow)
109118 # Footprint coords: [1]=BL, [2]=BR, [3]=TR, [4]=TL
@@ -115,7 +124,6 @@ georef_one <- function(src, fp, out_file) {
115124 )
116125
117126 # Step 1: translate with GCPs
118-
119127 tmp_file <- tempfile(fileext = " .tif" )
120128 on.exit(unlink(tmp_file ), add = TRUE )
121129
@@ -125,11 +133,20 @@ georef_one <- function(src, fp, out_file) {
125133 options = c(" -a_srs" , " EPSG:3005" , gcp_args )
126134 )
127135
128- # Step 2: warp to target CRS
136+ # Step 2: warp to target CRS with nodata handling
137+ # RGB: add alpha band (-dstalpha) for clean masking in mosaics
138+ # Grayscale: set nodata=0 (losing some shadow detail is acceptable)
139+ warp_opts <- c(" -t_srs" , " EPSG:3005" , " -r" , " bilinear" )
140+ if (is_rgb ) {
141+ warp_opts <- c(warp_opts , " -dstalpha" )
142+ } else {
143+ warp_opts <- c(warp_opts , " -dstnodata" , " 0" )
144+ }
145+
129146 sf :: gdal_utils(" warp" ,
130147 source = tmp_file ,
131148 destination = out_file ,
132- options = c( " -t_srs " , " EPSG:3005 " , " -r " , " bilinear " )
149+ options = warp_opts
133150 )
134151
135152 file.exists(out_file ) && file.size(out_file ) > 0
0 commit comments