center_crop in image_utils.py is broken for inputs that are not PIL Images
Author: hollance
Pull request: no
Labels: name: bug

name: Feature extractors

### System Info

```shell
- `transformers` version: 4.20.0.dev0
- Platform: macOS-10.16-x86_64-i386-64bit
- Python version: 3.9.12
- Huggingface_hub version: 0.5.1
- PyTorch version (GPU?): 1.11.0 (False)
- Tensorflow version (GPU?): 2.8.0 (False)
- Flax version (CPU?/GPU?/TPU?): 0.4.1 (cpu)
- Jax version: 0.3.7
- JaxLib version: 0.3.7
- Using GPU in script?: <fill in>
- Using distributed or parallel set-up in script?: <fill in>
```


### Who can help?

@Niels

### Information

- [ ] The official example scripts
- [ ] My own modified scripts

### Tasks

- [ ] An officially supported task in the `examples` folder (such as GLUE/SQuAD, ...)
- [ ] My own task or dataset (give details below)

### Reproduction

The feature extractor for MobileViT (see the PR at https://github.com/huggingface/transformers/pull/17354) implements its own version of the `center_crop` method, instead of using the one from image_utils. The CLIP model also does this. The reason for this custom cropping method is that the "official" one is broken for certain inputs.

In normal usage, the feature extractor first resizes the image and then performs a center crop. Resizing always turns the input into a PIL Image, and then `center_crop` correctly works on the PIL Image.

However, the feature extractor can be configured to not perform the resize with the option `do_resize=False`. Now the input is passed directly into `center_crop`. When the input is a PIL Image this works fine, but when it is a numpy array or torch tensor, `center_crop` may calculate the wrong thing.

To reproduce:

```python
# load an image
from datasets import load_dataset
dataset = load_dataset("huggingface/cats-image")
image = dataset["test"]["image"][0]

# get the base class from image_utils
from transformers.image_utils import ImageFeatureExtractionMixin
mixin = ImageFeatureExtractionMixin()
```

The following outputs a PIL Image, which is correct and as expected:

```python
cropped = mixin.center_crop(image, size=256)
```

But when the input is a NumPy array, the output is a `(480, 256, 255)` tensor:

```python
import numpy as np
image_np = np.array(image)
inputs = mixin.center_crop(image_np, size=256)
inputs.shape
```

This happens because `center_crop` assumes that the tensor is already in the shape (channels, H, W) but it isn't.

When you transpose the image before cropping, the output is correct again:

```python
import numpy as np
image_np = np.array(image).transpose(2, 0, 1)
inputs = mixin.center_crop(image_np, size=256)
inputs.shape
```

However, the `resize` method does accept arrays and tensors in the shape (H, W, channels), and so it would be reasonable to assume that `center_crop` also should do this.


### Expected behavior

```shell
Any input that works correctly for `resize` should also work correctly for `center_crop`.
```


Comments:
You tagged the wrong Niels ;) also cc'ing @sgugger 

LOL, sorry Niels and other Niels.

That's because we don't convert images back to PIL in `center_crop` (which always happens in `resize`), but happy to look at a PR adding support for this.

I can add it to my to-do list, as it would be better to have this logic only in image_utils. 

This issue has been automatically marked as stale because it has not had recent activity. If you think this still needs to be addressed please comment on this thread.

Please note that issues that do not follow the [contributing guidelines](https://github.com/huggingface/transformers/blob/main/CONTRIBUTING.md) are likely to be ignored.