def _process_obs(self, obs):
        """
        **Overview**:
            Process obs, i.e., add optical flow information to original image.
        """
        # If current frame is the first frame, then the optical flow will be set to zeros.
        if self.last_frame is None:
            return np.stack([obs, np.zeros_like(obs), np.zeros_like(obs)])

        # Calculate optical flow using current frame and last frame.
        flow = cv2.calcOpticalFlowFarneback(self.last_frame, obs, None, 0.5, 3, 15, 3, 5, 1.2, 0)
        flow = (flow + 15) * (255.0 / (2 * 15))
        flow = np.round(flow).astype(np.uint8)
        # Clip the value into [0, 255).
        flow[flow >= 255] = 255
        flow[flow <= 0] = 0
        # Reshape optical flow array from [H, W, 2] to [2, H, W]
        flow = flow.transpose(2, 0, 1)
        # Concatenate optical flow with original frame.
        return np.concatenate([[obs], flow], axis=0)

        **Overview**:
            Process obs, i.e., add optical flow information to original image.
        
chapter3_obs/mario_wrapper.py