Skip to content

Instantly share code, notes, and snippets.

@arthurkushman
Last active August 29, 2015 14:06
Show Gist options
  • Save arthurkushman/aab678f851bae634b7d9 to your computer and use it in GitHub Desktop.
Save arthurkushman/aab678f851bae634b7d9 to your computer and use it in GitHub Desktop.
NudeFilter class filters nudity/porn content 85% garanty - 15% is positive/negative (weakly tested)
package com.anumbers.core;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import javax.imageio.ImageIO;
/**
*
* @author Arthur Kushman
*/
public class NudeFilter {
private final int rangeRGBMin = 7944996, // #79 3B 24
rangeRGBMax = 16696767; // #FE C5 BF
private static final int PIXELS_MIN_FACTOR = 3, PIXELS_MAX_FACTOR = 9;
private int[] rgbMin, rgbMax;
public NudeFilter() {
// U can play with RGB as long as U need =)
rgbMin = new int[3];
// rgbMin[0] = 90; // red - original
// rgbMin[1] = 90; // green - original
// rgbMin[2] = 80; // blue - original
rgbMin[0] = 100; // red
rgbMin[1] = 100; // green
rgbMin[2] = 90; // blue
rgbMax = new int[3];
// rgbMax[0] = 210; // red - original
// rgbMax[1] = 165; // green - original
// rgbMax[2] = 175; // blue - original
rgbMax[0] = 245; // red
rgbMax[1] = 180; // green
rgbMax[2] = 175; // blue
}
// main method needed only if U test it locally - it is quite convinient
public static void main(String[] args) throws IOException {
String path = "C:\\pics\\";
File dir = new File(path);
File[] files = dir.listFiles();
String[] imgs = new String[files.length];
int c = 0;
for (File f : dir.listFiles()) {
imgs[c] = path+f.getName();
c++;
}
NudeFilter filter = new NudeFilter();
for (String img : imgs) {
int points = filter.countPoints(img);
System.out.print(points+" - "+img);
if (points >= 65) {
System.out.print(" Banned...");
}
System.out.println();
}
}
public int countPoints(String sourceImg) throws IOException {
BufferedImage bi = ImageIO.read(new File(sourceImg));
int width = bi.getWidth();
int height = bi.getHeight();
int[] xPoints = new int[6];
int[] yPoints = new int[6];
int[] zPoints = new int[4];
xPoints[0] = width / 8;
xPoints[1] = width / 4;
xPoints[2] = (width / 8 + width / 4);
xPoints[3] = width + (width / 8 + width / 4);
xPoints[4] = width - (width / 4);
xPoints[5] = width - (width / 8);
yPoints[0] = height / 8;
yPoints[1] = height / 4;
yPoints[2] = (height / 8 + height / 4);
yPoints[3] = height + (height / 8 + height / 4);
yPoints[4] = height - (height / 4);
yPoints[5] = height - (height / 8);
zPoints[0] = xPoints[2]/2;
zPoints[1] = yPoints[1];
zPoints[2] = xPoints[5];
zPoints[3] = height;
Map<Integer, Map<Integer, Integer>> pixelsCollection = new HashMap<>();
// collect all the x, y coord by color
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int rgbPixel = bi.getRGB(x, y);
int red = (rgbPixel >> 16) & 0xff;
int green = (rgbPixel >> 8) & 0xff;
int blue = rgbPixel & 0xff;
// fit colors
if (green >= rgbMin[1] && green <= rgbMax[1]
&& blue >= rgbMin[2] && blue <= rgbMax[2]
&& red >= rgbMin[0] && red <= rgbMax[0]) {
// offset from all sides
if (x >= zPoints[0] && y >= zPoints[1]
&& x <= zPoints[2] && y <= zPoints[3]) {
if (pixelsCollection.containsKey(rgbPixel)) { // add coords to existing color
pixelsCollection.get(rgbPixel).put(x, y);
} else { // add new color with 1-st coords
Map<Integer, Integer> coords = new HashMap<>();
coords.put(x, y);
pixelsCollection.put(rgbPixel, coords);
}
}
}
}
}
int pixelsMax = width/PIXELS_MAX_FACTOR;
int pixelsMin = pixelsMax/PIXELS_MIN_FACTOR;
double points = incrementPoint(pixelsCollection, pixelsMin, pixelsMax);
return countPointsRatioToSize(points, width, height);
}
private double incrementPoint(Map<Integer,
Map<Integer, Integer>> pixelsCollection, int pixelsMin, int pixelsMax) {
double points = 0;
// detect shapes by color - leave small/x-large areas ex.: 8>x<32 - nipples
for (Entry<Integer, Map<Integer, Integer>> color : pixelsCollection.entrySet()) {
Map<Integer, Integer> xy = color.getValue();
int sizeOfShape = xy.size();
if (sizeOfShape > pixelsMin && sizeOfShape < pixelsMax) {
if (sizeOfShape<=pixelsMax/2 && sizeOfShape>=pixelsMax/3) { // golden avg
points+=0.4;
} else if (sizeOfShape<pixelsMax/3 && sizeOfShape>pixelsMin) { // min shape
points+=0.3;
} else if (sizeOfShape>pixelsMax/2 && sizeOfShape<pixelsMax) { // max shape
points+=0.2;
}
}
}
return points;
}
private int countPointsRatioToSize(double points, int width, int height) {
int p = (int) (points * 100000) / (width * height) * 2;
if (p>100) p=100;
return p;
}
}
@arthurkushman
Copy link
Author

3 step porn filter:

  1. color skin detection RGB (problems with extreme black/white darkened/lightened skins)
  2. left-up-right sides truncation
  3. shapes by pixel range with image size consideration and factor division

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment