PSA (Professional Sports Authenticator) grades trading cards on a 1-10 scale. The difference between a PSA 9 and PSA 10
  can be thousands of dollars – but to the naked eye, they look
   identical.
Even more confusing: people regularly resubmit PSA 9s and get
   10s on the second attempt. The grading process has inherent
  subjectivity.
This makes it perfect for machine learning – finding patterns
   in noisy, subjective data.
What PSA Graders Look For
Professional graders examine four aspects:
- Surface: Scratches, print lines, dots
- Corners: Whitening, bending, softness
- Edges: Chipping, wear, roughness
- Centering: Front/back alignment measured in percentages
At $30+ per card submission, guessing wrong gets expensive
  fast.
The Approach: Ensemble Learning > Single Model
My first attempt was a single CNN trained on thousands of
  graded cards. Accuracy was disappointing.
The problem: one network trying to learn everything at once
  doesn't work well. So I built specialist networks:
class CardGradingEnsemble:
      def init(self):
          self.surface_model = SurfaceDefectDetector()
          self.corner_model = CornerAnalyzer()
          self.edge_model = EdgeWearClassifier()
          self.centering_model = CenteringMeasurer()
Each model focuses on ONE aspect. Combined predictions with
  weighted scoring.
Transfer Learning Beat Custom Architecture
I spent weeks building custom CNNs. Results were decent but
  not great.
Then I tried EfficientNet with transfer learning:
backbone = models.efficientnet_b0(weights='IMAGENET1K_V1')
# Freeze early layers - they already know edges/textures
  for param in backbone.features.parameters():
      param.requires_grad = False
# Only train the final layers for card-specific patterns
  backbone.classifier = nn.Sequential(
      nn.Linear(num_features, 512),
      nn.ReLU(),
      nn.Linear(512, 2)  # Binary: submit or don't
  )
Accuracy improved significantly overnight.
Current Performance
The system catches most PSA 10s while avoiding obvious 8s. It
   occasionally suggests grading some 9s, which isn't terrible
  given how often 9s regrade as 10s anyway.
Not perfect, but useful for bulk submissions.
The Hardest Part: Edge Detection
Cards have different borders – black, yellow, holographic. My
   edge model kept confusing card design with damage.
Solution:
def isolate_edge_wear(image, card_mask):
      # Don't analyze the printed border design
      # Just the physical card edge
      physical_edge = extract_card_outline(card_mask)
      edge_region = dilate(physical_edge, 3) - physical_edge
  return image * edge_region
Simple morphological operations fixed weeks of poor
  performance.
Production Challenges
Problem 1: Training data had perfect white backgrounds. Real
  photos have kitchen tables, hands, random surfaces.
Solution: Aggressive augmentation + background removal
  preprocessing.
Problem 2: High-res photos lose critical details when
  resized. Surface scratches disappear at lower resolutions.
Solution: Smart cropping that analyzes regions at different
  scales:
def multi_scale_analysis(image):
      # Analyze corners at high resolution for whitening
      corners = extract_corners_highres(image)
  # Center can be lower res (centering measurement)
  center = extract_center_lowres(image)
  # Surface needs medium res to catch scratches
  surface_patches = extract_surface_patches(image)
  return combine_analyses(corners, center, surface_patches)
Real-World Application
We integrated this into https://pokeinvest.io where
  collectors track their portfolios. The pre-grading
  recommendations help users decide which cards are worth the
  submission cost.
What's Next
Current limitations:
- Training on pristine photos – Need more real-world, poorly-lit, handheld photos
- Limited fine-tuning data – Getting verified PSA grades for training is expensive
- Clean backgrounds in training set – Real submissions have messy backgrounds that confuse the model
- Calibration drift – Model trained on one grader's standards, but PSA has many graders
Exploring:
- Data augmentation to simulate poor photo conditions
- Active learning to identify which cards would most improve the model
- Semi-supervised learning using ungraded cards
Key Takeaways
- Ensemble specialist models > One model for everything
- Transfer learning > Custom architectures (usually)
- Domain-specific preprocessing matters more than model complexity
- Even moderate accuracy can be commercially valuable
Working on similar computer vision problems? I'm curious 
  about other niche applications – especially in 
  collectibles/grading. Drop a comment.
The pre-grading tool is available at https://pokeinvest.io 
  for those tracking card portfolios.
 

 
    
Top comments (0)