Convert torch Tensors into image numpy arrays. After clamping to [min, max], values will be normalized to [0, 1]. Args: tensor (Tensor or list[Tensor]): Accept shapes: 1) 4D mini-batch Tensor of shape (B x 3/1 x H x W); 2) 3D Tensor of shape (3/1 x H x W);
(tensor, rgb2bgr=True, out_type=np.uint8, min_max=(0, 1))
| 110 | |
| 111 | |
| 112 | def tensor2img(tensor, rgb2bgr=True, out_type=np.uint8, min_max=(0, 1)): |
| 113 | """Convert torch Tensors into image numpy arrays. |
| 114 | |
| 115 | After clamping to [min, max], values will be normalized to [0, 1]. |
| 116 | |
| 117 | Args: |
| 118 | tensor (Tensor or list[Tensor]): Accept shapes: |
| 119 | 1) 4D mini-batch Tensor of shape (B x 3/1 x H x W); |
| 120 | 2) 3D Tensor of shape (3/1 x H x W); |
| 121 | 3) 2D Tensor of shape (H x W). |
| 122 | Tensor channel should be in RGB order. |
| 123 | rgb2bgr (bool): Whether to change rgb to bgr. |
| 124 | out_type (numpy type): output types. If ``np.uint8``, transform outputs |
| 125 | to uint8 type with range [0, 255]; otherwise, float type with |
| 126 | range [0, 1]. Default: ``np.uint8``. |
| 127 | min_max (tuple[int]): min and max values for clamp. |
| 128 | |
| 129 | Returns: |
| 130 | (Tensor or list): 3D ndarray of shape (H x W x C) OR 2D ndarray of |
| 131 | shape (H x W). The channel order is BGR. |
| 132 | """ |
| 133 | if not (torch.is_tensor(tensor) or (isinstance(tensor, list) and all(torch.is_tensor(t) for t in tensor))): |
| 134 | raise TypeError(f'tensor or list of tensors expected, got {type(tensor)}') |
| 135 | |
| 136 | if torch.is_tensor(tensor): |
| 137 | tensor = [tensor] |
| 138 | result = [] |
| 139 | for _tensor in tensor: |
| 140 | _tensor = _tensor.squeeze(0).float().detach().cpu().clamp_(*min_max) |
| 141 | _tensor = (_tensor - min_max[0]) / (min_max[1] - min_max[0]) |
| 142 | |
| 143 | n_dim = _tensor.dim() |
| 144 | if n_dim == 4: |
| 145 | img_np = make_grid(_tensor, nrow=int(math.sqrt(_tensor.size(0))), normalize=False).numpy() |
| 146 | img_np = img_np.transpose(1, 2, 0) |
| 147 | if rgb2bgr: |
| 148 | img_np = cv2.cvtColor(img_np, cv2.COLOR_RGB2BGR) |
| 149 | elif n_dim == 3: |
| 150 | img_np = _tensor.numpy() |
| 151 | img_np = img_np.transpose(1, 2, 0) |
| 152 | if img_np.shape[2] == 1: # gray image |
| 153 | img_np = np.squeeze(img_np, axis=2) |
| 154 | else: |
| 155 | if rgb2bgr: |
| 156 | img_np = cv2.cvtColor(img_np, cv2.COLOR_RGB2BGR) |
| 157 | elif n_dim == 2: |
| 158 | img_np = _tensor.numpy() |
| 159 | else: |
| 160 | raise TypeError(f'Only support 4D, 3D or 2D tensor. But received with dimension: {n_dim}') |
| 161 | if out_type == np.uint8: |
| 162 | # Unlike MATLAB, numpy.unit8() WILL NOT round by default. |
| 163 | img_np = (img_np * 255.0).round() |
| 164 | img_np = img_np.astype(out_type) |
| 165 | result.append(img_np) |
| 166 | if len(result) == 1: |
| 167 | result = result[0] |
| 168 | return result |
| 169 |
no outgoing calls
no test coverage detected