[2021]一些常见的机器视觉用到的神经网络结构(keras) huoji AI,机器学习,神经网络,人工智能,机器视觉,车牌识别 2021-02-24 1063 次浏览 5 次点赞 收藏一些常见的机器视觉用到的神经网络结构,以后不用自己构造网络了! 这些都咋用呢? 我已经写好祖传代码了: ```python def build_save_model(train_data, test_data): # 构建模型 CBAPD network_model = VGG16() network_model.compile(optimizer='adam', loss=tensorflow.keras.losses.SparseCategoricalCrossentropy( from_logits=False), metrics=['accuracy']) #cp_callback = tensorflow.keras.callbacks.ModelCheckpoint(filepath=checkpoint_save_path,save_weights_only=True,save_best_only=True) # 如果要保存点自己在fit加这个参数 # callbacks=[cp_callback] #checkpoint_save_path = "./checkpoint.ckpt" # if os.path.exists(checkpoint_save_path + '.index'): # print('-------------load the model-----------------') # network_model.load_weights(checkpoint_save_path) network_model.fit(train_data, epochs=100, validation_data=test_data, batch_size=64) network_model.summary() network_model.evaluate(test_data) tensorflow.saved_model.save( network_model, '\\model\\') ``` VGG网络: ```python class VGG16(tensorflow.keras.Model): def __init__(self): super(VGG16, self).__init__() self.c1 = tensorflow.keras.layers.Conv2D(filters=64, kernel_size=( 3, 3), padding='same') # 卷积层1 self.b1 = tensorflow.keras.layers.BatchNormalization() # BN层1 self.a1 = tensorflow.keras.layers.Activation('relu') # 激活层1 self.c2 = tensorflow.keras.layers.Conv2D( filters=64, kernel_size=(3, 3), padding='same', ) self.b2 = tensorflow.keras.layers.BatchNormalization() # BN层1 self.a2 = tensorflow.keras.layers.Activation('relu') # 激活层1 self.p1 = tensorflow.keras.layers.MaxPool2D( pool_size=(2, 2), strides=2, padding='same') self.d1 = tensorflow.keras.layers.Dropout(0.2) # dropout层 self.c3 = tensorflow.keras.layers.Conv2D( filters=128, kernel_size=(3, 3), padding='same') self.b3 = tensorflow.keras.layers.BatchNormalization() # BN层1 self.a3 = tensorflow.keras.layers.Activation('relu') # 激活层1 self.c4 = tensorflow.keras.layers.Conv2D( filters=128, kernel_size=(3, 3), padding='same') self.b4 = tensorflow.keras.layers.BatchNormalization() # BN层1 self.a4 = tensorflow.keras.layers.Activation('relu') # 激活层1 self.p2 = tensorflow.keras.layers.MaxPool2D( pool_size=(2, 2), strides=2, padding='same') self.d2 = tensorflow.keras.layers.Dropout(0.2) # dropout层 self.c5 = tensorflow.keras.layers.Conv2D( filters=256, kernel_size=(3, 3), padding='same') self.b5 = tensorflow.keras.layers.BatchNormalization() # BN层1 self.a5 = tensorflow.keras.layers.Activation('relu') # 激活层1 self.c6 = tensorflow.keras.layers.Conv2D( filters=256, kernel_size=(3, 3), padding='same') self.b6 = tensorflow.keras.layers.BatchNormalization() # BN层1 self.a6 = tensorflow.keras.layers.Activation('relu') # 激活层1 self.c7 = tensorflow.keras.layers.Conv2D( filters=256, kernel_size=(3, 3), padding='same') self.b7 = tensorflow.keras.layers.BatchNormalization() self.a7 = tensorflow.keras.layers.Activation('relu') self.p3 = tensorflow.keras.layers.MaxPool2D( pool_size=(2, 2), strides=2, padding='same') self.d3 = tensorflow.keras.layers.Dropout(0.2) self.c8 = tensorflow.keras.layers.Conv2D( filters=512, kernel_size=(3, 3), padding='same') self.b8 = tensorflow.keras.layers.BatchNormalization() # BN层1 self.a8 = tensorflow.keras.layers.Activation('relu') # 激活层1 self.c9 = tensorflow.keras.layers.Conv2D( filters=512, kernel_size=(3, 3), padding='same') self.b9 = tensorflow.keras.layers.BatchNormalization() # BN层1 self.a9 = tensorflow.keras.layers.Activation('relu') # 激活层1 self.c10 = tensorflow.keras.layers.Conv2D( filters=512, kernel_size=(3, 3), padding='same') self.b10 = tensorflow.keras.layers.BatchNormalization() self.a10 = tensorflow.keras.layers.Activation('relu') self.p4 = tensorflow.keras.layers.MaxPool2D( pool_size=(2, 2), strides=2, padding='same') self.d4 = tensorflow.keras.layers.Dropout(0.2) self.c11 = tensorflow.keras.layers.Conv2D( filters=512, kernel_size=(3, 3), padding='same') self.b11 = tensorflow.keras.layers.BatchNormalization() # BN层1 self.a11 = tensorflow.keras.layers.Activation('relu') # 激活层1 self.c12 = tensorflow.keras.layers.Conv2D( filters=512, kernel_size=(3, 3), padding='same') self.b12 = tensorflow.keras.layers.BatchNormalization() # BN层1 self.a12 = tensorflow.keras.layers.Activation('relu') # 激活层1 self.c13 = tensorflow.keras.layers.Conv2D( filters=512, kernel_size=(3, 3), padding='same') self.b13 = tensorflow.keras.layers.BatchNormalization() self.a13 = tensorflow.keras.layers.Activation('relu') self.p5 = tensorflow.keras.layers.MaxPool2D( pool_size=(2, 2), strides=2, padding='same') self.d5 = tensorflow.keras.layers.Dropout(0.2) self.flatten = tensorflow.keras.layers.Flatten() self.f1 = tensorflow.keras.layers.Dense(512, activation='relu') self.d6 = tensorflow.keras.layers.Dropout(0.2) self.f2 = tensorflow.keras.layers.Dense(512, activation='relu') self.d7 = tensorflow.keras.layers.Dropout(0.2) self.f3 = tensorflow.keras.layers.Dense( 65, activation='softmax') # <-输出65个分类 def call(self, x): x = self.c1(x) x = self.b1(x) x = self.a1(x) x = self.c2(x) x = self.b2(x) x = self.a2(x) x = self.p1(x) x = self.d1(x) x = self.c3(x) x = self.b3(x) x = self.a3(x) x = self.c4(x) x = self.b4(x) x = self.a4(x) x = self.p2(x) x = self.d2(x) x = self.c5(x) x = self.b5(x) x = self.a5(x) x = self.c6(x) x = self.b6(x) x = self.a6(x) x = self.c7(x) x = self.b7(x) x = self.a7(x) x = self.p3(x) x = self.d3(x) x = self.c8(x) x = self.b8(x) x = self.a8(x) x = self.c9(x) x = self.b9(x) x = self.a9(x) x = self.c10(x) x = self.b10(x) x = self.a10(x) x = self.p4(x) x = self.d4(x) x = self.c11(x) x = self.b11(x) x = self.a11(x) x = self.c12(x) x = self.b12(x) x = self.a12(x) x = self.c13(x) x = self.b13(x) x = self.a13(x) x = self.p5(x) x = self.d5(x) x = self.flatten(x) x = self.f1(x) x = self.d6(x) x = self.f2(x) x = self.d7(x) y = self.f3(x) return y ``` 一个不知道从哪来的但是可以做通用车牌识别的网络: ```python from keras.models import Sequential from keras.layers import Dense, Flatten, GlobalAveragePooling2D from keras.layers.convolutional import Conv2D from keras.layers.convolutional import MaxPooling2D from keras.models import load_model import os import cv2 import numpy import tensorflow def cnn_train(): char_dict = {"京": 0, "沪": 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, "0": 31, "1": 32, "2": 33, "3": 34, "4": 35, "5": 36, "6": 37, "7": 38, "8": 39, "9": 40, "A": 41, "B": 42, "C": 43, "D": 44, "E": 45, "F": 46, "G": 47, "H": 48, "J": 49, "K": 50, "L": 51, "M": 52, "N": 53, "P": 54, "Q": 55, "R": 56, "S": 57, "T": 58, "U": 59, "V": 60, "W": 61, "X": 62, "Y": 63, "Z": 64} # 读取数据集 path = 'F:\\github\\ai\\车牌\\car_plate\\' # 车牌号数据集路径(车牌图片宽272,高72) pic_name = sorted(os.listdir(path)) n = len(pic_name) X_train, y_train = [], [] for i in range(n): # print("正在读取第%d张图片" % pic_name) # cv2.imshow无法读取中文路径图片,改用此方式 img = cv2.imdecode(numpy.fromfile( path + pic_name[i], dtype=numpy.uint8), -1) label = [char_dict[name] for name in pic_name[i][0:7]] # 图片名前7位为车牌标签 img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 加灰度 img = cv2.medianBlur(img, 5) # 中值滤波 ret, img = cv2.threshold( img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU) X_train.append(img) y_train.append(label) break X_train = numpy.array(X_train) # y_train是长度为7的列表,其中每个都是shape为(n,)的ndarray,分别对应n张图片的第一个字符,第二个字符....第七个字符 y_train = [numpy.array(y_train)[:, i] for i in range(7)] # cnn模型 https://blog.csdn.net/qq_32194791/article/details/106748685 model = tensorflow.keras.Sequential() model.add(tensorflow.keras.Input((72, 272, 1))) model.add(tensorflow.keras.layers.Conv2D(filters=16, kernel_size=( 3, 3), strides=1, padding='same', activation='relu')) model.add(tensorflow.keras.layers.MaxPool2D( pool_size=(2, 2), padding='same', strides=2)) model.summary() model.compile(optimizer='adam', # y_train未进行one-hot编码,所以loss选择sparse_categorical_crossentropy loss='sparse_categorical_crossentropy', metrics=['accuracy']) # 模型训练 _callbacks = [tensorflow.keras.callbacks.TensorBoard( log_dir='./keras_log'.format(model))] print("开始训练cnn") model.fit(X_train, y_train, epochs=100, batch_size=128, callbacks=_callbacks) # 总loss为7个loss的和 model.save('cnn.h5') print('cnn.h5保存成功!!!') cnn_train() ``` alexnet: ```python class AlexNet8(Model): def __init__(self): super(AlexNet8, self).__init__() self.c1 = Conv2D(filters=96, kernel_size=(3, 3)) self.b1 = BatchNormalization() self.a1 = Activation('relu') self.p1 = MaxPool2D(pool_size=(3, 3), strides=2) self.c2 = Conv2D(filters=256, kernel_size=(3, 3)) self.b2 = BatchNormalization() self.a2 = Activation('relu') self.p2 = MaxPool2D(pool_size=(3, 3), strides=2) self.c3 = Conv2D(filters=384, kernel_size=(3, 3), padding='same', activation='relu') self.c4 = Conv2D(filters=384, kernel_size=(3, 3), padding='same', activation='relu') self.c5 = Conv2D(filters=256, kernel_size=(3, 3), padding='same', activation='relu') self.p3 = MaxPool2D(pool_size=(3, 3), strides=2) self.flatten = Flatten() self.f1 = Dense(2048, activation='relu') self.d1 = Dropout(0.5) self.f2 = Dense(2048, activation='relu') self.d2 = Dropout(0.5) self.f3 = Dense(10, activation='softmax') def call(self, x): x = self.c1(x) x = self.b1(x) x = self.a1(x) x = self.p1(x) x = self.c2(x) x = self.b2(x) x = self.a2(x) x = self.p2(x) x = self.c3(x) x = self.c4(x) x = self.c5(x) x = self.p3(x) x = self.flatten(x) x = self.f1(x) x = self.d1(x) x = self.f2(x) x = self.d2(x) y = self.f3(x) return y model = AlexNet8() ``` 我非常喜欢的resnet ```python class ResnetBlock(Model): def __init__(self, filters, strides=1, residual_path=False): super(ResnetBlock, self).__init__() self.filters = filters self.strides = strides self.residual_path = residual_path self.c1 = Conv2D(filters, (3, 3), strides=strides, padding='same', use_bias=False) self.b1 = BatchNormalization() self.a1 = Activation('relu') self.c2 = Conv2D(filters, (3, 3), strides=1, padding='same', use_bias=False) self.b2 = BatchNormalization() # residual_path为True时,对输入进行下采样,即用1x1的卷积核做卷积操作,保证x能和F(x)维度相同,顺利相加 if residual_path: self.down_c1 = Conv2D(filters, (1, 1), strides=strides, padding='same', use_bias=False) self.down_b1 = BatchNormalization() self.a2 = Activation('relu') def call(self, inputs): residual = inputs # residual等于输入值本身,即residual=x # 将输入通过卷积、BN层、激活层,计算F(x) x = self.c1(inputs) x = self.b1(x) x = self.a1(x) x = self.c2(x) y = self.b2(x) if self.residual_path: residual = self.down_c1(inputs) residual = self.down_b1(residual) out = self.a2(y + residual) # 最后输出的是两部分的和,即F(x)+x或F(x)+Wx,再过激活函数 return out class ResNet18(Model): def __init__(self, block_list, initial_filters=64): # block_list表示每个block有几个卷积层 super(ResNet18, self).__init__() self.num_blocks = len(block_list) # 共有几个block self.block_list = block_list self.out_filters = initial_filters self.c1 = Conv2D(self.out_filters, (3, 3), strides=1, padding='same', use_bias=False) self.b1 = BatchNormalization() self.a1 = Activation('relu') self.blocks = tf.keras.models.Sequential() # 构建ResNet网络结构 for block_id in range(len(block_list)): # 第几个resnet block for layer_id in range(block_list[block_id]): # 第几个卷积层 if block_id != 0 and layer_id == 0: # 对除第一个block以外的每个block的输入进行下采样 block = ResnetBlock(self.out_filters, strides=2, residual_path=True) else: block = ResnetBlock(self.out_filters, residual_path=False) self.blocks.add(block) # 将构建好的block加入resnet self.out_filters *= 2 # 下一个block的卷积核数是上一个block的2倍 self.p1 = tf.keras.layers.GlobalAveragePooling2D() self.f1 = tf.keras.layers.Dense(10, activation='softmax', kernel_regularizer=tf.keras.regularizers.l2()) def call(self, inputs): x = self.c1(inputs) x = self.b1(x) x = self.a1(x) x = self.blocks(x) x = self.p1(x) y = self.f1(x) return y model = ResNet18([2, 2, 2, 2]) ``` 2021-03-10补充: 车牌生成: ```python import os import cv2 as cv import numpy as np from math import * from PIL import ImageFont from PIL import Image from PIL import ImageDraw index = {"京": 0, "沪": 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, "0": 31, "1": 32, "2": 33, "3": 34, "4": 35, "5": 36, "6": 37, "7": 38, "8": 39, "9": 40, "A": 41, "B": 42, "C": 43, "D": 44, "E": 45, "F": 46, "G": 47, "H": 48, "J": 49, "K": 50, "L": 51, "M": 52, "N": 53, "P": 54, "Q": 55, "R": 56, "S": 57, "T": 58, "U": 59, "V": 60, "W": 61, "X": 62, "Y": 63, "Z": 64} chars = ["京", "沪", "津", "渝", "冀", "晋", "蒙", "辽", "吉", "黑", "苏", "浙", "皖", "闽", "赣", "鲁", "豫", "鄂", "湘", "粤", "桂", "琼", "川", "贵", "云", "藏", "陕", "甘", "青", "宁", "新", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"] def AddSmudginess(img, Smu): """ 模糊处理 :param img: 输入图像 :param Smu: 模糊图像 :return: 添加模糊后的图像 """ rows = r(Smu.shape[0] - 50) cols = r(Smu.shape[1] - 50) adder = Smu[rows:rows + 50, cols:cols + 50] adder = cv.resize(adder, (50, 50)) img = cv.resize(img, (50, 50)) img = cv.bitwise_not(img) img = cv.bitwise_and(adder, img) img = cv.bitwise_not(img) return img def rot(img, angel, shape, max_angel): """ 添加透视畸变 """ size_o = [shape[1], shape[0]] size = (shape[1] + int(shape[0] * cos((float(max_angel) / 180) * 3.14)), shape[0]) interval = abs(int(sin((float(angel) / 180) * 3.14) * shape[0])) pts1 = np.float32( [[0, 0], [0, size_o[1]], [size_o[0], 0], [size_o[0], size_o[1]]]) if angel > 0: pts2 = np.float32([[interval, 0], [0, size[1]], [size[0], 0], [ size[0] - interval, size_o[1]]]) else: pts2 = np.float32([[0, 0], [interval, size[1]], [ size[0] - interval, 0], [size[0], size_o[1]]]) M = cv.getPerspectiveTransform(pts1, pts2) dst = cv.warpPerspective(img, M, size) return dst def rotRandrom(img, factor, size): """ 添加放射畸变 :param img: 输入图像 :param factor: 畸变的参数 :param size: 图片目标尺寸 :return: 放射畸变后的图像 """ shape = size pts1 = np.float32( [[0, 0], [0, shape[0]], [shape[1], 0], [shape[1], shape[0]]]) pts2 = np.float32([[r(factor), r(factor)], [r(factor), shape[0] - r(factor)], [shape[1] - r(factor), r(factor)], [shape[1] - r(factor), shape[0] - r(factor)]]) M = cv.getPerspectiveTransform(pts1, pts2) dst = cv.warpPerspective(img, M, size) return dst def tfactor(img): """ 添加饱和度光照的噪声 """ hsv = cv.cvtColor(img, cv.COLOR_BGR2HSV) hsv[:, :, 0] = hsv[:, :, 0] * (0.8 + np.random.random() * 0.2) hsv[:, :, 1] = hsv[:, :, 1] * (0.3 + np.random.random() * 0.7) hsv[:, :, 2] = hsv[:, :, 2] * (0.2 + np.random.random() * 0.8) img = cv.cvtColor(hsv, cv.COLOR_HSV2BGR) return img def random_envirment(img, noplate_bg): """ 添加自然环境的噪声, noplate_bg为不含车牌的背景图 """ bg_index = r(len(noplate_bg)) env = cv.imread(noplate_bg[bg_index]) env = cv.resize(env, (img.shape[1], img.shape[0])) bak = (img == 0) bak = bak.astype(np.uint8) * 255 inv = cv.bitwise_and(bak, env) img = cv.bitwise_or(inv, img) return img def GenCh(f, val): """ 生成中文字符 """ img = Image.new("RGB", (45, 70), (255, 255, 255)) draw = ImageDraw.Draw(img) draw.text((0, 3), val, (0, 0, 0), font=f) img = img.resize((23, 70)) A = np.array(img) return A def GenCh1(f, val): """ 生成英文字符 """ img = Image.new("RGB", (23, 70), (255, 255, 255)) draw = ImageDraw.Draw(img) draw.text((0, 2), val, (0, 0, 0), font=f) # val.decode('utf-8') A = np.array(img) return A def AddGauss(img, level): """ 添加高斯模糊 """ return cv.blur(img, (level * 2 + 1, level * 2 + 1)) def r(val): return int(np.random.random() * val) def AddNoiseSingleChannel(single): """ 添加高斯噪声 """ diff = 255 - single.max() noise = np.random.normal(0, 1 + r(6), single.shape) noise = (noise - noise.min()) / (noise.max() - noise.min()) noise *= diff # noise= noise.astype(np.uint8) dst = single + noise return dst def addNoise(img): # sdev = 0.5,avg=10 img[:, :, 0] = AddNoiseSingleChannel(img[:, :, 0]) img[:, :, 1] = AddNoiseSingleChannel(img[:, :, 1]) img[:, :, 2] = AddNoiseSingleChannel(img[:, :, 2]) return img class GenPlate: def __init__(self, fontCh, fontEng, NoPlates): self.fontC = ImageFont.truetype(fontCh, 43, 0) self.fontE = ImageFont.truetype(fontEng, 60, 0) self.img = np.array(Image.new("RGB", (226, 70), (255, 255, 255))) self.bg = cv.resize(cv.imread("images\\template.bmp"), (226, 70)) # template.bmp:车牌背景图 self.smu = cv.imread("images\\smu2.jpg") # smu2.jpg:模糊图像 self.noplates_path = [] for parent, parent_folder, filenames in os.walk(NoPlates): for filename in filenames: path = parent + "\\" + filename self.noplates_path.append(path) def draw(self, val): offset = 2 self.img[0:70, offset+8:offset+8+23] = GenCh(self.fontC, val[0]) self.img[0:70, offset+8+23+6:offset+8 + 23+6+23] = GenCh1(self.fontE, val[1]) for i in range(5): base = offset + 8 + 23 + 6 + 23 + 17 + i * 23 + i * 6 self.img[0:70, base:base+23] = GenCh1(self.fontE, val[i+2]) return self.img def generate(self, text): if len(text) == 7: fg = self.draw(text) # decode(encoding="utf-8") fg = cv.bitwise_not(fg) com = cv.bitwise_or(fg, self.bg) com = rot(com, r(60)-30, com.shape, 30) com = rotRandrom(com, 10, (com.shape[1], com.shape[0])) com = tfactor(com) com = random_envirment(com, self.noplates_path) com = AddGauss(com, 1+r(4)) com = addNoise(com) return com @staticmethod def genPlateString(pos, val): """ 生成车牌string,存为图片 生成车牌list,存为label """ plateStr = "" box = [0, 0, 0, 0, 0, 0, 0] if pos != -1: box[pos] = 1 for unit, cpos in zip(box, range(len(box))): if unit == 1: plateStr += val else: if cpos == 0: plateStr += chars[r(31)] elif cpos == 1: plateStr += chars[41 + r(24)] else: plateStr += chars[31 + r(34)] return plateStr @staticmethod def genBatch(batchsize, outputPath, size): """ 将生成的车牌图片写入文件夹,对应的label写入label.txt :param batchsize: 批次大小 :param outputPath: 输出图像的保存路径 :param size: 输出图像的尺寸 :return: None """ if not os.path.exists(outputPath): os.mkdir(outputPath) for i in range(batchsize): plateStr = G.genPlateString(-1, -1) # print(plateStr, plate) img = G.generate(plateStr) img = cv.resize(img, size) #cv.imwrite(outputPath + "\\" + plateStr + ".jpg", img) cv.imencode('.jpg', img)[1].tofile( outputPath + "\\" + plateStr + ".jpg") # 正确的解决办法 if __name__ == '__main__': G = GenPlate("font\\platech.ttf", 'font\\platechar.ttf', "NoPlates") G.genBatch(6000, 'car_plate', (272, 72)) ``` [车牌.rar](https://key08.com/usr/uploads/2021/03/2080950142.rar) 本文由 huoji 创作,采用 知识共享署名 3.0,可自由转载、引用,但需署名作者且注明文章出处。 点赞 5
http://www.baidu.com