一个简单的javascript库,帮助您快速识别不合适的图像。所有的这些都是在客户端上进行。本秘籍将以 react 为框架来搭建使用。如果你还不熟悉 react,请自行学习,本秘籍不再讲述 react,或者您也可以直接看代码进行学习并在自己的框架上进行尝试。

图像等级

  • Drawing - 安全的
  • Hentai - 变态色情的
  • Neutral - 中性的
  • Porn - 色情的
  • Sexy - 性感的

demo 搭建

  1. create-react-app
    • 确保本机全局已安装了 react-app
    • create-react-app myApp
  2. 将 github 项目上的 example/public/model 目录复制到本地 react 项目的 public 文件夹下。
    • model:这些文件是客户端图片鉴黄的基础文件和配置
  3. npm install —save @tensorflow/tfjs nsfwjs
  4. 修改 App.js 和 App.css

App.js

  1. /*
  2. * 图片鉴黄
  3. * 逻辑:
  4. * 0. 初始化时读取 public/model 中的 AI 数据
  5. * 1. 先将图片转化为 base64 码,在渲染出来之后,再进行下一步
  6. * 2. 将 img 节点导入到 nsfw model 中进行检测
  7. * */
  8. import React from 'react';
  9. import * as nsfwjs from 'nsfwjs';
  10. import './index.css';
  11. class App extends React.PureComponent {
  12. state = {
  13. nsfwModel: null,
  14. base64: null,
  15. predictions: null,
  16. message: 'Ready to Classify',
  17. };
  18. componentDidMount() {
  19. nsfwjs.load('/model/').then((model) => {
  20. this.setState({
  21. nsfwModel: model,
  22. });
  23. });
  24. }
  25. getPredictions = () => {
  26. // 使用定时器获取 img DOM,此时获取到的 dom 为拥有 base64 的图片节点
  27. setTimeout(() => {
  28. const { nsfwModel } = this.state;
  29. const img = document.getElementById('img');
  30. nsfwModel.classify(img).then((predictions) => {
  31. this.setState({
  32. predictions,
  33. message: `Identified as ${predictions[0].className}`,
  34. });
  35. });
  36. }, 60);
  37. };
  38. onChange = (e) => {
  39. this.reset();
  40. const that = this;
  41. const file = e.currentTarget.files[0];
  42. const reader = new FileReader();
  43. // eslint-disable-next-line
  44. reader.onload = (file) => {
  45. that.setState({
  46. base64: file.target.result,
  47. }, this.getPredictions);
  48. };
  49. reader.readAsDataURL(file);
  50. };
  51. reset = () => {
  52. this.setState({
  53. base64: null,
  54. predictions: null,
  55. });
  56. };
  57. render() {
  58. const { base64, predictions, message } = this.state;
  59. return (
  60. <React.Fragment>
  61. <div className="fileBox">
  62. <img id="img" className="img" src={base64} alt="" />
  63. <label className="fileBtn" htmlFor="file" />
  64. </div>
  65. <input
  66. id="file"
  67. type="file"
  68. className="hidden"
  69. onChange={this.onChange}
  70. accept="image/gif, image/jpeg, image/png,"
  71. />
  72. <div className="content">
  73. <div className="content_title">{message}</div>
  74. {predictions && predictions.map(item => (
  75. <div className="item" key={item.className}>
  76. {`${item.className} - ${(item.probability * 100).toFixed(2)}%`}
  77. </div>
  78. ))}
  79. </div>
  80. </React.Fragment>
  81. );
  82. }
  83. }
  84. export default App;

App.css 添加样式

  1. .hidden {
  2. display: none;
  3. }
  4. .fileBox {
  5. position: relative;
  6. margin: 0 auto;
  7. width: 400px;
  8. min-height: 400px;
  9. border: 5px dashed #000;
  10. }
  11. .fileBtn {
  12. top: 0;
  13. left: 0;
  14. position: absolute;
  15. width: 100%;
  16. height: 100%;
  17. cursor: pointer;
  18. z-index: 9;
  19. }
  20. .img {
  21. width: 100%;
  22. }
  23. .content {
  24. width: 350px;
  25. margin: 0 auto;
  26. padding-top: 30px;
  27. text-align: center;
  28. }
  29. .content_title {
  30. border-bottom: 2px solid #000;
  31. font-size: 30px;
  32. font-weight: bold;
  33. }
  34. .item {
  35. color: #e79f23;
  36. font-size: 25px;
  37. }
  1. npm start
    • 此时如果浏览器报错:tf.loadModel is not function 时,请将依赖 @tensorflow/tfjs 的版本调整至 0.15.1。

注意

请在 nsfwjs.load(‘/model/‘) 完全读取完成后才能进行图片分析,否则将会报错。所以建议在加载期间进行 loading 处理。本秘籍并没有做此功能,请自行添加。