Python: Use opennsfw2 para identificar imagens/vídeos amarelos


Introdução

Usando o modelo TensorFlow 2 Open-NSFW de código aberto do Yahoo, NSFW: não é seguro para o trabalho, não é adequado para o local de trabalho

prática

1. Preparação do ambiente,

Para Python 3.7 e superior, instale a biblioteca opennsfw2. Por favor, consulte o endereço no resumo para baixar o material de imagem.

pip install opennsfw2

2. Prática de código

O código de identificação da imagem é o seguinte:

import opennsfw2 as n2

# 将自动下载预训练模型 open_nsfw_weights.h5 到 C:\Users\Administrator\.opennsfw2\weights
# pip install opennsfw2

# 单张预测
image_path = '1.jpg'
nsfw_probability = n2.predict_image(image_path)
print(nsfw_probability)
# 0.16282974183559418

# 批量预测
image_paths = ['1.jpg', '2.jpg']
nsfw_probabilities = n2.predict_images(image_paths)
print(nsfw_probabilities)
# [0.16282965242862701, 0.8638442158699036]

O código de identificação do vídeo é o seguinte:

import opennsfw2 as n2

video_path = '1.mp4'
elapsed_seconds, nsfw_probabilities = n2.predict_video_frames(video_path)
for second, probability in zip(elapsed_seconds, nsfw_probabilities):
    print(f'{
      
      second:.2f}s: {
      
      probability * 100:.0f} %')
# 0.03s: 1%
# ...
# 10.01s: 87.00%
# ...
# 10.64s: 69.00%

uso avançado

1. Como carregar

import numpy as np
from PIL import Image
from opennsfw2._model import make_open_nsfw_model
from opennsfw2._image import preprocess_image, Preprocessing

image_path = '1.jpg'
image = preprocess_image(Image.open(image_path), Preprocessing.YAHOO)
model = make_open_nsfw_model()
nsfw_probability = float(model.predict(np.expand_dims(image, 0), batch_size=1)[0][1])
print(nsfw_probability)
# 0.16282974183559418

2. Detecção de velocidade do veículo

import time
import numpy as np
import tkinter as tk
from pathlib import Path
from tkinter import filedialog
from tkinter import messagebox
from PIL import ImageTk, Image

from opennsfw2._model import make_open_nsfw_model
from opennsfw2._image import preprocess_image, Preprocessing

begin = time.time()
model = make_open_nsfw_model()  # 加载模型
elapsed = time.time() - begin  # 加载模型耗时
initialdir = Path.cwd()  # 初始化目录,可切换为图片Path.home() / 'Pictures'
img = None  # 当前打开的图片


def scale(size, width=None, height=None):
    """获取按比例缩放后的宽高"""
    if not width and not height:
        width, height = size
    if not width or not height:
        _width, _height = size
        height = width * _height / _width if width else height
        width = height * _width / _height if height else width
    return int(width), int(height)


def img_resize(event=None):
    """显示图片"""
    global img
    if img:
        _img = img.resize(scale(img.size, height=win.winfo_height()))
        _img = ImageTk.PhotoImage(_img)
        label.config(image=_img)
        label.image = _img


def on_closing():
    """关闭事件"""
    if messagebox.askokcancel('关闭', '是否退出程序?'):
        win.destroy()


def open_file(event=None):
    """打开图片"""
    global initialdir
    global img
    file_path = filedialog.askopenfilename(title='选择图片', initialdir=initialdir,
                                           filetypes=[('image files', ('.png', '.jpg', '.jpeg', '.gif'))])
    if file_path:
        statusbar.config(text='正在加载...')
        statusbar.update_idletasks()
        begin = time.time()
        path = Path(file_path)
        initialdir = path.parent
        img = Image.open(file_path)
        img_resize()
        _img = preprocess_image(Image.open(file_path), Preprocessing.YAHOO)
        probability = float(model.predict(np.expand_dims(_img, 0), batch_size=1)[0][1])
        print(probability)
        end = time.time()
        statusbar.config(text=f'{
      
      path.name} 耗时: {
      
      end - begin:.2f}s 概率: {
      
      probability * 100:.2f} %')


win = tk.Tk()
win.title('黄图检测')  # 标题
menu = tk.Menu(win)
menu.add_command(label='打开', command=open_file)
win.config(menu=menu)
win.bind('<Configure>', img_resize)
win.geometry('600x300+300+300')
win.minsize(200, 200)
win.protocol('WM_DELETE_WINDOW', on_closing)
statusbar = tk.Label(win, text=f'加载模型耗时: {
      
      elapsed:.2f}s', bd=1, relief=tk.SUNKEN, anchor=tk.W, name='statusbar')
