Created
May 25, 2025 02:53
-
-
Save soswow/29b488cd33c1a563ac14ceee56a6cbcc to your computer and use it in GitHub Desktop.
Script to find vertical lines in the middle of the image and convert location to a distance on sensor from center
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import sys | |
import os | |
from PIL import Image, ImageDraw | |
def find_vertical_lines_by_gradient(image_path, gradient_threshold=10, min_width=1, max_width=7): | |
""" | |
Find vertical lines by detecting strong contrast changes in the middle row, scanning from center to left. | |
Returns a list of center X positions for each detected line. | |
min_width and max_width now refer to the actual pixel width of the detected line. | |
""" | |
img = Image.open(image_path).convert('L') # Convert to grayscale | |
width, height = img.size | |
middle_row = height // 2 | |
pixels = img.load() | |
# Get the pixel values for the middle row | |
row = [pixels[x, middle_row] for x in range(width)] | |
# Compute the gradient (difference between neighbors) | |
center = width // 2 | |
x = center | |
edge_positions = [] | |
while x > 0: | |
diff = abs(row[x] - row[x-1]) | |
if diff >= gradient_threshold: | |
edge_positions.append(x) | |
x -= 1 | |
# Group close edges as a single line, using actual pixel width | |
edge_positions.sort() | |
lines = [] | |
group = [] | |
for pos in edge_positions: | |
if not group: | |
group = [pos] | |
elif pos - group[-1] <= max_width: | |
group.append(pos) | |
else: | |
group_width = group[-1] - group[0] + 1 | |
if min_width <= group_width <= max_width: | |
center_x = (group[0] + group[-1]) / 2 | |
lines.append(center_x) | |
group = [pos] | |
# Handle last group | |
if group: | |
group_width = group[-1] - group[0] + 1 | |
if min_width <= group_width <= max_width: | |
center_x = (group[0] + group[-1]) / 2 | |
lines.append(center_x) | |
return lines | |
def main(): | |
if len(sys.argv) < 2: | |
print("Usage: python find_vertical_lines.py <image1.png> [image2.png ...]") | |
return | |
image_paths = sys.argv[1:] | |
DEBUG_IMAGE = True # Set to False to disable debug image output | |
sensor_width_px = 5496 | |
sensor_width_mm = 35.9 | |
sensor_middle_mm = sensor_width_mm / 2 | |
px_to_mm = sensor_width_mm / sensor_width_px | |
results = {} | |
max_lines = 0 | |
for image_path in image_paths: | |
lines = find_vertical_lines_by_gradient(image_path) | |
lines_mm = [sensor_middle_mm - (center_x * px_to_mm) for center_x in lines] | |
lines_mm.sort() | |
base = os.path.splitext(os.path.basename(image_path))[0] | |
results[base] = lines_mm | |
if len(lines_mm) > max_lines: | |
max_lines = len(lines_mm) | |
if DEBUG_IMAGE: | |
orig_img = Image.open(image_path).convert('RGB') | |
width, height = orig_img.size | |
debug_img = orig_img.copy() | |
draw = ImageDraw.Draw(debug_img) | |
for center_x in lines: | |
x = int(round(center_x)) | |
draw.line([(x, 0), (x, height - 1)], fill=(255, 0, 0), width=1) | |
debug_img.save(f"{base}_lines.png") | |
print(f"Debug image with detected lines saved as {base}_lines.png") | |
# Write tab-separated CSV | |
bases = list(results.keys()) | |
with open("lines_output.tsv", "w") as f: | |
f.write("\t".join(bases) + "\n") | |
for i in range(max_lines): | |
row = [] | |
for base in bases: | |
if i < len(results[base]): | |
row.append(f"{results[base][i]:.2f}") | |
else: | |
row.append("") | |
f.write("\t".join(row) + "\n") | |
print("Tab-separated results written to lines_output.tsv") | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment