Permalink
Browse files

add function to extract characters

  • Loading branch information...
sdpython committed Jan 17, 2018
1 parent 4d0cbb2 commit e8f2b096b18fa6173a7ca113010c75437e2cfbc4
View
@@ -24,7 +24,7 @@ README
.. image:: https://badge.waffle.io/sdpython/code_beatrix.png?label=ready&title=Ready
:alt: Waffle
:target: https://waffle.io/actuariat_python/code_beatrix
:target: https://waffle.io/sdpython/code_beatrix
.. image:: https://img.shields.io/badge/license-MIT-blue.svg
:alt: MIT License
@@ -2,10 +2,15 @@
API
===
Cette section résume les principales fonctionnalités
implémentées dans ce module et principalement destinées
à la préparation d'ateliers de découverte de la programmation.
.. toctree::
:maxdepth: 2
ai
algorithm
notebooks
video
videodl
@@ -0,0 +1,17 @@
.. _l-api-videodl:
Traitements complexes de vidéos
===============================
Cette section présente des fonctions qui opère des traitements
complexes sur une vidéo comme flouter les silhouettes
de personnages.
.. contents::
:local:
Deep Learning
+++++++++++++
.. autosignature:: code_beatrix.art.videodl.video_map_images
@@ -113,7 +113,7 @@ Contacts
.. image:: https://badge.waffle.io/sdpython/code_beatrix.png?label=ready&title=Ready
:alt: Waffle
:target: https://waffle.io/actuariat_python/code_beatrix
:target: https://waffle.io/sdpython/code_beatrix
.. image:: https://img.shields.io/badge/license-MIT-blue.svg
:alt: MIT License
View
Binary file not shown.
@@ -0,0 +1,71 @@
# -*- coding: utf-8 -*-
"""
@brief test log(time=1000s)
Duraction is around a few seconds but the test needs to be run
at the end of the series of unitests as it interferes
with the notebook unittesting (it uses Popen too).
"""
import sys
import os
import unittest
try:
import pyquickhelper
except ImportError:
path = os.path.normpath(
os.path.abspath(
os.path.join(
os.path.split(__file__)[0],
"..",
"..",
"..",
"pyquickhelper",
"src")))
if path not in sys.path:
sys.path.append(path)
import pyquickhelper
try:
import src
except ImportError:
path = os.path.normpath(
os.path.abspath(
os.path.join(
os.path.split(__file__)[0],
"..",
"..")))
if path not in sys.path:
sys.path.append(path)
import src
from pyquickhelper.loghelper import fLOG
from pyquickhelper.pycode import get_temp_folder, ExtTestCase
from src.code_beatrix.art.videodl import video_map_images
from src.code_beatrix.art.video import video_save, video_extract_video
class TestVideoDLPeople(ExtTestCase):
def test_modify_avideo(self):
fLOG(
__file__,
self._testMethodName,
OutputPrint=__name__ == "__main__")
temp = get_temp_folder(__file__, "temp_videodl_people")
vid = os.path.join(temp, '..', 'data', 'mur.mp4')
vide = video_extract_video(vid, 0, 5 if __name__ == "__main__" else 1)
vid2 = video_map_images(
vide, fps=10, name="people", progress_bar=__name__ == "__main__", fLOG=fLOG)
exp = os.path.join(temp, "people.mp4")
video_save(vid2, exp)
self.assertExists(exp)
if __name__ == "__main__":
unittest.main()
@@ -73,7 +73,8 @@ def ModelFile(self):
"""
return self._model_file
def _new_size(self, old_size, new_size):
@staticmethod
def _new_size(old_size, new_size):
"""
Computes a new size.
@@ -128,13 +129,19 @@ def _load_image(self, img, resize=None):
feat = skimage.io.imread(img)
else:
pilimg = Image.open(img)
si = self._new_size(pilimg.size, resize)
si = DLImageSegmentation._new_size(pilimg.size, resize)
pilimg2 = pilimg.resize(si)
feat = pil_to_ndarray(pilimg2)
elif isinstance(img, numpy.ndarray):
if resize is not None:
raise NotImplementedError('resize not None is not implemented')
feat = img
if resize is None:
feat = img
else:
# Does not work...
# feat = skimage.transform.resize(img, resize)
# So...
pilimg = Image.fromarray(img).convert('RGB')
pilimg2 = pilimg.resize(resize)
feat = pil_to_ndarray(pilimg)
else:
raise NotImplementedError(
"Not implemented for type '{0}'".format(type(img)))
View
Binary file not shown.
@@ -0,0 +1,156 @@
# -*- coding: utf-8 -*-
"""
@file
@brief Fonctions proposant de traiter des vidéos
avec des traitements compliqués type
:epkg:`deep learning`.
"""
from moviepy.video.io.ImageSequenceClip import ImageSequenceClip
from ..ai import DLImageSegmentation
from .video import video_enumerate_frames
def video_map_images(video_or_file, name, fLOG=None, **kwargs):
"""
Applies one complex process to a video such as
extracting characters from videos and
removing the backaground. It is done image by image.
Applique un traitement compliqué sur une séquence
d'images telle que la séparation des personnages et du fond.
@param video_or_file string or :epkg:`VideoClip`
@param name name of the processing to do,
see the list below
@param fLOG logging function
@param kwargs additional parameters
@return :epkg:`VideoClip`
List of available treatments:
* ``'people'``: extracts characters from a movie.
The movie is composed with an image and a
`mask <https://zulko.github.io/moviepy/ref/AudioClip.html?highlight=mask#moviepy.audio.AudioClip.AudioClip.set_ismask>`_.
Parameters: see @fn video_map_images_people.
.. warning:: A couple of errors timeout, out of memory...
The following processes might be quite time consuming
or memory consuming. If it is the case, you should think
of reducing the resolution, the number of frames per seconds
(*fps*). You can also split the video and process each piece
independently and finally concatenate them.
"""
allowed = {'people'}
if name == 'people':
return video_map_images_people(video_or_file, fLOG=fLOG, **kwargs)
else:
raise ValueError("Unknown process '{}', should be among: {}".format(
name, ','.join(allowed)))
def video_map_images_people(video_or_file, resize=('max2', 400), fps=None,
with_times=False, progress_bar=False, dtype=None,
class_to_keep=15, fLOG=None, **kwargs):
"""
Extracts characters from a movie.
The movie is composed with an image and a
`mask <https://zulko.github.io/moviepy/ref/AudioClip.html?highlight=mask#moviepy.audio.AudioClip.AudioClip.set_ismask>`_.
Extrait les personnages d'un film, le résultat est
composé d'une image et d'un masque transparent
qui laissera apparaître l'image d'en dessous si cette
vidéo est aposée sur une autre.
@param video_or_file string or :epkg:`VideoClip`
@param resize see :meth:`predict <code_beatrix.ai.image_segmentation.DLImageSegmentation.predict>`
@param fps see @see fn video_enumerate_frames
@param with_times see @see fn video_enumerate_frames
@param progress_bar see @see fn video_enumerate_frames
@param dtype see @see fn video_enumerate_frames
@param class_to_keep class to keep from the image, it can
a number (15 for the background, a list of classes,
a function which takes an image and the prediction
and returns an image)
@param fLOG logging function
@param kwargs see @see cl DLImageSegmentation
@return :epkg:`VideoClip`
.. warning:: A couple of errors timeout, out of memory...
The following processes might be quite time consuming
or memory consuming. If it is the case, you should think
of reducing the resolution, the number of frames per seconds
(*fps*). You can also split the video and process each piece
independently and finally concatenate them.
.. exref::
:title: Extract characters from a video.
The following example shows how to extract a movie with
people and without the background. It works better
if the contrast between the characters and the background is
high.
::
from code_beatrix.art.video import video_extract_video, video_save
from code_beatrix.art.videodl import video_map_images
vide = video_extract_video("something.mp4", 0, 5)
vid2 = video_map_images(vide, fps=10, name="people", progress_bar=True)
video_save(vid2, "people.mp4")
The function returns something like the the following.
The character is wearing black and the background is quite
dark too. That explains that the kind of large halo
around the character.
.. video:: videodl.mp4
"""
if isinstance(class_to_keep, int):
def local_mask(img, pred):
img[pred != class_to_keep] = 0
return img
elif isinstance(class_to_keep, (set, tuple, list)):
def local_mask(img, pred):
dist = set(pred.ravel())
rem = set(class_to_keep)
for cl in dist:
if cl not in rem:
img[pred == cl] = 0
return img
elif callable(class_to_keep):
local_mask = class_to_keep
else:
raise TypeError("class_to_keep should be an int, a list or a function not {0}".format(
type(class_to_keep)))
if fLOG:
fLOG('[video_map_images_people] loads deep learning model')
model = DLImageSegmentation(fLOG=fLOG, **kwargs)
iter = video_enumerate_frames(video_or_file, fps=fps, with_times=with_times,
progress_bar=progress_bar, dtype=dtype)
if fLOG is not None:
if fps is not None:
every = max(fps, 1)
unit = 's'
else:
every = 20
unit = 'i'
if fLOG:
fLOG('[video_map_images_people] starts extracting characters')
seq = []
for i, img in enumerate(iter):
if not progress_bar and fLOG is not None and i % every == 0:
fLOG('[video_map_images_people] process %d%s images' % (i, unit))
if resize is not None and isinstance(resize[0], str):
if len(img.shape) == 2:
resize = DLImageSegmentation._new_size(img.shape, resize)
else:
resize = DLImageSegmentation._new_size(img.shape[:2], resize)
img, pred = model.predict(img, resize=resize)
img2 = local_mask(img, pred)
seq.append(img2)
if fLOG:
fLOG('[video_map_images_people] done.')
return ImageSequenceClip(seq, fps=fps)

0 comments on commit e8f2b09

Please sign in to comment.