statusbar.pack(side=tk.BOTTOM, fill=tk.X)
label = tk.Label(win, text='双击打开图片')
label.bind('<Double-Button-1>', open_file)
label.pack(fill=tk.BOTH, expand=True)
win.mainloop()

3. Detecção de velocidade de vídeo (silencioso)

import time
import threading
import tkinter as tk
from pathlib import Path
from tkinter import filedialog
from tkinter import messagebox
from timeit import default_timer as timer

import imageio
import numpy as np
from PIL import ImageTk, Image

from opennsfw2._model import make_open_nsfw_model
from opennsfw2._image import preprocess_image, Preprocessing

# pip install imageio-ffmpeg

begin = time.time()
model = make_open_nsfw_model()  # 加载模型
elapsed = time.time() - begin  # 加载模型耗时
initialdir = Path.cwd()  # 初始化目录,可切换为图片Path.home() / 'Pictures'
reader = None  # 视频读取器

accum_time = 0
curr_fps = 0
last_fps = 0
prev_time = timer()


def on_closing():
    """关闭事件"""
    if messagebox.askokcancel('关闭', '是否退出程序?'):
        win.destroy()


def play():
    global reader
    global prev_time, accum_time, curr_fps
    for image in reader:
        image = Image.fromarray(image)
        frame_image = ImageTk.PhotoImage(image)
        label.config(image=frame_image)
        label.image = frame_image
        _img = preprocess_image(image, Preprocessing.YAHOO)
        probability = float(model.predict(np.expand_dims(_img, 0), batch_size=1)[0][1])

        # FPS
        curr_time = timer()
        exec_time = curr_time - prev_time
        prev_time = curr_time
        accum_time = accum_time + exec_time
        curr_fps = curr_fps + 1
        if accum_time > 1:
            accum_time = accum_time - 1
            last_fps = curr_fps
            curr_fps = 0
            statusbar.config(text=f'概率: {
      
      probability * 100:.2f} % FPS: {
      
      last_fps}')


def open_file(event=None):
    """打开视频"""
    global initialdir
    global reader
    file_path = filedialog.askopenfilename(title='选择视频', initialdir=initialdir,
                                           filetypes=[('Select files', ('.mp4', '.mkv', '.avi', '.wmv'))])
    if file_path:
        statusbar.config(text='正在加载...')
        statusbar.update_idletasks()
        path = Path(file_path)
        initialdir = path.parent
        reader = imageio.get_reader(path)
        thread = threading.Thread(target=play, daemon=True)
        thread.start()


win = tk.Tk()
win.title('黄图检测')  # 标题
menu = tk.Menu(win)
menu.add_command(label='打开', command=open_file)
win.config(menu=menu)
win.geometry('1280x720+300+300')
win.minsize(200, 200)
win.protocol('WM_DELETE_WINDOW', on_closing)
statusbar = tk.Label(win, text=f'加载模型耗时: {
      
      elapsed:.2f}s', bd=1, relief=tk.SUNKEN, anchor=tk.W, name='statusbar')
statusbar.pack(side=tk.BOTTOM, fill=tk.X)
label = tk.Label(win, text='双击打开视频')
label.bind('<Double-Button-1>', open_file)
label.pack(fill=tk.BOTH, expand=True)
win.mainloop()

4. Detecção de velocidade de vídeo (com som)

import io

import pyglet
import numpy as np
from PIL import Image
from opennsfw2._model import make_open_nsfw_model
from opennsfw2._image import preprocess_image, Preprocessing

# pip install pyglet

model = make_open_nsfw_model()
filename = '1.mp4'
source = pyglet.media.load(filename)
video_format = source.video_format
width, height = video_format.width, video_format.height
title = 'Video Player'
window = pyglet.window.Window(width, height, title)
player = pyglet.media.Player()
player.queue(source)
player.play()


@window.event
def on_draw():
    window.clear()
    if player.source and player.source.video_format:
        player.get_texture().blit(0, 0, width=width, height=height)
        image_data = player.get_texture().get_image_data()
        pitch = -(image_data.width * len('RGB'))
        data = image_data.get_data('RGB', pitch)
        _img = preprocess_image(Image.frombytes('RGB', (width, height), data, 'raw'), Preprocessing.YAHOO)
        probability = float(model.predict(np.expand_dims(_img, 0), batch_size=1)[0][1])
        print(probability)


pyglet.app.run()

resultado da operação:

效率分析:
get_data() 0.941 s
frombytes() 0.001 s
preprocess_image() 0.006 s
predict() 0.052 s

resumo

Referência: https://blog.csdn.net/lly1122334/article/details/121247781
https://github.com/bhky/opennsfw2

Recursos: https://img-blog.csdnimg.cn/20210702231858370.jpg
http://www.lenna.org/full/len_full.jpg

おすすめ

転載: blog.csdn.net/zhanggqianglovec/article/details/128188702