Skip to content

ChromProcessor

Chrominance-based rPPG method introduced by de Haan & Jeanne (2013).

de Haan, G., & Jeanne, V. (2013). Robust Pulse Rate From Chrominance-Based rPPG. IEEE Transactions on Biomedical Engineering, 60(10), 2878-2886. https://doi.org/10.1109/TBME.2013.2266196

ChromProcessor

Bases: Processor

Chrominance-based rPPG algorithm by de Haan & Jeanne (2013).

Parameters:

Name Type Description Default
winsize int

window size for moving average calculations. Defaults to 45.

45
method Literal['fixed', 'xovery']

method to use. Can be 'xovery' or 'fixed'. Defaults to "xovery".

'xovery'
Source code in src\yarppg\processors\chrom.py
class ChromProcessor(Processor):
    """Chrominance-based rPPG algorithm by de Haan & Jeanne (2013).

    Args:
        winsize: window size for moving average calculations. Defaults to 45.
        method: method to use. Can be 'xovery' or 'fixed'. Defaults to "xovery".
    """

    def __init__(
        self, winsize: int = 45, method: Literal["fixed", "xovery"] = "xovery"
    ):
        Processor.__init__(self)

        self.winsize = winsize
        self.method = method

        self._rgbs: list[Color] = []
        self._xs: list[float] = []
        self._ys: list[float] = []

    def process(self, roi: RegionOfInterest) -> RppgResult:
        """Calculate pulse signal update according to Chrom algorithm."""
        result = super().process(roi)
        self._rgbs.append(result.roi_mean)

        if self.method == "fixed":
            result.value = self._calculate_fixed_update()

        elif self.method == "xovery":
            result.value = self._calculate_xovery_update()

        return result

    def _calculate_fixed_update(self) -> float:
        rgbmean = Color.from_array(np.mean(self._rgbs[-self.winsize :], axis=0))

        rn = self._rgbs[-1].r / (rgbmean.r or 1.0)
        gn = self._rgbs[-1].g / (rgbmean.g or 1.0)
        bn = self._rgbs[-1].b / (rgbmean.b or 1.0)

        self._xs.append(3 * rn - 2 * gn)
        self._ys.append(1.5 * rn + gn - 1.5 * bn)

        return self._xs[-1] / (self._ys[-1] or 1.0) - 1

    def _calculate_xovery_update(self) -> float:
        rgb = self._rgbs[-1]

        self._xs.append(rgb.r - rgb.g)
        self._ys.append(0.5 * rgb.r + 0.5 * rgb.g - rgb.b)

        xmean = np.mean(self._xs[-self.winsize :])
        ymean = np.mean(self._ys[-self.winsize :])

        return float(xmean / (ymean or 1) - 1)

    def reset(self):
        """Reset internal state and intermediate values."""
        self._rgbs.clear()
        self._xs.clear()
        self._ys.clear()

process(roi)

Calculate pulse signal update according to Chrom algorithm.

Source code in src\yarppg\processors\chrom.py
def process(self, roi: RegionOfInterest) -> RppgResult:
    """Calculate pulse signal update according to Chrom algorithm."""
    result = super().process(roi)
    self._rgbs.append(result.roi_mean)

    if self.method == "fixed":
        result.value = self._calculate_fixed_update()

    elif self.method == "xovery":
        result.value = self._calculate_xovery_update()

    return result

reset()

Reset internal state and intermediate values.

Source code in src\yarppg\processors\chrom.py
def reset(self):
    """Reset internal state and intermediate values."""
    self._rgbs.clear()
    self._xs.clear()
    self._ys.clear()