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

Run on every frame in Video #39

Open
GantMan opened this issue Mar 4, 2019 · 18 comments
Open

Run on every frame in Video #39

GantMan opened this issue Mar 4, 2019 · 18 comments
Assignees
Labels
enhancement New feature or request hacktoberfest-accepted help wanted Extra attention is needed

Comments

@GantMan
Copy link
Member

GantMan commented Mar 4, 2019

Much like the discussion over in #38
There's been a request to run on every frame in a video.

It's possible to do in JS like so: https://jsfiddle.net/bmartel/3h98gsvk/11/

Maybe a syntax like model.classifyVideo(video) or model.classifyAny(img|gif|video)

@GantMan GantMan added enhancement New feature or request help wanted Extra attention is needed labels Mar 4, 2019
@GantMan GantMan mentioned this issue Mar 4, 2019
@fvonhoven
Copy link

I'll take this one!

@stared
Copy link

stared commented Mar 15, 2019

I would be interested in one.

THough, for video I am curious about performance. (Did you benchmark frames per second? In my case, on a 8-year-old Macbook Pro, it takes ~10s for image classification.)

@GantMan
Copy link
Member Author

GantMan commented Mar 16, 2019

I imagine this would take a while client-side. However, I'd like to start at (just do it) and then work on doing it fast. There could be a "random scan" which checks every 10 or 100 frames. Just TOL.

@bongobongo
Copy link

Depending on the hardware on the client side, the speed could be increased drastically by creating several instances of the nsfwjs - using Web Workers. Then one could classify multiple frames in parallell. The number of workers that could work efficiently is probably defined by frame size (image size), CPU and memory. I have tested Web Workers against the current version of NSFWJS, and it works in the latest versions of Chrome and Opera. I did it because my web clients need to interact with the page UI immediately, and not wait 5 - 20 seconds (or more, e.g. mobile) for the model to load. Runing NSFWJS in a Web Worker - made it so that both the loading and classifying of images was done in a process separated from what happens in javascript in the main page. More about it here:
#94 (comment)

@GantMan
Copy link
Member Author

GantMan commented May 1, 2019

I like this idea.

@qgustavor
Copy link

qgustavor commented Jan 26, 2020

How about using keyframe or scene detection to better select what frames to analyze?

@GantMan
Copy link
Member Author

GantMan commented Jan 28, 2020

I really like that. Is that doable in JS?

@yzevm
Copy link
Contributor

yzevm commented Jul 29, 2020

I'll try to implement it

@uzaysan
Copy link

uzaysan commented Sep 2, 2020

Hi @YegorZaremba Any update on this?

@yzevm
Copy link
Contributor

yzevm commented Sep 2, 2020

@uzaysan Yeap, we can use same interface for classifyVideo method as we use for classifyGif https://github.com/infinitered/nsfwjs/pull/401/files#diff-f41e9d04a45c83f3b6f6e630f10117feL194

Add guard that checks is video fully buffered, if not - throw an error. Also for nodejs usage, we should accept Buffers you can see how it works for gif https://github.com/infinitered/nsfwjs/pull/401/files#diff-f41e9d04a45c83f3b6f6e630f10117feR206

  async classifyVideo(
    video: HTMLVideoElement,
    config: classifyConfig = { topk: 5, fps: 25 }
  ): Promise<Array<Array<predictionClassType>>> {
    const totalFrames: number = Math.floor(video.duration * config.fps)
    const interval: number = video.duration / totalFrames

    // @NOTE Messy, but after refactoring please test with 25+ fps
    const acceptedFrames: number[] = []
    for (let i = 0; i < totalFrames; i++) {
      const frame = Math.floor((i * interval) * 100) / 100
      acceptedFrames.push(frame)
    }

    const canvas = createCanvas(video.offsetWidth, video.offsetHeight)
    const context = canvas.getContext('2d')
    const arrayOfClasses: predictionClassType[][]  = []
    for (let i = 0; i < acceptedFrames.length; i++) {
      video.currentTime = acceptedFrames[i]
      context.drawImage(video, 0, 0, canvas.width, canvas.height);

      const image = await loadImage(canvas.toDataURL()) // new Image() onload onerror
      // @ts-ignore
      const classes = await this.classify(image, config.topk);
      arrayOfClasses.push(classes)
    }

    return arrayOfClasses
  }

Problems

const image = await loadImage(canvas.toDataURL())

For most browser using this line of code will throw an error like https://stackoverflow.com/questions/35244215/html5-video-screenshot-via-canvas-using-cors/35245146
I have no idea how to fix it, we can implement this logic as is, and if we have that error, just throw new NSFWError(error), but as led dev of @nsfw-filter is not solved my problems at all

UPD1, I'll return to this issue when I have free time and announce to everyone on this issue

@uzaysan
Copy link

uzaysan commented Sep 2, 2020

@YegorZaremba Thanks for quick reply. I'm using this library in server side(NodeJs). But when I pass video buffer, It throws an unsuported Image error.

Expected image (BMP, JPEG, PNG, or GIF), but got unsupported image type

I'm using it like this:

const model = await nsfwlib.load();
const video = await tf.node.decodeImage(videoBuffer);
const predictions = await model.classify(video);

Also I'm using version 2.2.0

What am I doing wrong? Can you please help me?

@yzevm
Copy link
Contributor

yzevm commented Sep 2, 2020

But when I pass video buffer, It throws an unsupported Image error.

@uzaysan This feature is not implemented yet, you can slice your video to images by yourself and predict these image, just google some lib mp4 to img node.js, I hope sth exists in the npm

@uzaysan
Copy link

uzaysan commented Sep 2, 2020

So I should classify video frames one by one. Am I right? But Also I can use library bu converting video to gif? Can you confirm?

Also when will video classification be available? Do you have an estimate date? I saw in some issues, you associated this feature to v2.3.0. When will that version come out.

Thanks.

@yzevm
Copy link
Contributor

yzevm commented Sep 2, 2020

yeap, great idea
So if you want use classifyGif pls install @nsfw-filter/nsfwjs because this feature(classifyGif) has the status "Work in progress" (just some fixes for nsfw.com) but we use this package in @nsfw-filter. It works pretty slow for Buffers in Nodejs (but it works :D)

@uzaysan
Copy link

uzaysan commented Sep 2, 2020

Thank you I will try

@MINORITYmaN
Copy link

Hi there!
Offscreen canvas could help get it more perfomant with web workers, but https://caniuse.com/offscreencanvas :(

https://developers.google.com/web/updates/2018/08/offscreen-canvas

@RanaOsamaAsif
Copy link

Hi all,

It's been almost 2.5 years since the last comment 😅

Are there any updates on this being implemented?

@GantMan
Copy link
Member Author

GantMan commented Mar 18, 2023

Currently, we are looking for someone to champion this task/example.

I've been playing with the idea of putting time into updating the library to separate out GIF/VID into separate libraries that depend on this one. But without a break in time, or a client looking to sponsor the project, it's hard to find the time.

@cdanwards - if we ever have non-billable time for you, this might be a good task for the community.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request hacktoberfest-accepted help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

10 participants