当前位置:   article > 正文

利用DCGAN-生成对抗网络和CNN-卷积神经网络对图像进行训练和分类_dcgan平面网络结构图

dcgan平面网络结构图

利用DCGAN-生成对抗网络和CNN-卷积神经网络对图像进行训练和分类

总体流程步骤

C:\Users\hujq\AppData\Roaming\Typora\typora-user-images\image-20200328113524608.png" alt="image-20200328113524608在这里插入图片描述

一、图像处理部分

如下图,分别是由SAR卫星获取的极化SAR图像及其标签图

图片名称 图片名称

根据不同的颜色标签(红、绿、黄、白)可以将原图分为四个部分(下图只有三部分,白色区域图片没有展示)

图片名称 图片名称 图片名称

对于图片中有效区域进行裁切分割,按照类型分别存储在不同的文件夹中作为训练数据。

二、训练GAN网络生成模拟图像

​ 每次运行该程序选择某一文件夹的所有图片进行训练得到效果图,直到将所有类型图片都训练完成一遍

# 生成对抗网络模型,训练模型生成仿真图片。
import argparse
import torch
import torchvision
import torchvision.utils as vutils
import torch.nn as nn
import numpy as np
from random import randint
import matplotlib.pyplot as plt

class NetG(nn.Module):
    def __init__(self, ngf, nz):
        super(NetG, self).__init__()
        # layer1输入的是一个100x1x1的随机噪声, 输出尺寸(ngf*8)x4x4
        # Sequential是一个时序容器modules会以他们传入时的顺序添加到容器中
        # ConvTranspose2d是二维卷积转置操作,将普通卷积的输出作为转置卷积的输入
        # BatchNorm2d是一个批标准化操作,对每一个小批量中计算各维度的均值和标准差
        # inplace=True代表的对源数据进行原地操作
        self.layer1 = nn.Sequential(
            # 参数分别有:输入通道数,输出通道数,卷积核大小,计算步长大小,补充0的层数,偏置
            nn.ConvTranspose2d(nz, ngf * 8, kernel_size=4, stride=1, padding=0, bias=False),
            nn.BatchNorm2d(ngf * 8),
            nn.ReLU(inplace=True)
        )
        # layer2输出尺寸(ngf*4)x8x8
        self.layer2 = nn.Sequential(
            nn.ConvTranspose2d(ngf * 8, ngf * 4, 4, 2, 1, bias=False),
            nn.BatchNorm2d(ngf * 4),
            nn.ReLU(inplace=True)
        )
        # layer3输出尺寸(ngf*2)x16x16
        self.layer3 = nn.Sequential(
            nn.ConvTranspose2d(ngf * 4, ngf * 2, 4, 2, 1, bias=False),
            nn.BatchNorm2d(ngf * 2),
            nn.ReLU(inplace=True)
        )
        # layer4输出尺寸(ngf)x32x32
        self.layer4 = nn.Sequential(
            nn.ConvTranspose2d(ngf * 2, ngf, 4, 2, 1, bias=False),
            nn.BatchNorm2d(ngf),
            nn.ReLU(inplace=True)
        )
        # layer5输出尺寸 3x96x96
        self.layer5 = nn.Sequential(
            nn.ConvTranspose2d(ngf, 3, 5, 3, 1, bias=False),
            nn.Tanh()
        )

    # 定义NetG的前向传播
    def forward(self, x):
        out = self.layer1(x)
        out = self.layer2(out)
        out = self.layer3(out)
        out = self.layer4(out)
        out = self.layer5(out)
        return out


# 定义鉴别器网络D
class NetD(nn.Module):
    def __init__(self, ndf):
        super(NetD, self).__init__()
        # layer1 输入 3 x 96 x 96, 输出 (ndf) x 32 x 32
        self.layer1 = nn.Sequential(
            nn.Conv2d(3, ndf, kernel_size=5, stride=3, padding=1, bias=False),
            nn.BatchNorm2d(ndf),
            nn.LeakyReLU(0.2, inplace=True)
        )
        # layer2 输出 (ndf*2) x 16 x 16
        self.layer2 = nn.Sequential(
            nn.Conv2d(ndf, ndf * 2, 4, 2, 1, bias=False),
            nn.BatchNorm2d(ndf * 2),
            nn.LeakyReLU(0.2, inplace=True)
        )
        # layer3 输出 (ndf*4) x 8 x 8
        self.layer3 = nn.Sequential(
            nn.Conv2d(ndf * 2, ndf * 4, 4, 2, 1, bias=False),
            nn.BatchNorm2d(ndf * 4),
            nn.LeakyReLU(0.2, inplace=True)
        )
        # layer4 输出 (ndf*8) x 4 x 4
        self.layer4 = nn.Sequential(
            nn.Conv2d(ndf * 4, ndf * 8, 4, 2, 1, bias=False),
            nn.BatchNorm2d(ndf * 8),
            nn.LeakyReLU(0.2, inplace=True)
        )
        # layer5 输出一个数(概率)
        self.layer5 = nn.Sequential(
            nn.Conv2d(ndf * 8, 1, 4, 1, 0, bias=False),
            nn.Sigmoid()
        )

    # 定义NetD的前向传播
    def forward(self,x):
        out = self.layer1(x)
        out = self.layer2(out)
        out = self.layer3(out)
        out = self.layer4(out)
        out = self.layer5(out)
        return out


parser = argparse.ArgumentParser()
parser.add_argument('--batchSize', type=int, default=64)  # 每次处理的图片数量
parser.add_argument('--imageSize', type=int, default=96)  # 图片像素大小
parser.add_argument('--nz', type=int, default=100, help='size of the latent z vector')  # 图片信息维度
parser.add_argument('--ngf', type=int, default=64)
parser.add_argument('--ndf', type=int, default=64)
parser.add_argument('--epoch', type=int, default=4000, help='number of epochs to train for')
parser.add_argument('--lr', type=float, default=0.0002, help='learning rate, default=0.0002')
parser.add_argument('--beta1', type=float, default=0.5, help='beta1 for adam. default=0.5')
parser.add_argument('--data_path', default='data/', help='folder to train data')
parser.add_argument('--outf', default='img/', help='folder to output images and model checkpoints')
opt = parser.parse_args()

# 图像读入与预处理 包括统一大小、转化为张量、归一化操作
transforms = torchvision.transforms.Compose([
    torchvision.transforms.Scale(opt.imageSize),
    torchvision.transforms.ToTensor(),
    torchvision.transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)), ])

# 将指定路径的数据集加载到程序中
dataset = torchvision.datasets.ImageFolder(opt.data_path, transform=transforms)
dataloader = torch.utils.data.DataLoader(
    dataset=dataset,
    batch_size=opt.batchSize,
    shuffle=True,
    drop_last=True,  # 丢弃最后一批数据
)

# 定义是否使用GPU
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
netG = NetG(opt.ngf, opt.nz).to(device)
netD = NetD(opt.ndf).to(device)

# 以以二分类的交叉熵作为损失函数,以Adam优化函数优化随机目标函数
criterion = nn.BCELoss()
optimizerG = torch.optim.Adam(netG.parameters(), lr=opt.lr, betas=(opt.beta1, 0.999))
optimizerD = torch.optim.Adam(netD.parameters(), lr=opt.lr, betas=(opt.beta1, 0.999))

# 将一个批次的数据传入label中
label = torch.FloatTensor(opt.batchSize)
real_label = 1
fake_label = 0

loss_D = []
loss_G = []

for epoch in range(1, opt.epoch + 1):
    for i, (imgs, _) in enumerate(dataloader):
        # 固定生成器G,训练鉴别器D,将梯度初始化为0
        optimizerD.zero_grad()
        # 让D尽可能的把真图片判别为1,计算D网络判别结果和实际结果的的交叉熵损失,
        imgs=imgs.to(device)
        output = netD(imgs)
        label.data.fill_(real_label)
        label=label.to(device)
        errD_real = criterion(output, label)
        errD_real.backward()
        # 让D尽可能把假图片判别为0
        label.data.fill_(fake_label)
        noise = torch.randn(opt.batchSize, opt.nz, 1, 1)
        noise=noise.to(device)
        fake = netG(noise)  # 生成假图
        output = netD(fake.detach())  # 避免梯度传到G,因为不需要计算G的梯度。不加则反向传播会进行计算,节约时间和内存
        errD_fake = criterion(output, label)
        errD_fake.backward()
        errD = errD_fake + errD_real
        optimizerD.step()

        # 固定鉴别器D,训练生成器G
        optimizerG.zero_grad()
        # 让D尽可能把G生成的假图判别为1
        label.data.fill_(real_label)
        label = label.to(device)
        output = netD(fake)
        errG = criterion(output, label)
        errG.backward()
        optimizerG.step()
        
        # 每两个epoch将值填入loss_D和l中H中,作为后期画图用数据
        if epoch % 2 == 0:
            loss_D.append(errD.item())
            loss_G.append(errG.item())

		# 将数据显示到控制台,直观看出当前两个网络的损失函数变化情况
        print('[%d/%d][%d/%d] Loss_D: %.3f Loss_G %.3f'
              % (epoch, opt.epoch, i, len(dataloader), errD.item(), errG.item()))
        
    # 每三十个epoch保存当前网络G生成图片效果
    if epoch % 30 == 0:
        vutils.save_image(fake.data,
                      '%s/fake_samples_epoch_%03d.png' % (opt.outf, epoch),
                      normalize=True)
        
	# 每500epoch保存当前网络G和网络D的神经模型作为后续使用
    if epoch % 500 == 0:
        torch.save(netG.state_dict(), '%s/netG_%03d.pth' % (opt.outf, epoch))
        torch.save(netD.state_dict(), '%s/netD_%03d.pth' % (opt.outf, epoch))

# 将损失函数变化显示出来
# index = np.arange(100)
# y1 = loss_D
# y2 = loss_G
# fig = plt.figure()
# ax1 = fig.add_subplot(111)
# ax1.plot(index, y1)
# ax1.set_xlabel('epoch')
# ax1.set_label('loss')
# ax1.set_ylabel('loss')
# ax1.set_xlim(0, 120)
# ax1.set_title('loss and correct')
# ax2 = ax1.twinx()
# ax2.set_label('correct')
# ax2.plot(index, y2, 'r')
# ax2.set_ylabel('correct')
# plt.show()

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218

生成图片效果如下图所示:

图片名称

得到生成图片后需要进行裁切处理,裁切方法如下

# -*- coding: utf-8 -*-
# 将生成网络模型的生成图片进行处理和切割。

from PIL import Image
import sys

# 将图片填充为正方形
def fill_image(image):
    width, height = image.size
    # 选取长和宽中较大值作为新图片的
    new_image_length = width if width > height else height
    # 生成新图片[白底]
    new_image = Image.new(image.mode, (new_image_length, new_image_length), color='blue')
    # 将之前的图粘贴在新图上,居中
    if width > height:  # 原图宽大于高,则填充图片的竖直维度
        # (x,y)二元组表示粘贴上图相对下图的起始位置
        new_image.paste(image, (0, int((new_image_length - height) / 2)))
    else:
        new_image.paste(image, (int((new_image_length - width) / 2), 0))

    return new_image


def cut_image(image):
    width, height = image.size
    item_width = int(width / 6)
    box_list = []
    # (left, upper, right, lower)
    for i in range(0, 6):  # 两重循环,生成若干张图片基于原图的位置
        for j in range(0, 6):
            # print((i*item_width,j*item_width,(i+1)*item_width,(j+1)*item_width))
            box = (j*item_width, i*item_width, (j+1)*item_width, (i+1)*item_width)
            box_list.append(box)

    image_list = [image.crop(box) for box in box_list]
    return image_list

#保存
def save_images(image_list):
    index = 1
    for image in image_list:
        image.save(r'H:\new_cutSAR\realSAR\pau\label/'+str(index) + '.png', 'PNG')
        index += 1

if __name__ == '__main__':
    file_path = r"H:\new_cutSAR\realSAR\pau/xx2.jpg"
    image = Image.open(file_path)
    #image.show()
    image = fill_image(image)
    image_list = cut_image(image)
    save_images(image_list)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52

GAN训练过程损失函数变化

图片名称

三、以GAN生成图片作为CNN训练数据进行CNN训练和分类

在得到GAN生成的图片后,以文件夹名作为label分别存储,作为CNN的训练数据进行训练

# encoding=utf-8
# 以卷积神经网络来对图像进行模型训练和分类工作
import torch
import torchvision
import torchvision.transforms as transforms
import torchvision.utils as vutils
import torch.nn as nn
import torch.nn.functional as F
from torch.autograd import Variable
import torch.optim as optim
import matplotlib.pyplot as plt
import numpy as np
import os.path
from PIL import Image


class Net(nn.Module):  # 定义网络,继承torch.nn.Module
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(3, 6, 5)  # 卷积层
        self.pool = nn.MaxPool2d(2, 2)  # 池化层
        self.conv2 = nn.Conv2d(6, 16, 5)  # 卷积层
        self.fc1 = nn.Linear(16 * 5 * 5, 120)  # 全连接层
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, 10)  # 10个输出

    def forward(self, x):  # 前向传播

        x = self.pool(F.relu(self.conv1(x)))  # F就是torch.nn.functional
        x = self.pool(F.relu(self.conv2(x)))
        x = x.view(-1, 16 * 5 * 5)  # .view( )是一个tensor的方法,使得tensor改变size但是元素的总数是不变的。
        # 从卷基层到全连接层的维度转换

        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x

# 分类类型标识
classes = ('green', 'red', 'white', 'yellow')

# 加载训练CNN网络的数据样本
def loadtraindata():
    path = r"E:\pythontest\new_cutSAR\train/"  # 路径
    trainset = torchvision.datasets.ImageFolder(path,
                                                transform=transforms.Compose([
                                                    transforms.Resize((32, 32)),  # 将图片缩放到指定大小(h,w)或者保持长宽比并缩放最短的边到int大小
                                                    transforms.CenterCrop(32),
                                                    transforms.ToTensor()])
                                                )

    trainloader = torch.utils.data.DataLoader(trainset, batch_size=4,
                                              shuffle=True, num_workers=5)
    return trainloader

# 加载分类测试用数据
def loadtestdata():
    path = r"E:\pythontest\new_cutSAR\test/"
    testset = torchvision.datasets.ImageFolder(path,
                                               transform=transforms.Compose([
                                                   transforms.Resize((32, 32)),  # 将图片缩放到指定大小(h,w)或者保持长宽比并缩放最短的边到int大小
                                                   transforms.ToTensor()])
                                               )
    testloader = torch.utils.data.DataLoader(testset, batch_size=262, shuffle=False, num_workers=5)
    return testloader

# 训练CNN网络
def trainandsave():
    trainloader = loadtraindata()
    # 神经网络结构
    net = Net()
    optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)  # 学习率为0.001
    criterion = nn.CrossEntropyLoss()  # 损失函数也可以自己定义,我们这里用的交叉熵损失函数
    cor = []  # 定义正确率和损失函数随epoch增加的变化
    los = []
    max = 0
    # 训练部分
    for epoch in range(200):  # 训练的数据量为200个epoch,每个epoch为一个循环
        # 每个epoch要训练所有的图片,每训练完成50张便打印一下训练的效果(loss值)
        running_loss = 0.0  # 定义一个变量方便我们对loss和correct进行输出
        correct = 0.0
        for i, data in enumerate(trainloader, 0):
            # 这里我们遇到了第一步中出现的trailoader,代码传入数据
            # enumerate是python的内置函数,既获得索引也获得数据
            # get the inputs
            inputs, labels = data  # data是从enumerate返回的data,包含数据和标签信息,分别赋值给inputs和labels

            # wrap them in Variable
            inputs, labels = Variable(inputs), Variable(labels)  # 转换数据格式用Variable

            optimizer.zero_grad()  # 梯度置零,因为反向传播过程中梯度会累加上一次循环的梯度

            # forward + backward + optimize
            outputs = net(inputs)  # 把数据输进CNN网络net

            # 正确率
            _, predicted = torch.max(outputs.data, 1)
            correct += (predicted == labels.data).sum().item()

            loss = criterion(outputs, labels)  # 计算损失值
            loss.backward()  # loss反向传播 该图会动态生成并自动微分,会自动计算图中参数的导数;
            optimizer.step()  # 反向传播后参数更新
            running_loss += loss.item()  # loss累加

			# 限制训练次数不能超过最大值
            if i>max:
                max = i

            if i % 50 == 49:
                print('[%d, %5d] loss: %.3f  acc: %.1f%%' %
                      (epoch + 1, i + 1, running_loss / 50, (50*correct)/100))  # 然后再除以200,就得到这两百次的平均损失值
                los.append(running_loss/50)
                cor.append((50*correct)/100)
                running_loss = 0.0  # 这一个50次结束后,就把running_loss归零,下一个200次继续使用
                correct = 0.0
        print(max)
        
    # 展示训练效果变化图片
    index = np.arange(1000)
    y1 = los
    y2 = cor
    fig = plt.figure()
    ax1 = fig.add_subplot(111)
    ax1.plot(index, y1)
    ax1.set_xlabel('epoch')
    ax1.set_label('loss')
    ax1.set_ylabel('loss')
    ax1.set_xlim(0, 200)
    ax1.set_title('loss and correct')
    ax2 = ax1.twinx()
    ax2.set_label('correct')
    ax2.plot(index, y2, 'r')
    ax2.set_ylabel('correct')

    plt.show()
    print('Finished Training')
    # 保存神经网络
    torch.save(net, 'net.pkl')  # 保存整个神经网络的结构和模型参数
    torch.save(net.state_dict(), 'net_params.pkl')  # 只保存神经网络的模型参
    # trainandsave()

