Repository: ultralytics/ultralytics
Issue category: Bug Report

Issue:
Save_crop method from Results with default params results in double file extension
### Search before asking

- [X] I have searched the Ultralytics YOLO [issues](https://github.com/ultralytics/ultralytics/issues) and found no similar bug report.


### Ultralytics YOLO Component

Predict

### Bug

Save_crop method in the Results object already adds file extension to the saved image (.jpg) and default value is set as 'im.jpg' so when using default behaviour we get a file named **"im.jpg.jpg"**
With this few examples
`results[0].save_crop(save_dir='../out')`
`results[0].save_crop(save_dir='../out', file_name='img.png')`
`results[0].save_crop(save_dir='../out', file_name='img')`
Here are the outputs in a File Explorer, only one without double extension is when you add file_name without any extension
![image](https://github.com/user-attachments/assets/873bb127-ca4e-439d-8f74-8aece55fd3fa)


### Environment

Setup complete ✅ (8 CPUs, 15.9 GB RAM, 477.1/931.5 GB disk) 

OS                  Windows-10-10.0.17763-SP0
Environment         Windows
Python              3.10.15
Install             pip
RAM                 15.94 GB
Disk                477.1/931.5 GB
CPU                 Intel Core(TM) i7-9700 3.00GHz
CPU count           8
GPU                 NVIDIA GeForce GTX 1660, 6144MiB
GPU count           1
CUDA                11.8

numpy               ✅ 1.26.3>=1.23.0                                                                                                                                                                                               
matplotlib          ✅ 3.9.2>=3.3.0 
opencv-python       ✅ 4.10.0.84>=4.6.0                                                                                                                                                                                             
pillow              ✅ 10.2.0>=7.1.2                                                                                                                                                                                                
pyyaml              ✅ 6.0.2>=5.3.1                                                                                                                                                                                                 
requests            ✅ 2.32.3>=2.23.0                                                                                                                                                                                               
scipy               ✅ 1.14.1>=1.4.1 
torch               ✅ 2.5.1+cu118>=1.8.0                                                                                                                                                                                           
torchvision         ✅ 0.20.1+cu118>=0.9.0                                                                                                                                                                                          
tqdm                ✅ 4.67.0>=4.64.0                                                                                                                                                                                               
psutil              ✅ 6.1.0                                                                                                                                                                                                        
py-cpuinfo          ✅ 9.0.0                                                                                                                                                                                                        
pandas              ✅ 2.2.3>=1.1.4                                                                                                                                                                                                 
seaborn             ✅ 0.13.2>=0.11.0                                                                                                                                                                                               
ultralytics-thop    ✅ 2.0.11>=2.0.0                                                                                                                                                                                                
numpy               ✅ 1.26.3<2.0.0; sys_platform == "darwin"                                                                                                                                                                       
torch               ✅ 2.5.1+cu118!=2.4.0,>=1.8.0; sys_platform == "win32"   

### Minimal Reproducible Example

```
model = YOLO('../model/yolov8s.pt')
results = model.predict(frame, conf=0.5)
results[0].save_crop(save_dir='../out')
```

### Additional

_No response_

### Are you willing to submit a PR?

- [X] Yes I'd like to help by submitting a PR!


Hints:
👋 Hello @M3nxudo, thank you for bringing this to our attention! We're excited to assist you 🚀 and appreciate your proactive approach to contribute with a PR.

For anyone facing similar issues, we highly recommend checking out our [Docs](https://docs.ultralytics.com) for guidance on both [Python](https://docs.ultralytics.com/usage/python/) and [CLI](https://docs.ultralytics.com/usage/cli/) usage.

Since this seems to be a 🐛 Bug Report, please ensure that the provided [minimal reproducible example](https://docs.ultralytics.com/help/minimum_reproducible_example/) accurately reflects the issue you're facing. This will help us diagnose the problem more efficiently.

For real-time help or to engage with our vibrant community, you can join us on [Discord](https://ultralytics.com/discord) 🎧. For more in-depth discussions, consider visiting our [Discourse](https://community.ultralytics.com) or share insights with members on our [Subreddit](https://reddit.com/r/ultralytics).

## Upgrade

Make sure you're using the latest version of the `ultralytics` package, along with all its [requirements](https://github.com/ultralytics/ultralytics/blob/main/pyproject.toml). Verify this in a [**Python>=3.8**](https://www.python.org/) environment with [**PyTorch>=1.8**](https://pytorch.org/get-started/locally/):

```bash
pip install -U ultralytics
```

## Environments

You can run YOLO in various verified environments that include all necessary dependencies, such as [CUDA](https://developer.nvidia.com/cuda), [Python](https://www.python.org/), and [PyTorch](https://pytorch.org/):

- **Notebooks** with free GPU: <a href="https://console.paperspace.com/github/ultralytics/ultralytics"><img src="https://assets.paperspace.io/img/gradient-badge.svg" alt="Run on Gradient"/></a> <a href="https://colab.research.google.com/github/ultralytics/ultralytics/blob/main/examples/tutorial.ipynb"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"></a> <a href="https://www.kaggle.com/models/ultralytics/yolo11"><img src="https://kaggle.com/static/images/open-in-kaggle.svg" alt="Open In Kaggle"></a>
- **Google Cloud** Deep Learning VM: Check the [GCP Quickstart Guide](https://docs.ultralytics.com/yolov5/environments/google_cloud_quickstart_tutorial/)
- **Amazon** Deep Learning AMI: See the [AWS Quickstart Guide](https://docs.ultralytics.com/yolov5/environments/aws_quickstart_tutorial/)
- **Docker Image**: Refer to the [Docker Quickstart Guide](https://docs.ultralytics.com/yolov5/environments/docker_image_quickstart_tutorial/) <a href="https://hub.docker.com/r/ultralytics/ultralytics"><img src="https://img.shields.io/docker/pulls/ultralytics/ultralytics?logo=docker" alt="Docker Pulls"></a>

## Status

<a href="https://github.com/ultralytics/ultralytics/actions/workflows/ci.yaml?query=event%3Aschedule"><img src="https://github.com/ultralytics/ultralytics/actions/workflows/ci.yaml/badge.svg" alt="Ultralytics CI"></a>

Our [Ultralytics CI](https://github.com/ultralytics/ultralytics/actions/workflows/ci.yaml?query=event%3Aschedule) tests run every 24 hours and on all commits to ensure smooth operation across different environments and verify correct functionality for all YOLO [Modes](https://docs.ultralytics.com/modes/) and [Tasks](https://docs.ultralytics.com/tasks/).

This is an automated response and an Ultralytics engineer will review your issue shortly. Thank you for your understanding and collaboration! 🌟
Easiest solution would be to change the default value of the file_name param from  line 721 of results.py:
https://github.com/ultralytics/ultralytics/blob/main/ultralytics/engine/results.py
`def save_crop(self, save_dir, file_name=Path("im.jpg")):` 
to
 **file_name=Path("im")**
since on line 753 we already add the file extension:
`file=Path(save_dir) / self.names[int(d.cls)] / f"{Path(file_name)}.jpg",`

Patch:
diff --git a/ultralytics/engine/results.py b/ultralytics/engine/results.py
index 029e4471e04..8de0a2e6a1c 100644
--- a/ultralytics/engine/results.py
+++ b/ultralytics/engine/results.py
@@ -750,7 +750,7 @@ def save_crop(self, save_dir, file_name=Path("im.jpg")):
             save_one_box(
                 d.xyxy,
                 self.orig_img.copy(),
-                file=Path(save_dir) / self.names[int(d.cls)] / f"{Path(file_name)}.jpg",
+                file=Path(save_dir) / self.names[int(d.cls)] / Path(file_name).with_suffix(".jpg"),
                 BGR=True,
             )
 


Test patch: