img.save参数详解
时间: 2023-08-31 21:34:11 浏览: 59
`img.save()` 是 PIL 库中用于保存图像的方法,它可以将 PIL 图像对象保存为指定格式的文件。其常用的参数包括:
- file: 保存的文件名或文件对象。可以是字符串类型的文件名,也可以是一个类文件对象。
- format: 保存的文件格式。可以是常见的图片格式,如 JPEG、PNG、BMP、GIF 等。如果不指定,则根据文件名的后缀自动判断格式。
- mode: 保存的图像模式。可以是 RGB、RGBA、L、1 等模式。如果不指定,则根据图像对象的模式自动选择。
- quality: 保存的图像质量。只有对 JPEG 格式有效,取值范围为 0~100,值越大质量越好。
- optimize: 是否启用优化。只有对 JPEG 格式有效,如果设为 True,则会对图像进行优化处理以减小文件大小。
- progressive: 是否启用渐进式显示。只有对 JPEG 格式有效,如果设为 True,则会生成渐进式 JPEG 文件,可以在下载过程中逐步显示图像。
- subsampling: 亚采样率。只有对 JPEG 格式有效,可以指定 YCbCr 子采样模式,取值为 0、1、2 或 3。默认为 0,代表不进行亚采样。
示例代码如下:
```python
from PIL import Image
# 打开图像文件
img = Image.open("example.jpg")
# 保存图像文件
img.save("example.png", format="PNG", quality=90)
```
相关问题
yolov7 test.py详解
YoloV7是目标检测算法YOLO的最新版本,相较于之前的版本,它在模型结构、训练策略和速度等方面都有了较大的改进。test.py文件是用于测试已经训练好的模型的脚本,下面是对test.py文件的详细解释:
1. 导入必要的库和模块
```python
import argparse
import os
import platform
import shutil
import time
from pathlib import Path
import cv2
import torch
import torch.backends.cudnn as cudnn
import numpy as np
from models.experimental import attempt_load
from utils.datasets import LoadStreams, LoadImages
from utils.general import check_img_size, check_requirements, check_imshow, \
non_max_suppression, apply_classifier, scale_coords, xyxy2xywh, strip_optimizer, set_logging
from utils.plots import plot_one_box
from utils.torch_utils import select_device, load_classifier, time_synchronized
```
这里导入了一些必要的库和模块,比如PyTorch、OpenCV、NumPy等,以及用于测试的模型、数据集和一些工具函数。
2. 定义输入参数
```python
parser = argparse.ArgumentParser()
parser.add_argument('--weights', nargs='+', type=str, default='yolov5s.pt', help='model.pt path(s)')
parser.add_argument('--source', type=str, default='data/images', help='source')
parser.add_argument('--img-size', type=int, default=640, help='inference size (pixels)')
parser.add_argument('--conf-thres', type=float, default=0.25, help='object confidence threshold')
parser.add_argument('--iou-thres', type=float, default=0.45, help='IOU threshold for NMS')
parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu')
parser.add_argument('--view-img', action='store_true', help='display results')
parser.add_argument('--save-txt', action='store_true', help='save results to *.txt')
parser.add_argument('--save-conf', action='store_true', help='save confidences in --save-txt labels')
parser.add_argument('--save-crop', action='store_true', help='save cropped prediction boxes')
parser.add_argument('--nosave', action='store_true', help='do not save images/videos')
parser.add_argument('--classes', nargs='+', type=int, help='filter by class: --class 0, or --class 0 2 3')
parser.add_argument('--agnostic-nms', action='store_true', help='class-agnostic NMS')
parser.add_argument('--augment', action='store_true', help='augmented inference')
parser.add_argument('--update', action='store_true', help='update all models')
parser.add_argument('--project', default='runs/detect', help='save results to project/name')
parser.add_argument('--name', default='exp', help='save results to project/name')
parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment')
opt = parser.parse_args()
```
这里使用Python的argparse库来定义输入参数,包括模型权重文件、输入数据源、推理尺寸、置信度阈值、NMS阈值等。
3. 加载模型
```python
# 加载模型
model = attempt_load(opt.weights, map_location=device) # load FP32 model
imgsz = check_img_size(opt.img_size, s=model.stride.max()) # check img_size
if device.type != 'cpu':
model(torch.zeros(1, 3, imgsz, imgsz).to(device).type_as(next(model.parameters()))) # run once
```
这里使用`attempt_load()`函数来加载模型,该函数会根据传入的权重文件路径自动选择使用哪个版本的YoloV7模型。同时,这里还会检查输入图片的大小是否符合模型的要求。
4. 设置计算设备
```python
# 设置计算设备
device = select_device(opt.device)
half = device.type != 'cpu' # half precision only supported on CUDA
# Initialize model
model.to(device).eval()
```
这里使用`select_device()`函数来选择计算设备(GPU或CPU),并将模型移动到选择的设备上。
5. 加载数据集
```python
# 加载数据集
if os.path.isdir(opt.source):
dataset = LoadImages(opt.source, img_size=imgsz)
else:
dataset = LoadStreams(opt.source, img_size=imgsz)
```
根据输入参数中的数据源,使用`LoadImages()`或`LoadStreams()`函数来加载数据集。这两个函数分别支持从图片文件夹或摄像头/视频中读取数据。
6. 定义类别和颜色
```python
# 定义类别和颜色
names = model.module.names if hasattr(model, 'module') else model.names
colors = [[np.random.randint(0, 255) for _ in range(3)] for _ in names]
```
这里从模型中获取类别名称,同时为每个类别随机生成一个颜色,用于在图片中绘制框和标签。
7. 定义输出文件夹
```python
# 定义输出文件夹
save_dir = Path(increment_path(Path(opt.project) / opt.name, exist_ok=opt.exist_ok)) # increment run
(save_dir / 'labels' if opt.save_txt else save_dir).mkdir(parents=True, exist_ok=True) # make dir
```
这里使用`increment_path()`函数来生成输出文件夹的名称,同时创建相应的文件夹。
8. 开始推理
```python
# 开始推理
for path, img, im0s, vid_cap in dataset:
t1 = time_synchronized()
# 图像预处理
img = torch.from_numpy(img).to(device)
img = img.half() if half else img.float()
img /= 255.0
if img.ndimension() == 3:
img = img.unsqueeze(0)
# 推理
pred = model(img)[0]
# 后处理
pred = non_max_suppression(pred, opt.conf_thres, opt.iou_thres, classes=opt.classes, agnostic=opt.agnostic_nms)
t2 = time_synchronized()
# 处理结果
for i, det in enumerate(pred): # detections per image
if webcam: # batch_size >= 1
p, s, im0 = path[i], f'{i}: ', im0s[i].copy()
else:
p, s, im0 = path, '', im0s
save_path = str(save_dir / p.name)
txt_path = str(save_dir / 'labels' / p.stem) + ('' if dataset.mode == 'image' else f'_{counter}') + '.txt'
if det is not None and len(det):
det[:, :4] = scale_coords(img.shape[2:], det[:, :4], im0.shape).round()
for *xyxy, conf, cls in reversed(det):
c = int(cls)
label = f'{names[c]} {conf:.2f}'
plot_one_box(xyxy, im0, label=label, color=colors[c], line_thickness=3)
if opt.save_conf:
with open(txt_path, 'a') as f:
f.write(f'{names[c]} {conf:.2f}\n')
if opt.save_crop:
w = int(xyxy[2] - xyxy[0])
h = int(xyxy[3] - xyxy[1])
x1 = int(xyxy[0])
y1 = int(xyxy[1])
x2 = int(xyxy[2])
y2 = int(xyxy[3])
crop_img = im0[y1:y2, x1:x2]
crop_path = save_path + f'_{i}_{c}.jpg'
cv2.imwrite(crop_path, crop_img)
# 保存结果
if opt.nosave:
pass
elif dataset.mode == 'images':
cv2.imwrite(save_path, im0)
else:
if vid_path != save_path: # new video
vid_path = save_path
if isinstance(vid_writer, cv2.VideoWriter):
vid_writer.release() # release previous video writer
fourcc = 'mp4v' # output video codec
fps = vid_cap.get(cv2.CAP_PROP_FPS)
w = int(vid_cap.get(cv2.CAP_PROP_FRAME_WIDTH))
h = int(vid_cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
vid_writer = cv2.VideoWriter(save_path, cv2.VideoWriter_fourcc(*fourcc), fps, (w, h))
vid_writer.write(im0)
# 打印结果
print(f'{s}Done. ({t2 - t1:.3f}s)')
# 释放资源
if cv2.waitKey(1) == ord('q'): # q to quit
raise StopIteration
elif cv2.waitKey(1) == ord('p'): # p to pause
cv2.waitKey(-1)
```
这里使用一个循环来遍历数据集中的所有图像或视频帧,对每张图像或视频帧进行以下操作:
- 图像预处理:将图像转换为PyTorch张量,并进行归一化和类型转换。
- 推理:将图像张量传入模型进行推理,得到预测结果。
- 后处理:对预测结果进行非极大值抑制、类别筛选等后处理操作,得到最终的检测结果。
- 处理结果:对每个检测框进行标签和颜色的绘制,同时可以选择保存检测结果的图片或视频以及标签信息的TXT文件。
- 释放资源:根据按键输入决定是否退出或暂停程序。
9. 总结
以上就是YoloV7的测试脚本test.py的详细解释,通过这个脚本可以方便地测试已经训练好的模型,并对检测结果进行可视化和保存等操作。
yolov7train.py详解
yolov7train.py 是使用 YOLOv7 算法进行目标检测的训练脚本。下面对 yolov7train.py 的主要代码进行简单的解释:
1. 导入相关库
```python
import argparse
import yaml
import time
import torch
from torch.utils.data import DataLoader
from torchvision import datasets
from models.yolov7 import Model
from utils.datasets import ImageFolder
from utils.general import (
check_img_size, non_max_suppression, apply_classifier, scale_coords,
xyxy2xywh, plot_one_box, strip_optimizer, set_logging)
from utils.torch_utils import (
select_device, time_synchronized, load_classifier, model_info)
```
这里导入了 argparse 用于解析命令行参数,yaml 用于解析配置文件,time 用于记录时间,torch 用于神经网络训练,DataLoader 用于读取数据集,datasets 和 ImageFolder 用于加载数据集,Model 用于定义 YOLOv7 模型,各种工具函数用于辅助训练。
2. 定义命令行参数
```python
parser = argparse.ArgumentParser()
parser.add_argument('--data', type=str, default='data.yaml', help='dataset.yaml path')
parser.add_argument('--hyp', type=str, default='hyp.yaml', help='hyperparameters path')
parser.add_argument('--epochs', type=int, default=300)
parser.add_argument('--batch-size', type=int, default=16, help='total batch size for all GPUs')
parser.add_argument('--img-size', nargs='+', type=int, default=[640, 640], help='[train, test] image sizes')
parser.add_argument('--rect', action='store_true', help='rectangular training')
parser.add_argument('--resume', nargs='?', const='yolov7.pt', default=False, help='resume most recent training')
parser.add_argument('--nosave', action='store_true', help='only save final checkpoint')
parser.add_argument('--notest', action='store_true', help='only test final epoch')
parser.add_argument('--evolve', action='store_true', help='evolve hyperparameters')
parser.add_argument('--bucket', type=str, default='', help='gsutil bucket')
opt = parser.parse_args()
```
这里定义了许多命令行参数,包括数据集路径、超参数路径、训练轮数、批量大小、图片大小、是否使用矩形训练、是否从最近的检查点恢复训练、是否只保存最终的检查点、是否只测试最终的模型、是否进行超参数进化、gsutil 存储桶等。
3. 加载数据集
```python
with open(opt.data) as f:
data_dict = yaml.load(f, Loader=yaml.FullLoader)
train_path = data_dict['train']
test_path = data_dict['test']
num_classes = data_dict['nc']
names = data_dict['names']
train_dataset = ImageFolder(train_path, img_size=opt.img_size[0], rect=opt.rect)
test_dataset = ImageFolder(test_path, img_size=opt.img_size[1], rect=True)
batch_size = opt.batch_size
train_dataloader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True, num_workers=8, pin_memory=True, collate_fn=train_dataset.collate_fn)
test_dataloader = DataLoader(test_dataset, batch_size=batch_size * 2, num_workers=8, pin_memory=True, collate_fn=test_dataset.collate_fn)
```
这里读取了数据集的配置文件,包括训练集、测试集、类别数和类别名称等信息。然后使用 ImageFolder 加载数据集,设置图片大小和是否使用矩形训练。最后使用 DataLoader 加载数据集,并设置批量大小、是否 shuffle、是否使用 pin_memory 等参数。
4. 定义 YOLOv7 模型
```python
model = Model(opt.hyp, num_classes, opt.img_size)
model.nc = num_classes
device = select_device(opt.device, batch_size=batch_size)
model.to(device).train()
criterion = model.loss
optimizer = torch.optim.SGD(model.parameters(), lr=hyp['lr0'], momentum=hyp['momentum'], weight_decay=hyp['weight_decay'])
scheduler = torch.optim.lr_scheduler.CosineAnnealingWarmRestarts(optimizer, T_0=1, T_mult=2)
start_epoch = 0
best_fitness = 0.0
```
这里使用 Model 类定义了 YOLOv7 模型,并将其放到指定设备上进行训练。使用交叉熵损失函数作为模型的损失函数,使用 SGD 优化器进行训练,并使用余弦退火学习率调整策略。定义了起始轮数、最佳精度等变量。
5. 开始训练
```python
for epoch in range(start_epoch, opt.epochs):
model.train()
mloss = torch.zeros(4).to(device) # mean losses
for i, (imgs, targets, paths, _) in enumerate(train_dataloader):
ni = i + len(train_dataloader) * epoch # number integrated batches (since train start)
imgs = imgs.to(device)
targets = targets.to(device)
loss, _, _ = model(imgs, targets)
loss.backward()
optimizer.step()
optimizer.zero_grad()
mloss = (mloss * i + loss.detach().cpu()) / (i + 1) # update mean losses
# Print batch results
if ni % 20 == 0:
print(f'Epoch {epoch}/{opt.epochs - 1}, Batch {i}/{len(train_dataloader) - 1}, lr={optimizer.param_groups[0]["lr"]:.6f}, loss={mloss[0]:.4f}')
# Update scheduler
scheduler.step()
# Update Best fitness
with torch.no_grad():
fitness = model_fitness(model)
if fitness > best_fitness:
best_fitness = fitness
# Save checkpoint
if (not opt.nosave) or (epoch == opt.epochs - 1):
ckpt = {
'epoch': epoch,
'best_fitness': best_fitness,
'state_dict': model.state_dict(),
'optimizer': optimizer.state_dict()
}
torch.save(ckpt, f'checkpoints/yolov7_epoch{epoch}.pt')
# Test
if not opt.notest:
t = time_synchronized()
model.eval()
for j, (imgs, targets, paths, shapes) in enumerate(test_dataloader):
if j == 0:
pred = model(imgs.to(device))
pred = non_max_suppression(pred, conf_thres=0.001, iou_thres=0.6)
else:
break
t1 = time_synchronized()
if isinstance(pred, int) or isinstance(pred, tuple):
print(f'Epoch {epoch}/{opt.epochs - 1}, test_loss={mloss[0]:.4f}, test_mAP={0.0}')
else:
pred = pred[0].cpu()
iou_thres = 0.5
niou = [iou_thres] * num_classes
ap, p, r = ap_per_class(pred, targets, shapes, iou_thres=niou)
mp, mr, map50, f1, _, _ = stats(ap, p, r, gt=targets)
print(f'Epoch {epoch}/{opt.epochs - 1}, test_loss={mloss[0]:.4f}, test_mAP={map50:.2f} ({mr*100:.1f}/{mp*100:.1f})')
# Plot images
if epoch == 0 and j == 0:
for i, det in enumerate(pred): # detections per image
img = cv2.imread(paths[i]) # BGR
img = plot_results(img, det, class_names=names)
cv2.imwrite(f'runs/test{i}.jpg', img)
if i == 3:
break
```
这里进行了多个 epoch 的训练。在每个 epoch 中,对于每个批量的数据,先将数据移动到指定设备上,然后计算模型的损失函数,并进行反向传播和梯度下降。在每个 epoch 结束时,更新学习率调整策略和最佳精度,保存当前的检查点。如果 opt.notest 为 False,则进行测试,并输出测试结果。最后,如果是第一个 epoch,则绘制部分图像用于可视化。
相关推荐
![doc](https://img-home.csdnimg.cn/images/20210720083327.png)
![pdf](https://img-home.csdnimg.cn/images/20210720083512.png)
![docx](https://img-home.csdnimg.cn/images/20210720083331.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![pdf](https://img-home.csdnimg.cn/images/20210720083512.png)
![pdf](https://img-home.csdnimg.cn/images/20210720083512.png)
![pdf](https://img-home.csdnimg.cn/images/20210720083512.png)
![pdf](https://img-home.csdnimg.cn/images/20210720083512.png)