Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Video Scanning Features #29

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 27 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
# nude.js

***nude.js*** is a JavaScript implementation of a nudity scanner based on approaches from research papers. HTMLCanvas makes it possible to analyse image data and afterwards decide whether it should be displayed or not. The detection algorithm runs at the client, therefore it's possible (with user interaction) to display the image even if it's identified as nude (false positive)
***nude.js*** is a JavaScript implementation of a nudity scanner based on approaches from research papers. HTMLCanvas makes it possible to analyse image data and video data eventually converting it into image and afterwards decide whether it should be displayed or not. The detection algorithm runs at the client, therefore it's possible (with user interaction) to display the image even if it's identified as nude (false positive)
The real world usage for client side nudity detection could be in webproxies with child security filters, and maybe even more (e.g. on social media plattforms)
nude.js is Open Source. Contributions are very welcome, the goal is to build a reliable client-side nudity scanner.

**NOTE** The algorithm is mostly based on the following paper:
https://sites.google.com/a/dcs.upd.edu.ph/csp-proceedings/Home/pcsc-2005/AI4.pdf?attredirects=0

### Demo
Test the nudity detection script on several predefined images, I didn't have enough time to build a nice demo with flickr image support but feel free to test some of your images too. nude.js is currently supported in IE9(excanvas), FF 3.6+, Chrome, Safari and Opera. For really fast results try Chrome.
Test the nudity detection script on several predefined images and videos, I didn't have enough time to build a nice demo with flickr image support but feel free to test some of your images too and don't forget to add your video and correct the path in predefined div for video in my html. nude.js is currently supported in IE9(excanvas), FF 3.6+, Chrome, Safari and Opera. For really fast results try Chrome.

Include nude.js as ususal
```HTML
Expand All @@ -20,9 +20,16 @@ Add images as usual
<img src="sample2.jpg" alt="Alt text" id="image2" onclick="onImageClick('image2');" />
<img src="sample3.jpg" alt="Alt text" id="image3" onclick="onImageClick('image3');" />
```
Then run the checking algorithm on the images you want to run it on
Add videos as usual (
```HTML
<video id="demoVideo" width="320" height="240" controls>
<source src="sample1.mp4" type="video/mp4">
</video>
```

##### nude.js provides 3 functions:
Then run the checking algorithm on the images and video you want to run it on

##### nude.js provides 4 functions:

**nude.init()**

Expand All @@ -37,14 +44,30 @@ It uses 2 types of parameters: a valid id of an element in the document’s body

This function initiates the scanning process, the optional function is executed after the scanning process finished.

**nude.scanVideo(imageData, width, height, callback)**

Allows direct scanning of provided image data. Parameters include the image data, width, height, and a callback function to handle the result.

### Example
```Javascript
//for scanning images
nude.load(node);
// Scan it
nude.scan(function(result){
alert(result ? "Nudity found in " + node.id + "!" : "Not nude");
});
```
```Javascript
//for scanning videos
var imageData = /* obtain image data */;
var width = /* video frame width */;
var height = /* video frame height */;

// Perform direct video scan
nude.scanVideo(imageData, width, height, function(result) {
alert(result ? "Nudity found in video frame!" : "No nudity detected in video frame");
});
```

### Project page
https://www.patrick-wied.at/static/nudejs/
Expand Down
2 changes: 1 addition & 1 deletion compressed/nude.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

26 changes: 20 additions & 6 deletions nude.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* Nude.js - Nudity detection with Javascript and HTMLCanvas
*
* Author: Patrick Wied ( http://www.patrick-wied.at )
* Nude.js - Nudity detection with Javascript and HTMLCanvas
*
* Author: Patrick Wied ( http://www.patrick-wied.at )
* Version: 0.1 (2010-11-21)
* License: MIT License
*/
Expand Down Expand Up @@ -55,6 +55,18 @@
resultHandler(event.data);
}
},
// Function to directly scan the provided image data
scanVideo = function(imageData, width, height, callback) {
myWorker = new Worker('worker.nude.js'); // Create worker here
myWorker.postMessage([imageData, width, height]);
myWorker.onmessage = function(event) {
callback(event.data);
terminateWorker(); // Terminate the worker after processing the image
};
};
terminateWorker = function() {
myWorker.terminate();
},
// the result handler will be executed when the analysing process is done
// the result contains true (it is nude) or false (it is not nude)
// if the user passed an result function to the scan function, the result function will be executed
Expand All @@ -74,7 +86,7 @@
initCanvas();
// if web worker are not supported, append the noworker script
if(!!!window.Worker){
document.write(unescape("%3Cscript src='noworker.nude.js' type='text/javascript'%3E%3C/script%3E"));
document.write(decodeURIComponent("%3Cscript src='noworker.nude.js' type='text/javascript'%3E%3C/script%3E"));
}

},
Expand All @@ -84,18 +96,20 @@
}else{
loadImageByElement(param);
}

},
scan: function(fn){
if(arguments.length>0 && typeof(arguments[0]) == "function"){
resultFn = fn;
}
scanImage();
}
},
scanVideo: scanVideo
};
})();
// register nude at window object
if(!window.nude)
window.nude = nude;
// and initialize it
nude.init();
})();
})();
28 changes: 24 additions & 4 deletions tests/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,35 +8,55 @@
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body>

