125 lines
4.2 KiB
Python
125 lines
4.2 KiB
Python
def calculate_receptive_field_size(layers):
|
||
"""
|
||
Parameters
|
||
----------
|
||
layers : list of dict
|
||
Each dict must contain
|
||
─ 'kernel_size' : (k_h, k_w)
|
||
─ 'stride' : (s_h, s_w)
|
||
─ 'dilation' : (d_h, d_w) # optional; defaults to (1, 1)
|
||
|
||
Returns
|
||
-------
|
||
(rf_h, rf_w) : tuple of ints
|
||
Receptive-field size in pixels for height and width.
|
||
"""
|
||
rf_h = rf_w = 1 # start with a 1×1 pixel
|
||
jump_h = jump_w = 1 # effective stride so far
|
||
|
||
for layer in layers:
|
||
k_h, k_w = layer["kernel_size"]
|
||
s_h, s_w = layer["stride"]
|
||
d_h, d_w = layer.get("dilation", (1, 1)) # default = 1
|
||
|
||
# Dumoulin & Visin recurrence, now with dilation
|
||
rf_h += (k_h - 1) * d_h * jump_h
|
||
rf_w += (k_w - 1) * d_w * jump_w
|
||
|
||
jump_h *= s_h
|
||
jump_w *= s_w
|
||
|
||
return rf_h, rf_w
|
||
|
||
|
||
def calculate_angular_receptive_field(
|
||
rf_height: int,
|
||
rf_width: int,
|
||
vertical_res: int,
|
||
horizontal_res: int,
|
||
vertical_fov: float,
|
||
horizontal_fov: float,
|
||
) -> tuple[float, float]:
|
||
"""Calculate the angular size of a receptive field in degrees.
|
||
|
||
Args:
|
||
rf_height: Receptive field height in pixels
|
||
rf_width: Receptive field width in pixels
|
||
vertical_res: Vertical resolution of input in pixels
|
||
horizontal_res: Horizontal resolution of input in pixels
|
||
vertical_fov: Vertical field of view in degrees
|
||
horizontal_fov: Horizontal field of view in degrees
|
||
|
||
Returns:
|
||
tuple[float, float]: Angular size (height, width) in degrees
|
||
"""
|
||
# Calculate degrees per pixel for each axis
|
||
vertical_deg_per_pixel = vertical_fov / vertical_res
|
||
horizontal_deg_per_pixel = horizontal_fov / horizontal_res
|
||
|
||
# Calculate angular size of receptive field
|
||
rf_vertical_deg = rf_height * vertical_deg_per_pixel
|
||
rf_horizontal_deg = rf_width * horizontal_deg_per_pixel
|
||
|
||
return rf_vertical_deg, rf_horizontal_deg
|
||
|
||
|
||
def calculate_pixels_per_degree(resolution: int, fov: float) -> float:
|
||
"""Calculate pixels per degree for a given resolution and field of view.
|
||
|
||
Args:
|
||
resolution: Number of pixels
|
||
fov: Field of view in degrees
|
||
|
||
Returns:
|
||
float: Pixels per degree
|
||
"""
|
||
return resolution / fov
|
||
|
||
|
||
horizontal_resolution = 2048
|
||
horizontal_fov = 360.0
|
||
vertical_resolution = 32
|
||
vertical_fov = 31.76
|
||
|
||
lenet_network_config = [
|
||
{"name": "Conv1", "kernel_size": (5, 5), "stride": (1, 1), "dilation": (1, 1)},
|
||
{"name": "MaxPool1", "kernel_size": (2, 2), "stride": (2, 2), "dilation": (1, 1)},
|
||
{"name": "Conv2", "kernel_size": (5, 5), "stride": (1, 1), "dilation": (1, 1)},
|
||
{"name": "MaxPool2", "kernel_size": (2, 2), "stride": (2, 2), "dilation": (1, 1)},
|
||
]
|
||
|
||
# Calculate and print results for LeNet
|
||
rf_h, rf_w = calculate_receptive_field_size(lenet_network_config)
|
||
rf_vert_deg, rf_horiz_deg = calculate_angular_receptive_field(
|
||
rf_h, rf_w, vertical_resolution, horizontal_resolution, vertical_fov, horizontal_fov
|
||
)
|
||
print(f"SubTer LeNet RF size: {rf_h} × {rf_w} pixels")
|
||
print(f"SubTer LeNet RF angular size: {rf_vert_deg:.2f}° × {rf_horiz_deg:.2f}°")
|
||
|
||
|
||
asym_network_config = [
|
||
{"name": "Conv1", "kernel_size": (3, 17), "stride": (1, 1), "dilation": (1, 1)},
|
||
{"name": "MaxPool1", "kernel_size": (2, 2), "stride": (2, 2), "dilation": (1, 1)},
|
||
{"name": "Conv2", "kernel_size": (3, 17), "stride": (1, 1), "dilation": (1, 1)},
|
||
{"name": "MaxPool2", "kernel_size": (2, 2), "stride": (2, 2), "dilation": (1, 1)},
|
||
]
|
||
|
||
# Calculate and print results for Asymmetric network
|
||
rf_h, rf_w = calculate_receptive_field_size(asym_network_config)
|
||
rf_vert_deg, rf_horiz_deg = calculate_angular_receptive_field(
|
||
rf_h, rf_w, vertical_resolution, horizontal_resolution, vertical_fov, horizontal_fov
|
||
)
|
||
print(f"SubTer LeNet (Asymmetric kernels) RF size: {rf_h} × {rf_w} pixels")
|
||
print(
|
||
f"SubTer LeNet (Asymmetric kernels) RF angular size: {rf_vert_deg:.2f}° × {rf_horiz_deg:.2f}°"
|
||
)
|
||
|
||
# Calculate pixels per degree
|
||
horizontal_ppd = calculate_pixels_per_degree(horizontal_resolution, horizontal_fov)
|
||
vertical_ppd = calculate_pixels_per_degree(vertical_resolution, vertical_fov)
|
||
|
||
print("\nPixels per Degree:")
|
||
print(f"Horizontal: {horizontal_ppd:.2f} px/°")
|
||
print(f"Vertical: {vertical_ppd:.2f} px/°")
|
||
print()
|