删除 p5.js 中的顺序重复帧

Posted

技术标签:

【中文标题】删除 p5.js 中的顺序重复帧【英文标题】:Remove sequentially duplicate frames in p5.js 【发布时间】:2021-12-18 03:13:34 【问题描述】:
    在下面的代码中,我想获取前 120 帧。 然后我想删除顺序重复的

ffmpeg 有一个 mpdecimate 过滤器,它应该丢弃彼此没有太大差异的帧。

但我不知道是否有 ffmpeg Js 库(或等效的)可以在 p5.js 上下文中执行类似的操作。

function setup() 
  frameRate(24)
  video = createCapture(VIDEO)
  video.size(videoWidth, videoHeight)
  video.hide()

  createCanvas(canvasWidth, canvasWidth)


let frames       = []
let uniqueFrames = []
let STOP         = false

function draw() 

  if (video && video.loadedmetadata && frameCount <= 100) 
    frames.push(image(video.get()))
   else if (!STOP) 
    STOP = true
    uniqueFrames = removeDuplicates(frames)
  

【问题讨论】:

【参考方案1】:

您可以做的一件事是获取两个帧之间的绝对差。

当您这样做时,如果所有像素都匹配,则结果将是一个完全黑色的图像,否则您将在帧不同的地方拥有更亮的像素。对于一堆传统的计算机视觉任务来说,这是一项非常有用的基本技术。

你可以做的是编写一个函数,它接收两帧,计算绝对差,计算非零像素并返回它。此值在针对阈值的 if 条件中很有用:也许帧不需要 100% 相同,但如果它们假设 85% 相同,那么您可以将其标记为重复。

Kyle McDonald's Frame Difference p5.js example 太棒了!

作为参考,我只是在这里列出凯尔的例子:

// https://kylemcdonald.github.io/cv-examples/

var capture;
var previousPixels;
var w = 640;
var h = 480;

function setup() 
    capture = createCapture(
        audio: false,
        video: 
            width: w,
            height: h
        
    , function() 
        console.log('capture ready.')
    );
    capture.elt.setAttribute('playsinline', '');
    capture.size(w, h);
    createCanvas(w, h);
    capture.hide();


function copyImage(src, dst) 
    var n = src.length;
    if (!dst || dst.length != n) dst = new src.constructor(n);
    while (n--) dst[n] = src[n];
    return dst;


function draw() 
    capture.loadPixels();
    var total = 0;
    if (capture.pixels.length > 0)  // don't forget this!
        if (!previousPixels) 
            previousPixels = copyImage(capture.pixels, previousPixels);
         else 
            var w = capture.width,
                h = capture.height;
            var i = 0;
            var pixels = capture.pixels;
            var thresholdAmount = select('#thresholdAmount').value() * 255. / 100.;
            thresholdAmount *= 3; // 3 for r, g, b
            for (var y = 0; y < h; y++) 
                for (var x = 0; x < w; x++) 
                    // calculate the differences
                    var rdiff = Math.abs(pixels[i + 0] - previousPixels[i + 0]);
                    var gdiff = Math.abs(pixels[i + 1] - previousPixels[i + 1]);
                    var bdiff = Math.abs(pixels[i + 2] - previousPixels[i + 2]);
                    // copy the current pixels to previousPixels
                    previousPixels[i + 0] = pixels[i + 0];
                    previousPixels[i + 1] = pixels[i + 1];
                    previousPixels[i + 2] = pixels[i + 2];
                    var diffs = rdiff + gdiff + bdiff;
                    var output = 0;
                    if (diffs > thresholdAmount) 
                        output = 255;
                        total += diffs;
                    
                    pixels[i++] = output;
                    pixels[i++] = output;
                    pixels[i++] = output;
                    // also try this:
                    // pixels[i++] = rdiff;
                    // pixels[i++] = gdiff;
                    // pixels[i++] = bdiff;
                    i++; // skip alpha
                
            
        
    
    // need this because sometimes the frames are repeated
    if (total > 0) 
        select('#motion').elt.innerText = total;
        capture.updatePixels();
        image(capture, 0, 0, 640, 480);
    
<html>

<head>
    <meta charset="UTF-8">
    <title>DifferenceImage</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.6.1/p5.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.6.1/addons/p5.dom.min.js"></script>
    <link rel="stylesheet" type="text/css" href="style.css">
</head>

<body>
    <p>
        Threshold: <input type="range" id="thresholdAmount" value="25">
    </p>
    <p>
        Motion: <span id="motion">0</span>
    </p>
    <script src="sketch.js"></script>
</body>

</html>

看到它在行动here。

祝你好运,将帧差代码封装成一个可重用的函数,您可以在 removeDiplicates() 中调用该函数。

【讨论】:

原来有一个ffmpeg.js 库,所以我将尝试ffmpegmpdecimate 过滤器。谢谢! 哇,我尝试了您的示例,这非常棒:) 我已将链接包含在您的答案中。不知道如何将其整合到我的问题中:D. 那么如果total &gt; 0那么当前帧与前一帧相同,我可以忽略当前帧,是吗? 我不知道 ffmpeg 的 mpdecimate:太酷了!感谢分享。重构做得很好。 total 正在计算不同的像素数(给定阈值)。如果total == 0 则当前前一帧之间的所有像素都匹配(注意结果是完全黑帧)。这有意义吗? 如此接近!那里有两个陷阱:1.您正在推送帧的base64编码表示:如果您想使用image()进行渲染,只需存储p5.Image的副本(例如uniqueFrames.push(capture.get())),2.@987654334 @ 您尝试使用 image() 渲染帧的地方只被调用一次:您可能打算在更高级别添加一个 else,就在 draw() 结束之前,3. 可选:您可能喜欢使用 @987654338 @:index = (index + 1) % uniqueFrames.length;

以上是关于删除 p5.js 中的顺序重复帧的主要内容,如果未能解决你的问题,请参考以下文章

使用 FFmpeg 时删除顺序重复的帧

删除单链表保留顺序中的重复项

python删除列表中的重复元素并保持相对顺序不变

如何在保留顺序的同时删除列表中的重复元素?

去除ArrayList中的重复元素并保持顺序

在保留顺序函数的同时删除向量中的重复项的逻辑错误