From 1bebda6924711c4390384edd39e9d80515e6e5e7 Mon Sep 17 00:00:00 2001 From: CoprDistGit Date: Mon, 15 May 2023 05:05:51 +0000 Subject: automatic import of python-opennsfw2 --- .gitignore | 1 + python-opennsfw2.spec | 857 ++++++++++++++++++++++++++++++++++++++++++++++++++ sources | 1 + 3 files changed, 859 insertions(+) create mode 100644 python-opennsfw2.spec create mode 100644 sources diff --git a/.gitignore b/.gitignore index e69de29..cec3ec3 100644 --- a/.gitignore +++ b/.gitignore @@ -0,0 +1 @@ +/opennsfw2-0.10.2.tar.gz diff --git a/python-opennsfw2.spec b/python-opennsfw2.spec new file mode 100644 index 0000000..e1f340c --- /dev/null +++ b/python-opennsfw2.spec @@ -0,0 +1,857 @@ +%global _empty_manifest_terminate_build 0 +Name: python-opennsfw2 +Version: 0.10.2 +Release: 1 +Summary: TensorFlow 2 implementation of the Yahoo Open-NSFW model +License: MIT License +URL: https://github.com/bhky/opennsfw2 +Source0: https://mirrors.nju.edu.cn/pypi/web/packages/53/24/ee44a3761a4dd54a83db5ea00260adc7b1fbfc9c2f3cc6631386ab222350/opennsfw2-0.10.2.tar.gz +BuildArch: noarch + +Requires: python3-gdown +Requires: python3-matplotlib +Requires: python3-numpy +Requires: python3-opencv-python +Requires: python3-Pillow +Requires: python3-scikit-image +Requires: python3-tensorflow +Requires: python3-tqdm + +%description +![logo](logo/opennsfw2_logo.png) + +[![ci](https://github.com/bhky/opennsfw2/actions/workflows/ci.yml/badge.svg)](https://github.com/bhky/opennsfw2/actions) +[![License MIT 1.0](https://img.shields.io/badge/license-MIT%201.0-blue.svg)](LICENSE) + +# Introduction + +Detecting Not-Suitable-For-Work (NSFW) content is a high demand task in +computer vision. While there are many types of NSFW content, here we focus on +the pornographic images and videos. + +The [Yahoo Open-NSFW model](https://github.com/yahoo/open_nsfw) originally +developed with the Caffe framework has been a favourite choice, but the work +is now discontinued and Caffe is also becoming less popular. +Please see the description on the Yahoo project page for +the context, definitions, and model training details. + +This **Open-NSFW 2** project provides a TensorFlow 2 implementation of the +Yahoo model, with references to its previous third-party +[TensorFlow 1 implementation](https://github.com/mdietrichstein/tensorflow-open_nsfw). + +A simple API is provided for making predictions on images and videos. + +# Installation + +Tested for Python 3.8, 3.9, and 3.10. + +The best way to install Open-NSFW 2 with its dependencies is from PyPI: +```shell +python3 -m pip install --upgrade opennsfw2 +``` +Alternatively, to obtain the latest version from this repository: +```shell +git clone git@github.com:bhky/opennsfw2.git +cd opennsfw2 +python3 -m pip install . +``` + +# Usage + +Quick examples for getting started are given below. +For more details, please refer to the [API](#api) section. + +## Images + +```python +import opennsfw2 as n2 + +# To get the NSFW probability of a single image. +image_path = "path/to/your/image.jpg" + +nsfw_probability = n2.predict_image(image_path) + +# To get the NSFW probabilities of a list of images. +# This is better than looping with `predict_image` as the model will only be instantiated once +# and batching is used during inference. +image_paths = [ + "path/to/your/image1.jpg", + "path/to/your/image2.jpg", + # ... +] + +nsfw_probabilities = n2.predict_images(image_paths) +``` + +## Video + +```python +import opennsfw2 as n2 + +# The video can be in any format supported by OpenCV. +video_path = "path/to/your/video.mp4" + +# Return two lists giving the elapsed time in seconds and the NSFW probability of each frame. +elapsed_seconds, nsfw_probabilities = n2.predict_video_frames(video_path) +``` + +## Lower level with TensorFlow / Keras + +```python +import numpy as np +import opennsfw2 as n2 +from PIL import Image + +# Load and preprocess image. +image_path = "path/to/your/image.jpg" +pil_image = Image.open(image_path) +image = n2.preprocess_image(pil_image, n2.Preprocessing.YAHOO) +# The preprocessed image is a NumPy array of shape (224, 224, 3). + +# Create the model. +# By default, this call will search for the pre-trained weights file from path: +# $HOME/.opennsfw2/weights/open_nsfw_weights.h5 +# If not exists, the file will be downloaded from this repository. +# The model is a `tf.keras.Model` object. +model = n2.make_open_nsfw_model() + +# Make predictions. +inputs = np.expand_dims(image, axis=0) # Add batch axis (for single image). +predictions = model.predict(inputs) + +# The shape of predictions is (num_images, 2). +# Each row gives [sfw_probability, nsfw_probability] of an input image, e.g.: +sfw_probability, nsfw_probability = predictions[0] +``` + +# API + +### `preprocess_image` +Apply necessary preprocessing to the input image. +- Parameters: + - `pil_image` (`PIL.Image`): Input as a Pillow image. + - `preprocessing` (`Preprocessing` enum, default `Preprocessing.YAHOO`): + See [preprocessing details](#preprocessing-details). +- Return: + - NumPy array of shape `(224, 224, 3)`. + +### `Preprocessing` +Enum class for preprocessing options. +- `Preprocessing.YAHOO` +- `Preprocessing.SIMPLE` + +### `make_open_nsfw_model` +Create an instance of the NSFW model, optionally with pre-trained weights from Yahoo. +- Parameters: + - `input_shape` (`Tuple[int, int, int]`, default `(224, 224, 3)`): + Input shape of the model, this should not be changed. + - `weights_path` (`Optional[str]`, default `$HOME/.opennsfw/weights/open_nsfw_weights.h5`): + Path to the weights in HDF5 format to be loaded by the model. + The weights file will be downloaded if not exists. + If `None`, no weights will be downloaded nor loaded to the model. + Users can provide path if the default is not preferred. + The environment variable `OPENNSFW2_HOME` can also be used to indicate + where the `.opennsfw2/` directory should be located. +- Return: + - `tf.keras.Model` object. + +### `predict_image` +End-to-end pipeline function from the input image to the predicted NSFW probability. +- Parameters: + - `image_path` (`str`): Path to the input image file. + The image format must be supported by Pillow. + - `preprocessing`: Same as that in `preprocess_image`. + - `weights_path`: Same as that in `make_open_nsfw_model`. + - `grad_cam_path` (`Optional[str]`, default `None`): If not `None`, e.g., `cam.jpg`, + a [Gradient-weighted Class Activation Mapping (Grad-CAM)](https://keras.io/examples/vision/grad_cam/) + overlay plot will be saved, which highlights the important region(s) of the + (preprocessed) input image that lead to the prediction. + - `alpha` (`float`, default `0.8`): Opacity of the Grad-CAM layer of the plot, + only valid if `grad_cam_path` is not `None`. +- Return: + - `nsfw_probability` (`float`): The predicted NSFW probability of the image. + +### `predict_images` +End-to-end pipeline function from the input images to the predicted NSFW probabilities. +- Parameters: + - `image_paths` (`Sequence[str]`): List of paths to the input image files. + The image format must be supported by Pillow. + - `batch_size` (`int`, default `8`): Batch size to be used for model inference. + Choose a value that works the best with your device resources. + - `preprocessing`: Same as that in `preprocess_image`. + - `weights_path`: Same as that in `make_open_nsfw_model`. + - `grad_cam_paths` (`Optional[Sequence[str]]`, default `None`): If not `None`, + the corresponding Grad-CAM plots for the input images will be saved. + See the description in `predict_image`. + - `alpha`: Same as that in `predict_image`. +- Return: + - `nsfw_probabilities` (`List[float]`): Predicted NSFW probabilities of the images. + +### `Aggregation` +Enum class for aggregation options in video frames prediction. +- `Aggregation.MEAN` +- `Aggregation.MEDIAN` +- `Aggregation.MAX` +- `Aggregation.MIN` + +### `predict_video_frames` +End-to-end pipeline function from the input video to predictions. +- Parameters: + - `video_path` (`str`): Path to the input video source. + The video format must be supported by OpenCV. + - `frame_interval` (`int`, default `8`): Prediction will be done on every this + number of frames, starting from frame 1, i.e., if this is 8, then + prediction will only be done on frame 1, 9, 17, etc. + - `aggregation_size` (`int`, default `8`): + Number of frames for which their predicted NSFW probabilities will be aggregated. + For instance, if a prediction will be done "on" frame 9 (decided by `frame_interval`), + then it actually means prediction will be done on `aggregation_size` frames + starting from frame 9, e.g., frames 9 to 16 if the size is 8. + The predicted probabilities will be aggregated. After aggregation, + each of these frames in that interval will be assumed the same aggregated probability. + - `aggregation` (`Aggregation` enum, default `Aggregation.MEAN`): + The aggregation method. + - `batch_size` (`int`, default `8`, upper-bounded by `aggregation_size`): + Batch size to be used for model inference. Choose a value that works the best + with your device resources. + - `output_video_path` (`Optional[str]`, default `None`): + If not `None`, e.g., `out.mp4`, + an output MP4 video with the same frame size and frame rate as + the input video will be saved via OpenCV. The predicted NSFW probability + is printed on the top-left corner of each frame. Be aware that the output + file size could be much larger than the input file size. + This output video is for reference only. + - `preprocessing`: Same as that in `preprocess_image`. + - `weights_path`: Same as that in `make_open_nsfw_model`. + - `progress_bar` (`bool`, default `True`): Whether to show the progress bar. +- Return: + - Tuple of `List[float]`, each with length equals to the number of video frames. + - `elapsed_seconds`: Video elapsed time in seconds at each frame. + - `nsfw_probabilities`: NSFW probability of each frame. + For any `frame_interval > 1`, all frames without a prediction + will be assumed to have the NSFW probability of the previous predicted frame. + +# Preprocessing details + +## Options + +This implementation provides the following preprocessing options. +- `YAHOO`: The default option which was used in the original + [Yahoo's Caffe](https://github.com/yahoo/open_nsfw/blob/master/classify_nsfw.py#L19-L80) + and the later + [TensorFlow 1](https://github.com/mdietrichstein/tensorflow-open_nsfw/blob/master/image_utils.py#L4-L53) + implementations. The key steps are: + - Resize the input Pillow image to `(256, 256)`. + - Store the image as JPEG in memory and reload it again to a NumPy image + (this step is mysterious, but somehow it really makes a difference). + - Crop the centre part of the NumPy image with size `(224, 224)`. + - Swap the colour channels to BGR. + - Subtract the training dataset mean value of each channel: `[104, 117, 123]`. +- `SIMPLE`: A simpler and probably more intuitive preprocessing option is also provided, + but note that the model output probabilities will be different. + The key steps are: + - Resize the input Pillow image to `(224, 224)`. + - Convert to a NumPy image. + - Swap the colour channels to BGR. + - Subtract the training dataset mean value of each channel: `[104, 117, 123]`. + +## Comparison + +Using 521 private test images, the NSFW probabilities given by +three different settings are compared: +- [TensorFlow 1 implementation](https://github.com/mdietrichstein/tensorflow-open_nsfw) with `YAHOO` preprocessing. +- TensorFlow 2 implementation with `YAHOO` preprocessing. +- TensorFlow 2 implementation with `SIMPLE` preprocessing. + +The following figure shows the result: + +![NSFW probabilities comparison](docs/nsfw_probabilities_comparison.png) + +The current TensorFlow 2 implementation with `YAHOO` preprocessing +can totally reproduce the well-tested TensorFlow 1 result, +with small floating point errors only. + +With `SIMPLE` preprocessing the result is different, where the model tends +to give lower probabilities over the current test images. + +Note that this comparison does not conclude which preprocessing method is +"better", it only shows their discrepancies. However, users that prefer the +original Yahoo result should go for the default `YAHOO` preprocessing. + + +%package -n python3-opennsfw2 +Summary: TensorFlow 2 implementation of the Yahoo Open-NSFW model +Provides: python-opennsfw2 +BuildRequires: python3-devel +BuildRequires: python3-setuptools +BuildRequires: python3-pip +%description -n python3-opennsfw2 +![logo](logo/opennsfw2_logo.png) + +[![ci](https://github.com/bhky/opennsfw2/actions/workflows/ci.yml/badge.svg)](https://github.com/bhky/opennsfw2/actions) +[![License MIT 1.0](https://img.shields.io/badge/license-MIT%201.0-blue.svg)](LICENSE) + +# Introduction + +Detecting Not-Suitable-For-Work (NSFW) content is a high demand task in +computer vision. While there are many types of NSFW content, here we focus on +the pornographic images and videos. + +The [Yahoo Open-NSFW model](https://github.com/yahoo/open_nsfw) originally +developed with the Caffe framework has been a favourite choice, but the work +is now discontinued and Caffe is also becoming less popular. +Please see the description on the Yahoo project page for +the context, definitions, and model training details. + +This **Open-NSFW 2** project provides a TensorFlow 2 implementation of the +Yahoo model, with references to its previous third-party +[TensorFlow 1 implementation](https://github.com/mdietrichstein/tensorflow-open_nsfw). + +A simple API is provided for making predictions on images and videos. + +# Installation + +Tested for Python 3.8, 3.9, and 3.10. + +The best way to install Open-NSFW 2 with its dependencies is from PyPI: +```shell +python3 -m pip install --upgrade opennsfw2 +``` +Alternatively, to obtain the latest version from this repository: +```shell +git clone git@github.com:bhky/opennsfw2.git +cd opennsfw2 +python3 -m pip install . +``` + +# Usage + +Quick examples for getting started are given below. +For more details, please refer to the [API](#api) section. + +## Images + +```python +import opennsfw2 as n2 + +# To get the NSFW probability of a single image. +image_path = "path/to/your/image.jpg" + +nsfw_probability = n2.predict_image(image_path) + +# To get the NSFW probabilities of a list of images. +# This is better than looping with `predict_image` as the model will only be instantiated once +# and batching is used during inference. +image_paths = [ + "path/to/your/image1.jpg", + "path/to/your/image2.jpg", + # ... +] + +nsfw_probabilities = n2.predict_images(image_paths) +``` + +## Video + +```python +import opennsfw2 as n2 + +# The video can be in any format supported by OpenCV. +video_path = "path/to/your/video.mp4" + +# Return two lists giving the elapsed time in seconds and the NSFW probability of each frame. +elapsed_seconds, nsfw_probabilities = n2.predict_video_frames(video_path) +``` + +## Lower level with TensorFlow / Keras + +```python +import numpy as np +import opennsfw2 as n2 +from PIL import Image + +# Load and preprocess image. +image_path = "path/to/your/image.jpg" +pil_image = Image.open(image_path) +image = n2.preprocess_image(pil_image, n2.Preprocessing.YAHOO) +# The preprocessed image is a NumPy array of shape (224, 224, 3). + +# Create the model. +# By default, this call will search for the pre-trained weights file from path: +# $HOME/.opennsfw2/weights/open_nsfw_weights.h5 +# If not exists, the file will be downloaded from this repository. +# The model is a `tf.keras.Model` object. +model = n2.make_open_nsfw_model() + +# Make predictions. +inputs = np.expand_dims(image, axis=0) # Add batch axis (for single image). +predictions = model.predict(inputs) + +# The shape of predictions is (num_images, 2). +# Each row gives [sfw_probability, nsfw_probability] of an input image, e.g.: +sfw_probability, nsfw_probability = predictions[0] +``` + +# API + +### `preprocess_image` +Apply necessary preprocessing to the input image. +- Parameters: + - `pil_image` (`PIL.Image`): Input as a Pillow image. + - `preprocessing` (`Preprocessing` enum, default `Preprocessing.YAHOO`): + See [preprocessing details](#preprocessing-details). +- Return: + - NumPy array of shape `(224, 224, 3)`. + +### `Preprocessing` +Enum class for preprocessing options. +- `Preprocessing.YAHOO` +- `Preprocessing.SIMPLE` + +### `make_open_nsfw_model` +Create an instance of the NSFW model, optionally with pre-trained weights from Yahoo. +- Parameters: + - `input_shape` (`Tuple[int, int, int]`, default `(224, 224, 3)`): + Input shape of the model, this should not be changed. + - `weights_path` (`Optional[str]`, default `$HOME/.opennsfw/weights/open_nsfw_weights.h5`): + Path to the weights in HDF5 format to be loaded by the model. + The weights file will be downloaded if not exists. + If `None`, no weights will be downloaded nor loaded to the model. + Users can provide path if the default is not preferred. + The environment variable `OPENNSFW2_HOME` can also be used to indicate + where the `.opennsfw2/` directory should be located. +- Return: + - `tf.keras.Model` object. + +### `predict_image` +End-to-end pipeline function from the input image to the predicted NSFW probability. +- Parameters: + - `image_path` (`str`): Path to the input image file. + The image format must be supported by Pillow. + - `preprocessing`: Same as that in `preprocess_image`. + - `weights_path`: Same as that in `make_open_nsfw_model`. + - `grad_cam_path` (`Optional[str]`, default `None`): If not `None`, e.g., `cam.jpg`, + a [Gradient-weighted Class Activation Mapping (Grad-CAM)](https://keras.io/examples/vision/grad_cam/) + overlay plot will be saved, which highlights the important region(s) of the + (preprocessed) input image that lead to the prediction. + - `alpha` (`float`, default `0.8`): Opacity of the Grad-CAM layer of the plot, + only valid if `grad_cam_path` is not `None`. +- Return: + - `nsfw_probability` (`float`): The predicted NSFW probability of the image. + +### `predict_images` +End-to-end pipeline function from the input images to the predicted NSFW probabilities. +- Parameters: + - `image_paths` (`Sequence[str]`): List of paths to the input image files. + The image format must be supported by Pillow. + - `batch_size` (`int`, default `8`): Batch size to be used for model inference. + Choose a value that works the best with your device resources. + - `preprocessing`: Same as that in `preprocess_image`. + - `weights_path`: Same as that in `make_open_nsfw_model`. + - `grad_cam_paths` (`Optional[Sequence[str]]`, default `None`): If not `None`, + the corresponding Grad-CAM plots for the input images will be saved. + See the description in `predict_image`. + - `alpha`: Same as that in `predict_image`. +- Return: + - `nsfw_probabilities` (`List[float]`): Predicted NSFW probabilities of the images. + +### `Aggregation` +Enum class for aggregation options in video frames prediction. +- `Aggregation.MEAN` +- `Aggregation.MEDIAN` +- `Aggregation.MAX` +- `Aggregation.MIN` + +### `predict_video_frames` +End-to-end pipeline function from the input video to predictions. +- Parameters: + - `video_path` (`str`): Path to the input video source. + The video format must be supported by OpenCV. + - `frame_interval` (`int`, default `8`): Prediction will be done on every this + number of frames, starting from frame 1, i.e., if this is 8, then + prediction will only be done on frame 1, 9, 17, etc. + - `aggregation_size` (`int`, default `8`): + Number of frames for which their predicted NSFW probabilities will be aggregated. + For instance, if a prediction will be done "on" frame 9 (decided by `frame_interval`), + then it actually means prediction will be done on `aggregation_size` frames + starting from frame 9, e.g., frames 9 to 16 if the size is 8. + The predicted probabilities will be aggregated. After aggregation, + each of these frames in that interval will be assumed the same aggregated probability. + - `aggregation` (`Aggregation` enum, default `Aggregation.MEAN`): + The aggregation method. + - `batch_size` (`int`, default `8`, upper-bounded by `aggregation_size`): + Batch size to be used for model inference. Choose a value that works the best + with your device resources. + - `output_video_path` (`Optional[str]`, default `None`): + If not `None`, e.g., `out.mp4`, + an output MP4 video with the same frame size and frame rate as + the input video will be saved via OpenCV. The predicted NSFW probability + is printed on the top-left corner of each frame. Be aware that the output + file size could be much larger than the input file size. + This output video is for reference only. + - `preprocessing`: Same as that in `preprocess_image`. + - `weights_path`: Same as that in `make_open_nsfw_model`. + - `progress_bar` (`bool`, default `True`): Whether to show the progress bar. +- Return: + - Tuple of `List[float]`, each with length equals to the number of video frames. + - `elapsed_seconds`: Video elapsed time in seconds at each frame. + - `nsfw_probabilities`: NSFW probability of each frame. + For any `frame_interval > 1`, all frames without a prediction + will be assumed to have the NSFW probability of the previous predicted frame. + +# Preprocessing details + +## Options + +This implementation provides the following preprocessing options. +- `YAHOO`: The default option which was used in the original + [Yahoo's Caffe](https://github.com/yahoo/open_nsfw/blob/master/classify_nsfw.py#L19-L80) + and the later + [TensorFlow 1](https://github.com/mdietrichstein/tensorflow-open_nsfw/blob/master/image_utils.py#L4-L53) + implementations. The key steps are: + - Resize the input Pillow image to `(256, 256)`. + - Store the image as JPEG in memory and reload it again to a NumPy image + (this step is mysterious, but somehow it really makes a difference). + - Crop the centre part of the NumPy image with size `(224, 224)`. + - Swap the colour channels to BGR. + - Subtract the training dataset mean value of each channel: `[104, 117, 123]`. +- `SIMPLE`: A simpler and probably more intuitive preprocessing option is also provided, + but note that the model output probabilities will be different. + The key steps are: + - Resize the input Pillow image to `(224, 224)`. + - Convert to a NumPy image. + - Swap the colour channels to BGR. + - Subtract the training dataset mean value of each channel: `[104, 117, 123]`. + +## Comparison + +Using 521 private test images, the NSFW probabilities given by +three different settings are compared: +- [TensorFlow 1 implementation](https://github.com/mdietrichstein/tensorflow-open_nsfw) with `YAHOO` preprocessing. +- TensorFlow 2 implementation with `YAHOO` preprocessing. +- TensorFlow 2 implementation with `SIMPLE` preprocessing. + +The following figure shows the result: + +![NSFW probabilities comparison](docs/nsfw_probabilities_comparison.png) + +The current TensorFlow 2 implementation with `YAHOO` preprocessing +can totally reproduce the well-tested TensorFlow 1 result, +with small floating point errors only. + +With `SIMPLE` preprocessing the result is different, where the model tends +to give lower probabilities over the current test images. + +Note that this comparison does not conclude which preprocessing method is +"better", it only shows their discrepancies. However, users that prefer the +original Yahoo result should go for the default `YAHOO` preprocessing. + + +%package help +Summary: Development documents and examples for opennsfw2 +Provides: python3-opennsfw2-doc +%description help +![logo](logo/opennsfw2_logo.png) + +[![ci](https://github.com/bhky/opennsfw2/actions/workflows/ci.yml/badge.svg)](https://github.com/bhky/opennsfw2/actions) +[![License MIT 1.0](https://img.shields.io/badge/license-MIT%201.0-blue.svg)](LICENSE) + +# Introduction + +Detecting Not-Suitable-For-Work (NSFW) content is a high demand task in +computer vision. While there are many types of NSFW content, here we focus on +the pornographic images and videos. + +The [Yahoo Open-NSFW model](https://github.com/yahoo/open_nsfw) originally +developed with the Caffe framework has been a favourite choice, but the work +is now discontinued and Caffe is also becoming less popular. +Please see the description on the Yahoo project page for +the context, definitions, and model training details. + +This **Open-NSFW 2** project provides a TensorFlow 2 implementation of the +Yahoo model, with references to its previous third-party +[TensorFlow 1 implementation](https://github.com/mdietrichstein/tensorflow-open_nsfw). + +A simple API is provided for making predictions on images and videos. + +# Installation + +Tested for Python 3.8, 3.9, and 3.10. + +The best way to install Open-NSFW 2 with its dependencies is from PyPI: +```shell +python3 -m pip install --upgrade opennsfw2 +``` +Alternatively, to obtain the latest version from this repository: +```shell +git clone git@github.com:bhky/opennsfw2.git +cd opennsfw2 +python3 -m pip install . +``` + +# Usage + +Quick examples for getting started are given below. +For more details, please refer to the [API](#api) section. + +## Images + +```python +import opennsfw2 as n2 + +# To get the NSFW probability of a single image. +image_path = "path/to/your/image.jpg" + +nsfw_probability = n2.predict_image(image_path) + +# To get the NSFW probabilities of a list of images. +# This is better than looping with `predict_image` as the model will only be instantiated once +# and batching is used during inference. +image_paths = [ + "path/to/your/image1.jpg", + "path/to/your/image2.jpg", + # ... +] + +nsfw_probabilities = n2.predict_images(image_paths) +``` + +## Video + +```python +import opennsfw2 as n2 + +# The video can be in any format supported by OpenCV. +video_path = "path/to/your/video.mp4" + +# Return two lists giving the elapsed time in seconds and the NSFW probability of each frame. +elapsed_seconds, nsfw_probabilities = n2.predict_video_frames(video_path) +``` + +## Lower level with TensorFlow / Keras + +```python +import numpy as np +import opennsfw2 as n2 +from PIL import Image + +# Load and preprocess image. +image_path = "path/to/your/image.jpg" +pil_image = Image.open(image_path) +image = n2.preprocess_image(pil_image, n2.Preprocessing.YAHOO) +# The preprocessed image is a NumPy array of shape (224, 224, 3). + +# Create the model. +# By default, this call will search for the pre-trained weights file from path: +# $HOME/.opennsfw2/weights/open_nsfw_weights.h5 +# If not exists, the file will be downloaded from this repository. +# The model is a `tf.keras.Model` object. +model = n2.make_open_nsfw_model() + +# Make predictions. +inputs = np.expand_dims(image, axis=0) # Add batch axis (for single image). +predictions = model.predict(inputs) + +# The shape of predictions is (num_images, 2). +# Each row gives [sfw_probability, nsfw_probability] of an input image, e.g.: +sfw_probability, nsfw_probability = predictions[0] +``` + +# API + +### `preprocess_image` +Apply necessary preprocessing to the input image. +- Parameters: + - `pil_image` (`PIL.Image`): Input as a Pillow image. + - `preprocessing` (`Preprocessing` enum, default `Preprocessing.YAHOO`): + See [preprocessing details](#preprocessing-details). +- Return: + - NumPy array of shape `(224, 224, 3)`. + +### `Preprocessing` +Enum class for preprocessing options. +- `Preprocessing.YAHOO` +- `Preprocessing.SIMPLE` + +### `make_open_nsfw_model` +Create an instance of the NSFW model, optionally with pre-trained weights from Yahoo. +- Parameters: + - `input_shape` (`Tuple[int, int, int]`, default `(224, 224, 3)`): + Input shape of the model, this should not be changed. + - `weights_path` (`Optional[str]`, default `$HOME/.opennsfw/weights/open_nsfw_weights.h5`): + Path to the weights in HDF5 format to be loaded by the model. + The weights file will be downloaded if not exists. + If `None`, no weights will be downloaded nor loaded to the model. + Users can provide path if the default is not preferred. + The environment variable `OPENNSFW2_HOME` can also be used to indicate + where the `.opennsfw2/` directory should be located. +- Return: + - `tf.keras.Model` object. + +### `predict_image` +End-to-end pipeline function from the input image to the predicted NSFW probability. +- Parameters: + - `image_path` (`str`): Path to the input image file. + The image format must be supported by Pillow. + - `preprocessing`: Same as that in `preprocess_image`. + - `weights_path`: Same as that in `make_open_nsfw_model`. + - `grad_cam_path` (`Optional[str]`, default `None`): If not `None`, e.g., `cam.jpg`, + a [Gradient-weighted Class Activation Mapping (Grad-CAM)](https://keras.io/examples/vision/grad_cam/) + overlay plot will be saved, which highlights the important region(s) of the + (preprocessed) input image that lead to the prediction. + - `alpha` (`float`, default `0.8`): Opacity of the Grad-CAM layer of the plot, + only valid if `grad_cam_path` is not `None`. +- Return: + - `nsfw_probability` (`float`): The predicted NSFW probability of the image. + +### `predict_images` +End-to-end pipeline function from the input images to the predicted NSFW probabilities. +- Parameters: + - `image_paths` (`Sequence[str]`): List of paths to the input image files. + The image format must be supported by Pillow. + - `batch_size` (`int`, default `8`): Batch size to be used for model inference. + Choose a value that works the best with your device resources. + - `preprocessing`: Same as that in `preprocess_image`. + - `weights_path`: Same as that in `make_open_nsfw_model`. + - `grad_cam_paths` (`Optional[Sequence[str]]`, default `None`): If not `None`, + the corresponding Grad-CAM plots for the input images will be saved. + See the description in `predict_image`. + - `alpha`: Same as that in `predict_image`. +- Return: + - `nsfw_probabilities` (`List[float]`): Predicted NSFW probabilities of the images. + +### `Aggregation` +Enum class for aggregation options in video frames prediction. +- `Aggregation.MEAN` +- `Aggregation.MEDIAN` +- `Aggregation.MAX` +- `Aggregation.MIN` + +### `predict_video_frames` +End-to-end pipeline function from the input video to predictions. +- Parameters: + - `video_path` (`str`): Path to the input video source. + The video format must be supported by OpenCV. + - `frame_interval` (`int`, default `8`): Prediction will be done on every this + number of frames, starting from frame 1, i.e., if this is 8, then + prediction will only be done on frame 1, 9, 17, etc. + - `aggregation_size` (`int`, default `8`): + Number of frames for which their predicted NSFW probabilities will be aggregated. + For instance, if a prediction will be done "on" frame 9 (decided by `frame_interval`), + then it actually means prediction will be done on `aggregation_size` frames + starting from frame 9, e.g., frames 9 to 16 if the size is 8. + The predicted probabilities will be aggregated. After aggregation, + each of these frames in that interval will be assumed the same aggregated probability. + - `aggregation` (`Aggregation` enum, default `Aggregation.MEAN`): + The aggregation method. + - `batch_size` (`int`, default `8`, upper-bounded by `aggregation_size`): + Batch size to be used for model inference. Choose a value that works the best + with your device resources. + - `output_video_path` (`Optional[str]`, default `None`): + If not `None`, e.g., `out.mp4`, + an output MP4 video with the same frame size and frame rate as + the input video will be saved via OpenCV. The predicted NSFW probability + is printed on the top-left corner of each frame. Be aware that the output + file size could be much larger than the input file size. + This output video is for reference only. + - `preprocessing`: Same as that in `preprocess_image`. + - `weights_path`: Same as that in `make_open_nsfw_model`. + - `progress_bar` (`bool`, default `True`): Whether to show the progress bar. +- Return: + - Tuple of `List[float]`, each with length equals to the number of video frames. + - `elapsed_seconds`: Video elapsed time in seconds at each frame. + - `nsfw_probabilities`: NSFW probability of each frame. + For any `frame_interval > 1`, all frames without a prediction + will be assumed to have the NSFW probability of the previous predicted frame. + +# Preprocessing details + +## Options + +This implementation provides the following preprocessing options. +- `YAHOO`: The default option which was used in the original + [Yahoo's Caffe](https://github.com/yahoo/open_nsfw/blob/master/classify_nsfw.py#L19-L80) + and the later + [TensorFlow 1](https://github.com/mdietrichstein/tensorflow-open_nsfw/blob/master/image_utils.py#L4-L53) + implementations. The key steps are: + - Resize the input Pillow image to `(256, 256)`. + - Store the image as JPEG in memory and reload it again to a NumPy image + (this step is mysterious, but somehow it really makes a difference). + - Crop the centre part of the NumPy image with size `(224, 224)`. + - Swap the colour channels to BGR. + - Subtract the training dataset mean value of each channel: `[104, 117, 123]`. +- `SIMPLE`: A simpler and probably more intuitive preprocessing option is also provided, + but note that the model output probabilities will be different. + The key steps are: + - Resize the input Pillow image to `(224, 224)`. + - Convert to a NumPy image. + - Swap the colour channels to BGR. + - Subtract the training dataset mean value of each channel: `[104, 117, 123]`. + +## Comparison + +Using 521 private test images, the NSFW probabilities given by +three different settings are compared: +- [TensorFlow 1 implementation](https://github.com/mdietrichstein/tensorflow-open_nsfw) with `YAHOO` preprocessing. +- TensorFlow 2 implementation with `YAHOO` preprocessing. +- TensorFlow 2 implementation with `SIMPLE` preprocessing. + +The following figure shows the result: + +![NSFW probabilities comparison](docs/nsfw_probabilities_comparison.png) + +The current TensorFlow 2 implementation with `YAHOO` preprocessing +can totally reproduce the well-tested TensorFlow 1 result, +with small floating point errors only. + +With `SIMPLE` preprocessing the result is different, where the model tends +to give lower probabilities over the current test images. + +Note that this comparison does not conclude which preprocessing method is +"better", it only shows their discrepancies. However, users that prefer the +original Yahoo result should go for the default `YAHOO` preprocessing. + + +%prep +%autosetup -n opennsfw2-0.10.2 + +%build +%py3_build + +%install +%py3_install +install -d -m755 %{buildroot}/%{_pkgdocdir} +if [ -d doc ]; then cp -arf doc %{buildroot}/%{_pkgdocdir}; fi +if [ -d docs ]; then cp -arf docs %{buildroot}/%{_pkgdocdir}; fi +if [ -d example ]; then cp -arf example %{buildroot}/%{_pkgdocdir}; fi +if [ -d examples ]; then cp -arf examples %{buildroot}/%{_pkgdocdir}; fi +pushd %{buildroot} +if [ -d usr/lib ]; then + find usr/lib -type f -printf "/%h/%f\n" >> filelist.lst +fi +if [ -d usr/lib64 ]; then + find usr/lib64 -type f -printf "/%h/%f\n" >> filelist.lst +fi +if [ -d usr/bin ]; then + find usr/bin -type f -printf "/%h/%f\n" >> filelist.lst +fi +if [ -d usr/sbin ]; then + find usr/sbin -type f -printf "/%h/%f\n" >> filelist.lst +fi +touch doclist.lst +if [ -d usr/share/man ]; then + find usr/share/man -type f -printf "/%h/%f.gz\n" >> doclist.lst +fi +popd +mv %{buildroot}/filelist.lst . +mv %{buildroot}/doclist.lst . + +%files -n python3-opennsfw2 -f filelist.lst +%dir %{python3_sitelib}/* + +%files help -f doclist.lst +%{_docdir}/* + +%changelog +* Mon May 15 2023 Python_Bot - 0.10.2-1 +- Package Spec generated diff --git a/sources b/sources new file mode 100644 index 0000000..c68dc8a --- /dev/null +++ b/sources @@ -0,0 +1 @@ +6b16c3d2ad70e67a619c16dbef1deddc opennsfw2-0.10.2.tar.gz -- cgit v1.2.3