Chapter 57 Advanced ~50 min read

Computer Vision and Video Analysis

Using computer vision to extract insights from basketball video.

The Vision Frontier

Computer vision enables automated extraction of information from video that previously required manual observation. Pose estimation tracks player body positions. Object detection identifies the ball. Motion analysis characterizes movement patterns. These capabilities open new analytical frontiers.

Automated Play Classification

Computer vision can classify plays from video: pick-and-rolls, isolations, cuts, screens. This automation enables systematic analysis of tactical patterns at scale that manual coding could never achieve. Teams can analyze every possession across seasons rather than sampling.

Defensive Coverage Analysis

Video analysis reveals defensive schemes and assignments better than tracking data alone. Computer vision can identify who's guarding whom, detect switches and rotations, and characterize coverage tendencies. This information helps prepare for specific opponents.

Historical Video Analysis

Computer vision enables analysis of historical games from before tracking data existed. By applying modern techniques to old broadcast video, we can generate tracking-style data for historical comparison. This bridges the data gap between eras.

Technical Challenges

Video analysis faces challenges: camera angles are limited, players occlude each other, and broadcast video doesn't show the full court. Current technology handles these constraints imperfectly. Accuracy remains below tracking systems installed in arenas.

Implementation in R

# Passing network analysis
library(tidyverse)
library(igraph)

build_passing_network <- function(pass_data) {
  # Create edge list
  edges <- pass_data %>%
    group_by(passer_name, receiver_name) %>%
    summarise(
      passes = n(),
      assists = sum(assist),
      .groups = "drop"
    ) %>%
    filter(passes >= 10)

  # Build network
  g <- graph_from_data_frame(edges, directed = TRUE)

  # Calculate centrality
  centrality <- tibble(
    player = V(g)$name,
    degree = degree(g, mode = "all"),
    in_degree = degree(g, mode = "in"),
    out_degree = degree(g, mode = "out"),
    betweenness = betweenness(g),
    pagerank = page_rank(g)$vector
  )

  list(graph = g, centrality = centrality)
}

passes <- read_csv("team_passes.csv")
network <- build_passing_network(passes)
print(network$centrality)

Implementation in Python

# Passing network analysis
import pandas as pd
import networkx as nx

def build_passing_network(pass_data):
    # Aggregate passes
    edges = pass_data.groupby(["passer_name", "receiver_name"]).agg({
        "pass_id": "count",
        "assist": "sum"
    }).rename(columns={"pass_id": "passes"}).reset_index()

    edges = edges[edges["passes"] >= 10]

    # Build network
    G = nx.from_pandas_edgelist(
        edges,
        source="passer_name",
        target="receiver_name",
        edge_attr=["passes", "assist"],
        create_using=nx.DiGraph()
    )

    # Calculate centrality
    centrality = pd.DataFrame({
        "player": list(G.nodes()),
        "degree": dict(G.degree()).values(),
        "betweenness": nx.betweenness_centrality(G).values(),
        "pagerank": nx.pagerank(G).values()
    })

    return G, centrality

passes = pd.read_csv("team_passes.csv")
graph, centrality = build_passing_network(passes)
print(centrality.sort_values("pagerank", ascending=False))

Implementation in R

# Passing network analysis
library(tidyverse)
library(igraph)

build_passing_network <- function(pass_data) {
  # Create edge list
  edges <- pass_data %>%
    group_by(passer_name, receiver_name) %>%
    summarise(
      passes = n(),
      assists = sum(assist),
      .groups = "drop"
    ) %>%
    filter(passes >= 10)

  # Build network
  g <- graph_from_data_frame(edges, directed = TRUE)

  # Calculate centrality
  centrality <- tibble(
    player = V(g)$name,
    degree = degree(g, mode = "all"),
    in_degree = degree(g, mode = "in"),
    out_degree = degree(g, mode = "out"),
    betweenness = betweenness(g),
    pagerank = page_rank(g)$vector
  )

  list(graph = g, centrality = centrality)
}

passes <- read_csv("team_passes.csv")
network <- build_passing_network(passes)
print(network$centrality)

Implementation in Python

# Passing network analysis
import pandas as pd
import networkx as nx

def build_passing_network(pass_data):
    # Aggregate passes
    edges = pass_data.groupby(["passer_name", "receiver_name"]).agg({
        "pass_id": "count",
        "assist": "sum"
    }).rename(columns={"pass_id": "passes"}).reset_index()

    edges = edges[edges["passes"] >= 10]

    # Build network
    G = nx.from_pandas_edgelist(
        edges,
        source="passer_name",
        target="receiver_name",
        edge_attr=["passes", "assist"],
        create_using=nx.DiGraph()
    )

    # Calculate centrality
    centrality = pd.DataFrame({
        "player": list(G.nodes()),
        "degree": dict(G.degree()).values(),
        "betweenness": nx.betweenness_centrality(G).values(),
        "pagerank": nx.pagerank(G).values()
    })

    return G, centrality

passes = pd.read_csv("team_passes.csv")
graph, centrality = build_passing_network(passes)
print(centrality.sort_values("pagerank", ascending=False))
Chapter Summary

You've completed Chapter 57: Computer Vision and Video Analysis.