赞
踩
from PIL import Image # 读取待训练图片00001 Image.open(r'C:\Users\HP\Anaconda3\envs\pytorch\data\PennFudanPed\PNGImages\FudanPed00001.png') # 读取对应图片的掩码图片 mask = Image.open(r'C:\Users\HP\Anaconda3\envs\pytorch\data\PennFudanPed\PedMasks\FudanPed00001_mask.png') # 读取的mask默认为“L”模式,需要转换为“P”模式调用调色板函数 mask = mask.convert("P") # 针对“P”类图片调用调色板函数 # 看来掩码图片存的不是RGB数值,而是类别index mask.putpalette([ 0, 0, 0, # 0号像素为黑色 255, 0, 0, # 1号像素为红色 255, 255, 0, # 2号像素为黄色 255, 153, 0, # 3号像素为黄色 ]) mask
import os import torch import numpy as np import torch.utils.data from PIL import Image class PennFudanDataset(torch.utils.data.Dataset): def __init__(self, root, transforms=None): self.root = root # 数据集的根路径 self.transforms = transforms # 数据集的预处理变形参数 # 路径组合后返回该路径下的排序过的文件名(排序是为了对齐) self.imgs = list(sorted(os.listdir(os.path.join(root, "PNGImages")))) # self.imgs 是一个全部待训练图片文件名的有序列表 self.masks = list(sorted(os.listdir(os.path.join(root, "PedMasks")))) # self.masks 是一个全部掩码图片文件名的有序列表 # 根据idx对应读取待训练图片以及掩码图片 def __getitem__(self, idx): # 根据idx针对img与mask组合路径 img_path = os.path.join(self.root, "PNGImages", self.imgs[idx]) mask_path = os.path.join(self.root, "PedMasks", self.masks[idx]) # 根据路径读取三色图片并转为RGB格式 img = Image.open(img_path).convert("RGB") # 根据路径读取掩码图片默认“L”格式 mask = Image.open(mask_path) # 将mask转为numpy格式,h*w的矩阵,每个元素是一个颜色id mask = np.array(mask) # 获取mask中的id组成列表,obj_ids=[0,1,2] obj_ids = np.unique(mask) # 列表中第一个元素代表背景,不属于我们的目标检测范围,obj_ids=[1,2] obj_ids = obj_ids[1:] # obj_ids[:,None,None]:[[[1]],[[2]]],masks(2,536,559) # 为每一种类别序号都生成一个布尔矩阵,标注每个元素是否属于该颜色 masks = mask == obj_ids[:, None, None] # 为每个目标计算边界框,存入boxes num_objs = len(obj_ids) # 目标个数N boxes = [] # 边界框四个坐标的列表,维度(N,4) for i in range(num_objs): pos = np.where(masks[i]) # pos为mask[i]值为True的地方,也就是属于该颜色类别的id组成的列表 xmin = np.min(pos[1]) # pos[1]为x坐标,x坐标的最小值 xmax = np.max(pos[1]) ymin = np.min(pos[0]) # pos[0]为y坐标 ymax = np.max(pos[0]) boxes.append([xmin, ymin, xmax, ymax]) # 将boxes转化为tensor boxes = torch.as_tensor(boxes, dtype=torch.float32) # 初始化类别标签 labels = torch.ones((num_objs,), dtype=torch.int64) # labels[1,1] (2,)的array masks = torch.as_tensor(masks, dtype=torch.uint8) # 将masks转换为tensor # 将图片序号idx转换为tensor image_id = torch.tensor([idx]) # 计算每个边界框的面积 area = (boxes[:, 3] - boxes[:, 1]) * (boxes[:, 2] - boxes[:, 0]) # 假设所有实例都不是人群 iscrowd = torch.zeros((num_objs,), dtype=torch.int64) # iscrowd[0,0] (2,)的array # 生成一个字典 target = {} target["boxes"] = boxes target["labels"] = labels target["masks"] = masks target["image_id"] = image_id target["area"] = area target["iscrowd"] = iscrowd # 变形transform if self.transforms is not None: img, target = self.transforms(img, target) return img, target def __len__(self): return len(self.imgs)
dataset = PennFudanDataset(r'C:\Users\HP\Anaconda3\envs\pytorch\data\PennFudanPed/')
dataset[0]
import torchvision
from torchvision.models.detection.faster_rcnn import FastRCNNPredictor
# 下载在COCO数据集上预训练的resnet50
model = torchvision.models.detection.fasterrcnn_resnet50_fpn(pretrained=True)
# 设定最后的分类类别为2,一个为person,一个为background
num_classes = 2
# 获取预训练模型最后一层预测层的输入维度
in_features = model.roi_heads.box_predictor.cls_score.in_features
# 将预训练模型的最后一层替换为FastRCNN的预测层
model.roi_heads.box_predictor = FastRCNNPredictor(in_features, num_classes)
import torchvision from torchvision.models.detection import FasterRCNN from torchvision.models.detection.rpn import AnchorGenerator # 采取更轻量级的mobilenet特征部分替换Faster R-CNN的骨干部分 backbone = torchvision.models.mobilenet_v2(pretrained=True).features # 需要获取骨干部分的输出通道,同时也是预测部分的输入通道,需要指定参数 # 对于mobilenet_v2模型来说,骨干部分的输出通道就是1280 backbone.out_channels = 1280 # RPN网络的锚框anchor生成器 # 以下参数一般不变,都是5个size和3个ratios anchor_generator = AnchorGenerator(sizes=((32, 64, 128, 256, 512),), aspect_ratios=((0.5, 1.0, 2.0),)) # 定义ROIAlign部分 # 对齐的含义在于:由于锚框大小不一,为了获得统一大小的特征图,因此需要对齐 roi_pooler = torchvision.ops.MultiScaleRoIAlign(featmap_names=[0], output_size=7, sampling_ratio=2) # 调用现有的Faster R-CNN框架 # 传入我们定义的参数,骨干网络backbone,分类个数为2,锚框生成器、RoIAlign model = FasterRCNN(backbone, num_classes=2, rpn_anchor_generator=anchor_generator, box_roi_pool=roi_pooler)
import torchvision from torchvision.models.detection.faster_rcnn import FastRCNNPredictor from torchvision.models.detection.mask_rcnn import MaskRCNNPredictor def get_instance_segmentation_model(num_classes): # 准备预训练模型(Mask R-CNN模型) model = torchvision.models.detection.maskrcnn_resnet50_fpn(pretrained=True) # 获取预训练模型的打分模块的输入维度,也就是特征提取模块的输出维度 in_features = model.roi_heads.box_predictor.cls_score.in_features # 将预训练模型的预测部分修改为FastR-CNN的预测部分(Fast R-CNN与Faster R-CNN的预测部分相同) model.roi_heads.box_predictor = FastRCNNPredictor(in_features, num_classes) # 获取预训练模型中像素级别预测器的输入维度 in_features_mask = model.roi_heads.mask_predictor.conv5_mask.in_channels hidden_layer = 256 # 使用自己的参数生成Mask预测器替换预训练模型中的Mask预测器部分 # 三个参数,输入维度,中间层维度,输出维度(类别个数) model.roi_heads.mask_predictor = MaskRCNNPredictor(in_features_mask, hidden_layer, num_classes) return model
import utils
# import detection.engine
import transforms as T
from engine import train_one_epoch, evaluate
# 定义变形函数
# 首先将PIL图片转变为tensor格式
# 如果是训练集,那么加入随机水平翻转,否则不进行任何操作
def get_transform(train):
transforms = []
transforms.append(T.ToTensor())
if train:
transforms.append(T.RandomHorizontalFlip(0.5))
return T.Compose(transforms)
# 定义训练集和测试集类 # get_transform分别为训练集和测试集获得transform参数 dataset = PennFudanDataset(r'C:\Users\HP\Anaconda3\envs\pytorch\data\PennFudanPed/', get_transform(train=True)) dataset_test = PennFudanDataset(r'C:\Users\HP\Anaconda3\envs\pytorch\data\PennFudanPed/', get_transform(train=False)) # 使用相同的随机化种子,确保每次参数初始化的值相同 torch.manual_seed(1) # 返回一个包含数据集标号的随机列表,相当于随机化打乱标号 # torch.randperm(4).tolist() [2,1,0,3] indices = torch.randperm(len(dataset)).tolist() # 完成训练集和测试集的分割,dataset取dataset第一个到第倒数50个,dataset_test取倒数五十个? dataset = torch.utils.data.Subset(dataset, indices[:-50]) dataset_test = torch.utils.data.Subset(dataset_test, indices[-50:]) # 定义数据集的读取实例DataLoader # 注意windows需要把num_workers设定为0 data_loader = torch.utils.data.DataLoader( dataset, batch_size=2, shuffle=True, num_workers=0, collate_fn=utils.collate_fn) # collate_fn是取样本的方法参数 data_loader_test = torch.utils.data.DataLoader( dataset_test, batch_size=1, shuffle=False, num_workers=0, collate_fn=utils.collate_fn) # 定义训练设备device device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') # 目标分类个数只有两个,person与background num_classes = 2 # 获取之前定义的实例分割模型 model = get_instance_segmentation_model(num_classes) # 将模型放到设备device上 model.to(device) # 定义待训练的参数以及优化器 params = [p for p in model.parameters() if p.requires_grad] # 模型中的参数,凡是需要计算梯度的,统统列为待训练参数 optimizer = torch.optim.SGD(params, lr=0.005, momentum=0.9, weight_decay=0.0005) # 学习率的动态调整,每3个epochs将学习率缩小0.1倍 lr_scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=3, gamma=0.1)
# 训练
need_training = True
num_epochs = 10
if need_training == True:
for epoch in range(num_epochs):
# train for one epoch, printing every 10 iterations
train_one_epoch(model, optimizer, data_loader, device, epoch, print_freq=10)
# 手动更新学习率
lr_scheduler.step()
# 在测试集上评估模型
evaluate(model, data_loader_test, device=device)
PATH = r"C:\Users\HP\Anaconda3\model\mask2.pt"
if need_training == True:
# 存储模型
torch.save(model, PATH)
else:
# 加载模型
model = torch.load(PATH)
PATH = r"C:\Users\HP\Anaconda3\model\mask2.pt"
model2 = torch.load(PATH)
# 从测试集中挑选一张图片
img2, _ = dataset_test[30]
# 将模型设置为评估模式
model2.eval()
with torch.no_grad():
prediction = model2([img2.to(device)])
Image.fromarray(img2.mul(255).permute(1, 2, 0).byte().numpy())
Image.fromarray(prediction[0]['masks'][0, 0].mul(255).byte().cpu().numpy())
import cv2
a = cv2.imread(r'C:\Users\HP\Anaconda3\envs\pytorch\img\catdog.jpg', 1) # 参数1表示读取彩色图片
b = np.zeros(a.shape, dtype=np.uint8)
b[10:100, 20:200] = 255
# 注意imread默认读取的通道维是BGR,所以直接显示的图片会发蓝,需要加下面语句调整为RGB
a = cv2.cvtColor(a,cv2.COLOR_BGR2RGB)
c = cv2.bitwise_and(a, b)
cv2.imwrite('b.jpg', b)
cv2.imwrite('c.jpg', c)
Image.fromarray(a)
Image.fromarray(b)
Image.fromarray(c)
cur_img = img2.mul(255).permute(1, 2, 0).byte().numpy()
# 注意cv2的通道维写入顺序为BGR,所以我们需要将正常的RGB图片转成BGR图片
cur_img = cv2.cvtColor(cur_img,cv2.COLOR_RGB2BGR)
cur_mask = prediction[0]['masks'][0,].mul(255).byte()
cur_mask = torch.cat((cur_mask, cur_mask, cur_mask), axis = 0)
cur_mask = cur_mask.permute(1,2,0)
cur_mask = cur_mask.cpu().numpy()
cur_cut = cv2.bitwise_and(cur_img, cur_mask)
cv2.imwrite(r'C:\Users\HP\Anaconda3\envs\pytorch\img\cur_mask.jpg', cur_mask)
cv2.imwrite(r'C:\Users\HP\Anaconda3\envs\pytorch\img\cur_cut.jpg', cur_cut)
def transparent_back(img):
img = img.convert('RGBA')
L, H = img.size
color_0 = img.getpixel((0,0))
for h in range(H):
for l in range(L):
dot = (l,h)
color_1 = img.getpixel(dot)
if color_1 == color_0:
color_1 = color_1[:-1] + (0,)
img.putpixel(dot,color_1)
return img
img=Image.open(r'C:\Users\HP\Anaconda3\envs\pytorch\img\cur_cut.jpg')
img=transparent_back(img)
img.save(r'C:\Users\HP\Anaconda3\envs\pytorch\img\cur_cut_new.png')
PATH = "C:\\Users\\HP\\Anaconda3\\envs\\pytorch\\img\\pennfudan\\" img=Image.open(r'C:\Users\HP\Anaconda3\envs\pytorch\img\cur_cut.jpg') img=transparent_back(img) mydir = PATH + 'img'+ str(1) if not os.path.exists(mydir): # 如果不存在路径,则创建这个路径,关键函数就在这两行,其他可以改变 os.makedirs(mydir) filename= '\cur_cut_' + str(1) + '.png' img.save(mydir + filename) num_test = len(dataset_test) model.eval() for i in range(num_test): # 1.读取img img, _ = dataset_test[i] # 2.生成该图片的路径 cur_dir = PATH + 'img' + str(i) if not os.path.exists(cur_dir): os.makedirs(cur_dir) # 3.获得预测结果prediction和掩码个数num_masks with torch.no_grad(): prediction = model([img.to(device)]) num_masks = prediction[0]['masks'].shape[0] for j in range(num_masks): # 4.生成掩码array cur_mask cur_mask = prediction[0]['masks'][j,].mul(255).byte() cur_mask = torch.cat((cur_mask, cur_mask, cur_mask), axis = 0) cur_mask = cur_mask.permute(1,2,0) cur_mask = cur_mask.cpu().numpy() # 5.调整cur_img的色彩维顺序 # 注意cv2的通道维写入顺序为BGR,所以我们需要将正常的RGB图片转成BGR图片 cur_img = img.mul(255).permute(1, 2, 0).byte().numpy() cur_img = cv2.cvtColor(cur_img,cv2.COLOR_RGB2BGR) # 6.生成切片图片 cur_cut cur_cut = cv2.bitwise_and(cur_img, cur_mask) # 7.写入该路径 mask_name = '\mask_' + str(j) + '.jpg' cv2.imwrite(cur_dir + mask_name, cur_mask) cut_name = '\cut_' + str(j) + '.jpg' cv2.imwrite(cur_dir + cut_name, cur_cut) # img=transparent_back(img) # img.save(r'C:\Users\HP\Anaconda3\envs\pytorch\img\cur_cut_new.png')
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。