<div id="wrapper">


<h1>Demo pictures</h1>
<div class="entry">
<img id="testImage" src="images/1.jpg" width="500" height="375" alt="" />
<div class="btn" onclick="nude.load('testImage');nude.scan(function(result){ if(!result) document.getElementById('result1').innerHTML='No nude!'; });">Scan Image</div>
<div class="btn" onclick="nude.load('testImage');nude.scan(function(result){ if(!result) document.getElementById('result1').innerHTML='No nude!';else{ document.getElementById('result1').innerHTML='Nude!!'; } });">Scan Image</div>
<div style="float:right;margin-top:-20px;" id="result1"></div>
</div>
<div class="entry">
<img id="testImage2" src="images/2.jpg" width="500" height="375" alt="" />
<div class="btn" onclick="nude.load('testImage2');nude.scan(function(result){ if(!result) document.getElementById('result2').innerHTML='No nude!!'; });">Scan Image</div>
<div class="btn" onclick="nude.load('testImage2');nude.scan(function(result){ if(!result) document.getElementById('result2').innerHTML='No nude!!';else{ document.getElementById('result2').innerHTML='Nude!!'; } });">Scan Image</div>
<div style="float:right;margin-top:-20px;" id="result2"></div>
</div>
<div class="entry">
<img id="testImage3" src="images/3.jpg" width="500" height="375" alt="" />
<div class="btn" onclick="nude.load('testImage3');nude.scan(function(result){ if(!result) document.getElementById('result3').innerHTML='No nude!!'; });">Scan Image</div>
<div class="btn" onclick="nude.load('testImage3');nude.scan(function(result){ if(!result) document.getElementById('result3').innerHTML='No nude!!';else{ document.getElementById('result3').innerHTML='Nude!!'; } });">Scan Image</div>
<div style="float:right;margin-top:-20px;" id="result3"></div>
</div>
<div class="entry">
<img id="testImage4" src="images/4.jpg" width="500" height="375" alt="" />
<div class="btn" onclick="nude.load('testImage4');nude.scan(function(result){ if(!result){ document.getElementById('result4').innerHTML='No nude!!'; }else{ document.getElementById('result4').innerHTML='Nude!!'; } });">Scan Image</div>
<div style="float:right;margin-top:-20px;" id="result4"></div>
</div>
<video id="demoVideo" width="500" height="375" controls>
<source src="images/demo.mp4" type="video/mp4">
</video>
<div id="videoResult"></div>





</div>
<!-- please download excanvas if you use ie -->
<!--[if IE]>
<script type="text/javascript" src="excanvas.js"></script>




<script type="text/javascript" src="excanvas.js"></script>
<![endif]-->
<script type="text/javascript" src="nude.min.js"></script>




<script type="text/javascript" src="../nude.js"></script>
<script type="text/javascript" src="test.nude.js"></script>

</body>
Expand Down
2 changes: 1 addition & 1 deletion tests/nude.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

60 changes: 59 additions & 1 deletion tests/test.nude.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,62 @@ window.onload = function(){



}
}


var scanCount = 0;
var videoContainer = document.getElementById('videoResult');
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d', { willReadFrequently: true }); // Set willReadFrequently to true

// Variable to track the last scan time
var lastScanTime = 0;

// Add event listener to start scanning when video starts playing
document.getElementById('demoVideo').addEventListener('play', function() {
var video = this;

var scanFrame = function() {
if (!video.paused && !video.ended) {
var currentTime = video.currentTime;
var timeDiff = currentTime - lastScanTime;

// Check if at least 5 seconds have elapsed since the last scan
if (timeDiff >= 5) {
canvas.width = Math.min(video.videoWidth, 1920); // Limit width to 1920 pixels (1080p)
canvas.height = Math.min(video.videoHeight, 1080); // Limit height to 1080 pixels (1080p)
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);

// Convert ImageData to a format that can be used by nude.scan()
nude.scanVideo(imageData.data, canvas.width, canvas.height, function(result) {
console.log("Nudity found in frame: " + (result ? "Yes" : "No"));
scanCount++; // Increment scan counter
displayResultOnVideoContainer(scanCount, result);
});

// Update the last scan time
lastScanTime = currentTime;
}
}
};

// Scan every second
var scanInterval = setInterval(function() {
scanFrame();
}, 1000); // Scan every 1 second

// Stop scanning when the video ends
video.addEventListener('ended', function() {
clearInterval(scanInterval); // Stop scanning
console.log("Video scanning complete.");
});
});

function displayResultOnVideoContainer(scanNumber, result) {
var resultText = "Nudity found in scan " + scanNumber + ": " + (result ? "Yes" : "No");
var resultDiv = document.createElement('div');
resultDiv.textContent = resultText;
videoContainer.innerHTML = ''; // Clear previous results
videoContainer.appendChild(resultDiv);
}
2 changes: 2 additions & 0 deletions worker.nude.js → tests/worker.nude.js
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,8 @@ for(var i = 0, u = 1; i < length; i+=4, u++){

}



merge(detectedRegions, mergeRegions);
analyseRegions();
};
Expand Down