μ½˜ν…μΈ λ‘œ κ±΄λ„ˆλ›°κΈ°

μ°Έμ‘° ultralytics/trackers/utils/kalman_filter.py

μ°Έκ³ 

이 νŒŒμΌμ€ https://github.com/ultralytics/ ultralytics/blob/main/ ultralytics/trackers/utils/kalman_filter .pyμ—μ„œ 확인할 수 μžˆμŠ΅λ‹ˆλ‹€. 문제λ₯Ό λ°œκ²¬ν•˜λ©΄ ν’€ λ¦¬ν€˜μŠ€νŠΈ (πŸ› οΈ)λ₯Ό μ œμΆœν•˜μ—¬ 문제λ₯Ό ν•΄κ²°ν•˜λ„λ‘ λ„μ™€μ£Όμ„Έμš”. κ°μ‚¬ν•©λ‹ˆλ‹€ πŸ™!



ultralytics.trackers.utils.kalman_filter.KalmanFilterXYAH

λ°”μ΄νŠΈ νŠΈλž™μš©. 이미지 κ³΅κ°„μ—μ„œ λ°”μš΄λ”© λ°•μŠ€λ₯Ό μΆ”μ ν•˜κΈ° μœ„ν•œ κ°„λ‹¨ν•œ 칼만 ν•„ν„°μž…λ‹ˆλ‹€.

