├── .DS_Store ├── .gitattributes ├── README.md ├── data ├── .DS_Store ├── train │ ├── .DS_Store │ ├── neutral │ │ ├── [pic.sogou.com][197]d52704b61c70ae76-8a6775c3c4e1c205-368ce5700c4a0097a128a1130f24f882.jpg │ │ ├── [www.google.com][12706].jpg │ │ ├── [www.google.com][15189].jpg │ │ ├── [www.google.com][17085].jpg │ │ ├── [www.google.com][18507].jpg │ │ ├── [www.google.com][1989].jpg │ │ ├── [www.google.com][20999].jpg │ │ ├── [www.google.com][24183].jpg │ │ ├── [www.google.com][3024].jpg │ │ ├── [www.google.com][32869].jpg │ │ ├── [www.google.com][39087].jpg │ │ ├── [www.google.com][39437].jpg │ │ ├── [www.google.com][396].jpg │ │ ├── [www.google.com][44918].jpg │ │ ├── [www.google.com][4506].jpg │ │ ├── [www.google.com][49973].jpg │ │ ├── [www.google.com][54121].jpg │ │ ├── [www.google.com][61303].jpg │ │ ├── [www.google.com][65962].jpg │ │ └── [www.google.com][76361].jpg │ ├── political │ │ ├── [www.google.com][10805].jpg │ │ ├── [www.google.com][16483].jpg │ │ ├── [www.google.com][25429].jpg │ │ ├── [www.google.com][440].jpg │ │ ├── [www.google.com][44315].jpg │ │ ├── [www.google.com][466].jpg │ │ ├── [www.google.com][47135].jpg │ │ ├── [www.google.com][49474].jpg │ │ ├── [www.google.com][59870].jpg │ │ ├── [www.google.com][61954].jpg │ │ ├── [www.google.com][64658].jpg │ │ ├── [www.google.com][67184].jpg │ │ ├── [www.google.com][67735].jpg │ │ ├── [www.google.com][68523].jpg │ │ ├── [www.google.com][82199].jpg │ │ ├── [www.google.com][86551].jpg │ │ ├── [www.google.com][89140].jpg │ │ ├── [www.google.com][91976].jpg │ │ ├── [www.google.com][96367].jpg │ │ └── [www.google.com][98553].jpg │ ├── porn │ │ ├── 153142_10big.jpg │ │ ├── 171865_14big.jpg │ │ ├── 184860_06big.jpg │ │ ├── 19bac.jpg │ │ ├── 1a5ne.jpg │ │ ├── 1h1gh.jpg │ │ ├── 200178_12big.jpg │ │ ├── 212515_16big.jpg │ │ ├── 221891_12big.jpg │ │ ├── 226563_04big.jpg │ │ ├── 267359_12big.jpg │ │ ├── [www.google.com][10382].jpg │ │ ├── [www.google.com][16973].jpg │ │ ├── [www.google.com][18585].jpg │ │ ├── [www.google.com][23921].jpg │ │ ├── [www.google.com][27032].jpg │ │ ├── [www.google.com][36956].jpg │ │ ├── [www.google.com][45609].jpg │ │ ├── [www.google.com][61230].jpg │ │ └── [www.google.com][78657].jpg │ └── terrorism │ │ ├── [www.google.com][11335].jpg │ │ ├── [www.google.com][14589].jpg │ │ ├── [www.google.com][17398].jpg │ │ ├── [www.google.com][19339].jpg │ │ ├── [www.google.com][24555].jpg │ │ ├── [www.google.com][27220].jpg │ │ ├── [www.google.com][32867].jpg │ │ ├── [www.google.com][36935].jpg │ │ ├── [www.google.com][3791].jpg │ │ ├── [www.google.com][40227].jpg │ │ ├── [www.google.com][44667].jpg │ │ ├── [www.google.com][46334].jpg │ │ ├── [www.google.com][46470].jpg │ │ ├── [www.google.com][5399].jpg │ │ ├── [www.google.com][54032].jpg │ │ ├── [www.google.com][59852].jpg │ │ ├── [www.google.com][601].jpg │ │ ├── [www.google.com][6719].jpg │ │ ├── [www.google.com][7041].jpg │ │ └── [www.google.com][76135].jpg └── validation │ ├── .DS_Store │ ├── neutral │ ├── .DS_Store │ ├── [pic.sogou.com][197]d52704b61c70ae76-8a6775c3c4e1c205-368ce5700c4a0097a128a1130f24f882.jpg │ ├── [www.google.com][1989].jpg │ └── [www.google.com][396].jpg │ ├── political │ ├── .DS_Store │ ├── [www.google.com][10805].jpg │ ├── [www.google.com][440].jpg │ └── [www.google.com][466].jpg │ ├── porn │ ├── .DS_Store │ ├── [www.google.com][10382].jpg │ ├── [www.google.com][16973].jpg │ └── [www.google.com][18585].jpg │ └── terrorism │ ├── [www.google.com][3791].jpg │ ├── [www.google.com][5399].jpg │ └── [www.google.com][601].jpg ├── log └── .DS_Store ├── main.py ├── predictWithMyModel.py ├── reTrainMyDataWithKerasModel.py ├── trainMyDataWithKerasModel.py └── utils └── image2Bash64.py /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/.DS_Store -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # generalImageClassification 2 | [toc] 3 | 4 | 本项目是通用的图像分类项目,并以涉黄、涉政、涉恐和普通图片4分类为例。图像违规质检本质是图像分类,所以关键点在于两个: 5 | 6 | 1. 图像分类的数据准备; 7 | 2. 图像分类的模型选择、训练; 8 | 9 | ## 1 数据准备 10 | 11 | 为了达到特定类别的分类,准备相应的图片数据, 12 | - 1 开源的数据集。 13 | - 2 自己写爬虫,爬取数据。但是没时间写,而且反爬虫设施的破解很费时间。 14 | - 3 利用特定的网站(爬虫),帮你取下载数据。 15 | 16 | ### 1.1 开源数据集 17 | 18 | 如果开始一个图像相关的项目,而这个领域又有公开、开源的数据集,那是最幸福的一件事了。所以有了项目需求之后,第一件事情,可以去github等网站搜寻一下有没有可以直接使用的数据集。 19 | 20 | 而对我们的“图片质检”项目,涉政图片、涉恐图片网上找不到现成的数据集。但是涉黄图片却又很多公开数据集,并且图片质量灰常的“优秀”。下面给出两个实例: 21 | 22 | 1. nsfw_data_scrapper公开数据集(下面是图片地址,和一些介绍如何使用的博客): 23 | - nsfw_data_scraper 数据 https://github.com/alex000kim/nsfw_data_scraper 24 | - NSFW Model(使用nsfw_data_scrapper数据训练resnet) https://github.com/rockyzhengwu/nsfw 25 | - nsfw_data_scraper 博客 https://www.ctolib.com/topics-137790.html 26 | - nsfw_data_scraper 博客 https://blog.csdn.net/yH0VLDe8VG8ep9VGe/article/details/86653609 27 | 2. nsfw_data_source_urls公开数据集: 28 | - 另外一个数据库nsfw_data_source_urls: https://github.com/EBazarov/nsfw_data_source_urls 29 | - nsfw_data_source_urls:博客https://www.tinymind.cn/articles/4025 30 | 31 | 32 | 33 | 34 | ### 1.2 利用特定网站爬数据 35 | 最近发现一个特别好的图片爬虫网站:[imagecyborg](https://imagecyborg.com/),只需要把你想下载的图片的网页地址放进去,他就可以帮你打包下载。使用方法: 36 | - 谷歌图像搜索相关的关键词。 37 | - 把网址放入 https://imagecyborg.com/ 中帮你下载。 38 | 39 | ## 2 分类模型的选择 40 | 41 | 图像分类研究近些年已经非常的成熟,涌现出的大批的优秀模型,并且已经被深度学习框架纳入自己的版图.对于工程界的我们一般只需要微调这些成熟的模型即可。 42 | 43 | 下面是keras框架内置的模型介绍,本项目考虑准确率和运行速度两个问题,所以选择了InceptionV3这个模型,准确率也可以,模型也不太深 参数不算过多。 44 | |模型|大小|Top1准确率|Top5准确率|参数数量|深度| 45 | |:-:|:-:|:-:|:-:|:-:|:-:| 46 | Xception |88 MB |0.790 |0.945 |22,910,480 |126 47 | InceptionV3 |92 MB |0.779 |0.937 |23,851,784 |159 48 | ResNeXt50 |96 MB |0.777 |0.938 |25,097,128 |- 49 | DenseNet201 |80 MB |0.773 |0.936 |20,242,984 |201 50 | DenseNet169 |57 MB |0.762 |0.932 |14,307,880 |169 51 | ResNet50V2 |98 MB |0.760 |0.930 |25,613,800 |- 52 | DenseNet121 |33 MB |0.750 |0.923 |8,062,504 |121 53 | 54 | 55 | > 参考: 56 | - keras微调模型 https://blog.keras.io/building-powerful-image-classification-models-using-very-little-data.html 57 | - 《Keras:自建数据集图像分类的模型训练、保存与恢复》 https://blog.csdn.net/akadiao/article/details/80456742 58 | 59 | ## 3 代码结构及使用方法 60 | 61 | ### 3.1 代码结构 62 | - data:存放数据的文件夹。 63 | - train:存放训练图片数据的文件夹。 64 | - validation:存放validation图片数据的文件夹。 65 | - modelFile:存放训练好的模型的文件夹。 66 | - log:存放log的文件夹。 67 | - trainMyDataWithKerasModel.py:训练模型的文件。 68 | - predictWithMyModel.py:使用训练好的模型进行单次预测。 69 | - reTrainMyDataWithKerasModel.py:对训练好的模型进行再训练。 70 | - main.py:使用flask将predictWithMyModel.py作为接口开放出去。 71 | 72 | 73 | 74 | ### 3.2 使用方法 75 | 76 | 主要需求的python包: 77 | - tensorflow:1.4.0 78 | - keras:2.3.1 79 | - flask:1.0.2 (非必须) 80 | 81 | 数据输入 和 数据lable生成:项目使用了keras的ImageDataGenerator这一个神器,会根据data文件夹下的子文件夹的名字生成lable。 -------------------------------------------------------------------------------- /data/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/.DS_Store -------------------------------------------------------------------------------- /data/train/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/.DS_Store -------------------------------------------------------------------------------- /data/train/neutral/[pic.sogou.com][197]d52704b61c70ae76-8a6775c3c4e1c205-368ce5700c4a0097a128a1130f24f882.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/neutral/[pic.sogou.com][197]d52704b61c70ae76-8a6775c3c4e1c205-368ce5700c4a0097a128a1130f24f882.jpg -------------------------------------------------------------------------------- /data/train/neutral/[www.google.com][12706].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/neutral/[www.google.com][12706].jpg -------------------------------------------------------------------------------- /data/train/neutral/[www.google.com][15189].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/neutral/[www.google.com][15189].jpg -------------------------------------------------------------------------------- /data/train/neutral/[www.google.com][17085].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/neutral/[www.google.com][17085].jpg -------------------------------------------------------------------------------- /data/train/neutral/[www.google.com][18507].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/neutral/[www.google.com][18507].jpg -------------------------------------------------------------------------------- /data/train/neutral/[www.google.com][1989].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/neutral/[www.google.com][1989].jpg -------------------------------------------------------------------------------- /data/train/neutral/[www.google.com][20999].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/neutral/[www.google.com][20999].jpg -------------------------------------------------------------------------------- /data/train/neutral/[www.google.com][24183].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/neutral/[www.google.com][24183].jpg -------------------------------------------------------------------------------- /data/train/neutral/[www.google.com][3024].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/neutral/[www.google.com][3024].jpg -------------------------------------------------------------------------------- /data/train/neutral/[www.google.com][32869].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/neutral/[www.google.com][32869].jpg -------------------------------------------------------------------------------- /data/train/neutral/[www.google.com][39087].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/neutral/[www.google.com][39087].jpg -------------------------------------------------------------------------------- /data/train/neutral/[www.google.com][39437].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/neutral/[www.google.com][39437].jpg -------------------------------------------------------------------------------- /data/train/neutral/[www.google.com][396].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/neutral/[www.google.com][396].jpg -------------------------------------------------------------------------------- /data/train/neutral/[www.google.com][44918].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/neutral/[www.google.com][44918].jpg -------------------------------------------------------------------------------- /data/train/neutral/[www.google.com][4506].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/neutral/[www.google.com][4506].jpg -------------------------------------------------------------------------------- /data/train/neutral/[www.google.com][49973].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/neutral/[www.google.com][49973].jpg -------------------------------------------------------------------------------- /data/train/neutral/[www.google.com][54121].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/neutral/[www.google.com][54121].jpg -------------------------------------------------------------------------------- /data/train/neutral/[www.google.com][61303].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/neutral/[www.google.com][61303].jpg -------------------------------------------------------------------------------- /data/train/neutral/[www.google.com][65962].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/neutral/[www.google.com][65962].jpg -------------------------------------------------------------------------------- /data/train/neutral/[www.google.com][76361].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/neutral/[www.google.com][76361].jpg -------------------------------------------------------------------------------- /data/train/political/[www.google.com][10805].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/political/[www.google.com][10805].jpg -------------------------------------------------------------------------------- /data/train/political/[www.google.com][16483].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/political/[www.google.com][16483].jpg -------------------------------------------------------------------------------- /data/train/political/[www.google.com][25429].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/political/[www.google.com][25429].jpg -------------------------------------------------------------------------------- /data/train/political/[www.google.com][440].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/political/[www.google.com][440].jpg -------------------------------------------------------------------------------- /data/train/political/[www.google.com][44315].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/political/[www.google.com][44315].jpg -------------------------------------------------------------------------------- /data/train/political/[www.google.com][466].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/political/[www.google.com][466].jpg -------------------------------------------------------------------------------- /data/train/political/[www.google.com][47135].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/political/[www.google.com][47135].jpg -------------------------------------------------------------------------------- /data/train/political/[www.google.com][49474].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/political/[www.google.com][49474].jpg -------------------------------------------------------------------------------- /data/train/political/[www.google.com][59870].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/political/[www.google.com][59870].jpg -------------------------------------------------------------------------------- /data/train/political/[www.google.com][61954].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/political/[www.google.com][61954].jpg -------------------------------------------------------------------------------- /data/train/political/[www.google.com][64658].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/political/[www.google.com][64658].jpg -------------------------------------------------------------------------------- /data/train/political/[www.google.com][67184].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/political/[www.google.com][67184].jpg -------------------------------------------------------------------------------- /data/train/political/[www.google.com][67735].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/political/[www.google.com][67735].jpg -------------------------------------------------------------------------------- /data/train/political/[www.google.com][68523].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/political/[www.google.com][68523].jpg -------------------------------------------------------------------------------- /data/train/political/[www.google.com][82199].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/political/[www.google.com][82199].jpg -------------------------------------------------------------------------------- /data/train/political/[www.google.com][86551].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/political/[www.google.com][86551].jpg -------------------------------------------------------------------------------- /data/train/political/[www.google.com][89140].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/political/[www.google.com][89140].jpg -------------------------------------------------------------------------------- /data/train/political/[www.google.com][91976].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/political/[www.google.com][91976].jpg -------------------------------------------------------------------------------- /data/train/political/[www.google.com][96367].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/political/[www.google.com][96367].jpg -------------------------------------------------------------------------------- /data/train/political/[www.google.com][98553].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/political/[www.google.com][98553].jpg -------------------------------------------------------------------------------- /data/train/porn/153142_10big.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/porn/153142_10big.jpg -------------------------------------------------------------------------------- /data/train/porn/171865_14big.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/porn/171865_14big.jpg -------------------------------------------------------------------------------- /data/train/porn/184860_06big.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/porn/184860_06big.jpg -------------------------------------------------------------------------------- /data/train/porn/19bac.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/porn/19bac.jpg -------------------------------------------------------------------------------- /data/train/porn/1a5ne.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/porn/1a5ne.jpg -------------------------------------------------------------------------------- /data/train/porn/1h1gh.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/porn/1h1gh.jpg -------------------------------------------------------------------------------- /data/train/porn/200178_12big.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/porn/200178_12big.jpg -------------------------------------------------------------------------------- /data/train/porn/212515_16big.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/porn/212515_16big.jpg -------------------------------------------------------------------------------- /data/train/porn/221891_12big.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/porn/221891_12big.jpg -------------------------------------------------------------------------------- /data/train/porn/226563_04big.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/porn/226563_04big.jpg -------------------------------------------------------------------------------- /data/train/porn/267359_12big.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/porn/267359_12big.jpg -------------------------------------------------------------------------------- /data/train/porn/[www.google.com][10382].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/porn/[www.google.com][10382].jpg -------------------------------------------------------------------------------- /data/train/porn/[www.google.com][16973].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/porn/[www.google.com][16973].jpg -------------------------------------------------------------------------------- /data/train/porn/[www.google.com][18585].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/porn/[www.google.com][18585].jpg -------------------------------------------------------------------------------- /data/train/porn/[www.google.com][23921].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/porn/[www.google.com][23921].jpg -------------------------------------------------------------------------------- /data/train/porn/[www.google.com][27032].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/porn/[www.google.com][27032].jpg -------------------------------------------------------------------------------- /data/train/porn/[www.google.com][36956].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/porn/[www.google.com][36956].jpg -------------------------------------------------------------------------------- /data/train/porn/[www.google.com][45609].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/porn/[www.google.com][45609].jpg -------------------------------------------------------------------------------- /data/train/porn/[www.google.com][61230].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/porn/[www.google.com][61230].jpg -------------------------------------------------------------------------------- /data/train/porn/[www.google.com][78657].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/porn/[www.google.com][78657].jpg -------------------------------------------------------------------------------- /data/train/terrorism/[www.google.com][11335].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/terrorism/[www.google.com][11335].jpg -------------------------------------------------------------------------------- /data/train/terrorism/[www.google.com][14589].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/terrorism/[www.google.com][14589].jpg -------------------------------------------------------------------------------- /data/train/terrorism/[www.google.com][17398].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/terrorism/[www.google.com][17398].jpg -------------------------------------------------------------------------------- /data/train/terrorism/[www.google.com][19339].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/terrorism/[www.google.com][19339].jpg -------------------------------------------------------------------------------- /data/train/terrorism/[www.google.com][24555].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/terrorism/[www.google.com][24555].jpg -------------------------------------------------------------------------------- /data/train/terrorism/[www.google.com][27220].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/terrorism/[www.google.com][27220].jpg -------------------------------------------------------------------------------- /data/train/terrorism/[www.google.com][32867].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/terrorism/[www.google.com][32867].jpg -------------------------------------------------------------------------------- /data/train/terrorism/[www.google.com][36935].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/terrorism/[www.google.com][36935].jpg -------------------------------------------------------------------------------- /data/train/terrorism/[www.google.com][3791].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/terrorism/[www.google.com][3791].jpg -------------------------------------------------------------------------------- /data/train/terrorism/[www.google.com][40227].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/terrorism/[www.google.com][40227].jpg -------------------------------------------------------------------------------- /data/train/terrorism/[www.google.com][44667].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/terrorism/[www.google.com][44667].jpg -------------------------------------------------------------------------------- /data/train/terrorism/[www.google.com][46334].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/terrorism/[www.google.com][46334].jpg -------------------------------------------------------------------------------- /data/train/terrorism/[www.google.com][46470].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/terrorism/[www.google.com][46470].jpg -------------------------------------------------------------------------------- /data/train/terrorism/[www.google.com][5399].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/terrorism/[www.google.com][5399].jpg -------------------------------------------------------------------------------- /data/train/terrorism/[www.google.com][54032].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/terrorism/[www.google.com][54032].jpg -------------------------------------------------------------------------------- /data/train/terrorism/[www.google.com][59852].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/terrorism/[www.google.com][59852].jpg -------------------------------------------------------------------------------- /data/train/terrorism/[www.google.com][601].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/terrorism/[www.google.com][601].jpg -------------------------------------------------------------------------------- /data/train/terrorism/[www.google.com][6719].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/terrorism/[www.google.com][6719].jpg -------------------------------------------------------------------------------- /data/train/terrorism/[www.google.com][7041].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/terrorism/[www.google.com][7041].jpg -------------------------------------------------------------------------------- /data/train/terrorism/[www.google.com][76135].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/train/terrorism/[www.google.com][76135].jpg -------------------------------------------------------------------------------- /data/validation/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/validation/.DS_Store -------------------------------------------------------------------------------- /data/validation/neutral/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/validation/neutral/.DS_Store -------------------------------------------------------------------------------- /data/validation/neutral/[pic.sogou.com][197]d52704b61c70ae76-8a6775c3c4e1c205-368ce5700c4a0097a128a1130f24f882.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/validation/neutral/[pic.sogou.com][197]d52704b61c70ae76-8a6775c3c4e1c205-368ce5700c4a0097a128a1130f24f882.jpg -------------------------------------------------------------------------------- /data/validation/neutral/[www.google.com][1989].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/validation/neutral/[www.google.com][1989].jpg -------------------------------------------------------------------------------- /data/validation/neutral/[www.google.com][396].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/validation/neutral/[www.google.com][396].jpg -------------------------------------------------------------------------------- /data/validation/political/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/validation/political/.DS_Store -------------------------------------------------------------------------------- /data/validation/political/[www.google.com][10805].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/validation/political/[www.google.com][10805].jpg -------------------------------------------------------------------------------- /data/validation/political/[www.google.com][440].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/validation/political/[www.google.com][440].jpg -------------------------------------------------------------------------------- /data/validation/political/[www.google.com][466].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/validation/political/[www.google.com][466].jpg -------------------------------------------------------------------------------- /data/validation/porn/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/validation/porn/.DS_Store -------------------------------------------------------------------------------- /data/validation/porn/[www.google.com][10382].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/validation/porn/[www.google.com][10382].jpg -------------------------------------------------------------------------------- /data/validation/porn/[www.google.com][16973].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/validation/porn/[www.google.com][16973].jpg -------------------------------------------------------------------------------- /data/validation/porn/[www.google.com][18585].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/validation/porn/[www.google.com][18585].jpg -------------------------------------------------------------------------------- /data/validation/terrorism/[www.google.com][3791].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/validation/terrorism/[www.google.com][3791].jpg -------------------------------------------------------------------------------- /data/validation/terrorism/[www.google.com][5399].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/validation/terrorism/[www.google.com][5399].jpg -------------------------------------------------------------------------------- /data/validation/terrorism/[www.google.com][601].jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/data/validation/terrorism/[www.google.com][601].jpg -------------------------------------------------------------------------------- /log/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xqtbox/generalImageClassification/10652ec9db4e13b9e319d15284add3e6441280a9/log/.DS_Store -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | import json 3 | import logging 4 | import timeit 5 | import flask as flask 6 | import predictWithMyModel 7 | 8 | ##### flask初始化 9 | ImageIllehalDetectionApp = flask.Flask(__name__) # __name__代表当前的python文件。把当前的python文件当做一个服务启动 10 | 11 | 12 | #### Hello World ! 13 | @ImageIllehalDetectionApp.route("/helloWorld") 14 | def helloWorld(): 15 | """ 16 | 当用户访问这个端口时,返回Hello World ! 17 | :return: 18 | """ 19 | return "图像内容违规检测,涉黄、涉政、涉恐,Hello World ! " 20 | 21 | 22 | #### 图片检测的接口 23 | @ImageIllehalDetectionApp.route("/image/detection", methods=['post']) 24 | def imageDetection(): 25 | """ 26 | 图片检测的接口 27 | """ 28 | imageBase64String = flask.request.values.get('imageBase64String')# 接收post参数 29 | if not imageBase64String : 30 | # 传入参数为空的错误控制 31 | ret = {} 32 | ret['code'] = "98" 33 | ret['message'] = "缺少必要传入参数" 34 | logger.info(ret) 35 | return json.dumps(ret, ensure_ascii=True) 36 | 37 | 38 | startTime = timeit.default_timer() # 记录开始时间 39 | code, msg, predictedClass, probability = predictWithMyModel.predictWithImageBase64(imageBase64String) # 查询数据 40 | endTime = timeit.default_timer() # 记录 结束时间 41 | print('------------------- flask图片检测时间:', endTime - startTime, 's -------------------') 42 | logger.info('------------------- flask图片检测时间:{}s ------------------- '.format(endTime - startTime)) 43 | 44 | # 定义flask返回值ret的数据结构 45 | if code == '00': 46 | ret = {} 47 | ret['code'] = code 48 | if int(probability) < 0.75: 49 | predictedClass = "neutral" # 若盖里比较低说明,模型判断不准,就返回无违规 50 | ret['message'] = '图片检测成功,类别是:'+ str(predictedClass) 51 | ret['predictedClass'] = predictedClass 52 | ret['probability'] = str(probability) 53 | print(ret) 54 | logger.info(ret) 55 | return json.dumps(ret, ensure_ascii=True) 56 | elif code == '98': 57 | ret = {} 58 | ret['code'] = code 59 | ret['message'] = '图片检测失败,原因是:'+str(msg) 60 | logger.info(ret) 61 | return json.dumps(ret, ensure_ascii=True) 62 | 63 | 64 | 65 | 66 | 67 | if __name__ == '__main__': 68 | # 配置日志 69 | logger = logging.getLogger(__name__) 70 | logging.basicConfig(filename='./log/log_my_image.log', level=logging.INFO, format='%(asctime)s - %(filename)s - %(levelname)s - %(message)s') 71 | 72 | 73 | ##### flask初始化 74 | ImageIllehalDetectionApp.run( 75 | port=8133, 76 | debug=False, 77 | threaded=False, 78 | host='0.0.0.0' 79 | ) 80 | 81 | -------------------------------------------------------------------------------- /predictWithMyModel.py: -------------------------------------------------------------------------------- 1 | import timeit 2 | import numpy as np 3 | import base64 4 | from io import BytesIO 5 | import logging 6 | from keras.models import load_model 7 | from keras.preprocessing import image 8 | from keras import backend as K 9 | from PIL import ImageFile 10 | ImageFile.LOAD_TRUNCATED_IMAGES = True 11 | 12 | 13 | if K.image_data_format() == 'channels_first': 14 | input_shape = (3, 224, 224) 15 | else: 16 | input_shape = (224, 224, 3) 17 | 18 | ## 定义log 19 | logger = logging.getLogger(__name__) 20 | 21 | # 返回一个编译好的模型 22 | # 与之前那个相同 23 | print("开始加载模型:") 24 | logger.info("开始加载模型") 25 | starttime = timeit.default_timer() 26 | model = load_model('data/modelFile/my_model02.h5') 27 | endtime = timeit.default_timer() 28 | print("模型加载完成,用时为:", endtime - starttime) 29 | logger.info("模型加载完成,用时为:%s", endtime - starttime) 30 | 31 | 32 | 33 | 34 | def predictWithImagePath(img_path): 35 | """ 36 | 根据输入图像path,来分析图像,并作出分类。 37 | :param img_path:图像路径 38 | :return:图像的类别 39 | """ 40 | # 加载图像 41 | img = image.load_img(img_path, target_size = input_shape) 42 | # 图像预处理 43 | x = image.img_to_array(img) / 255.0 # 与训练一致 44 | x = np.expand_dims(x, axis=0) 45 | 46 | # 对图像进行分类 47 | preds = model.predict(x) # Predicted: [[1.0000000e+00 1.4072199e-33 1.0080164e-22 3.4663230e-32]] 48 | print('Predicted:', preds) # 输出预测概率 49 | predicted_class_indices = np.argmax(preds,axis=1) 50 | print('predicted_class_indices:', predicted_class_indices) # 输出预测类别的int 51 | 52 | labels = {'neutral': 0, 'political': 1, 'porn': 2, 'terrorism': 3} 53 | labels = dict((v, k) for k, v in labels.items()) 54 | predicted_class = labels[predicted_class_indices[0]] 55 | # predictions = [labels[k] for k in predicted_class_indices] 56 | print("predicted_class :", predicted_class) 57 | return predicted_class, preds[0][predicted_class_indices[0]] 58 | 59 | def predictWithImageBase64(imageBase64String): 60 | """ 61 | 根据输入图像Base64,来分析图像,并作出分类。 62 | :param ImageBase64:图像Base64编码 63 | :return:图像的类别 64 | """ 65 | try: 66 | # 加载图像 base64 67 | imageBase64String = imageBase64String.split(',') 68 | if (len(imageBase64String) > 1): 69 | imageBase64String = imageBase64String[1] 70 | else: 71 | imageBase64String = imageBase64String[0] 72 | 73 | imageBinaryData = base64.b64decode(imageBase64String) # 解码base64 74 | imageData = BytesIO(imageBinaryData) # 在内存中读取 75 | 76 | img = image.load_img(imageData, target_size = input_shape)# 读取图片,并压缩至指定大小 77 | # 图像预处理 78 | x = image.img_to_array(img) / 255.0 # 与训练一致 79 | x = np.expand_dims(x, axis=0) 80 | except: 81 | return "98", "失败,解析 imageBase64String 参数的过程失败。",0,0 82 | 83 | 84 | # 对图像进行分类 85 | try: 86 | preds = model.predict(x) # Predicted: [[1.0000000e+00 1.4072199e-33 1.0080164e-22 3.4663230e-32]] 87 | except: 88 | return "98", "失败,模型运行失败。",0,0 89 | print('Predicted:', preds) # 输出预测概率 90 | logger.info('Predicted:%s', preds) 91 | predicted_class_indices = np.argmax(preds,axis=1) 92 | print('predicted_class_indices:', predicted_class_indices) # 输出预测类别的int 93 | logger.info('predicted_class_indices:%s', predicted_class_indices) 94 | 95 | labels = {'neutral': 0, 'political': 1, 'porn': 2, 'terrorism': 3} 96 | labels = dict((v, k) for k, v in labels.items()) 97 | predicted_class = labels[predicted_class_indices[0]] 98 | # predictions = [labels[k] for k in predicted_class_indices] 99 | print("predicted_class :", predicted_class) 100 | logger.info('predicted_class:%s', predicted_class) 101 | 102 | return "00", "成功",predicted_class,preds[0][predicted_class_indices[0]] 103 | 104 | 105 | if __name__ == '__main__': 106 | img_path_list = [ 107 | "data/validation/neutral/[www.google.com][1989].jpg", # neutral 108 | "data/validation/neutral/[www.google.com][12706].jpg", # neutral 109 | "data/validation/neutral/[www.google.com][396].jpg", # neutral 110 | "data/validation/neutral/[www.google.com][18507].jpg", # neutral 111 | "data/validation/political/[www.google.com][49474].jpg", # political 112 | "data/validation/political/[www.google.com][96367].jpg", # political 113 | "data/validation/porn/184860_06big.jpg", # porn 114 | "data/validation/porn/[www.google.com][23921].jpg", # porn 115 | "data/validation/terrorism/[www.google.com][76135].jpg", # terrorism 116 | "data/validation/terrorism/[www.google.com][46334].jpg", # terrorism 117 | ] 118 | print("开始预测:") 119 | for i in img_path_list: 120 | starttime = timeit.default_timer() 121 | print(predictWithImagePath(i)) 122 | endtime = timeit.default_timer() 123 | print("单次调用模型预测时间为:", endtime - starttime) 124 | 125 | 126 | # 使用base64 处理 127 | base64String = "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" 128 | starttime = timeit.default_timer() 129 | print(predictWithImageBase64(base64String)) 130 | endtime = timeit.default_timer() 131 | print("单次调用模型预测时间为:", endtime - starttime) -------------------------------------------------------------------------------- /reTrainMyDataWithKerasModel.py: -------------------------------------------------------------------------------- 1 | from keras.preprocessing.image import ImageDataGenerator 2 | from keras.preprocessing import image 3 | from keras.models import load_model 4 | from keras.optimizers import RMSprop 5 | from keras import backend as K 6 | import numpy as np 7 | import timeit 8 | from PIL import ImageFile 9 | ImageFile.LOAD_TRUNCATED_IMAGES = True 10 | 11 | print("本py用来构建在老模型的基础上再训练。") 12 | 13 | 14 | 15 | ### 超参数: 16 | # dimensions of InceptionV3. 17 | old_model_path = "data/modelFile/my_model02.h5" # 你要在哪个模型的基础上训练? 18 | new_model_path = "data/modelFile/my_model03.h5" # 新模型存储到哪里? 19 | img_width, img_height = 224, 224 # 20 | train_data_dir = 'data/train' 21 | validation_data_dir = 'data/validation' 22 | nb_train_samples = 8571 23 | nb_validation_samples = 80 24 | epochs = 10 # 图像的轮数 25 | batch_size = 32 # 每个batch32张图片 26 | learning_rate = 0.0001 # 如果在原有图片的基础上再训练,为防治过拟合,建议设置小一点:0.0001 27 | # 如果是新的图片数据,且比较重要,建议设置:0.001 甚至更高:0.002 28 | 29 | 30 | if K.image_data_format() == 'channels_first': 31 | input_shape = (3, img_width, img_height) 32 | else: 33 | input_shape = (img_width, img_height, 3) 34 | 35 | ### 返回一个编译好的模型 36 | print("开始加载模型:") 37 | starttime = timeit.default_timer() 38 | model = load_model(old_model_path) 39 | endtime = timeit.default_timer() 40 | print("模型加载完成,用时为:", endtime - starttime) 41 | 42 | # 让我们可视化层名称和层索引以查看有多少层 43 | print("打印old模型结构:") 44 | for i, layer in enumerate(model.layers): 45 | print(i, layer.name) # 311层 + 2 dense 46 | 47 | # 我们选择训练 top 2 个dense块,即我们将冻结前311层(锁住所有 InceptionV3 的卷积层),其余的解冻: 48 | for layer in model.layers[:-2]: 49 | layer.trainable = False 50 | for layer in model.layers[-2:]: 51 | layer.trainable = True 52 | 53 | ## 我们需要重新编译模型以使这些修改生效 54 | # 注意:(一定要在锁层以后操作) 55 | # 我们使用的学习率较低,微调 56 | model.compile(optimizer=RMSprop(lr = learning_rate), loss='categorical_crossentropy',metrics=["accuracy"]) 57 | 58 | ### 数据集 59 | # 这是我们将用于训练的扩充配置 60 | train_datagen = ImageDataGenerator( 61 | rescale=1. / 255, 62 | shear_range=0.2, # 用来进行剪切变换的程度 63 | zoom_range=0.2, # 用来进行随机的放大 64 | horizontal_flip=True) # 随机的对图片进行水平翻转 65 | # 这是我们将用于测试的扩充配置: 66 | valid_datagen = ImageDataGenerator(rescale=1. / 255)# 仅缩放 67 | 68 | # 这是一个生成器,将读取在“train_data_dir”子文档中找到的图片,并无限期地生成一批增强图像数据 69 | train_generator = train_datagen.flow_from_directory( # 使用.flow_from_directory()来从我们的jpgs图片中直接产生数据和标签。 70 | train_data_dir, 71 | target_size=(img_width, img_height), # 所有图像将调整为224x224 72 | batch_size=batch_size, 73 | class_mode='categorical', 74 | # classes = ["neutral","political","porn","terrorism"] 75 | ) 76 | print(train_generator.class_indices) #{'neutral': 0, 'political': 1, 'porn': 2, 'terrorism': 3} 77 | 78 | 79 | validation_generator = valid_datagen.flow_from_directory( 80 | validation_data_dir, 81 | target_size=(img_width, img_height), 82 | batch_size=batch_size, 83 | class_mode='categorical', 84 | # classes = ["neutral","political","porn","terrorism"] 85 | ) 86 | print(validation_generator.class_indices) # {'neutral': 0, 'political': 1, 'porn': 2, 'terrorism': 3} 87 | 88 | # 在新的数据集上训练几代 89 | print("开始训练:") 90 | model.fit_generator( 91 | train_generator, 92 | steps_per_epoch = nb_train_samples // batch_size, # 一个 epoch 完成并开始下一个 epoch 之前,如果未指定,将使用len(generator) 作为步数。 93 | epochs = epochs, 94 | validation_data = validation_generator, 95 | validation_steps = nb_validation_samples // batch_size) 96 | 97 | print("开始validation") 98 | 99 | 100 | ## 保存模型 101 | model.save(new_model_path) # 创建 HDF5 文件 'my_model01.h5' 102 | print("保存模型成功。") 103 | 104 | 105 | ### 使用模型预测: 106 | print("使用模型预测:-----------") 107 | img_path = 'data/validation/neutral/[www.google.com][1989].jpg' # neutral 2 108 | # 加载图像 109 | img = image.load_img(img_path, target_size = input_shape) 110 | # 图像预处理 111 | x = image.img_to_array(img) 112 | x = np.expand_dims(x, axis=0) 113 | 114 | # 对图像进行分类 115 | preds = model.predict(x) # Predicted: [[1.0000000e+00 1.4072199e-33 1.0080164e-22 3.4663230e-32]] 116 | classes = np.argmax(preds,axis=1) 117 | # 输出预测概率 118 | print('Predicted:', preds) 119 | print('classes:', classes) 120 | -------------------------------------------------------------------------------- /trainMyDataWithKerasModel.py: -------------------------------------------------------------------------------- 1 | from keras.applications.inception_v3 import InceptionV3 2 | from keras.preprocessing.image import ImageDataGenerator 3 | from keras.preprocessing import image 4 | from keras.models import Model 5 | from keras.layers import Dense, GlobalAveragePooling2D 6 | from keras import backend as K 7 | import numpy as np 8 | from PIL import ImageFile 9 | ImageFile.LOAD_TRUNCATED_IMAGES = True 10 | 11 | ### 超参数: 12 | # dimensions of InceptionV3. 13 | img_width, img_height = 224, 224 # 14 | 15 | train_data_dir = 'data/train' 16 | validation_data_dir = 'data/validation' 17 | nb_train_samples = 8571 18 | nb_validation_samples = 80 19 | epochs = 20 20 | batch_size = 32 21 | 22 | 23 | if K.image_data_format() == 'channels_first': 24 | input_shape = (3, img_width, img_height) 25 | else: 26 | input_shape = (img_width, img_height, 3) 27 | 28 | 29 | 30 | 31 | # 构建不带分类器的预训练模型 32 | base_model = InceptionV3(weights='imagenet', include_top=False) 33 | 34 | # 添加全局平均池化层 35 | x = base_model.output 36 | x = GlobalAveragePooling2D()(x) 37 | 38 | # 添加一个全连接层 39 | x = Dense(512, activation='relu')(x) 40 | 41 | # 添加一个分类器,假设我们有4个类 42 | predictions = Dense(4, activation='softmax')(x) 43 | 44 | # 构建我们需要训练的完整模型 45 | model = Model(inputs=base_model.input, outputs=predictions) 46 | 47 | # 首先,我们只训练顶部的几层(随机初始化的层) 48 | # 锁住所有 InceptionV3 的卷积层 49 | for layer in base_model.layers: 50 | layer.trainable = False 51 | 52 | # 编译模型(一定要在锁层以后操作) 53 | model.compile(optimizer='rmsprop', loss='categorical_crossentropy',metrics=["accuracy"]) 54 | 55 | 56 | ### 数据集 57 | ## 扩充数据集 58 | # 这是我们将用于训练的扩充配置 59 | train_datagen = ImageDataGenerator(rescale=1. / 255, # 预测的时候,特征也要这么处理 60 | shear_range=0.2, # 用来进行剪切变换的程度 61 | zoom_range=0.2, # 用来进行随机的放大 62 | horizontal_flip=True) # 随机的对图片进行水平翻转 63 | # 这是我们将用于测试的扩充配置: 64 | valid_datagen = ImageDataGenerator(rescale=1. / 255)# 仅缩放 65 | 66 | # 这是一个生成器,将读取在“train_data_dir”子文档中找到的图片,并无限期地生成一批增强图像数据 67 | train_generator = train_datagen.flow_from_directory( # 使用.flow_from_directory()来从我们的jpgs图片中直接产生数据和标签。 68 | train_data_dir, 69 | target_size=(img_width, img_height), # 所有图像将调整为224x224 70 | batch_size=batch_size, 71 | class_mode='categorical', 72 | # classes = ["neutral","political","porn","terrorism"] 73 | ) 74 | print(train_generator.class_indices) #{'neutral': 0, 'political': 1, 'porn': 2, 'terrorism': 3} 75 | 76 | 77 | validation_generator = valid_datagen.flow_from_directory( 78 | validation_data_dir, 79 | target_size=(img_width, img_height), 80 | batch_size=batch_size, 81 | class_mode='categorical', 82 | ) 83 | print(validation_generator.class_indices) # 输出生成的label名称 {'neutral': 0, 'political': 1, 'porn': 2, 'terrorism': 3} 84 | 85 | ### 在新的数据集上训练几代 86 | print("开始训练:") 87 | model.fit_generator( 88 | train_generator, 89 | steps_per_epoch = nb_train_samples // batch_size, # 一个 epoch 完成并开始下一个 epoch 之前,如果未指定,将使用len(generator) 作为步数。 90 | epochs = epochs, 91 | validation_data = validation_generator, 92 | validation_steps = nb_validation_samples // batch_size) 93 | 94 | 95 | 96 | ## 保存模型 97 | model.save('data/modelFile/my_model.h5') # 创建 HDF5 文件 'my_model01.h5' 98 | print("保存模型成功。") 99 | 100 | # del model # 删除现有模型 101 | 102 | # 返回一个编译好的模型 103 | # 与之前那个相同 104 | ### model = load_model('data/modelFile/my_model01.h5') 105 | 106 | 107 | ### 使用模型预测: 108 | print("使用模型预测:-----------") 109 | img_path = 'data/validation/neutral/[www.google.com][1989].jpg' # neutral 2 110 | # 加载图像 111 | img = image.load_img(img_path, target_size = input_shape) 112 | # 图像预处理 113 | x1 = image.img_to_array(img) / 255.0 # 与训练一致 114 | x1 = np.expand_dims(x1, axis=0) 115 | 116 | # 对图像进行分类 117 | preds = model.predict(x1) # Predicted: [[1.0000000e+00 1.4072199e-33 1.0080164e-22 3.4663230e-32]] 118 | print('Predicted:', preds) # 输出预测概率 119 | predicted_class_indices = np.argmax(preds,axis=1) 120 | print('predicted_class_indices:', predicted_class_indices) # 输出预测类别的int 121 | 122 | labels = {'neutral': 0, 'political': 1, 'porn': 2, 'terrorism': 3} 123 | labels = dict((v, k) for k, v in labels.items()) 124 | predicted_class = labels[predicted_class_indices[0]] 125 | # predictions = [labels[k] for k in predicted_class_indices] 126 | print("predicted_class :", predicted_class) 127 | -------------------------------------------------------------------------------- /utils/image2Bash64.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import base64 3 | 4 | 5 | 6 | 7 | 8 | 9 | def Image2Base64(imagePath = '../data/validation/neutral/[www.google.com][1989].jpg'): 10 | ''' 11 | :desc 用户给出图片路径,将其转化为bash64形式 12 | :param imagePath: 13 | :return: 14 | ''' 15 | with open(imagePath,'rb') as f: 16 | imageda = f.read() 17 | Base64 = base64.b64encode(imageda).decode("utf8") 18 | print(Base64) 19 | return Base64 20 | 21 | 22 | 23 | def base64ToImage(base64String, imagePath ): 24 | """ 25 | decrib :用户发过来图片的bash64形式字符串,函数读取后返回出去。 26 | :param base64String: 27 | :param imageName: 28 | :return:imageData 29 | """ 30 | imageData = base64.b64decode(base64String) 31 | with open(imagePath,'wb') as f: 32 | f.write(imageData) 33 | return imagePath 34 | 35 | 36 | 37 | 38 | if __name__ == '__main__': 39 | Base64String = Image2Base64(imagePath = '../data/train/neutral/[www.google.com][219].jpg') 40 | Base64String = "/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBxMTEhUUEhQVFRUWGBgaGBgWGR0XGhoXFxUbGhgdGBgYHSggGholHRYXITEiJSkrMC4uGB8zODMtNygtLisBCgoKDg0OGxAQGyslHR0tLSsrLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS03LS0tLTcyN//AABEIAMIBAwMBIgACEQEDEQH/xAAcAAACAgMBAQAAAAAAAAAAAAAABQQGAgMHAQj/xABDEAABAwIEAgYHBQYFBQEBAAABAAIRAyEEEjFBBVEGEyJhcYEyQpGSobHRBxRS0vAVI2JyweEWM1SC8SRDU6KyRBf/xAAZAQEAAwEBAAAAAAAAAAAAAAAAAQIEAwX/xAAoEQACAgICAgIBBAMBAAAAAAAAAQIRAxIhMQRRE0EiFDJCcSNhwQX/2gAMAwEAAhEDEQA/AOGoQhACEIQAhCEAIQhACEIQAhCEAIQhACEIQAhCEAIQhACEIQAhCEAIQhACEIQAhCEAIQhACEIQAhCEAIXq8QAhCEAIQhACEIQAherxACF6hAeIQhACEIQAhCEAIQvUB4hCEAIQhACEIQAhCEAIQhACEIQH2lSw9MR2We636LM4VmzGe6PolP7RdMH4gTC30uIWUNFLJhFMa02+6PosM1L8DfdCxZVB5FYurBt9goJTJTWUj6jfdH0Xpo0/wM90KF98BAMyDcEbjujZan4tqhckvgluw7D6LGTyLR9FoqBoN2t8Mo+ijvxgG4Cw+/HWZ8VdJCzOs6kdabJ/latYwVF3/ab7FsGPk3DfMBbjiQNvYY+AU7IWRzwzD7jL5D6LV+xGTbJH8oUrrGHmF4ajBu6PZ8lKnRY1t4DTGpb7oUyhwWgPVDvIfKFHOJZqJWQx/wCgocmxYz+60wPQZ7o+i9FCn+Bnuj6JScYJuTfzWbeIMbqSFXVgbfdaf4Ge6PotFXA0z6jPdH0S+jxYyc0gcxEqbTxwIkOkfrVRTQNVXho2az3R/UKO/BHdlP3W/RSvvX/Kg1+KsDoL2zfmR9JRSYs308CzVzWDuDW/0WVXCU+TfdCj1cU0ntOB8/ovW4mnsRbmb/2UqXIsz+6U7wxnuj6LxuEZ+Bnf2R9EfeGneP1zWjEcRp0wS54AHOPqulojYl0sLSn0WR/K36L2pgWE9ljCeWQFVDH/AGg4JkzUDj3f2KVH7V8I09mVGxJ0BnDzNqdMf7W/Rb6XCxN2s9g+i59hPtawzjBMeNleuCcfZiG5mEEcwquQsY0+H0x6jT/tH0W37rT/AAM90fReurCJkRz2UCtxC3Yk+OkKqTZBNdh6Y9Rnuj6LEYemfUZH8oUYY1rhdxnkdlg3EtnW/wCue6tXANr+D0CZ6tvkI/oheioefxXicklTpcWaTp7VuqcQYBMEDu0SYOpD8PnBWqpWZF4jx09i5ucWcrHv7TF4v56IPEwJ0tG+xAP9fnyVfbXbsG85mwjcnkl+J4iHVCWH92GhgI9YAuLnDulxjwXDJnUUa/F8WWZ8fRso419GrUpNJFPPmaD6ragDhl5AZjbSyl9GeNvxFSHN9Fzb6SXDNEfyke0pIXE1JMwG02Zj62RmUvgaTylbcLkwrHCm5zqtVvZkAAdgMLrGwABibzss+LPTlyej5HitqCiv7N7ePOaWuc4ljjHeINjPhfwzchLmnizsfiqnicD1lMta5jIBAzE7iB6IJ0J84TDEY1lPK0fvHGABTDjNubgA3xJXfD5ClFcmPy/FlGf4ob4jj4pPY0tLszSQcwF2uh1r2h7fYto6RyCclQAHYAjTmIuqxWxrKzakNd+6NF4Lr/5hixHdE9xCm0C8ZTTaDU0GZ8AgTo03MknTeVzy5ZKdWafHwY54tnHkdv4/Sdu4f7J+RK0VekdOWtBfBIEimYGYgAEugXJASHh7CJubF05CLdsmASZAHo3Oi1cdxBbTIrMdo7LNTtaESAAALkNnm9Rhzyk6bLeR4uOEbSLDhukAqU2vY4wQMvZymNrKW3ik2aTNhbUn9bKt4Pg80xlIsBLRNraE6WW3hmHIr05HZDpJ/lBcde4Lb8kTxVbkl7H7uLNkttO8a9/mNxtIXreLxz/XPmqNxPFOzUnAnMXAnwe9xj2ZvJN887q2PInGzpmg8ctSw1OLN/Vj8F4zibeRy73j2pFH6F1rq1QN4hWc0cbY9xHGYHIW0OwVI6R9NhTkUxmPwB8efcknSrjzpFOmTfXw0+KScLo5sTSa9pAJIgWuWm9+/mrJ2WswxXSzFuP+aW9zBlU/hnT7FU7Pd1je+x9u/mq5j6cPMaSoyoXOtf46FSkXhxGUXbyP63VA43x+pXN3OjYT8+ZSikT5HXl5rJ0vNlb6K1ya853JWK9c2F4lFgCtPQzpW/CVBLjkNjJ071Vl6FAPovh3SmjUALXAiNn5rzsNk2w/GmG942m6+ceDcVNF0yYG3zXRMLxBxa03AcGuEkixuNVZSS7IOn1OMNO9vC093evRxRg2nvN1zz70ZEH4DXxRUxnOdfD+qutSrkdG/bbd3PHg4NHsQuafeucoU0iLGNSk06WWo4dw0P69im4unTaYaSR7PkVpkbFeNsVI2KwxdTycnZwCLPIEBrydtY7ytP31rHU2upuJfEtuHNJFhFtLknbsjU2ZtcYcAA52VwbOz47J5a80qoPqVgHmo+SLloawwNQSGyIVJ69tHr+DLLKDjBkyrSIq5YhpDC0DWHDQzoZB+C0moM7gBZsaHNEtuHHSQZ8oWNCgGHd1g49rMSNr35FbuEYt9QuEAsDgBlAzA5bgA+pBG8kid4XOOPe6R6mTyPhUdndnhdJrNyAdXTLw4kxIcABc6uOgA9YGSo2JxIkUgO2+0k92YgDY5Yv/ABaLOkx0CnVcahouI7J9MsuNNXHlsSo/DcGalV9Z0WOUTJ9K7nD/ANQO5oXTHGF36Mnl5p48ff7iZw/BGnh6oce05ud0C2YPaYmNADbuCm4XOWEBxa0yCQBIAgyXHQAutebmNEU8GS17WQC9paC6cokgmTtYKO6rTinoc5MjtENblsXQNQfCZ7pMZE3Kyvgy/wATX3ZrwEZ6jWkPhzpce2HGcxcCPSkwVJ4zhqzWTDa+pyNptcWQCdIJuQGxeJPittPE4drcwpHsnIWNlrn7B7SDAGpvt4pdxNjA+r1IGUUzDgCO1lM3OqQ4ZpzJ5Itf8N+Ce9rG5icwAzbX3U3riylVqCQXDq27dp+u+zA4ylPR+kXNcJkmrUEX/HAhTOK4xrYAhzKNo2fVN6jgReGsB9w811lfSPF8bHeS30hYaY+9U8wbkaJuYnLTblA75fUNv6FPxiKAs6lfmHf2VfquNUOAlr2jPT5mm+S3XcX/APcbqXwfBkgONUmTdpaLHcSPJdFKkh5kfz2XTPcbXpFwFJ4bY+tm177eKUVOEh5DqlRzsoPZALWmb3jU358lajTbOgnmioRBEfFV+SmZDjHSPs4h7RYNIiOUA/1Wt1QtyPBuIOu8zr5Jj0vo/wDVO74Tbo3wBtXtObLA7L3Ofa3lMn+63xklAuouTVFaxVUVpcGBl9BJ77lLY5r6H4b0Vw4p3pN0jTXnPcuZ9P8Aol1LjUoNPV7j8J+ipHKm6NEvHlFWUVx8ltZIbab8lpT/AIBwmpUAcwWJDZ5nkO6xXSUqRyjHZ0QMJwmpU0gGRY7ymFPopW1dYfrnoukcO4GMOwTdxmTa08lG4pUEATqDqs3zSNPwJI5JiqRY4tOxK1Jt0gwjm1CSNd0spsLiABJOy0RdqzNJU6NmCID2zpmbPhN19BYfD0q4BaJBgNBG0W8oXBKvDajHNa4QSdOXiuq9D+NZaDA9wD6ZFtJa2ee8HzsuOU74VXY9xvRkCS0gdwFklxnD3MBhrXcoAlXfD4xtYS0zzhaamDaRouakzpPBCXRzN/WE+jHdB+q8V+fwps6IVtpFPgQgfiHfh+KBincmDxKhPB3a25/FvPjHcshS5sb5/wDK8+2YtSZ97P8ACPgtmK4U53ZbkZo97Q4Xz9rNldAvJ2ItaLqLTo20aPIJhheI1G9khj2/hexvtmJ+KlZKO2KSiR2GnmphhDsrIqOnPJL3GHEekWg/FeV8UJ6ugGUzALnsBJe1zRBaSbG0E6yDyUvEVKZactFtMmQCCSASImJHsSnC4ZtMF1dwgODmmcuUQGgTuDAkb92qJW3yen+qwpRXdGypXZSbABzZZa0G5IE5RaSS0E+7qXBbqFVhmq15bInK1uYOPdcR56X2slFfE0qLvvFWrnzSKeUE95Iy6EwO4CAE0qVKNOi+q0ljnQ4H0mgugZmt2cTHMTsr6argq/KhlbU+vo04/FCq0UHtyVHOloz5ocASM+gtLQ7btxJOkjN2XAN/y3NmBJLYOaXaNBJbpMASdSAg4XxaiHPc9zw+LEg3bJgM5ybk73MpzQ4pRecraozaQTHf8laa5qjNDyXjtR6CpiHH0LtrWHVi4DqYaTlmQA4vdczZnNHE3Ch1jSZDYbM3cMrS/wDlcZLN4c4clOrvaGdl+Qxd0gW3MzIHhHioTuDFpc+sYbSLZYSBDnOyszaZu04AADUzc3Rav66Oy82ai7fZtoYlwltFgpvzEOPc+C1zG7OIdMnczCV4w9a9tGmew30iN2yCT/uIDR/C0n1kz4hShrntdDy0MIJgQCYh205svONIJBC7heIY2s6gc3WRne5wy5tBb+GNNrIrdsplzR+NRj99k/HMdAqN9KlcRqafrt+AcO9qwq1oYX0j1YdGaDM5iIy3hsDMZ1gRIACk1cYKZpyCS9wAjSYJk91ioWN4WCG02F3VSZBFwCZytjX8M7NHeZrF8ps5488VjcZL+jPhNWo+mHucZe5zr8nOJaL6CFNe48ytZexoAygQAI+UbrfhcJXqBpbQc0P060tpixN+0RyValJukZEijdLuHZs1UE5m5bQPRNi6dZDsoj+JWPojjKVChQZXzANzPcGtLzme6dB4BM+K9DMXUaXHqmNIglr87oJ7Vmg93nurXguChtAdQ5hewQ1xbmBEDKSARJj4grdHbRJmjCuSLhuleHquDKfWd2am5gtpBcEg6S499YljeroU9HVapt4NZv5lPeE8OxXWZsTWFQCbBjWAcsobfY+1YcVw1BtZwrtBa6HMJE5THsVemb6co0zjnE+jgMuw7+sA1JGWfA6eScdEeJGjSazrWENqEGi4ZXjNq5jxrImx3XQuOYKmKYNMAgiddUk6BYSk9+KpOAz9Yxw7w9uX5hXU7TRylg0kmhbxvB4nM7rsTUZSkC7Q4AH0RGu6g4XCl0U6dZ1Vo5MMR3kldG4oKX3h4eQJsQbgjTyMKTiuG0abczR6Wp1Md0+Sraqiyxt8nMeK4EljmOGYbc5Vd6PcOIzPI9EwCdQNyNL3AV740BmMc/Yq7VfEzp3eNrG0yqqTqkVyQSlZC4q6XtJOa5gmxIEwSPBSeHUX1nEizN9O0dgP6lbOF4Flc536AkAEzpzjVWjC4UNAgCB3aDwXLJl14+zJky88EfhLatB0tJjcSSD9Fb8FxZrrGc0X5quVgeXkmPDsAWAVXi18vhzsq45tsnDkk3Q8GJC9VZxOPOYxJQtGzNOyKz0hw9Wq1opy3Ic1wZLgRlieV3C2yx4f94NcOqmGhsaBrTOXQ+tLr+RTHpKxxw7m0pJdA1jsk9oX0nTzSipwtwpU2U8QHAkWeL2a4uudrQLaxeJXKDUoUzzrHtXGhh7bTE7Ag9+ycvbgK1FwpYirSrFrsjqjDANriwkXmx0krnrOmBpNDKlIvcyO05xGl2mBvp+inXRvpFTxDocwMe2XAAlwIJ7RE6mT8VX4XBXQPejdKqxtWlWB62lVcHzcy6DM6kG5B79l50krU202msC5uezctnEbGDqBJTt1RpLjl7RiZ3gQInuCicRwbKoEtDdRuCMwg+iNf7rnGa+TZkWU3g/Fm0xkrUzUp6awWscCSB8DvonnRkH7uKbmm2nrNh/aBsI3+Cb1cEyG5aVIRFy2TY2HPb4rdgKZp0m0mk2BGkTJJtPiumXNGUeCboUO4dGI6wxkbS0I9CCSbbdkuVEdj5qP65ogk+k245TadLLqz6zjZ2XLpGs+PL/lIcd0dFTKQBAsZ3Bc5zvO49inDnX8hshbwvpHRp4c0qlJrxBYHB5ESDfLlMiCDHMKRwrE/e25OsJeMrnauJyOzDtOJJGaD4hvJbK3RkQ0MYG5S05ou7LEG3OCT/Mmg4Q1uIbiAGsyyDo3sFmUSNCQ691dzg+uw5WJMZwXE1DUqPqOzGo8lpBdmEyDawA/oFC4r0dxLsuZznwHATJsNxJtmvHsVtwXG6dao6nTqZi29haAbwd/JT+qgESZPh+oXL55x7Q2Yl4BwqrTpinWghuV1NxhxGYHM2/I8ualYrBPew0qILq1Tss5y4xM6gbztCnBkASdBz581cPs74O6XYl41tTnkfSd/T2qsLyTsGzoV9neHwQa+oBXxBuXvGbLpamDpFhOqccdoMqtyj0rRyM6A+N4PNNcQ/LUp8jmb5mCP/k+1IeIQCHR+7rdj+Wo49nwBcAO4leqki0StDDAtc3KO1aIGm4Nuaj8MrfdsWGH/LxDABJ/7jLgQbXBN+eUck4rjtyNXgO00cCQ74gnzVP6Z0c1IOgAt9FxOVzXAgjJ3yFWSNcXSsuOKrBzmicoaQTtpse5LekdcgtdU6tobdsOlxE8iJH9lW+BdJ8+Sni4DnC1TQOj8UaO+eyf4ro7JPVimGvMlz5cfG5IJ1AKys2RlfIupYgVGZhIaSY1A8QFTOCcXLeIVa1P1CyNw4NN/wBeCe9OMe3C0TTY4Z4AF733VN6DATUcYvAE91zHhZWSqLZk8jK7o6fxptaoczm0nUyB28pmDMX9vsWxrz1YZnz5REmxMDkkzajTSyuq4hppkwKXaaZ7oOX5LZgmBlMEZ737ZcSQdDB0PkqpKSOsMlqyJxJgyk9//KquNNyNk94pi5mD5/NIKom/s+p5BTGNHOc7JvROsAXs75HwBVtFo+S5tTrmm8OYe00zz8jHNWvhmNq4kgMpkR6Tnei3uEXJ7uWq45cDbsxOLbH+FZ1lRjAfSMX23M+QKtvFi1rAxtoAHkqzwANpYgQbtYSSf4uz8iVMxuOD3kSr4seqNGOGiK5iqUvdrqhe4qu3O6w15oXYmzJtEg3iDvlHO0aoqVBMR4gDae+FtLTF3R4Tpz15rYxotc/rvXmGAW4HhobWqVC1v7wXmDpEbwLzpyC1t4I7NSd2QWVHvtuHzbTSYsm8NA/X0Tbh3AnVWhwcA3S8k6naLWXaM5vovGDl0JiMrS4wABJNrxrKU8N4++vVDaTIo/icCSRN3EDQDl/VdJZ0NpZf3lQuBBlo7IIjQ7x4QlWN4JRo4Z7qBlj30y0tMZSJsI0GwHKy7QwqMbkXWL2L8ZhywgOkiJGsFuoNx8FHI5A+zu5rWypUAguc9rRDQ4CWga3329nmvHYh3J2nMLLKKvgpKr4JDqfOPNJeLcfw9Elrny7k05o57wFWOP8AG62IxAo4dzsvokD1jPazRqAq/wAa4fUp1S10FxgjLAmT+H1b2hasfirjZkUX9nSymWBzA4TIGYhunMCSqVxvpLXrjI5wy/wiJ5StTuj2Mb2eofvpBHtBhbOFcBqnEtpVG5C2HPDvwiD5z/VaI44Q5LDrhnRKuxlOvSqgVYDsjgRE6DN4K+CtbtESRcDYrV1gmJHgfkAsW1wBtzkC8+MaLDlyfJ2VJODotq1G0i9lNpIlz3BvZm+WdXRsuw4IMDQKcZQABFxA71yfozwxuLrupunKKbiT/FIDY8JUDiGDrYaoacuY9u7HFubkRGxXoeFhUo2uyk56HYuLUS6mcphze0097bhKzgqlSnVblID+2ybZXnURsQ4BwK5NxHpRjRQezrnOa5sGYmLzDokSDeVU28QxNOCaldgcJbLntsOUm48FufjyXZC8hH0E7o+57gS8NidBJMuJ8tVPodH8O1pbkBzAhxd2iQddVwDD9MMaz0cXWHi7N/8ASuPQf7RqvXinjamZj4a15ABa/QTEWPOLHuVZ4JJWWXkJsWdJeDihVfRcLNNnEQHNcJB7zBjxBUR1arTphtPEVMsGGTIFtp0AXYekfCcPVb11VsuptdDgC7KDr2R6XsO65zSwtKnVNQFvV5QRALS4xGaHaAzI5LHLHb4N0Mn4nJ+lLnioGvzEwHEuJJdmuCZuBGya4On1eFp5BDzLuZk6HutC24DB/tLirgQchLnOv6rABryJi3eukVeBspnq2sDnnQAew22srcLg5tN3JlH4P0ndT7WRxfEPAaTbxNuRjuTLG8afUBLabxbdpEeHcrk3oY/r6BcctJtN7nQJ/fEgNDuUMLo7ye5OXdG2G0zA+W471R46fAxSWts5FQwdSrdwLW7E9kE9w1cfBOaHRwOgvzOFoaN7W9FdXwPBqNG4ZLj6z4cb8+XgFuqRoIvb9eS74sP2zjlzXxE5thOiprObTIFJgbmdYSGZoENFpJB8gU94hgaWFpFtMABogAeGp5lTKWLNOoC45s9ItDogE0qjrwNJa74FVHpZxU5XTfX5LPnb2o04EtNios42WYlznHLLSLe0W3TPAcQLyXSCDvv5jmufY2qajzl19qsPA/3dMiCDNyTr5JrRG1sc4k9o3QktXFgky4fFCgFyq1wyJa68XvBBMSJ89lg2v7fwme7v/XNDQG3i084Glr7CI9myyfWgwWjSGmTmnSIdfc7heZZiYk6WcWdSptbS7L6joBBuB3eMwt/B+O4ilUdQzFlQtgNc4xIEtIOkGAN5nZecc4cajqTg3tNdItE5tDz757gpbsMC+o593OAEgiQByJtr8t1rjkjGKOkJ6kul0p4llLXU2iQYcXARIgGQYtqpuD4i7qcmJlji4/5MPY5xBLQGmCw7WkbkqKahdMloMbCL/LfZYtptlri3tNsCJLRaDAmx1uqPOy78hvs3lxBuIFiO8G4MG4MKLj8N1jXNBMHyNtraH6qSSNQSS4m8zB8NxvC153EEf02AMiZWdS/KzjtyQeFcJZQtSADjcv1J7pmw1FvPVQqfAWmqajWy9lZzrn02uaMonbKSY8k/DiSTAJuSNeQieX671m0ku0i95B5c+/vG4XZZmuy21Gmg0m9x3Hx7t0uHDCa5rkZTEC9yA2I8N00q1TeTf46xzutDczoABcdgASde75qinL6J2M20ATAuZm4i2n91oqNa08pHwPhpdPMH0ax1WCKeRp9aoQPOPS8oV56M9FWYZjs5bVe/0iW7bAA7LpjwSk+SKdlX+zarTpGq+pUaHPLWMzOAmJJiddRpyVj6T8Op4qlIOSqASwutaQCHfwm3tBTz9kUOrNPqmdWdW5RHs5pDV6O0qTgyiHszAz2nFsAzAbMC8bL0sS+NKvovopKmcn4hTyuIIgiQQbQQl9Su2pRNGsYAvSefUMejf1YgRykclfumfRo5XV2uzPHpiILgLTbUhc5rgGxEgjfwXpwyRyxMU8Msb5ETakSLW3G/gsw9Zfs6o6qGUmOqOPohozH2BbTw6sKZqOpuawPLCSNHiJHcbq9rpkKL7R137KemXXNGDxLpqNH7t59dg9U/xj4i+xULphwV9IVWNHZynqz/AAEknzBkeAC5TQrPpua9hLXtIc1w2I0hdlwPSD9q8OqhoH3ykx0sFpcQQC2fVdEjkVjzYqdo0Ysl8Mpv2PcHe+pVqs0BDS46Bov7b/BdlcxtOHS2bZiRJLYNgdlUOg9IYbhuHpts57TUqbHNUJcAfAFrfJS6uIMzMk7/ADjkqQxJ8k5Mr/aWHEceYLC5+Hx1WWCxweIAjkO79QqyxsmSpdOsfVtPxXbRHB5JMdV8VrNo+PMpZisWNR3yNNtlDrMcbTMX5rS+kCIJ5XV0qRVsj4xmYNjVpJHmTI85PmVXON8PztcPH5K0tcDMKDxKlcuve3w/sVk8nFf5I1ePmr8Wc5wnRwU3ZrHx5LLitgrPVp2sq3xWnfuWPZ/ZrpfRWKlMkkyEIrUyXEz8SvVJB0Xr41LrGdbEjQk6ERz1hYvqCYLI5XMkiNuepWT8RGpIOYdmfWkAS2ZjTnotTXhxJcTl56mxEakWvr3ALy6ZibHGB4Z1jA8kgnQECDJIGt9p+SyxvCYzBl3tAtAvJH1+Ch0OIVIhrg6CIJEn2uuN4EHu0Uipxh0gkta7MNoAtaDr6o9kq1mlPFr1yaeHYQVA7M6MsCB8zp+gmQ4SywDiMxse6OXh3pbhcW+kQRJB1zAZSRN5AmAJ05lZv4jUcXEhomNAd4uJvEm0/SRGN4lH8lyRc4AmNfCxEWI+KlYJoqtdLsuUgdkXMzIudDC10KLZbaYjU3zbzaIudLarNmIFHNLm5Tro4OiY8ZvcclWKbdI5Y9VO5dDFvDGh059ZIED0dAABGkAW/EoVLC1alQNykNBjORbSQBzmNORC01ONVgSSGsZENaQM0H8XIXNtblbOj3H6NPE9ZiGtfmHVioWyWC3PYxeOQXpQ/wDPk1tItkzYnJKKGOH4KxwNWq57mg5coIbP+5p0Hdort0dwlKm3NRptbnAcLAE66uFz4nuUhvD6BpxDSwiZG83BBHNbG0gxvZECmeyJ1HreV/gumPDoztLV/tRlXxlRurLc5/QS89I/3ZeGyGkg3Gxja3/O6euYHNjYjnB8iLpc/g9KIi2sEk/MrrJP6Jg4/wAjdg+IdZTD2xJE5SbxcbeCUO6QB5eMt2gHUbki8aaT5pvh8K2mOyLAWja5MeF0mxtIMf8A5TS11s0wWk5iQQbuBJ1F79yrKMqLQUdiJj8YH0z2XaD4gm3OLqiY/oRXLHVWZCwnstnK7LEzyF5Guy6NToNIMj42gDL8lhixkYWt0AIjxXOE5Q5O2TEpqmUbgnDjhmMcwuFV8ZyRdoM2HmNt55LHH4KwY52el1jnVpAh180eeWPCVOq42rftXAiIkTzvzv7SkHHsRXfh+rEBzrGBHcJ8BKr8k5SthKEI6pC6h0VpYp1SpRqtYzrCCxgkNAAmJIvJEbXU2nwOpwwnFUq5LqQJLS3KHszZS2ZNyRrsoGCx7sFRFOm4ZrySAZc7UneO5Qa/SLE1abqdWoHNfId2GgnMb3AWyHyy++DHKWGK65Ont4xSr0m1qR7LxZojskC4tuCo1LETuL3VG4HXbSZlboTJvurBhcaDvc/BakqPPk75LFSqDc7qQCUibjbwp9HFhSQhlmWD6YPzheUaw8VsMBCSG2kQe7ksnuG6lG61lmykgV4jhzXCW2J9n9lVuPcKqAegT4XHtCvDmRovAbLPPx4ydnbH5DjwzkD8A+dELrgaOXsCFT9Mjr+q/wBHz/X6R4l8ZqmmkNYN52ail0kxTdKp9jT8CEpQuOkfSOlIdM6V4wCBXcPJvwtYrKn0uxrTIruBPc3lH4UjQo+OHpChx/ijF69cZiJhsx45ZXp6U4v/AMzvMNP9EmQnxx9Imh2elmM/8zvY38vesT0oxcgms4kaSG28LJMhSoRXKRFDet0lxTvSrOPk36LUeO4j/wAh9g28ktQum0vZGq9Fpwf2h8TpU20qeKeGN9Fpax0eBc0mFv8A/wCn8Wv/ANW6/wDBT/IqehVLFxZ9qXFgIGMfA/gp/kQftS4sf/2P9yn+RU5CAuR+1Li3+sf7lP8AItNb7SeKOEOxTjefQp6+4qmhCbZa2/aPxMaYp3uU/wAixd9onEzrine6z8qqyFFIneXsfv6Z443Nd3us/KsHdLcYf+8fdb+VI0JSItjCvxqu8y6oSfAfRa/2pV/GfYPooaFZNoq0n2T28ZrjSofYPotrekOJGlV3sH0StCnZ+yNV6HDek+LGlZ3sb9Fm3pbjBpXd7G/RJEKNn7Gq9FgZ02x40xDvdb+VbR094j/qXe6z8qrSE2fsar0WX/HvEf8AUu91n5Uf494j/qXe6z8qrSFOz9jWPosh6ecQ/wBS73WflR/jviH+od7rPyqtoTZ+xrH0WL/HGP8A9Q73WflQq6hNn7GsfQIQhVLAhCEAIQhACEIQAhCEAIQhACEIQAhCEAIQhACEIQAhCEAIQhACEIQAhCEAIQhACEIQAhCEAIQhACEIQAhCEAIQhACEIQAhCEAIQhACEIQAhCEAIQhACEIQAhCEAIQhACEIQAhCEAIQhACEIQH/2Q==" 41 | # base64ToImage(Base64,"../data/validation/test.jpg") --------------------------------------------------------------------------------