synopsis-video
Version:
Create Video Synopsis from provided videos. Frames are extracted from each video provided and backgrounds are subtracted around moving elements and merged into a single video for quick review.
103 lines (98 loc) • 3.04 kB
JavaScript
const fs = require('fs');
const cv = require('opencv4nodejs');
const mainDirectory = process.cwd() + '/'
const firstFrameDirectory = mainDirectory + 'firstFrame/'
const rawDirectory = mainDirectory + 'rawSubtractions/'
exports.rawDirectory = rawDirectory
exports.mainDirectory = mainDirectory
exports.firstFrameDirectory = firstFrameDirectory
exports.mergedFramesDirectory = mainDirectory + 'mergedFrames/'
exports.createBaseFolder = (folderName) => {
try{
fs.mkdirSync(folderName)
}catch(err){
}
}
exports.makeVideoImagesFolder = (folderName) => {
try{
fs.mkdirSync(rawDirectory + folderName)
}catch(err){
}
}
exports.grabFrames = (videoFile, delay, onFrame, onDone) => {
const cap = new cv.VideoCapture(videoFile);
let done = false;
const intvl = setInterval(() => {
let frame = cap.read();
if (frame.empty) {
done = true
clearInterval(intvl);
onDone();
return
}
onFrame(frame);
const key = cv.waitKey(delay);
done = key !== -1 && key !== 255;
if (done) {
clearInterval(intvl);
console.log('Key pressed, exiting.');
}
}, 0);
};
exports.grabFirstFrame = (videoFile) => {
const cap = new cv.VideoCapture(videoFile);
let frame = cap.read();
// loop back to start on end of stream reached
if (frame.empty) {
return null;
}
cv.imwrite(`${firstFrameDirectory}${videoFile.split('.')[0]}.jpg`, frame);
};
exports.getMatricesOfContours = (binaryImg, minPxSize, fixedRectWidth, dstImage) => {
const {
centroids,
stats
} = binaryImg.connectedComponentsWithStats();
const matrices = [];
// pretend label 0 is background
for (let label = 1; label < centroids.rows; label += 1) {
const [x1, y1] = [stats.at(label, cv.CC_STAT_LEFT), stats.at(label, cv.CC_STAT_TOP)];
const [x2, y2] = [
x1 + (fixedRectWidth || stats.at(label, cv.CC_STAT_WIDTH)),
y1 + (fixedRectWidth || stats.at(label, cv.CC_STAT_HEIGHT))
];
const size = stats.at(label, cv.CC_STAT_AREA);
const blue = new cv.Vec(255, 0, 0);
if (minPxSize < size) {
if(dstImage){
dstImage.drawRectangle(
new cv.Point(x1, y1),
new cv.Point(x2, y2),
{ color: blue, thickness: 2 }
);
}else{
matrices.push([label,x1,y1,x2,y2]);
}
}
}
return dstImage ? dstImage : matrices
};
exports.stripNameJpg = (name) => {
return parseInt(name.replace('.jpg',''))
}
exports.stripNamePng = (name) => {
return parseInt(name.replace('img','').replace('.png',''))
}
exports.splitForFfmpeg = (ffmpegCommandAsString) => {
//this function ignores spaces inside quotes.
return ffmpegCommandAsString.replace(/\s+/g,' ').trim().match(/\\?.|^$/g).reduce((p, c) => {
if(c === '"'){
p.quote ^= 1;
}else if(!p.quote && c === ' '){
p.a.push('');
}else{
p.a[p.a.length-1] += c.replace(/\\(.)/,"$1");
}
return p;
}, {a: ['']}).a
}