python自動生成黃藍綠車牌,並自動標注yolo模型labelImg文件


參考作者:

作者:Charlotte77

出處:http://www.cnblogs.com/charlotte77/

本文以學習、研究和分享為主,如需轉載,請聯系本人,標明作者和出處,非商業用途!

介紹:本文靈感來自於作者:Charlotte77,在其自動生成車牌的基礎上稍作修改,可隨機生成三色車牌並標注xml文件。生成保存路徑和xml保存路徑以及單詞隨機生成個數,可在代碼中設置。因為我是做車牌字符的識別,所以生成時規定了省份簡稱,如需更換可修改代碼中相應部分,亦可隨機。

修改部分:使用pypinyin模塊得到省份簡稱的拼音,同音字已做區分,藏字得音為cang,需要注意!后續模型分類可另作修改。

注意:注釋不一定是原作者真是用意,請加以甄別!

 

RandomGenerationVLP.py
#coding=utf-8
"""
   genPlate.py:生成隨機車牌
"""

__author__ = "Huxiaoman"
__copyright__ = "Copyright (c) 2017 "

import PIL
from PIL import ImageFont
from PIL import Image
from PIL import ImageDraw
import cv2
import numpy as np
import os
from math import *
import pypinyin
import sys
import os
import xml.dom.minidom

import pypinyin


def genXML(plate, labels, xmlPath):  # 生成的字符列表和 標簽位置
    # pinyin = pypinyin.slug(imageName[0])
    # if imageName[0] == '貴':
    #     pinyin = 'gui'
    # elif imageName[0] == '桂':
    #     pinyin = 'guilin'
    # elif imageName[0] == '甘':
    #     pinyin = 'gan'
    # elif imageName[0] == '贛':
    #     pinyin = 'jiangxi'
    # elif imageName[0] == '豫':
    #     pinyin = 'yu'
    # elif imageName[0] == '渝':
    #     pinyin = 'chongqing'
    # elif imageName[0] == '晉':
    #     pinyin = 'jin'
    # elif imageName[0] == '津':
    #     pinyin = 'tianjin'

    new_txtname = ''.join(plate)  #

    # 創建空的Dom文檔對象
    doc = xml.dom.minidom.Document()
    # 創建根結點,根節點名為 annotation
    annotation = doc.createElement('annotation')  # 根節點
    # 將根節點添加到Dom文檔對象中
    doc.appendChild(annotation)

    # folder節點
    folder = doc.createElement('folder')  # 創建一個名叫folder的節點
    # 內容寫入
    folder_text = doc.createTextNode('JPEGImages')  # folder節點里面要寫的內容
    folder.appendChild(folder_text)  # 添加到folder節點下,如果是內容,節點內容createTextNode類型,就作為內容寫入;如果是createElement類型,就作為子節點添加進去
    annotation.appendChild(folder)  # 之后將添加好內容的folder節點,作為子節點添加到annotation節點中

    # filename節點
    filename = doc.createElement('filename')
    filename_text = doc.createTextNode(str(new_txtname) + '.jpg')  # 這個地方是隨機生成的圖片文件名
    filename.appendChild(filename_text)
    #
    annotation.appendChild(filename)

    # path節點
    path = doc.createElement('path')
    path_text = doc.createTextNode('E:\\darknet-master\\build\\darknet\\myVLPCharData\\JPEGImages\\%s.jpg' % new_txtname)
    path.appendChild(path_text)
    #
    annotation.appendChild(path)

    # sourch節點
    source = doc.createElement('source')
    #
    database = doc.createElement('database')
    database_text = doc.createTextNode('Unknown')
    database.appendChild(database_text)
    #
    source.appendChild(database)
    #
    annotation.appendChild(source)

    # size節點
    size = doc.createElement('size')

    width = doc.createElement('width')
    width_text = doc.createTextNode('272')
    width.appendChild(width_text)
    size.appendChild(width)

    height = doc.createElement('height')
    height_text = doc.createTextNode('72')
    height.appendChild(height_text)
    size.appendChild(height)

    depth = doc.createElement('depth')
    depth_text = doc.createTextNode('3')
    depth.appendChild(depth_text)
    size.appendChild(depth)
    #
    annotation.appendChild(size)

    # segmented節點
    segmented = doc.createElement('segmented')
    segmented_text = doc.createTextNode('0')
    segmented.appendChild(segmented_text)
    #
    annotation.appendChild(segmented)

    # object節點
    for [y1, y2, x1, x2], pChar in zip(labels, plate):
        object = doc.createElement('object')

        name = doc.createElement('name')
        name_text = doc.createTextNode(pChar)  # 這個地方是標簽的name,也就是分類名稱
        name.appendChild(name_text)
        object.appendChild(name)

        pose = doc.createElement('pose')
        pose_text = doc.createTextNode("Unspecified")
        pose.appendChild(pose_text)
        object.appendChild(pose)

        truncated = doc.createElement('truncated')
        truncated_text = doc.createTextNode("0")
        truncated.appendChild(truncated_text)
        object.appendChild(truncated)

        difficult = doc.createElement('difficult')
        difficult_text = doc.createTextNode("0")
        difficult.appendChild(difficult_text)
        object.appendChild(difficult)

        bndbox = doc.createElement('bndbox')
        #
        xmin = doc.createElement('xmin')
        xmin_text = doc.createTextNode(str(x1))
        xmin.appendChild(xmin_text)
        bndbox.appendChild(xmin)
        #
        ymin = doc.createElement('ymin')
        ymin_text = doc.createTextNode(str(y1))
        ymin.appendChild(ymin_text)
        bndbox.appendChild(ymin)
        #
        xmax = doc.createElement('xmax')
        xmax_text = doc.createTextNode(str(x2))
        xmax.appendChild(xmax_text)
        bndbox.appendChild(xmax)
        #
        ymax = doc.createElement('ymax')
        ymax_text = doc.createTextNode(str(y2))
        ymax.appendChild(ymax_text)
        bndbox.appendChild(ymax)
        #
        object.appendChild(bndbox)
        #
        annotation.appendChild(object)

    # 寫入xml文本文件中
    if not os.path.exists(xmlPath):
        os.mkdir(xmlPath)
    fp = open(xmlPath + '/%s.xml' % new_txtname, 'w+')
    doc.writexml(fp, indent='\n', addindent='\t', newl='', encoding='utf-8')
    fp.close()


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):
    rows = r(Smu.shape[0] - 50)
    cols = r(Smu.shape[1] - 50)
    adder = Smu[rows:rows + 50, cols:cols + 50]
    adder = cv2.resize(adder, (50, 50))
    #adder = cv2.bitwise_not(adder)
    img = cv2.resize(img,(50,50))
    img = cv2.bitwise_not(img)
    img = cv2.bitwise_and(adder, img)
    img = cv2.bitwise_not(img)
    return img

def rot(img,angel,shape,max_angel):  # com, [-30, 30), (70, 226, 3), 30
    """
        添加放射畸變
        img 輸入圖像
        factor 畸變的參數
        size 為圖片的目標尺寸
    """
    size_o = [shape[1], shape[0]]  # [226, 70]
    size = (shape[1] + int(shape[0] * cos((float(max_angel)/180) * 3.14)), shape[0])  # (226+60=286, 70)  # 寬度也就是shape[1]的長度加上高度乘以高度的傾斜寬30/180,等於最后放射的寬度
    interval = abs(int(sin((float(angel) / 180) * 3.14) * shape[0]))  # [0, 34]  # 0到34之間整數
    pts1 = np.float32([[0, 0], [0, size_o[1]], [size_o[0], 0], [size_o[0], size_o[1]]])  # [[0, 0], [0, 70], [226, 0], [226, 70]]
    if angel > 0:
        pts2 = np.float32([[interval, 0], [0, size[1]], [size[0], 0], [size[0]-interval, size_o[1]]])  # [[0到34, 0], [0, 70], [226, 0], [226-0到34, 70]]
    else:
        pts2 = np.float32([[0, 0], [interval, size[1]], [size[0]-interval, 0], [size[0], size_o[1]]])  # [[0, 0], [0到34, 70], [226-0到34, 0], [226, 70]]
    M = cv2.getPerspectiveTransform(pts1, pts2)
    dst = cv2.warpPerspective(img, M, size)
    return dst

def rotRandrom(img, factor, size):  # com, 10, (286, 70)  # com.shape = (70, 286, 3)
    """
    添加透視畸變
    """
    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 = cv2.getPerspectiveTransform(pts1, pts2)
    dst = cv2.warpPerspective(img, M, size)
    return dst

def tfactor(img):
    """
    添加飽和度光照的噪聲
    """
    hsv = cv2.cvtColor(img, cv2.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 = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)
    return img

def random_envirment(img, data_set):
    """
    添加自然環境的噪聲
    """
    index=r(len(data_set))
    env = cv2.imread(data_set[index])
    env = cv2.resize(env,(img.shape[1],img.shape[0]))
    bak = (img==0)
    bak = bak.astype(np.uint8)*255
    inv = cv2.bitwise_and(bak,env)
    img = cv2.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))  # 文字圖片轉換成了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.decode('utf-8'), (0, 0, 0), font=f)
    draw.text((0, 2), val, (0, 0, 0), font=f)
    A = np.array(img)
    return A

def AddGauss(img, level):  # level [1, 5)
    """
    添加高斯模糊
    """
    # return cv2.blur(img, (level*2 + 1, level*2 + 1))
    return cv2.blur(img, (5, 5))  # 可接受的模糊程度
    # return cv2.blur(img, (level, level))

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 = 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, xmlPath):  # "./font/platech.ttf", './font/platechar.ttf', "./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 = cv2.resize(cv2.imread("./images/template.bmp"), (226, 70))
        # 黃色車牌背景圖
        # self.bg = cv2.resize(cv2.imread("./images/y1.bmp"),(226,70))
        # # self.smu = cv2.imread("./images/smu2.jpg")
        # 綠色車牌背景圖
        # self.bg = cv2.resize(cv2.imread("./images/g1.jpg"),(226,70))
        self.noplates_path = []
        self.xmlPath = xmlPath  # xml文件保存位置
        for parent, parent_folder, filenames in os.walk(NoPlates):
            # print(parent, parent_folder, filenames)
            # ./NoPlates
            # []
            # ['A01_N84E28_1.jpg', 'A01_N84E28_2.jpg', 'A01_NMV802_1.jpg', 'A01_NMV802_2.jpg', 'A02_NBD719_1.jpg', 'A02_NBD719_2.jpg', 'A03_A05F26_1.jpg', 'A03_A137U8_1.jpg', 'A03_A137U8_2.jpg', 'A03_A137U8_3.jpg', 'A03_A19Z80_0.jpg', 'A03_A19Z80_1.jpg', 'A03_A19Z80_2.jpg', 'A03_A19Z80_3.jpg', 'A03_A19Z80_4.jpg', 'A03_A19Z80_5.jpg', 'A03_A19Z80_7.jpg', 'A03_A19Z80_8.jpg', 'A03_A1L828_0.jpg', 'A03_A1L828_1.jpg', 'A03_A1L828_2.jpg', 'A03_A1L828_4.jpg', 'A03_A1Z726_1.jpg', 'A03_A203J1_1.jpg', 'A03_A203J1_2.jpg', 'A03_A2H337_0.jpg', 'A03_A2H337_2.jpg', 'A03_A2M801_1.jpg', 'A03_A2M801_2.jpg', 'A03_A4F288_1.jpg', 'A03_A5X098_1.jpg', 'A03_A60L48_0.jpg', 'A03_A60L48_1.jpg', 'A03_A60L48_2.jpg', 'A03_A60L48_3.jpg', 'A03_A60L48_4.jpg', 'A03_A63X72_1.jpg', 'A03_A6U922_1.jpg', 'A03_A6U922_2.jpg', 'A03_A722S6_0.jpg', 'A03_A79A95_1.jpg', 'A03_A7N292_1.jpg', 'A03_A82E65_1.jpg', 'A03_A82E65_2.jpg', 'A03_A85V02_1.jpg', 'A03_A8B389_1.jpg', 'A03_A8B389_2.jpg', 'A03_A8B389_3.jpg', 'A03_A8B389_4.jpg', 'A03_A8E322_1.jpg', 'A03_A9F208_1.jpg', 'A03_A9F208_2.jpg', 'A03_AAC595_0.jpg', 'A03_AAC595_2.jpg', 'A03_AAC595_3.jpg', 'A03_AAC595_4.jpg', 'A03_AAC595_5.jpg', 'A03_AAQ839_0.jpg', 'A03_AAQ839_1.jpg', 'A03_AAQ839_2.jpg', 'A03_AAQ839_4.jpg', 'A03_AAQ839_5.jpg', 'A03_ABF318_1.jpg', 'A03_ABF318_2.jpg']
            for filename in filenames:
                path = parent + "/" + filename
                # path = os.path.join(parent, filename)
                # print(path)
                self.noplates_path.append(path)


    def draw(self,val):  # val =  # 鄂ARQ2CR
        offset = 2
        self.img[0:70, offset+8:offset+8+23] = GenCh(self.fontC, val[0])  # 第一個中文的位置 x, y, w, h 在0- 70行的 第10- 第10+23=33列
        # print(offset+8, ':', offset+8+23)
        self.img[0:70, offset+8+23+6:offset+8+23+6+23] = GenCh1(self.fontE, val[1])  # 第二個城市簡稱的位置在 第10+23 + 6 = 39- 第39+23= 62列
        # print(offset+8+23+6, ':', offset+8+23+6+23)
        for i in range(5):
            base = offset + 8 + 23 + 6 + 23 + 17 + i*23 + i*6  # 后五位編號的位置在第二個城市代號末尾列,也就是第10+23+6+23= 62列的后面加上17= 79列,17是城市代號到后五位編號中間的防偽標記點的占距
            self.img[0:70, base: base+23] = GenCh1(self.fontE, val[i+2])
            # print(base, ':', base+23)
        return self.img
        # 總結一下:(226, 70)   10-63行
        # 省份簡稱 [:, 10:33],
        # 城市代號[:, 39:62],
        # 第一位編號[:, 79:102],
        # 第二位編號[:, 108:131],
        # 第三位編號[:, 137:160],
        # 第四位編號[:, 166:189],
        # 第五位編號[:, 195:218]

        # 放大后
        # [11: 61, 12: 39]
        # [11:61, 46: 74]
        # [11:61, 95: 122]
        # [11:61, 129: 157]
        # [11:61, 164: 192]
        # [11:61, 199: 227]
        # [11:61, 234: 262]


    def generate(self, text):  # 鄂ARQ2CR
        # if len(text) == 9:
        if len(text) == 7:
            # fg = self.draw(text.decode(encoding="utf-8"))
            # text.encode(encoding="utf-8").decode(encoding="utf-8")
            # fg = self.draw(text.encode(encoding="utf-8").decode(encoding="utf-8"))
            fg = self.draw(text)  # 鄂ARQ2CR

            # 白色字體  # 使用時,注釋掉黑色字體部分
            fg = cv2.bitwise_not(fg)
            com = cv2.bitwise_or(fg, self.bg)
            # com = rot(com, r(60)-30, com.shape, 30)  # 放射畸變  # 整體效果為 車牌行數不變,列數拉伸成∠60°的平行四邊形狀
            # print(com.shape)  # (70, 286, 3)  #
            # 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)
            print(com.shape)

            # # 黑色字體  黃車牌適用  # 使用時,注釋掉白色字體部分
            # com = cv2.bitwise_and(fg,self.bg)
            #
            # com = addNoise(com)  # 先添加噪音,后進行其他操作對字體顏色的影響很小
            # # 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, 3 + r(2))

            return com

        else:
            return None

    def genPlateString(self, pos, val):  # -1, -1
        '''
        生成車牌String,存為圖片
        生成車牌list,存為label
        '''
        plateStr = ""
        plateList = []
        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
                #print plateStr
                plateList.append(val)
            else:
                if cpos == 0:
                    # plateStr += chars[r(31)]  # 控制省份隨機范圍,可指定某一省份
                    plateStr += chars[11]  # 控制省份隨機范圍,可指定某一省份  京 0  渝 3  30封頂
                    plateList.append(plateStr)
                elif cpos == 1:
                    plateStr += chars[41+r(24)]
                    plateList.append(plateStr)
                else:
                    plateStr += chars[31 + r(34)]
                    plateList.append(plateStr)
        plate = [plateList[0]]
        b = [plateList[i][-1] for i in range(len(plateList))]
        plate.extend(b[1:7])  # extend() 在一個list后面,添加另一個list的多個值
        return plateStr, plate

    # 將生成的車牌圖片寫入文件夾,對應的label寫入label.txt
    def genBatch(self, batchSize, pos, charRange, outputPath, size):
        if not os.path.exists(outputPath):
            os.mkdir(outputPath)
        outfile = open('label.txt', 'w')
        for i in range(batchSize):
            plateStr, plate = G.genPlateString(-1, -1)

            pinyin = pypinyin.slug(plateStr[0])
            if plateStr[0] == '':
                pinyin = 'gui'
            elif plateStr[0] == '':
                pinyin = 'guilin'
            elif plateStr[0] == '':
                pinyin = 'gan'
            elif plateStr[0] == '':
                pinyin = 'jiangxi'
            elif plateStr[0] == '':
                pinyin = 'yu'
            elif plateStr[0] == '':
                pinyin = 'chongqing'
            elif plateStr[0] == '':
                pinyin = 'jin'
            elif plateStr[0] == '':
                pinyin = 'tianjin'
            elif plateStr[0] == '':
                pinyin = 'hebei'
            elif plateStr[0] == '':
                pinyin = 'ji'

            labels = [
                [11, 61, 12, 39],
                [11, 61, 46, 74],
                [11, 61, 95, 122],
                [11, 61, 129, 157],
                [11, 61, 164, 192],
                [11, 61, 199, 227],
                [11, 61, 234, 262]
            ]
            #  修改后的位置
            labels = [
                [12, 61, 11, 40],
                [12, 61, 45, 75],
                [12, 61, 94, 123],
                [12, 61, 128, 158],
                [12, 61, 163, 193],
                [12, 61, 198, 228],
                [12, 61, 233, 263]
            ]

            imageName = pinyin + plateStr[1:]  # 省份簡稱替換成拼音
            plate[0] = pinyin  # 標簽換成轉換后的拼音

            genXML(plate, labels, self.xmlPath)  # 生成對應的標簽

            print(imageName)
            print(plateStr, plate)  # 鄂ARQ2CR ['鄂', 'A', 'R', 'Q', '2', 'C', 'R']
            img = G.generate(plateStr)
            # print(img.shape)
            img = cv2.resize(img, size)  # (272, 72)  # 注釋掉這一步是因為要get到沒放大的字符位置
            # print(img.shape)
            # cv2.imwrite(outputPath + "/" + str(i).zfill(2) + ".jpg", img)
            if not os.path.exists(outputPath):
                os.mkdir(outputPath)
            cv2.imwrite(outputPath + "/" + imageName + ".jpg", img)
            outfile.write(str(plate)+"\n")
        outfile.close()
