OpenNSFW模型简介
OpenNSFW是一个由 Yahoo 研究院开源的深度学习模型,用于识别和区分网络上的正常内容与不适宜内容(Not Safe For Work)。
项目地址:https://github.com/yahoo/open_nsfw
OpenNSFW主要基于Caffe框架实现,采用有监督的学习方式,对不良图片和正常图片进行标识,然后投入Caffe模型进行分类学习和计算。NSFW模型先用了ImageNet 1000数据集做了预训练,然后采用“finetune”工具,对NSFW的数据集进行再训练,微调了权重值。采用ResNet 50 框架用于预训练的网络并引入残差网络对模型进行修正。
在具体的模型实现过程中,雅虎的NSFW在具体实现过程中,引入了ResNet网络改善过拟合的问题,并在执行效率与精确性之间做了取舍权衡。在训练模型过程里,从下面的一些模型和框架做了评估和取舍,选择了ResNet-50-thin模型,在每一层只选择了一半的滤波器用于模型计算,兼顾效率和精确度。
流程如图所示
系统设计
1、视频预处理功能
对视频流进行抽帧处理,抽取I帧将要检测的图片序列。
2、图片预处理功能
对所抽取的I帧图片,进行肤色比例的快速检测,对于疑似不良图片进行筛选,进入二次待检序列。
基于YCbCr皮肤颜色比例的算法简述如下:由于在不同光照环境下,RGB颜色空间会因为其不同的明暗度,影响较大,在这个空间内做肤色识别,效果不好。而在YCbCr颜色空间中,Y代表亮度,Cb代表蓝色色度向量,Cr表示红色色度向量,具有亮度与色度分离的优点,肤色类聚度较好,可以取得较好的识别效果。
根据一般经验值,设置判断条件为:97.5≤Cb≤142.5 & 134≤Cr≤176。
基本分析过程如下:
● 遍历图片中的每个像素,按照上述约束条件检测像素颜色是否为肤色;
● 将相邻的肤色像素归为一个皮肤区域,得到若干个皮肤区域;
● 去除背景或其他特殊情景识别。
不良图片判定条件为:皮肤区域的像素与图像所有像素的比值大于30%。
3、不良图片检测
采用Caffe的不良图片预训练模型,进行图片推理。将分值高于0.85的图片列出,根据图片的标签信息(含影片ID、时间戳),对目标影片做标识。
程序示例
肤色检测
import cv2
import numpy as np
def is_skin_pixel(y, cb, cr):
return 97.5 <= cb <= 142.5 and 134 <= cr <= 176
def detect_skin_areas(image):
# 转换为 YCbCr 颜色空间
ycbcr_image = cv2.cvtColor(image, cv2.COLOR_BGR2YCrCb)
# 创建掩膜,用于标记肤色区域
skin_mask = np.zeros(ycbcr_image.shape[:2], dtype=np.uint8)
# 遍历每个像素,判断是否为肤色
for y in range(ycbcr_image.shape[0]):
for x in range(ycbcr_image.shape[1]):
Y, Cb, Cr = ycbcr_image[y, x]
if is_skin_pixel(Y, Cb, Cr):
skin_mask[y, x] = 255
return skin_mask
def calculate_skin_ratio(image, skin_mask):
total_pixels = image.shape[0] * image.shape[1]
skin_pixels = np.sum(skin_mask == 255)
return skin_pixels / total_pixels
def is_nsfw(image_path):
# 读取图片
image = cv2.imread(image_path)
# 检测皮肤区域
skin_mask = detect_skin_areas(image)
# 计算皮肤区域比例
skin_ratio = calculate_skin_ratio(image, skin_mask)
# 判断是否为不良图片
return skin_ratio > 0.30
# 示例用法
image_path = 'example.jpg'
if is_nsfw(image_path):
print("图片可能包含不良内容")
else:
print("图片内容正常")
推理检测
import caffe
import numpy as np
from PIL import Image
# 设置 Caffe 为 GPU 模式或 CPU 模式
caffe.set_mode_cpu()
# 加载模型
net = caffe.Net('deploy.prototxt', 'bvlc_nsfw.caffemodel', caffe.TEST)
# 加载图片
def preprocess_image(image_path):
image = Image.open(image_path).resize((224, 224))
image = np.array(image).astype(np.float32)
image = image - 127.5
image = image * 0.007843
return image
# 进行推理
def classify_image(image_path):
image = preprocess_image(image_path)
net.blobs['data'].data[...] = image
output = net.forward()
score = output['prob'][0][1]
return score
image_path = 'example.jpg'
score = classify_image(image_path)
print(f'NSFW score: {score}')