Constellation Detection: Computer Vision Meets Astronomy
For my NYU Computer Vision course, I tackled an interesting challenge: can we automatically identify star constellations in night sky images? Turns out, classical computer vision techniques work remarkably well.
Problem Statement
Given an image of the night sky, identify which constellation(s) are visible. Challenges: - Stars appear as small points of light - Images can be rotated, scaled, or partially visible - Background noise and atmospheric effects - Multiple constellations in one image
Classical CV Approach
Step 1: Star Detection
Use blob detection to find stars:
import cv2
import numpy as np
def detect_stars(image):
# Convert to grayscale
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# Gaussian blur to reduce noise
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
# Threshold to get bright points
_, thresh = cv2.threshold(blurred, 200, 255, cv2.THRESH_BINARY)
# Find contours (stars)
contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
# Extract star positions
stars = []
for cnt in contours:
M = cv2.moments(cnt)
if M['m00'] > 0:
cx = int(M['m10'] / M['m00'])
cy = int(M['m01'] / M['m00'])
stars.append((cx, cy))
return stars
Step 2: Feature Extraction
Create geometric features from star patterns:
def extract_constellation_features(stars):
"""Compute pairwise distances and angles"""
features = []
n = len(stars)
for i in range(n):
for j in range(i+1, n):
# Distance between stars
dist = np.linalg.norm(
np.array(stars[i]) - np.array(stars[j])
)
# Angle
angle = np.arctan2(
stars[j][1] - stars[i][1],
stars[j][0] - stars[i][0]
)
features.append({
'distance': dist,
'angle': angle,
'star_pair': (i, j)
})
return features
Step 3: Template Matching
Match detected pattern against known constellations:
def match_constellation(detected_features, templates):
"""Find best matching constellation template"""
best_match = None
best_score = 0
for name, template in templates.items():
score = compute_match_score(detected_features, template)
if score > best_score:
best_score = score
best_match = name
return best_match, best_score
def compute_match_score(features, template):
"""Compare feature sets using geometric hashing"""
matches = 0
tolerance = 0.1 # 10% tolerance
for f1 in features:
for f2 in template:
dist_diff = abs(f1['distance'] - f2['distance'])
angle_diff = abs(f1['angle'] - f2['angle'])
if (dist_diff < tolerance * f2['distance'] and
angle_diff < tolerance):
matches += 1
return matches / len(template)
Advanced Techniques
Handling Rotation and Scale
Use SIFT for scale/rotation invariance:
def detect_with_sift(image, template):
# Initialize SIFT
sift = cv2.SIFT_create()
# Detect keypoints and descriptors
kp1, des1 = sift.detectAndCompute(image, None)
kp2, des2 = sift.detectAndCompute(template, None)
# FLANN matcher
index_params = dict(algorithm=1, trees=5)
search_params = dict(checks=50)
flann = cv2.FlannBasedMatcher(index_params, search_params)
matches = flann.knnMatch(des1, des2, k=2)
# Ratio test
good_matches = []
for m, n in matches:
if m.distance < 0.7 * n.distance:
good_matches.append(m)
return len(good_matches)
Partial Visibility Handling
Sometimes only part of a constellation is visible:
def partial_match(detected_stars, constellation_template):
"""Match even if only subset of stars visible"""
min_stars = 3 # Minimum stars needed
# Try all subsets of detected stars
from itertools import combinations
best_match = 0
for subset in combinations(detected_stars, min_stars):
score = match_subset(subset, constellation_template)
best_match = max(best_match, score)
return best_match
Results
Tested on 50 images: - Accuracy: 87% for full constellations - Partial detection: 72% accuracy - Processing time: ~200ms per image - Robustness: Works with 15° rotation, 20% scale variation
Most recognized: - Orion: 95% (distinctive pattern) - Big Dipper: 92% (bright stars) - Cassiopeia: 89% (W shape)
Challenging: - Faint constellations: 65% - Crowded star fields: 70%
Real-World Applications
- Amateur astronomy: Help identify what you're seeing
- Educational tools: Interactive sky maps
- Telescope guidance: Auto-point telescopes
- Astrophotography: Auto-label star trail photos
Lessons Learned
- Classical CV still powerful: Sometimes simpler is better than deep learning
- Domain knowledge matters: Understanding astronomy helps
- Robustness through redundancy: Multiple matching techniques improve accuracy
- Template quality matters: Better templates = better matches
This project showed me that computer vision isn't always about neural networks - sometimes geometric reasoning is exactly what you need.