How a Camera Sensor Works
A camera sensor is like a grid of tiny buckets (pixels) that collect photons (light particles). When light hits a pixel, it generates an electrical charge proportional to brightness. The longer the exposure, the more light collected â like leaving a bucket in the rain.
Shutter Types: Global vs Rolling
The shutter determines how the sensor captures the image. This is critical for drones because they're always moving.
Global Shutter: Exposes all pixels simultaneously â like blinking your eyes. Every pixel captures the same moment. No distortion during fast motion.
Rolling Shutter: Exposes pixels row by row, from top to bottom. During fast motion, the image appears skewed or warped â known as the "jello effect."
Lens Selection for Drones
The lens determines what the camera "sees." Key parameters:
| Parameter | Description | Drone Impact |
|---|---|---|
| Focal length | Determines magnification | Longer = zoom, narrower FOV |
| Aperture (f-stop) | Light gathering ability | Lower f = more light, shallower DOF |
| FOV | Coverage area | Wide = more context, less detail |
| Distortion | Barrel/pincushion effects | Needs correction for mapping |
def compute_fov(sensor_width_mm, focal_length_mm):
"""Calculate horizontal field of view."""
return 2 * np.degrees(np.arctan(sensor_width_mm / (2 * focal_length_mm)))
# Common drone camera setups
sensors = {
"Mini 3 Pro": {"sensor": 6.3, "focal": 4.5}, # mm
"Mavic 3": {"sensor": 13.2, "focal": 12.8},
"Matrice 300 RTK": {"sensor": 17.3, "focal": 8.8},
}
for name, specs in sensors.items():
fov = compute_fov(specs["sensor"], specs["focal"])
print(f"{name}: {fov:.1f}° FOV ({specs['focal']}mm on {specs['sensor']}mm sensor)")
Camera Settings for Drone Operations
| Application | Shutter Speed | ISO | Aperture | White Balance |
|---|---|---|---|---|
| Survey mapping | 1/1000+ | 100-400 | f/5.6-f/8 | Auto |
| Cinematic video | 1/60 (24fps) | 100-200 | Wide open | Manual |
| Thermal imaging | Auto | N/A | Fixed | N/A |
| Night flying | 1/30 or slower | 800-3200 | Wide open | Auto |
RAW vs JPEG for Drone Work
JPEG: Compressed, smaller files, processed in-camera. Good for quick sharing.
RAW: Uncompressed sensor data, much larger files. Allows post-processing flexibility â critical for professional survey and inspection work.
# File size comparison
raw_size_mb = 25 # Typical 20MP RAW
jpeg_size_mb = 5 # Typical 20MP JPEG
# For a 1000-image survey
total_raw = raw_size_mb * 1000 / 1000 # GB
total_jpeg = jpeg_size_mb * 1000 / 1000 # GB
print(f"RAW: {total_raw:.1f} GB for 1000 images")
print(f"JPEG: {total_jpeg:.1f} GB for 1000 images")
print(f"RAW gives {raw_size_mb/jpeg_size_mb}x more data for post-processing")
Hands-On Project: Camera Calibration Checker
Build a tool to check camera calibration quality using OpenCV:
class CameraCalibrationChecker:
"""Simple camera calibration quality assessment."""
def __init__(self, image_size=(1920, 1080)):
self.image_size = image_size
def check_lens_distortion(self, image_path):
"""Analyze lens distortion from a calibration image."""
img = cv2.imread(image_path)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Find chessboard corners
ret, corners = cv2.findChessboardCorners(gray, (9, 6), None)
if ret:
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
corners = cv2.cornerSubPix(gray, corners, (11, 11), (-1, -1), criteria)
# Calculate distortion metrics
corner_diffs = np.diff(corners.reshape(-1, 2), axis=0)
distances = np.linalg.norm(corner_diffs, axis=1)
return {
"corners_found": len(corners),
"mean_distance": np.mean(distances),
"std_distance": np.std(distances),
"distortion_score": np.std(distances) / np.mean(distories)
}
return {"corners_found": 0, "error": "No chessboard found"}
def estimate_vignetting(self, image_path):
"""Check for vignetting (dark corners)."""
img = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE).astype(float)
center_brightness = img[img.shape[0]//2-50:img.shape[0]//2+50,
img.shape[1]//2-50:img.shape[1]//2+50].mean()
corner_brightness = (img[0:50, 0:50].mean() +
img[0:50, -50:].mean() +
img[-50:, 0:50].mean() +
img[-50:, -50:].mean()) / 4
vignetting_ratio = corner_brightness / center_brightness
return {
"center_brightness": center_brightness,
"corner_brightness": corner_brightness,
"vignetting_ratio": vignetting_ratio,
"assessment": "Good" if vignetting_ratio > 0.85 else "Needs correction"
}
# Usage
checker = CameraCalibrationChecker()
# distortion = checker.check_lens_distortion("calibration_image.jpg")
# vignetting = checker.estimate_vignetting("test_image.jpg")
# print(f"Distortion score: {distortion['distortion_score']:.4f}")
# print(f"Vignetting: {vignetting['assessment']}")
Key Takeaways
- Camera sensors convert light to digital signals through Bayer filtering and ADC
- Global shutter prevents distortion; rolling shutter causes jello effect
- Lens selection determines FOV, magnification, and light gathering
- RAW format preserves more data for post-processing
- Camera calibration is essential for accurate measurements from drone imagery