Python Nude Image Detection Using Pillow: Algorithm, Implementation, and Visualization
This tutorial explains how to build a Python program that detects nude images by analyzing skin-colored regions with Pillow, covering project setup, image preprocessing, pixel classification using RGB/HSV/YCrCb formulas, region merging, decision rules, and command‑line usage with optional visualization.
The article introduces a project that uses Python 3 and the Pillow library to identify whether an image contains nudity by detecting skin-colored areas. It first explains the purpose of the project and provides a brief overview of the PIL (Python Image Library) capabilities such as resizing, rotating, and color‑space conversion.
Environment preparation describes installing Pillow (the actively maintained fork of PIL) via pip and ensuring Python 3 is available. A simple command to upgrade pip and install Pillow is shown.
Program principle outlines the algorithm: iterate over each pixel, classify it as skin or not using several color‑space rules (RGB, normalized RGB, HSV, YCbCr), group adjacent skin pixels into regions, discard tiny regions, and apply four heuristic rules to decide if the image is non‑nude.
Key implementation steps include:
Loading an image and converting grayscale images to RGB.
Creating a Skin namedtuple to store pixel information (id, skin flag, region, x, y).
Iterating over all pixels, classifying skin with _classify_skin, and building region lists.
Merging connected regions using _add_merge and _merge.
Analyzing merged regions with _analyse_regions based on size, proportion, and count thresholds.
Providing an inspect method for a textual summary and a showSkinRegions method to generate a black‑and‑white visualization where skin pixels are white.
Key code snippets:
import sys
import os
import _io
from collections import namedtuple
from PIL import Image class Nude:
Skin = namedtuple("Skin", "id skin region x y")
def __init__(self, path_or_image):
# initialization logic ... def resize(self, maxwidth=1000, maxheight=1000):
ret = 0
if maxwidth and self.width > maxwidth:
wpercent = maxwidth / self.width
hsize = int(self.height * wpercent)
self.image = self.image.resize((maxwidth, hsize), Image.LANCZOS)
ret += 1
if maxheight and self.height > maxheight:
hpercent = maxheight / float(self.height)
wsize = int(self.width * hpercent)
self.image = self.image.resize((wsize, maxheight), Image.LANCZOS)
ret += 2
return ret def _classify_skin(self, r, g, b):
rgb_classifier = (r > 95 and g > 40 and g < 100 and b > 20 and
max([r, g, b]) - min([r, g, b]) > 15 and
abs(r - g) > 15 and r > g and r > b)
nr, ng, nb = self._to_normalized(r, g, b)
norm_rgb_classifier = (nr / ng > 1.185 and
(r * b) / ((r + g + b) ** 2) > 0.107 and
(r * g) / ((r + g + b) ** 2) > 0.112)
h, s, v = self._to_hsv(r, g, b)
hsv_classifier = (h > 0 and h < 35 and s > 0.23 and s < 0.68)
y, cb, cr = self._to_ycbcr(r, g, b)
ycbcr_classifier = (97.5 <= cb <= 142.5 and 134 <= cr <= 176)
return ycbcr_classifier def _to_normalized(self, r, g, b):
if r == 0: r = 0.0001
if g == 0: g = 0.0001
if b == 0: b = 0.0001
_sum = float(r + g + b)
return [r / _sum, g / _sum, b / _sum] def _add_merge(self, _from, _to):
self.last_from = _from
self.last_to = _to
# logic to add or merge region lists ... def _analyse_regions(self):
if len(self.skin_regions) < 3:
self.message = "Less than 3 skin regions ({})".format(len(self.skin_regions))
self.result = False
return self.result
# further heuristic checks ...
self.result = True
return self.resultThe script also includes a command‑line interface using argparse, allowing users to specify image files, optionally resize them for speed, and generate visualizations of detected skin regions.
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser(description='Detect nudity in images.')
parser.add_argument('files', metavar='image', nargs='+', help='Images you wish to test')
parser.add_argument('-r', '--resize', action='store_true', help='Reduce image size to increase speed of scanning')
parser.add_argument('-v', '--visualization', action='store_true', help='Generating areas of skin image')
args = parser.parse_args()
for fname in args.files:
if os.path.isfile(fname):
n = Nude(fname)
if args.resize:
n.resize(maxheight=800, maxwidth=600)
n.parse()
if args.visualization:
n.showSkinRegions()
print(n.result, n.inspect())
else:
print(fname, "is not a file")Finally, the article shows a test run on a normal image, demonstrates the command used, and concludes with a summary of what was learned, noting possible improvements such as better skin‑color formulas, refined heuristics, and performance optimizations using multithreading or multiprocessing.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Python Programming Learning Circle
A global community of Chinese Python developers offering technical articles, columns, original video tutorials, and problem sets. Topics include web full‑stack development, web scraping, data analysis, natural language processing, image processing, machine learning, automated testing, DevOps automation, and big data.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