8차원 μƒνƒœ 곡간(x, y, a, h, vx, vy, va, vh)μ—λŠ” λ°”μš΄λ”© λ°•μŠ€ 쀑심 μœ„μΉ˜(x, y), μ’…νš‘λΉ„( λΉ„μœ¨ a, 높이 h, 그리고 각각의 속도λ₯Ό ν¬ν•¨ν•©λ‹ˆλ‹€.

였브젝트 λͺ¨μ…˜μ€ 등속 λͺ¨λΈμ„ λ”°λ¦…λ‹ˆλ‹€. λ°”μš΄λ”© λ°•μŠ€ μœ„μΉ˜(x, y, a, h)λŠ” μƒνƒœ 곡간에 λŒ€ν•œ 직접적인 μƒνƒœ 곡간(μ„ ν˜• κ΄€μΈ‘ λͺ¨λΈ)을 직접 κ΄€μΈ‘ν•©λ‹ˆλ‹€.

의 μ†ŒμŠ€ μ½”λ“œ ultralytics/trackers/utils/kalman_filter.py
class KalmanFilterXYAH:
    """
    For bytetrack. A simple Kalman filter for tracking bounding boxes in image space.

    The 8-dimensional state space (x, y, a, h, vx, vy, va, vh) contains the bounding box center position (x, y), aspect
    ratio a, height h, and their respective velocities.

    Object motion follows a constant velocity model. The bounding box location (x, y, a, h) is taken as direct
    observation of the state space (linear observation model).
    """

    def __init__(self):
        """Initialize Kalman filter model matrices with motion and observation uncertainty weights."""
        ndim, dt = 4, 1.0

        # Create Kalman filter model matrices
        self._motion_mat = np.eye(2 * ndim, 2 * ndim)
        for i in range(ndim):
            self._motion_mat[i, ndim + i] = dt
        self._update_mat = np.eye(ndim, 2 * ndim)

        # Motion and observation uncertainty are chosen relative to the current state estimate. These weights control
        # the amount of uncertainty in the model.
        self._std_weight_position = 1.0 / 20
        self._std_weight_velocity = 1.0 / 160

    def initiate(self, measurement: np.ndarray) -> tuple:
        """
        Create track from unassociated measurement.

        Args:
            measurement (ndarray): Bounding box coordinates (x, y, a, h) with center position (x, y), aspect ratio a,
                and height h.

        Returns:
            (tuple[ndarray, ndarray]): Returns the mean vector (8 dimensional) and covariance matrix (8x8 dimensional)
                of the new track. Unobserved velocities are initialized to 0 mean.
        """
        mean_pos = measurement
        mean_vel = np.zeros_like(mean_pos)
        mean = np.r_[mean_pos, mean_vel]

        std = [
            2 * self._std_weight_position * measurement[3],
            2 * self._std_weight_position * measurement[3],
            1e-2,
            2 * self._std_weight_position * measurement[3],
            10 * self._std_weight_velocity * measurement[3],
            10 * self._std_weight_velocity * measurement[3],
            1e-5,
            10 * self._std_weight_velocity * measurement[3],
        ]
        covariance = np.diag(np.square(std))
        return mean, covariance

    def predict(self, mean: np.ndarray, covariance: np.ndarray) -> tuple:
        """
        Run Kalman filter prediction step.

        Args:
            mean (ndarray): The 8 dimensional mean vector of the object state at the previous time step.
            covariance (ndarray): The 8x8 dimensional covariance matrix of the object state at the previous time step.

        Returns:
            (tuple[ndarray, ndarray]): Returns the mean vector and covariance matrix of the predicted state. Unobserved
                velocities are initialized to 0 mean.
        """
        std_pos = [
            self._std_weight_position * mean[3],
            self._std_weight_position * mean[3],
            1e-2,
            self._std_weight_position * mean[3],
        ]
        std_vel = [
            self._std_weight_velocity * mean[3],
            self._std_weight_velocity * mean[3],
            1e-5,
            self._std_weight_velocity * mean[3],
        ]
        motion_cov = np.diag(np.square(np.r_[std_pos, std_vel]))

        mean = np.dot(mean, self._motion_mat.T)
        covariance = np.linalg.multi_dot((self._motion_mat, covariance, self._motion_mat.T)) + motion_cov

        return mean, covariance

    def project(self, mean: np.ndarray, covariance: np.ndarray) -> tuple:
        """
        Project state distribution to measurement space.

        Args:
            mean (ndarray): The state's mean vector (8 dimensional array).
            covariance (ndarray): The state's covariance matrix (8x8 dimensional).

        Returns:
            (tuple[ndarray, ndarray]): Returns the projected mean and covariance matrix of the given state estimate.
        """
        std = [
            self._std_weight_position * mean[3],
            self._std_weight_position * mean[3],
            1e-1,
            self._std_weight_position * mean[3],
        ]
        innovation_cov = np.diag(np.square(std))

        mean = np.dot(self._update_mat, mean)
        covariance = np.linalg.multi_dot((self._update_mat, covariance, self._update_mat.T))
        return mean, covariance + innovation_cov

    def multi_predict(self, mean: np.ndarray, covariance: np.ndarray) -> tuple:
        """
        Run Kalman filter prediction step (Vectorized version).

        Args:
            mean (ndarray): The Nx8 dimensional mean matrix of the object states at the previous time step.
            covariance (ndarray): The Nx8x8 covariance matrix of the object states at the previous time step.

        Returns:
            (tuple[ndarray, ndarray]): Returns the mean vector and covariance matrix of the predicted state. Unobserved
                velocities are initialized to 0 mean.
        """
        std_pos = [
            self._std_weight_position * mean[:, 3],
            self._std_weight_position * mean[:, 3],
            1e-2 * np.ones_like(mean[:, 3]),
            self._std_weight_position * mean[:, 3],
        ]
        std_vel = [
            self._std_weight_velocity * mean[:, 3],
            self._std_weight_velocity * mean[:, 3],
            1e-5 * np.ones_like(mean[:, 3]),
            self._std_weight_velocity * mean[:, 3],
        ]
        sqr = np.square(np.r_[std_pos, std_vel]).T

        motion_cov = [np.diag(sqr[i]) for i in range(len(mean))]
        motion_cov = np.asarray(motion_cov)

        mean = np.dot(mean, self._motion_mat.T)
        left = np.dot(self._motion_mat, covariance).transpose((1, 0, 2))
        covariance = np.dot(left, self._motion_mat.T) + motion_cov

        return mean, covariance

    def update(self, mean: np.ndarray, covariance: np.ndarray, measurement: np.ndarray) -> tuple:
        """
        Run Kalman filter correction step.

        Args:
            mean (ndarray): The predicted state's mean vector (8 dimensional).
            covariance (ndarray): The state's covariance matrix (8x8 dimensional).
            measurement (ndarray): The 4 dimensional measurement vector (x, y, a, h), where (x, y) is the center
                position, a the aspect ratio, and h the height of the bounding box.

        Returns:
            (tuple[ndarray, ndarray]): Returns the measurement-corrected state distribution.
        """
        projected_mean, projected_cov = self.project(mean, covariance)

        chol_factor, lower = scipy.linalg.cho_factor(projected_cov, lower=True, check_finite=False)
        kalman_gain = scipy.linalg.cho_solve(
            (chol_factor, lower), np.dot(covariance, self._update_mat.T).T, check_finite=False
        ).T
        innovation = measurement - projected_mean

        new_mean = mean + np.dot(innovation, kalman_gain.T)
        new_covariance = covariance - np.linalg.multi_dot((kalman_gain, projected_cov, kalman_gain.T))
        return new_mean, new_covariance

    def gating_distance(
        self,
        mean: np.ndarray,
        covariance: np.ndarray,
        measurements: np.ndarray,
        only_position: bool = False,
        metric: str = "maha",
    ) -> np.ndarray:
        """
        Compute gating distance between state distribution and measurements. A suitable distance threshold can be
        obtained from `chi2inv95`. If `only_position` is False, the chi-square distribution has 4 degrees of freedom,
        otherwise 2.

        Args:
            mean (ndarray): Mean vector over the state distribution (8 dimensional).
            covariance (ndarray): Covariance of the state distribution (8x8 dimensional).
            measurements (ndarray): An Nx4 matrix of N measurements, each in format (x, y, a, h) where (x, y)
                is the bounding box center position, a the aspect ratio, and h the height.
            only_position (bool, optional): If True, distance computation is done with respect to the bounding box
                center position only. Defaults to False.
            metric (str, optional): The metric to use for calculating the distance. Options are 'gaussian' for the
                squared Euclidean distance and 'maha' for the squared Mahalanobis distance. Defaults to 'maha'.

        Returns:
            (np.ndarray): Returns an array of length N, where the i-th element contains the squared distance between
                (mean, covariance) and `measurements[i]`.
        """
        mean, covariance = self.project(mean, covariance)
        if only_position:
            mean, covariance = mean[:2], covariance[:2, :2]
            measurements = measurements[:, :2]

        d = measurements - mean
        if metric == "gaussian":
            return np.sum(d * d, axis=1)
        elif metric == "maha":
            cholesky_factor = np.linalg.cholesky(covariance)
            z = scipy.linalg.solve_triangular(cholesky_factor, d.T, lower=True, check_finite=False, overwrite_b=True)
            return np.sum(z * z, axis=0)  # square maha
        else:
            raise ValueError("Invalid distance metric")

__init__()

λͺ¨μ…˜ 및 κ΄€μΈ‘ λΆˆν™•μ‹€μ„± κ°€μ€‘μΉ˜λ‘œ 칼만 ν•„ν„° λͺ¨λΈ 행렬을 μ΄ˆκΈ°ν™”ν•©λ‹ˆλ‹€.

의 μ†ŒμŠ€ μ½”λ“œ ultralytics/trackers/utils/kalman_filter.py
def __init__(self):
    """Initialize Kalman filter model matrices with motion and observation uncertainty weights."""
    ndim, dt = 4, 1.0

    # Create Kalman filter model matrices
    self._motion_mat = np.eye(2 * ndim, 2 * ndim)
    for i in range(ndim):
        self._motion_mat[i, ndim + i] = dt
    self._update_mat = np.eye(ndim, 2 * ndim)

    # Motion and observation uncertainty are chosen relative to the current state estimate. These weights control
    # the amount of uncertainty in the model.
    self._std_weight_position = 1.0 / 20
    self._std_weight_velocity = 1.0 / 160

gating_distance(mean, covariance, measurements, only_position=False, metric='maha')

μƒνƒœ 뢄포와 μΈ‘μ •κ°’ μ‚¬μ΄μ˜ κ²Œμ΄νŒ… 거리λ₯Ό κ³„μ‚°ν•©λ‹ˆλ‹€. μ μ ˆν•œ 거리 μž„κ³„κ°’μ€ μ—μ„œ 얻을 수 μžˆμŠ΅λ‹ˆλ‹€. chi2inv95. λ§Œμ•½ only_position κ°€ 거짓이면 카이제곱 λΆ„ν¬μ˜ μžμœ λ„κ°€ 4μž…λ‹ˆλ‹€, 그렇지 μ•ŠμœΌλ©΄ 2μž…λ‹ˆλ‹€.

λ§€κ°œλ³€μˆ˜:

이름 μœ ν˜• μ„€λͺ… κΈ°λ³Έκ°’
mean ndarray

μƒνƒœ 뢄포(8차원)에 λŒ€ν•œ 평균 λ²‘ν„°μž…λ‹ˆλ‹€.

ν•„μˆ˜
covariance ndarray

μƒνƒœ λΆ„ν¬μ˜ 곡뢄산(8x8 차원)μž…λ‹ˆλ‹€.

ν•„μˆ˜
measurements ndarray

N개의 츑정값이 각각 (x, y, a, h) ν˜•μ‹μ˜ Nx4 ν–‰λ ¬λ‘œ, μ—¬κΈ°μ„œ (x, y) λŠ” λ°”μš΄λ”© λ°•μŠ€ 쀑심 μœ„μΉ˜, aλŠ” κ°€λ‘œ μ„Έλ‘œ λΉ„μœ¨, hλŠ” λ†’μ΄μž…λ‹ˆλ‹€.

ν•„μˆ˜
only_position bool

True인 경우, 거리 계산은 경계 μƒμž 쀑심 μœ„μΉ˜λ§Œμ„ κΈ°μ€€μœΌλ‘œ 거리 계산이 μˆ˜ν–‰λ©λ‹ˆλ‹€. 기본값은 Falseμž…λ‹ˆλ‹€.

False
metric str

거리 계산에 μ‚¬μš©ν•  λ©”νŠΈλ¦­μž…λ‹ˆλ‹€. μ˜΅μ…˜μ€ κ°€μš°μŠ€ 거리의 경우 'κ°€μš°μŠ€' 제곱 μœ ν΄λ¦¬λ“œ 거리, λ§ˆν•˜λΌλ…ΈλΉ„μŠ€ 거리의 제곱 'maha'μž…λ‹ˆλ‹€. 기본값은 'λ§ˆν•˜'μž…λ‹ˆλ‹€.

'maha'

λ°˜ν™˜ν•©λ‹ˆλ‹€:

μœ ν˜• μ„€λͺ…
ndarray

길이 N의 배열을 λ°˜ν™˜ν•˜λ©°, μ—¬κΈ°μ„œ i 번째 μš”μ†Œμ—λŠ” (평균, 곡뢄산)κ³Ό measurements[i].

의 μ†ŒμŠ€ μ½”λ“œ ultralytics/trackers/utils/kalman_filter.py
def gating_distance(
    self,
    mean: np.ndarray,
    covariance: np.ndarray,
    measurements: np.ndarray,
    only_position: bool = False,
    metric: str = "maha",
) -> np.ndarray:
    """
    Compute gating distance between state distribution and measurements. A suitable distance threshold can be
    obtained from `chi2inv95`. If `only_position` is False, the chi-square distribution has 4 degrees of freedom,
    otherwise 2.

    Args:
        mean (ndarray): Mean vector over the state distribution (8 dimensional).
        covariance (ndarray): Covariance of the state distribution (8x8 dimensional).
        measurements (ndarray): An Nx4 matrix of N measurements, each in format (x, y, a, h) where (x, y)
            is the bounding box center position, a the aspect ratio, and h the height.
        only_position (bool, optional): If True, distance computation is done with respect to the bounding box
            center position only. Defaults to False.
        metric (str, optional): The metric to use for calculating the distance. Options are 'gaussian' for the
            squared Euclidean distance and 'maha' for the squared Mahalanobis distance. Defaults to 'maha'.

    Returns:
        (np.ndarray): Returns an array of length N, where the i-th element contains the squared distance between
            (mean, covariance) and `measurements[i]`.
    """
    mean, covariance = self.project(mean, covariance)
    if only_position:
        mean, covariance = mean[:2], covariance[:2, :2]
        measurements = measurements[:, :2]

    d = measurements - mean
    if metric == "gaussian":
        return np.sum(d * d, axis=1)
    elif metric == "maha":
        cholesky_factor = np.linalg.cholesky(covariance)
        z = scipy.linalg.solve_triangular(cholesky_factor, d.T, lower=True, check_finite=False, overwrite_b=True)
        return np.sum(z * z, axis=0)  # square maha
    else:
        raise ValueError("Invalid distance metric")

initiate(measurement)

μ—°κ²°λ˜μ§€ μ•Šμ€ μΈ‘μ •κ°’μ—μ„œ νŠΈλž™μ„ μƒμ„±ν•©λ‹ˆλ‹€.

λ§€κ°œλ³€μˆ˜:

이름 μœ ν˜• μ„€λͺ… κΈ°λ³Έκ°’
measurement ndarray

쀑심 μœ„μΉ˜(x, y), κ°€λ‘œ μ„Έλ‘œ λΉ„μœ¨ a. λ°”μš΄λ”© λ°•μŠ€ μ’Œν‘œ(x, y, a, h), 및 높이 h둜 κ΅¬μ„±λ©λ‹ˆλ‹€.

ν•„μˆ˜

λ°˜ν™˜ν•©λ‹ˆλ‹€:

μœ ν˜• μ„€λͺ…
tuple[ndarray, ndarray]

μƒˆ νŠΈλž™μ˜ 평균 벑터(8차원)와 곡뢄산 ν–‰λ ¬(8x8차원)을 λ°˜ν™˜ν•©λ‹ˆλ‹€. λ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€. κ΄€μΈ‘λ˜μ§€ μ•Šμ€ μ†λ„λŠ” 0 ν‰κ· μœΌλ‘œ μ΄ˆκΈ°ν™”λ©λ‹ˆλ‹€.

의 μ†ŒμŠ€ μ½”λ“œ ultralytics/trackers/utils/kalman_filter.py
def initiate(self, measurement: np.ndarray) -> tuple:
    """
    Create track from unassociated measurement.

    Args:
        measurement (ndarray): Bounding box coordinates (x, y, a, h) with center position (x, y), aspect ratio a,
            and height h.

    Returns:
        (tuple[ndarray, ndarray]): Returns the mean vector (8 dimensional) and covariance matrix (8x8 dimensional)
            of the new track. Unobserved velocities are initialized to 0 mean.
    """
    mean_pos = measurement
    mean_vel = np.zeros_like(mean_pos)
    mean = np.r_[mean_pos, mean_vel]

    std = [
        2 * self._std_weight_position * measurement[3],
        2 * self._std_weight_position * measurement[3],
        1e-2,
        2 * self._std_weight_position * measurement[3],
        10 * self._std_weight_velocity * measurement[3],
        10 * self._std_weight_velocity * measurement[3],
        1e-5,
        10 * self._std_weight_velocity * measurement[3],
    ]
    covariance = np.diag(np.square(std))
    return mean, covariance

multi_predict(mean, covariance)

칼만 ν•„ν„° 예츑 단계(λ²‘ν„°ν™”λœ 버전)λ₯Ό μ‹€ν–‰ν•©λ‹ˆλ‹€.

λ§€κ°œλ³€μˆ˜:

이름 μœ ν˜• μ„€λͺ… κΈ°λ³Έκ°’
mean ndarray

이전 μ‹œκ°„ λ‹¨κ³„μ—μ„œ 였브젝트 μƒνƒœμ˜ Nx8 차원 평균 ν–‰λ ¬μž…λ‹ˆλ‹€.

ν•„μˆ˜
covariance ndarray

이전 μ‹œκ°„ λ‹¨κ³„μ—μ„œ 였브젝트 μƒνƒœμ˜ Nx8x8 곡뢄산 ν–‰λ ¬μž…λ‹ˆλ‹€.

ν•„μˆ˜

λ°˜ν™˜ν•©λ‹ˆλ‹€:

μœ ν˜• μ„€λͺ…
tuple[ndarray, ndarray]

예츑된 μƒνƒœμ˜ 평균 벑터와 곡뢄산 행렬을 λ°˜ν™˜ν•©λ‹ˆλ‹€. κ΄€μΈ‘λ˜μ§€ μ•Šμ€ μ†λ„λŠ” 0 ν‰κ· μœΌλ‘œ μ΄ˆκΈ°ν™”λ©λ‹ˆλ‹€.

의 μ†ŒμŠ€ μ½”λ“œ ultralytics/trackers/utils/kalman_filter.py
def multi_predict(self, mean: np.ndarray, covariance: np.ndarray) -> tuple:
    """
    Run Kalman filter prediction step (Vectorized version).

    Args:
        mean (ndarray): The Nx8 dimensional mean matrix of the object states at the previous time step.
        covariance (ndarray): The Nx8x8 covariance matrix of the object states at the previous time step.

    Returns:
        (tuple[ndarray, ndarray]): Returns the mean vector and covariance matrix of the predicted state. Unobserved
            velocities are initialized to 0 mean.
    """
    std_pos = [
        self._std_weight_position * mean[:, 3],
        self._std_weight_position * mean[:, 3],
        1e-2 * np.ones_like(mean[:, 3]),
        self._std_weight_position * mean[:, 3],
    ]
    std_vel = [
        self._std_weight_velocity * mean[:, 3],
        self._std_weight_velocity * mean[:, 3],
        1e-5 * np.ones_like(mean[:, 3]),
        self._std_weight_velocity * mean[:, 3],
    ]
    sqr = np.square(np.r_[std_pos, std_vel]).T

    motion_cov = [np.diag(sqr[i]) for i in range(len(mean))]
    motion_cov = np.asarray(motion_cov)

    mean = np.dot(mean, self._motion_mat.T)
    left = np.dot(self._motion_mat, covariance).transpose((1, 0, 2))
    covariance = np.dot(left, self._motion_mat.T) + motion_cov

    return mean, covariance

predict(mean, covariance)

칼만 ν•„ν„° 예츑 단계λ₯Ό μ‹€ν–‰ν•©λ‹ˆλ‹€.

λ§€κ°œλ³€μˆ˜:

이름 μœ ν˜• μ„€λͺ… κΈ°λ³Έκ°’
mean ndarray

이전 μ‹œκ°„ λ‹¨κ³„μ—μ„œ 였브젝트 μƒνƒœμ˜ 8차원 평균 λ²‘ν„°μž…λ‹ˆλ‹€.

ν•„μˆ˜
covariance ndarray

이전 μ‹œκ°„ λ‹¨κ³„μ—μ„œ 였브젝트 μƒνƒœμ˜ 8x8 차원 곡뢄산 ν–‰λ ¬μž…λ‹ˆλ‹€.

ν•„μˆ˜

λ°˜ν™˜ν•©λ‹ˆλ‹€:

μœ ν˜• μ„€λͺ…
tuple[ndarray, ndarray]

예츑된 μƒνƒœμ˜ 평균 벑터와 곡뢄산 행렬을 λ°˜ν™˜ν•©λ‹ˆλ‹€. κ΄€μΈ‘λ˜μ§€ μ•Šμ€ μ†λ„λŠ” 0 ν‰κ· μœΌλ‘œ μ΄ˆκΈ°ν™”λ©λ‹ˆλ‹€.

의 μ†ŒμŠ€ μ½”λ“œ ultralytics/trackers/utils/kalman_filter.py
def predict(self, mean: np.ndarray, covariance: np.ndarray) -> tuple:
    """
    Run Kalman filter prediction step.

    Args:
        mean (ndarray): The 8 dimensional mean vector of the object state at the previous time step.
        covariance (ndarray): The 8x8 dimensional covariance matrix of the object state at the previous time step.

    Returns:
        (tuple[ndarray, ndarray]): Returns the mean vector and covariance matrix of the predicted state. Unobserved
            velocities are initialized to 0 mean.
    """
    std_pos = [
        self._std_weight_position * mean[3],
        self._std_weight_position * mean[3],
        1e-2,
        self._std_weight_position * mean[3],
    ]
    std_vel = [
        self._std_weight_velocity * mean[3],
        self._std_weight_velocity * mean[3],
        1e-5,
        self._std_weight_velocity * mean[3],
    ]
    motion_cov = np.diag(np.square(np.r_[std_pos, std_vel]))

    mean = np.dot(mean, self._motion_mat.T)
    covariance = np.linalg.multi_dot((self._motion_mat, covariance, self._motion_mat.T)) + motion_cov

    return mean, covariance

project(mean, covariance)

μΈ‘μ • 곡간에 μƒνƒœ 뢄포λ₯Ό νˆ¬μ˜ν•©λ‹ˆλ‹€.

λ§€κ°œλ³€μˆ˜:

이름 μœ ν˜• μ„€λͺ… κΈ°λ³Έκ°’
mean ndarray

μƒνƒœμ˜ 평균 벑터(8차원 λ°°μ—΄)μž…λ‹ˆλ‹€.

ν•„μˆ˜
covariance ndarray

μƒνƒœμ˜ 곡뢄산 ν–‰λ ¬(8x8 차원)μž…λ‹ˆλ‹€.

ν•„μˆ˜

λ°˜ν™˜ν•©λ‹ˆλ‹€:

μœ ν˜• μ„€λͺ…
tuple[ndarray, ndarray]

주어진 μƒνƒœ μΆ”μ •μΉ˜μ˜ μ˜ˆμƒ 평균 및 곡뢄산 행렬을 λ°˜ν™˜ν•©λ‹ˆλ‹€.

의 μ†ŒμŠ€ μ½”λ“œ ultralytics/trackers/utils/kalman_filter.py
def project(self, mean: np.ndarray, covariance: np.ndarray) -> tuple:
    """
    Project state distribution to measurement space.

    Args:
        mean (ndarray): The state's mean vector (8 dimensional array).
        covariance (ndarray): The state's covariance matrix (8x8 dimensional).

    Returns:
        (tuple[ndarray, ndarray]): Returns the projected mean and covariance matrix of the given state estimate.
    """
    std = [
        self._std_weight_position * mean[3],
        self._std_weight_position * mean[3],
        1e-1,
        self._std_weight_position * mean[3],
    ]
    innovation_cov = np.diag(np.square(std))

    mean = np.dot(self._update_mat, mean)
    covariance = np.linalg.multi_dot((self._update_mat, covariance, self._update_mat.T))
    return mean, covariance + innovation_cov

update(mean, covariance, measurement)

칼만 ν•„ν„° 보정 단계λ₯Ό μ‹€ν–‰ν•©λ‹ˆλ‹€.

λ§€κ°œλ³€μˆ˜:

이름 μœ ν˜• μ„€λͺ… κΈ°λ³Έκ°’
mean ndarray

예츑된 μƒνƒœμ˜ 평균 벑터(8차원)μž…λ‹ˆλ‹€.

ν•„μˆ˜
covariance ndarray

μƒνƒœμ˜ 곡뢄산 ν–‰λ ¬(8x8 차원)μž…λ‹ˆλ‹€.

ν•„μˆ˜
measurement ndarray

4차원 μΈ‘μ • 벑터(x, y, a, h)둜, μ—¬κΈ°μ„œ (x, y)λŠ” 쀑앙 μœ„μΉ˜, aλŠ” κ°€λ‘œ μ„Έλ‘œ λΉ„μœ¨, hλŠ” λ°”μš΄λ”© λ°•μŠ€μ˜ λ†’μ΄μž…λ‹ˆλ‹€.

ν•„μˆ˜

λ°˜ν™˜ν•©λ‹ˆλ‹€:

μœ ν˜• μ„€λͺ…
tuple[ndarray, ndarray]

츑정값이 λ³΄μ •λœ μƒνƒœ 뢄포λ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€.

의 μ†ŒμŠ€ μ½”λ“œ ultralytics/trackers/utils/kalman_filter.py
def update(self, mean: np.ndarray, covariance: np.ndarray, measurement: np.ndarray) -> tuple:
    """
    Run Kalman filter correction step.

    Args:
        mean (ndarray): The predicted state's mean vector (8 dimensional).
        covariance (ndarray): The state's covariance matrix (8x8 dimensional).
        measurement (ndarray): The 4 dimensional measurement vector (x, y, a, h), where (x, y) is the center
            position, a the aspect ratio, and h the height of the bounding box.

    Returns:
        (tuple[ndarray, ndarray]): Returns the measurement-corrected state distribution.
    """
    projected_mean, projected_cov = self.project(mean, covariance)

    chol_factor, lower = scipy.linalg.cho_factor(projected_cov, lower=True, check_finite=False)
    kalman_gain = scipy.linalg.cho_solve(
        (chol_factor, lower), np.dot(covariance, self._update_mat.T).T, check_finite=False
    ).T
    innovation = measurement - projected_mean

    new_mean = mean + np.dot(innovation, kalman_gain.T)
    new_covariance = covariance - np.linalg.multi_dot((kalman_gain, projected_cov, kalman_gain.T))
    return new_mean, new_covariance



ultralytics.trackers.utils.kalman_filter.KalmanFilterXYWH

베이슀: KalmanFilterXYAH

BoT-SORT용. 이미지 κ³΅κ°„μ—μ„œ 경계 μƒμžλ₯Ό μΆ”μ ν•˜κΈ° μœ„ν•œ κ°„λ‹¨ν•œ 칼만 ν•„ν„°μž…λ‹ˆλ‹€.

8차원 μƒνƒœ 곡간(x, y, w, h, vx, vy, vw, vh)μ—λŠ” λ°”μš΄λ”© λ°•μŠ€ 쀑심 μœ„μΉ˜(x, y), λ„ˆλΉ„ w, 높이 h 및 각각의 속도λ₯Ό ν¬ν•¨ν•©λ‹ˆλ‹€.

였브젝트 λͺ¨μ…˜μ€ 등속 λͺ¨λΈμ„ λ”°λ¦…λ‹ˆλ‹€. λ°”μš΄λ”© λ°•μŠ€ μœ„μΉ˜(x, y, w, h)λŠ” μƒνƒœ 곡간에 λŒ€ν•œ 직접적인 μƒνƒœ 곡간(μ„ ν˜• κ΄€μΈ‘ λͺ¨λΈ)을 직접 κ΄€μΈ‘ν•©λ‹ˆλ‹€.

의 μ†ŒμŠ€ μ½”λ“œ ultralytics/trackers/utils/kalman_filter.py
class KalmanFilterXYWH(KalmanFilterXYAH):
    """
    For BoT-SORT. A simple Kalman filter for tracking bounding boxes in image space.

    The 8-dimensional state space (x, y, w, h, vx, vy, vw, vh) contains the bounding box center position (x, y), width
    w, height h, and their respective velocities.

    Object motion follows a constant velocity model. The bounding box location (x, y, w, h) is taken as direct
    observation of the state space (linear observation model).
    """

    def initiate(self, measurement: np.ndarray) -> tuple:
        """
        Create track from unassociated measurement.

        Args:
            measurement (ndarray): Bounding box coordinates (x, y, w, h) with center position (x, y), width, and height.

        Returns:
            (tuple[ndarray, ndarray]): Returns the mean vector (8 dimensional) and covariance matrix (8x8 dimensional)
                of the new track. Unobserved velocities are initialized to 0 mean.
        """
        mean_pos = measurement
        mean_vel = np.zeros_like(mean_pos)
        mean = np.r_[mean_pos, mean_vel]

        std = [
            2 * self._std_weight_position * measurement[2],
            2 * self._std_weight_position * measurement[3],
            2 * self._std_weight_position * measurement[2],
            2 * self._std_weight_position * measurement[3],
            10 * self._std_weight_velocity * measurement[2],
            10 * self._std_weight_velocity * measurement[3],
            10 * self._std_weight_velocity * measurement[2],
            10 * self._std_weight_velocity * measurement[3],
        ]
        covariance = np.diag(np.square(std))
        return mean, covariance

    def predict(self, mean, covariance) -> tuple:
        """
        Run Kalman filter prediction step.

        Args:
            mean (ndarray): The 8 dimensional mean vector of the object state at the previous time step.
            covariance (ndarray): The 8x8 dimensional covariance matrix of the object state at the previous time step.

        Returns:
            (tuple[ndarray, ndarray]): Returns the mean vector and covariance matrix of the predicted state. Unobserved
                velocities are initialized to 0 mean.
        """
        std_pos = [
            self._std_weight_position * mean[2],
            self._std_weight_position * mean[3],
            self._std_weight_position * mean[2],
            self._std_weight_position * mean[3],
        ]
        std_vel = [
            self._std_weight_velocity * mean[2],
            self._std_weight_velocity * mean[3],
            self._std_weight_velocity * mean[2],
            self._std_weight_velocity * mean[3],
        ]
        motion_cov = np.diag(np.square(np.r_[std_pos, std_vel]))

        mean = np.dot(mean, self._motion_mat.T)
        covariance = np.linalg.multi_dot((self._motion_mat, covariance, self._motion_mat.T)) + motion_cov

        return mean, covariance

    def project(self, mean, covariance) -> tuple:
        """
        Project state distribution to measurement space.

        Args:
            mean (ndarray): The state's mean vector (8 dimensional array).
            covariance (ndarray): The state's covariance matrix (8x8 dimensional).

        Returns:
            (tuple[ndarray, ndarray]): Returns the projected mean and covariance matrix of the given state estimate.
        """
        std = [
            self._std_weight_position * mean[2],
            self._std_weight_position * mean[3],
            self._std_weight_position * mean[2],
            self._std_weight_position * mean[3],
        ]
        innovation_cov = np.diag(np.square(std))

        mean = np.dot(self._update_mat, mean)
        covariance = np.linalg.multi_dot((self._update_mat, covariance, self._update_mat.T))
        return mean, covariance + innovation_cov

    def multi_predict(self, mean, covariance) -> tuple:
        """
        Run Kalman filter prediction step (Vectorized version).

        Args:
            mean (ndarray): The Nx8 dimensional mean matrix of the object states at the previous time step.
            covariance (ndarray): The Nx8x8 covariance matrix of the object states at the previous time step.

        Returns:
            (tuple[ndarray, ndarray]): Returns the mean vector and covariance matrix of the predicted state. Unobserved
                velocities are initialized to 0 mean.
        """
        std_pos = [
            self._std_weight_position * mean[:, 2],
            self._std_weight_position * mean[:, 3],
            self._std_weight_position * mean[:, 2],
            self._std_weight_position * mean[:, 3],
        ]
        std_vel = [
            self._std_weight_velocity * mean[:, 2],
            self._std_weight_velocity * mean[:, 3],
            self._std_weight_velocity * mean[:, 2],
            self._std_weight_velocity * mean[:, 3],
        ]
        sqr = np.square(np.r_[std_pos, std_vel]).T

        motion_cov = [np.diag(sqr[i]) for i in range(len(mean))]
        motion_cov = np.asarray(motion_cov)

        mean = np.dot(mean, self._motion_mat.T)
        left = np.dot(self._motion_mat, covariance).transpose((1, 0, 2))
        covariance = np.dot(left, self._motion_mat.T) + motion_cov

        return mean, covariance

    def update(self, mean, covariance, measurement) -> tuple:
        """
        Run Kalman filter correction step.

        Args:
            mean (ndarray): The predicted state's mean vector (8 dimensional).
            covariance (ndarray): The state's covariance matrix (8x8 dimensional).
            measurement (ndarray): The 4 dimensional measurement vector (x, y, w, h), where (x, y) is the center
                position, w the width, and h the height of the bounding box.

        Returns:
            (tuple[ndarray, ndarray]): Returns the measurement-corrected state distribution.
        """
        return super().update(mean, covariance, measurement)

initiate(measurement)

μ—°κ²°λ˜μ§€ μ•Šμ€ μΈ‘μ •κ°’μ—μ„œ νŠΈλž™μ„ μƒμ„±ν•©λ‹ˆλ‹€.

λ§€κ°œλ³€μˆ˜:

이름 μœ ν˜• μ„€λͺ… κΈ°λ³Έκ°’
measurement ndarray

쀑심 μœ„μΉ˜(x, y), λ„ˆλΉ„, 높이가 ν¬ν•¨λœ λ°”μš΄λ”© λ°•μŠ€ μ’Œν‘œ(x, y, w, h)μž…λ‹ˆλ‹€.

ν•„μˆ˜

λ°˜ν™˜ν•©λ‹ˆλ‹€:

μœ ν˜• μ„€λͺ…
tuple[ndarray, ndarray]

μƒˆ νŠΈλž™μ˜ 평균 벑터(8차원)와 곡뢄산 ν–‰λ ¬(8x8차원)을 λ°˜ν™˜ν•©λ‹ˆλ‹€. λ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€. κ΄€μΈ‘λ˜μ§€ μ•Šμ€ μ†λ„λŠ” 0 ν‰κ· μœΌλ‘œ μ΄ˆκΈ°ν™”λ©λ‹ˆλ‹€.

의 μ†ŒμŠ€ μ½”λ“œ ultralytics/trackers/utils/kalman_filter.py
def initiate(self, measurement: np.ndarray) -> tuple:
    """
    Create track from unassociated measurement.

    Args:
        measurement (ndarray): Bounding box coordinates (x, y, w, h) with center position (x, y), width, and height.

    Returns:
        (tuple[ndarray, ndarray]): Returns the mean vector (8 dimensional) and covariance matrix (8x8 dimensional)
            of the new track. Unobserved velocities are initialized to 0 mean.
    """
    mean_pos = measurement
    mean_vel = np.zeros_like(mean_pos)
    mean = np.r_[mean_pos, mean_vel]

    std = [
        2 * self._std_weight_position * measurement[2],
        2 * self._std_weight_position * measurement[3],
        2 * self._std_weight_position * measurement[2],
        2 * self._std_weight_position * measurement[3],
        10 * self._std_weight_velocity * measurement[2],
        10 * self._std_weight_velocity * measurement[3],
        10 * self._std_weight_velocity * measurement[2],
        10 * self._std_weight_velocity * measurement[3],
    ]
    covariance = np.diag(np.square(std))
    return mean, covariance

multi_predict(mean, covariance)

칼만 ν•„ν„° 예츑 단계(λ²‘ν„°ν™”λœ 버전)λ₯Ό μ‹€ν–‰ν•©λ‹ˆλ‹€.

λ§€κ°œλ³€μˆ˜:

이름 μœ ν˜• μ„€λͺ… κΈ°λ³Έκ°’
mean ndarray

이전 μ‹œκ°„ λ‹¨κ³„μ—μ„œ 였브젝트 μƒνƒœμ˜ Nx8 차원 평균 ν–‰λ ¬μž…λ‹ˆλ‹€.

ν•„μˆ˜
covariance ndarray

이전 μ‹œκ°„ λ‹¨κ³„μ—μ„œ 였브젝트 μƒνƒœμ˜ Nx8x8 곡뢄산 ν–‰λ ¬μž…λ‹ˆλ‹€.

ν•„μˆ˜

λ°˜ν™˜ν•©λ‹ˆλ‹€:

μœ ν˜• μ„€λͺ…
tuple[ndarray, ndarray]

예츑된 μƒνƒœμ˜ 평균 벑터와 곡뢄산 행렬을 λ°˜ν™˜ν•©λ‹ˆλ‹€. κ΄€μΈ‘λ˜μ§€ μ•Šμ€ μ†λ„λŠ” 0 ν‰κ· μœΌλ‘œ μ΄ˆκΈ°ν™”λ©λ‹ˆλ‹€.

의 μ†ŒμŠ€ μ½”λ“œ ultralytics/trackers/utils/kalman_filter.py
def multi_predict(self, mean, covariance) -> tuple:
    """
    Run Kalman filter prediction step (Vectorized version).

    Args:
        mean (ndarray): The Nx8 dimensional mean matrix of the object states at the previous time step.
        covariance (ndarray): The Nx8x8 covariance matrix of the object states at the previous time step.

    Returns:
        (tuple[ndarray, ndarray]): Returns the mean vector and covariance matrix of the predicted state. Unobserved
            velocities are initialized to 0 mean.
    """
    std_pos = [
        self._std_weight_position * mean[:, 2],
        self._std_weight_position * mean[:, 3],
        self._std_weight_position * mean[:, 2],
        self._std_weight_position * mean[:, 3],
    ]
    std_vel = [
        self._std_weight_velocity * mean[:, 2],
        self._std_weight_velocity * mean[:, 3],
        self._std_weight_velocity * mean[:, 2],
        self._std_weight_velocity * mean[:, 3],
    ]
    sqr = np.square(np.r_[std_pos, std_vel]).T

    motion_cov = [np.diag(sqr[i]) for i in range(len(mean))]
    motion_cov = np.asarray(motion_cov)

    mean = np.dot(mean, self._motion_mat.T)
    left = np.dot(self._motion_mat, covariance).transpose((1, 0, 2))
    covariance = np.dot(left, self._motion_mat.T) + motion_cov

    return mean, covariance

predict(mean, covariance)

칼만 ν•„ν„° 예츑 단계λ₯Ό μ‹€ν–‰ν•©λ‹ˆλ‹€.

λ§€κ°œλ³€μˆ˜:

이름 μœ ν˜• μ„€λͺ… κΈ°λ³Έκ°’
mean ndarray

이전 μ‹œκ°„ λ‹¨κ³„μ—μ„œ 였브젝트 μƒνƒœμ˜ 8차원 평균 λ²‘ν„°μž…λ‹ˆλ‹€.

ν•„μˆ˜
covariance ndarray

이전 μ‹œκ°„ λ‹¨κ³„μ—μ„œ 였브젝트 μƒνƒœμ˜ 8x8 차원 곡뢄산 ν–‰λ ¬μž…λ‹ˆλ‹€.

ν•„μˆ˜

λ°˜ν™˜ν•©λ‹ˆλ‹€:

μœ ν˜• μ„€λͺ…
tuple[ndarray, ndarray]

예츑된 μƒνƒœμ˜ 평균 벑터와 곡뢄산 행렬을 λ°˜ν™˜ν•©λ‹ˆλ‹€. κ΄€μΈ‘λ˜μ§€ μ•Šμ€ μ†λ„λŠ” 0 ν‰κ· μœΌλ‘œ μ΄ˆκΈ°ν™”λ©λ‹ˆλ‹€.

의 μ†ŒμŠ€ μ½”λ“œ ultralytics/trackers/utils/kalman_filter.py
def predict(self, mean, covariance) -> tuple:
    """
    Run Kalman filter prediction step.

    Args:
        mean (ndarray): The 8 dimensional mean vector of the object state at the previous time step.
        covariance (ndarray): The 8x8 dimensional covariance matrix of the object state at the previous time step.

    Returns:
        (tuple[ndarray, ndarray]): Returns the mean vector and covariance matrix of the predicted state. Unobserved
            velocities are initialized to 0 mean.
    """
    std_pos = [
        self._std_weight_position * mean[2],
        self._std_weight_position * mean[3],
        self._std_weight_position * mean[2],
        self._std_weight_position * mean[3],
    ]
    std_vel = [
        self._std_weight_velocity * mean[2],
        self._std_weight_velocity * mean[3],
        self._std_weight_velocity * mean[2],
        self._std_weight_velocity * mean[3],
    ]
    motion_cov = np.diag(np.square(np.r_[std_pos, std_vel]))

    mean = np.dot(mean, self._motion_mat.T)
    covariance = np.linalg.multi_dot((self._motion_mat, covariance, self._motion_mat.T)) + motion_cov

    return mean, covariance

project(mean, covariance)

μΈ‘μ • 곡간에 μƒνƒœ 뢄포λ₯Ό νˆ¬μ˜ν•©λ‹ˆλ‹€.

λ§€κ°œλ³€μˆ˜:

이름 μœ ν˜• μ„€λͺ… κΈ°λ³Έκ°’
mean ndarray

μƒνƒœμ˜ 평균 벑터(8차원 λ°°μ—΄)μž…λ‹ˆλ‹€.

ν•„μˆ˜
covariance ndarray

μƒνƒœμ˜ 곡뢄산 ν–‰λ ¬(8x8 차원)μž…λ‹ˆλ‹€.

ν•„μˆ˜

λ°˜ν™˜ν•©λ‹ˆλ‹€:

μœ ν˜• μ„€λͺ…
tuple[ndarray, ndarray]

주어진 μƒνƒœ μΆ”μ •μΉ˜μ˜ μ˜ˆμƒ 평균 및 곡뢄산 행렬을 λ°˜ν™˜ν•©λ‹ˆλ‹€.

의 μ†ŒμŠ€ μ½”λ“œ ultralytics/trackers/utils/kalman_filter.py
def project(self, mean, covariance) -> tuple:
    """
    Project state distribution to measurement space.

    Args:
        mean (ndarray): The state's mean vector (8 dimensional array).
        covariance (ndarray): The state's covariance matrix (8x8 dimensional).

    Returns:
        (tuple[ndarray, ndarray]): Returns the projected mean and covariance matrix of the given state estimate.
    """
    std = [
        self._std_weight_position * mean[2],
        self._std_weight_position * mean[3],
        self._std_weight_position * mean[2],
        self._std_weight_position * mean[3],
    ]
    innovation_cov = np.diag(np.square(std))

    mean = np.dot(self._update_mat, mean)
    covariance = np.linalg.multi_dot((self._update_mat, covariance, self._update_mat.T))
    return mean, covariance + innovation_cov

update(mean, covariance, measurement)

칼만 ν•„ν„° 보정 단계λ₯Ό μ‹€ν–‰ν•©λ‹ˆλ‹€.

λ§€κ°œλ³€μˆ˜:

이름 μœ ν˜• μ„€λͺ… κΈ°λ³Έκ°’
mean ndarray

예츑된 μƒνƒœμ˜ 평균 벑터(8차원)μž…λ‹ˆλ‹€.

ν•„μˆ˜
covariance ndarray

μƒνƒœμ˜ 곡뢄산 ν–‰λ ¬(8x8 차원)μž…λ‹ˆλ‹€.

ν•„μˆ˜
measurement ndarray

4차원 μΈ‘μ • 벑터(x, y, w, h)둜, μ—¬κΈ°μ„œ (x, y)λŠ” 쀑심 μœ„μΉ˜, wλŠ” λ„ˆλΉ„, hλŠ” λ°”μš΄λ”© λ°•μŠ€μ˜ λ†’μ΄μž…λ‹ˆλ‹€.

ν•„μˆ˜

λ°˜ν™˜ν•©λ‹ˆλ‹€:

μœ ν˜• μ„€λͺ…
tuple[ndarray, ndarray]

츑정값이 λ³΄μ •λœ μƒνƒœ 뢄포λ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€.

의 μ†ŒμŠ€ μ½”λ“œ ultralytics/trackers/utils/kalman_filter.py
def update(self, mean, covariance, measurement) -> tuple:
    """
    Run Kalman filter correction step.

    Args:
        mean (ndarray): The predicted state's mean vector (8 dimensional).
        covariance (ndarray): The state's covariance matrix (8x8 dimensional).
        measurement (ndarray): The 4 dimensional measurement vector (x, y, w, h), where (x, y) is the center
            position, w the width, and h the height of the bounding box.

    Returns:
        (tuple[ndarray, ndarray]): Returns the measurement-corrected state distribution.
    """
    return super().update(mean, covariance, measurement)





Created 2023-11-12, Updated 2024-06-02
Authors: glenn-jocher (5), Burhan-Q (1)