# 加载上次训练结果模型,方便在上次基础上继续训练
def reload_net():
    trainednet = torch.load('net.pkl')
    return trainednet


def imshow(img):
    img = img / 2 + 0.5  # unnormalize
    npimg = img.numpy()
    plt.imshow(np.transpose(npimg, (1, 2, 0)))
    plt.show()


def alter(path, object):
    # 更改图片像素大小
    s = os.listdir(path)
    count = 1
    for i in s:
        document = os.path.join(path, i)
        img = Image.open(document)
        out = img.resize((96, 96))
        listStr = [str(count)]
        fileName = ''.join(listStr)
        out.save(object+os.sep+'%s.jpg' % fileName)
        count = count + 1

def test():
    testloader = loadtestdata()
    net = reload_net()  # 使用模型
    dataiter = iter(testloader)
    images, labels = dataiter.next()  #
    print('\nGroundTruth:'
          , " ".join('%5s' % classes[labels[j]] for j in range(262)))  # 打印前25个GT(test集里图片的标签)
    outputs = net(Variable(images))

    _, predicted = torch.max(outputs.data, 1)
    print('Predicted:  ', " ".join('%5s' % classes[predicted[j]] for j in range(262)))


    # 定义图片格式
    file_path = r'E:\pythontest\new_cutSAR\train\red96/red1.jpg'
    image1 = Image.open(file_path)
    # 将数据集的内容分类后分别放在各自的文件夹中
    for j in range(262):
        if classes[predicted[j]] == 'green':
            vutils.save_image(images[j], r'E:\pythontest\new_cutSAR\result\green/%s%05d.jpg' % (classes[labels[j]], j))
            # 对于不同的类别分别生成不同的图像标签
            new_image = Image.new(image1.mode, (32, 32), color='green')
            new_image.save( r'E:\pythontest\new_cutSAR\label\all/%s%05d.jpg' % (classes[labels[j]], j))

        elif classes[predicted[j]] == 'red':
            vutils.save_image(images[j], r'E:\pythontest\new_cutSAR\result\red/%s%05d.jpg' % (classes[labels[j]], j))
            new_image = Image.new(image1.mode, (32, 32), color='red')
            new_image.save(r'E:\pythontest\new_cutSAR\label\all/%s%05d.jpg' % (classes[labels[j]], j))

        elif classes[predicted[j]] == 'white':
            vutils.save_image(images[j], r'E:\pythontest\new_cutSAR\result\white/%s%05d.jpg' % (classes[labels[j]], j))
            new_image = Image.new(image1.mode, (32, 32), color='white')
            new_image.save(r'E:\pythontest\new_cutSAR\label\all/%s%05d.jpg' % (classes[labels[j]], j))

        elif classes[predicted[j]] == 'yellow':
            vutils.save_image(images[j], r'E:\pythontest\new_cutSAR\result\yellow/%s%05d.jpg' % (classes[labels[j]], j))
            new_image = Image.new(image1.mode, (32, 32), color='yellow')
            new_image.save(r'E:\pythontest\new_cutSAR\label\all/%s%54d.jpg' % (classes[labels[j]], j))


    cc = 0  # 识别正确图片数量
    for j in range(262):
        if classes[labels[j]] == classes[predicted[j]]:
            cc += 1
    print(cc)

    index = np.arange(263)  # 4097
    real = []
    predi = []
    real.append('xx')
    predi.append('xx')
    for j in range(262):
        real.append(classes[labels[j]])
        predi.append(classes[predicted[j]])
    width = 0.3
    plt.bar(left=index, height=real, width=width, color='yellow', label=u'real')
    plt.bar(left=index + width, height=predi, width=width, color='green', label=u'predict')
    plt.xlabel('epoch')
    plt.ylabel('real/predict')
    plt.legend(loc='best')
    plt.show()
            # 打印前25个预测值
            # imshow(torchvision.utils.make_grid(images, nrow=5))  # nrow是每行显示的图片数量,缺省值为8

            # test()
    correct, total = 0, 0
    with torch.no_grad():
        for images, labels in testloader:
            outputs = net(images)
            _, predicted = torch.max(outputs, 1)
            total += labels.size(0)
            correct += (labels == predicted).sum().item()
            print('total: %d' % total)
            print('Accuracy of the network on the 10000 test images: %d %%' % (
                            100 * correct / total))

# 训练CNN网络是,注释test()方法,执行trainandsave()
# 使用CNN网络进行分类,则注释trainandsave()方法,执行test()方法
if __name__ == "__main__":
        test()
        # trainandsave()

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249

CNN训练正确率和损失随训练次数变化情况

图片名称

随机选取三十张图片,显示CNN网络判别结果和实际类型的对比图

图片名称

四、将目标原图进行裁切,作为CNN网络最后的判定对象

将一张200×200大小的图像以20×20的窗口切割,从左到右,从上到下,每次移动一个像素点,总共得到40000张小图


import cv2

img = cv2.imread(r"E:\pythontest\new_cutSAR\realSAR\pau\yuan/3.png")
print(img.shape)

i = 0

j = 0
for i in range(0, 200, 1):
    for j in range(0, 200, 1):
        num = i * 200 + j
        # num = (i/20) * 10 + j/20
        cropped = img[i:i+20, j:j+20]  # 裁剪坐标为[y0:y1, x0:x1]
        cv2.imwrite(r"E:\pythontest\new_cutSAR\cutPixel\main/%05d.jpg" % num, cropped)  # y%d_x%d

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

将这40000张图片按序输入到CNN网络模型中进行判别,依据判别结果生成红、黄、绿、白四种颜色的像素块,存储到另一文件夹中

五、将像素文件夹中的像素块按序进行重新整合

# 将40000张由小像素点图像重组为一张200×200的大图

import PIL.Image as Image
import os


IMAGES_PATH = r'E:\pythontest\new_cutSAR\max3_3\yuan/'  # 图片集地址
# IMAGES_PATH = r'E:\pythontest\new_cutSAR\cutPixelResult/'  # 图片集地址

IMAGES_FORMAT = ['.png', '.JPG']  # 图片格式
IMAGE_SIZE = 400  # 每张小图片的大小
IMAGE_ROW = 3  # 图片间隔,也就是合并成一张图后,一共有几行
IMAGE_COLUMN = 3  # 图片间隔,也就是合并成一张图后,一共有几列
IMAGE_SAVE_PATH = 'maxyuan.png'  # 图片转换后的地址

# 获取图片集地址下的所有图片名称
image_names = [name for name in os.listdir(IMAGES_PATH) for item in IMAGES_FORMAT if
               os.path.splitext(name)[1] == item]

# 简单的对于参数的设定和实际图片集的大小进行数量判断
if len(image_names) != IMAGE_ROW * IMAGE_COLUMN:
    raise ValueError("合成图片的参数和要求的数量不能匹配!")


# 定义图像拼接函数
def image_compose():
    to_image = Image.new('RGB', (IMAGE_COLUMN * IMAGE_SIZE, IMAGE_ROW * IMAGE_SIZE))  # 创建一个新图
    # 循环遍历,把每张图片按顺序粘贴到对应位置上
    for y in range(1, IMAGE_ROW + 1):
        for x in range(1, IMAGE_COLUMN + 1):
            from_image = Image.open(IMAGES_PATH + image_names[IMAGE_COLUMN * (y - 1) + x - 1]).resize(
                (IMAGE_SIZE, IMAGE_SIZE), Image.ANTIALIAS)
            to_image.paste(from_image, ((x - 1) * IMAGE_SIZE, (y - 1) * IMAGE_SIZE))
    return to_image.save(IMAGE_SAVE_PATH)  # 保存新图


image_compose()  # 调用函数
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

​ 重组结果

图片名称

六、分类效果计算

# -*- coding: utf-8 -*-
#feimengjuan
# 比较两张图像的相似度

import cv2
import numpy as np
from matplotlib import pyplot as plt


# 平均哈希算法计算
def classify_aHash(image1,image2):
 image1 = cv2.resize(image1,(200,200))
 image2 = cv2.resize(image2,(200,200))
 gray1 = cv2.cvtColor(image1,cv2.COLOR_BGR2GRAY)
 gray2 = cv2.cvtColor(image2,cv2.COLOR_BGR2GRAY)
 hash1 = getHash(gray1)
 hash2 = getHash(gray2)
 return Hamming_distance(hash1,hash2)

def classify_pHash(image1,image2):
 image1 = cv2.resize(image1,(256,256))
 image2 = cv2.resize(image2,(256,256))
 gray1 = cv2.cvtColor(image1,cv2.COLOR_BGR2GRAY)
 gray2 = cv2.cvtColor(image2,cv2.COLOR_BGR2GRAY)
 # 将灰度图转为浮点型,再进行dct变换
 dct1 = cv2.dct(np.float32(gray1))
 dct2 = cv2.dct(np.float32(gray2))
 # 取左上角的8*8,这些代表图片的最低频率
 # 这个操作等价于c++中利用opencv实现的掩码操作
 # 在python中进行掩码操作,可以直接这样取出图像矩阵的某一部分
 dct1_roi = dct1[0:256,0:256]
 dct2_roi = dct2[0:256,0:256]
 hash1 = getHash(dct1_roi)
 hash2 = getHash(dct2_roi)
 return Hamming_distance(hash1,hash2)

# 输入灰度图,返回hash
def getHash(image):
 avreage = np.mean(image)
 hash = []
 for i in range(image.shape[0]):
  for j in range(image.shape[1]):
   if image[i,j] > avreage:
    hash.append(1)
   else:
    hash.append(0)
 return hash


# 计算汉明距离
def Hamming_distance(hash1,hash2):
 num = 0
 for index in range(len(hash1)):
  if hash1[index] != hash2[index]:
   num += 1
 return num


if __name__ == '__main__':
    img1 = cv2.imread("max_label.png")
    #cv2.imshow('img1',img1)
    img2 = cv2.imread("maxps1.png")
    #cv2.imshow('img2',img2)
    #degree1 = classify_gray_hist(img1,img2)
    #degree2 = classify_hist_with_split(img1,img2)
    degree3 = classify_aHash(img1,img2)
    correct3 = (40000-degree3)/40000.0 *100
    #degree4 = classify_pHash(img1,img2)
    #correct4 = (40000-degree4)/40000.0 *100
    #print("灰度直方图:%d" %degree1)
    #print("每个通道直方图%d" %degree2)
    print("平均哈希值:%.3f %%" %correct3)
    #print("感知哈希值:%.3f %%" %correct4)
    cv2.waitKey(0)

# 平均哈希法(aHash)
# 此算法是基于比较灰度图每个像素与平均值来实现的
# 一般步骤:
# 1.缩放图片,一般大小为8*8,64个像素值。
# 2.转化为灰度图
# 3.计算平均值:计算进行灰度处理后图片的所有像素点的平均值,直接用numpy中的mean()计算即可。
# 4.比较像素灰度值:遍历灰度图片每一个像素,如果大于平均值记录为1,否则为0.
# 5.得到信息指纹:组合64个bit位,顺序随意保持一致性。
# 最后比对两张图片的指纹,获得汉明距离即可。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
图片名称

参考博客:https://blog.csdn.net/jizhidexiaoming/article/details/97108754

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
  

闽ICP备14008679号