本人学习过程中随笔记录用。代码下载源暂时忘记了,日后找到补上。
第一部分构建不涉及分叉出去评分的部分
def FCN8_helper(nClasses, input_height, input_width): #分割类别 输入尺寸
assert input_height % 32 == 0 #检查输入的长宽,不符合退出
assert input_width % 32 == 0
img_input = Input(shape=(input_height, input_width, 3))
#把输入的形状规范,考虑到不是所有格式都是长宽通道的格式
model = vgg16.VGG16(
include_top=False,
weights='imagenet', input_tensor=img_input,
pooling=None,
classes=1000)
#include_top=False不保留顶层的3个全连接网络
#weights='imagenet'代表加载预训练权重
#input_tensor=img_input设置输入
#pooling=None 不进行池化操作
assert isinstance(model, Model)#判断model和keras库中Model是否同类别
o = Conv2D(
filters=4096,
kernel_size=(
7,
7),
padding="same",
activation="relu",
name="fc6")(
model.output)
#2维卷积层,输出维度4096,卷积核尺寸(7,7)激活函数用relu
#padding:same表示不够卷积核大小的块就补0,所以输出和输入形状相同
o = Dropout(rate=0.5)(o)#Dropout按比例随机置零,缓解过拟合。
o = Conv2D(
filters=4096,
kernel_size=(
1,
1),
padding="same",
activation="relu",
name="fc7")(o)
o = Dropout(rate=0.5)(o)
o = Conv2D(filters=nClasses, kernel_size=(1, 1), padding="same", activation="relu", kernel_initializer="he_normal",
name="score_fr")(o)
#kernel_initializer="he_normal"以He正态分布初始化,参数由0均值,标准差为sqrt(2 / fan_in) 的正态分布产生
o = Conv2DTranspose(filters=nClasses, kernel_size=(2, 2), strides=(2, 2), padding="valid", activation=None,
name="score2")(o)
fcn8 = Model(inputs=img_input, outputs=o)#构建模型
fcn8.summary()
return fcn8#返回模型
第二部分从评分VGG16的池化部分分出评分
def FCN8(nClasses, input_height, input_width):
fcn8 = FCN8_helper(nClasses, input_height, input_width)#上面的函数的输出
# Conv to be applied on Pool4
skip_con1 = Conv2D(nClasses, kernel_size=(1, 1), padding="same", activation=None, kernel_initializer="he_normal",
name="score_pool4")(fcn8.get_layer("block4_pool").output)
# 承接fcn8的输出
Summed = add(inputs=[skip_con1, fcn8.output])#求和
x = Conv2DTranspose(nClasses, kernel_size=(2, 2), strides=(2, 2), padding="valid", activation=None,
name="score4")(Summed)
#反卷积进行上采样
#padding=“valid”:表示不够卷积核大小的块,则丢弃;
###
skip_con2 = Conv2D(nClasses, kernel_size=(1, 1), padding="same", activation=None, kernel_initializer="he_normal",
name="score_pool3")(fcn8.get_layer("block3_pool").output)
Summed2 = add(inputs=[skip_con2, x])
#####
Up = Conv2DTranspose(nClasses, kernel_size=(8, 8), strides=(8, 8),
padding="valid", activation=None, name="upsample")(Summed2)
Up = Reshape((-1, nClasses))(Up)
Up = Activation("softmax")(Up)#softmax进行概率打分
mymodel = Model(inputs=fcn8.input, outputs=Up)
return mymodel
第三部分用于打印网络
if __name__ == '__main__':
m = FCN8(15, 320, 320)#输入的尺寸
from keras.utils.vis_utils import plot_model
plot_model(m, show_shapes=True, to_file=r'C:\Users\dai\Desktop\model_fcn8.png')
#把结果输出成png格式
print(len(m.layers))
#打印层数
对输入图片进行处理
def getImageArr(im):
img = im.astype(np.float32)
#把图片的种类转变为float32
img[:, :, 0] -= 103.939
img[:, :, 1] -= 116.779
img[:, :, 2] -= 123.68
#ImageNet平均 BGR [103.939, 116.779, 123.68]。去均值,有利于三通道的训练效果
return img
获得对分割图片进行编码,需输入分割图,类数,尺寸。
def getSegmentationArr(seg, nClasses, input_height, input_width):
seg_labels = np.zeros((input_height, input_width, nClasses))
#全置零
for c in range(nClasses):
seg_labels[:, :, c] = (seg == c).astype(int)
#合适的位置置1
seg_labels = np.reshape(seg_labels, (-1, nClasses))
#把形状变为(input_height*input_width,nClasses)
return seg_labels
加载图像文件
def imageSegmentationGenerator(images_path, segs_path, batch_size,
n_classes, input_height, input_width):
assert images_path[-1] == '/'
assert segs_path[-1] == '/'
#检测路径名最后是不是以'/'
images = sorted(glob.glob(images_path + "*.jpg") +
glob.glob(images_path + "*.png") + glob.glob(images_path + "*.jpeg"))
#加载指定目录里面所有的图片并排序
segmentations = sorted(glob.glob(segs_path + "*.jpg") +
glob.glob(segs_path + "*.png") + glob.glob(segs_path + "*.jpeg"))
zipped = itertools.cycle(zip(images, segmentations))
#zip把图片和分割结果的一一对应放在一起,zipped包含了所有的对
#print(list(itertools.islice(zipped, 0, 10, 1)))打印结果
while True:
X = []
Y = []
for _ in range(batch_size):
im, seg = zipped.__next__()
im = cv2.imread(im, 1)#读取彩色图片
seg = cv2.imread(seg, 0)#读取灰度图片
assert im.shape[:2] == seg.shape[:2]
#检测是否同长宽
assert im.shape[0] >= input_height and im.shape[1] >= input_width
#输入图片尺寸必须大于等于预设尺寸
xx = random.randint(0, im.shape[0] - input_height)
yy = random.randint(0, im.shape[1] - input_width)
im = im[xx:xx + input_height, yy:yy + input_width]
seg = seg[xx:xx + input_height, yy:yy + input_width]
#把原图分割成更小的块
X.append(getImageArr(im))
Y.append(
getSegmentationArr(
seg,
n_classes,
input_height,
input_width))
yield np.array(X), np.array(Y) #生成X和Y
执行函数读取
if __name__ == '__main__':
G = imageSegmentationGenerator("data/dataset1/images_prepped_train/",
"data/dataset1/annotations_prepped_train/", batch_size=16, n_classes=15, input_height=160, input_width=160)
x, y = G.__next__()
#由于imageSegmentationGenerator是生成器需要用__next__读取
#类似进行了一个循环把逐一访问所有元素,只能单向前进
print(x.shape, y.shape)
def imageSegmentationGenerator(images_path, segs_path, n_classes):
assert images_path[-1] == '/'
assert segs_path[-1] == '/'
#检查输入是否为路径
images = sorted(glob.glob(images_path +"*.jpg") +
glob.glob(images_path +"*.png") +
glob.glob(images_path +"*.jpeg"))
segmentations = sorted(glob.glob(segs_path + "*.jpg") +
glob.glob(segs_path + "*.png") +
glob.glob(segs_path + "*.jpeg"))
#按路径根据格式按顺序加载图片
colors = [(random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)) for _ in range(n_classes)]#给每一个类按照255随机选择一种颜色
assert len(images) == len(segmentations)#保证尺寸一致,是对应的图片
for im_fn, seg_fn in zip(images, segmentations):
img = cv2.imread(im_fn)
seg = cv2.imread(seg_fn) #读图
print(np.unique(seg)) #输出seg里用到的颜色通道
seg_img = np.zeros_like(seg)#构件全零阵,与seg同形状
for c in range(n_classes):
seg_img[:, :, 0] += ((seg[:, :, 0] == c) *
(colors[c][0])).astype('uint8')
seg_img[:, :, 1] += ((seg[:, :, 0] == c) *
(colors[c][1])).astype('uint8')
seg_img[:, :, 2] += ((seg[:, :, 0] == c) *
(colors[c][2])).astype('uint8')
#按照新颜色安排
eqaimg = color.rgb2hsv(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
eqaimg[:, :, 2] = exposure.equalize_hist(eqaimg[:, :, 2])
eqaimg = color.hsv2rgb(eqaimg)
cv2.imshow("img", img)
cv2.imshow("seg_img", seg_img)
cv2.imshow(
"equalize_hist_img",
cv2.cvtColor((eqaimg *255.).astype(np.uint8),cv2.COLOR_RGB2BGR))
cv2.waitKey()