# G = GenPlate("./font/platech.ttf", './font/platechar.ttf', "./NoPlates", 'E:\\darknet-master\\build\\darknet\\myVLPCharData\\Annotations')
G = GenPlate("./font/platech.ttf", './font/platechar.ttf', "./NoPlates", './xml')  # 測試修改時使用
#G.genBatch(100, 2, range(31, 65), "./plate_100", (272, 72))

if __name__ == '__main__':
    # G.genBatch(int(sys.argv[1]), 2, range(31, 65), sys.argv[2], (272, 72))
    # # # python genPlate.py 100 ./plate_100
    # G.genBatch(int(300), 2, range(31, 65), "E:\\darknet-master\\build\\darknet\\myVLPCharData\\JPEGImages", (272, 72))
    G.genBatch(int(13), 2, range(31, 65), "./plate_100", (272, 72))  # 測試修改時使用

    classDict = {'jing': "", 'hu': "", 'tianjin': "", 'chongqing': "", 'hebei': "", 'jin': "", 'meng': "",
                 'liao': "", 'ji': "", 'hei': "", 'su': "", 'zhe': "", 'wan': "", 'min': "", 'jiangxi': "",
                 'lu': "", 'yu': "", 'e': "", 'xiang': "", 'yue': "", 'guangxi': "", 'qiong': "", 'chuan': "",
                 'gui': "", 'yun': "", 'cang': "", 'shan': "", 'gan': "", 'qing': "", 'ning': "", 'xin': ""}

 

 

 

網盤文件鏈接(基礎代碼皆來自-作者:Charlotte77):

鏈接:https://pan.baidu.com/s/1qPnEvZh8fzmqmOuuZfe8Ag
提取碼:m1sw 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM