当前位置: 首页 > ds >正文

内容安全:使用开源框架Caffe实现上传图片进行敏感内容识别

上传图片进行敏感内容识别

预览效果

preview-html

环境准备

  • Ubuntu 16.04
  • python 2.7.12
  • caffe 1.0.0

安装调试环境:

sudo apt-get update
sudo apt-get install -y --no-install-recommends build-essential cmake git wget libatlas-base-dev libboost-all-dev libgflags-dev
sudo apt-get install -y --no-install-recommends libgoogle-glog-dev libhdf5-serial-dev libleveldb-dev liblmdb-dev libopencv-dev
sudo apt-get install -y --no-install-recommends libprotobuf-dev libsnappy-dev protobuf-compiler python-dev python-numpy python-pip python-setuptools python-scipy 
sudo apt-get install -y --no-install-recommends libprotobuf-dev libsnappy-dev protobuf-compiler python-dev python-numpy python-pip python-setuptools python-scipy 
# /var/lib/apt/lists/ 这个目录中存储的是 Ubuntu 或其他基于 Debian 的 Linux 系统在执行 apt-get update 命令时从软件源获取的包列表信息。
rm -rf /var/lib/apt/lists/*

拉取 caffe 源码, 并编译好

sudo mkdir -p /opt/caffe && cd /opt/caffe
sudo git clone -b 1.0 --depth 1 https://github.com/BVLC/caffe.git . 
python -m pip install --upgrade pip==20.3.4
cd python 
for req in $(cat requirements.txt) pydot; do pip install $req; done
cd ..
mkdir build
cd build 
cmake -DCPU_ONLY=1 ..
make -j"$(nproc)"

测试是否正确编译

make runtest
# 测试输出示例, 列举了部分输出
Built target caffeproto
Built target caffe
Built target gtest
Built target test.testbin
Note: Google Test filter = -*GPU*
Note: Randomizing tests' orders with a seed of 5941 .
[==========] Running 1162 tests from 152 test cases.
[----------] Global test environment set-up.
[----------] 6 tests from FlattenLayerTest/1, where TypeParam = caffe::CPUDevice<double>
[ RUN      ] FlattenLayerTest/1.TestForward
[       OK ] FlattenLayerTest/1.TestForward (5 ms)
[ RUN      ] FlattenLayerTest/1.TestSetupWithAxis
[       OK ] FlattenLayerTest/1.TestSetupWithAxis (0 ms)
[ RUN      ] FlattenLayerTest/1.TestSetup
[       OK ] FlattenLayerTest/1.TestSetup (0 ms)
[ RUN      ] FlattenLayerTest/1.
[  PASSED  ] 1162 tests.
Built target runtest

编写 demo 使用

将编译好的 caffe 配置到环境中,供 python 导入使用

export CAFFE_ROOT="/opt/caffe-master"
export PYCAFFE_ROOT="$CAFFE_ROOT/python"
export PYTHONPATH="$PYCAFFE_ROOT:$PYTHONPATH" 
export PATH="$CAFFE_ROOT/build/tools:$PYCAFFE_ROOT:$PATH"

使用 python Flask 提供服务

#!/usr/bin/env python
from flask import Flask, request, jsonify
from flask_cors import CORS
import caffe
from PIL import Image
import numpy as np
import io
from werkzeug.utils import secure_filename
import base64app = Flask(__name__)
CORS(app)model_def = '/home/joe/open_nsfw-master/nsfw_model/deploy.prototxt'
pretrained_model = '/home/joe/open_nsfw-master/nsfw_model/resnet_50_1by2_nsfw.caffemodel'# Load the Caffe model
nsfw_net = caffe.Net(model_def, pretrained_model, caffe.TEST)# Configure the transformer for preprocessing
caffe_transformer = caffe.io.Transformer({'data': nsfw_net.blobs['data'].data.shape})
caffe_transformer.set_transpose('data', (2, 0, 1))  # move image channels to outermost
caffe_transformer.set_mean('data', np.array([104, 117, 123]))  # Use the full mean array
caffe_transformer.set_raw_scale('data', 255)  # rescale from [0, 255] to [0, 1]
caffe_transformer.set_channel_swap('data', (2, 1, 0))  # swap channels from RGB to BGRdef resize_image(image_data, sz=(256, 256)):im = Image.open(io.BytesIO(image_data))if im.mode != "RGB":im = im.convert('RGB')imr = im.resize(sz, resample=Image.BILINEAR)fh_im = io.BytesIO()imr.save(fh_im, format='JPEG')fh_im.seek(0)return fh_im.getvalue()def caffe_preprocess_and_compute(pimg, caffe_transformer=None, caffe_net=None,output_layers=None):if caffe_net is not None:if output_layers is None:output_layers = caffe_net.outputsimg_data_rs = resize_image(pimg, sz=(256, 256))image = caffe.io.load_image(io.BytesIO(img_data_rs))H, W, _ = image.shape_, _, h, w = caffe_net.blobs['data'].data.shapeh_off = max((H - h) // 2, 0)w_off = max((W - w) // 2, 0)crop = image[h_off:h_off + h, w_off:w_off + w, :]transformed_image = caffe_transformer.preprocess('data', crop)transformed_image.shape = (1,) + transformed_image.shapeinput_name = caffe_net.inputs[0]all_outputs = caffe_net.forward_all(blobs=output_layers,**{input_name: transformed_image})outputs = all_outputs[output_layers[0]][0].astype(float)return outputselse:return []@app.route('/predict', methods=['POST'])
def predict():results = []for file in request.files.getlist('images'):try:filename = secure_filename(file.filename)image_data = file.read()encoded_img = base64.b64encode(image_data).decode('utf-8')scores = caffe_preprocess_and_compute(image_data, caffe_transformer=caffe_transformer, caffe_net=nsfw_net, output_layers=['prob'])results.append({'filename': filename,'score': float("{0:.10f}".format(scores[1])),'file': encoded_img})except Exception as e:return jsonify({'error': str(e)}), 500return jsonify([{'filename': item['filename'], 'score': item['score'], 'file': item['file']} for item in results])if __name__ == '__main__':app.run(host='0.0.0.0', port=5000)

使用 H5 提供简单的客户端

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0"/><title>NSFW Image Classifier</title><style>body {font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;background-color: #f4f4f9;margin: 0;padding: 2rem;color: #333;}h1 {text-align: center;margin-bottom: 2rem;color: #2c3e50;}form {display: flex;justify-content: center;gap: 1rem;flex-wrap: wrap;margin-bottom: 2rem;}input[type="file"] {padding: 0.5rem;border-radius: 5px;border: 1px solid #ccc;}button {padding: 0.6rem 1.5rem;font-size: 1rem;border: none;background-color: #3498db;color: white;border-radius: 5px;cursor: pointer;transition: background-color 0.3s ease;}button:hover {background-color: #2980b9;}#results {display: grid;grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));gap: 2rem;justify-items: center;}.result-item {background: white;border-radius: 10px;box-shadow: 0 4px 8px rgba(0,0,0,0.1);overflow: hidden;text-align: center;padding: 1rem;transition: transform 0.2s ease;}.result-item:hover {transform: translateY(-5px);}.result-item img {max-width: 100%;height: auto;display: block;border-bottom: 1px solid #eee;margin-bottom: 1rem;}.score-text {font-weight: bold;color: #e74c3c;}.loading {text-align: center;font-size: 1.2rem;color: #888;display: none;}.description-text {font-size: 0.9rem;color: #555;margin-top: 0.5rem;}</style>
</head>
<body><h1>上传图片进行敏感内容识别</h1><form id="uploadForm" enctype="multipart/form-data"><input type="file" name="images" id="images" multiple accept="image/*"/><button type="submit">Upload and Classify</button></form><!-- Loading Indicator --><div class="loading" id="loading">Processing images, please wait...</div><!-- Results Container --><div id="results"></div><script>document.getElementById('uploadForm').onsubmit = function(event) {event.preventDefault();const resultsDiv = document.getElementById('results');const loadingDiv = document.getElementById('loading');resultsDiv.innerHTML = '';loadingDiv.style.display = 'block';const formData = new FormData();const files = document.getElementById('images').files;for (let i = 0; i < files.length; i++) {formData.append('images', files[i]);}// 注意:将ip替换为自己提供服务的主机和端口fetch('http://192.168.3.87:5000/predict', {method: 'POST',body: formData,}).then(response => response.json()).then(data => {loadingDiv.style.display = 'none';resultsDiv.innerHTML = '';data.forEach(item => {try {// 去除可能的 base64 前缀let base64Data = item.file.split(',')[1] || item.file;const byteString = atob(base64Data);const ab = new ArrayBuffer(byteString.length);const ia = new Uint8Array(ab);for (let j = 0; j < byteString.length; j++) {ia[j] = byteString.charCodeAt(j);}const blob = new Blob([ia], { type: 'image/jpeg' });const url = URL.createObjectURL(blob);const imgElement = document.createElement('img');imgElement.src = url;const scoreText = document.createElement('p');scoreText.className = 'score-text';scoreText.textContent = `${item.filename} - NSFW Score: ${parseFloat(item.score).toFixed(4)}`;// 根据分数生成说明let description;const score = parseFloat(item.score);if (score <= 0.2) {description = "该图像被认为是安全的内容。";} else if (score <= 0.4) {description = "该图像可能包含轻微的敏感内容。";} else if (score <= 0.6) {description = "该图像可能包含中等程度的敏感内容。建议审慎处理。";} else if (score <= 0.8) {description = "该图像很可能包含较为明显的敏感内容。请注意审核。";} else {description = "该图像非常可能包含严重的敏感内容。请特别注意!";}const descText = document.createElement('p');descText.className = 'description-text';descText.textContent = description;const container = document.createElement('div');container.className = 'result-item';container.appendChild(imgElement);container.appendChild(scoreText);container.appendChild(descText); // 添加描述resultsDiv.appendChild(container);} catch (err) {console.error("Error processing image:", err);}});}).catch(error => {loadingDiv.style.display = 'none';console.error('Fetch error:', error);alert('请求处理过程中发生错误。');});};</script></body>
</html>

参考文献

  • OpenNSFW2(Yahoo NSFW 检测) GitHub: https://github.com/yahoo/open_nsfw
  • Caffe: a fast open framework for deep learning.
  • Caffe 官网
http://www.xdnf.cn/news/6958.html

相关文章:

  • HMDB51数据集划分
  • V 型不锈钢对夹球阀:高性价比流体控制的优选方案-耀圣
  • 联想笔记本黑屏了,排线出问题还是静电
  • QT调用Halcon查询所有摄像头名称
  • 遨游科普:三防平板是什么?有什么功能?
  • Linux安全篇 --firewalld
  • Windows系统永久暂停更新操作步骤
  • 微软家各种copilot的AI产品:Github copilot、Microsoft copilot
  • 什么是PMBus
  • 18-总线IIC
  • 大模型在腰椎间盘突出症预测与治疗方案制定中的应用研究
  • LeetCode 热题 100_寻找重复数(100_287_中等_C++)(技巧)(暴力解法;哈希集合;二分查找)
  • 字节2025实习/校招/社招 内推码:R9SZ7Y1
  • 车载以太网驱动智能化:域控架构设计与开发实践
  • 【Ubuntu】Waydroid-Linux安卓模拟器安装
  • 【数据结构】线性表--队列
  • 自动化脚本开发:Python调用云手机API实现TikTok批量内容发布
  • 卷积神经网络中的二维卷积与三维卷积详解
  • 山东大学计算机图形学期末复习10——CG12下
  • Redis设计与实现——分布式Redis
  • 共享内存【Linux操作系统】
  • Go语言语法---输入控制
  • Node.js 源码架构详解
  • [system-design] ByteByteGo_Note Summary
  • 如何开发专业小模型
  • 强化学习赋能医疗大模型:构建闭环检索-反馈-优化系统提升推理能力
  • 数据库实验报告 数据定义操作 3
  • 【leetcode】逐层探索:BFS求解最短路的原理与实践
  • 使用Python和Selenium打造一个全网页截图工具
  • CSS- 4.1 浮动(Float)