Recherche avancée

Médias (17)

Mot : - Tags -/wired

Autres articles (32)

  • Submit enhancements and plugins

    13 avril 2011

    If you have developed a new extension to add one or more useful features to MediaSPIP, let us know and its integration into the core MedisSPIP functionality will be considered.
    You can use the development discussion list to request for help with creating a plugin. As MediaSPIP is based on SPIP - or you can use the SPIP discussion list SPIP-Zone.

  • MediaSPIP Core : La Configuration

    9 novembre 2010, par

    MediaSPIP Core fournit par défaut trois pages différentes de configuration (ces pages utilisent le plugin de configuration CFG pour fonctionner) : une page spécifique à la configuration générale du squelettes ; une page spécifique à la configuration de la page d’accueil du site ; une page spécifique à la configuration des secteurs ;
    Il fournit également une page supplémentaire qui n’apparait que lorsque certains plugins sont activés permettant de contrôler l’affichage et les fonctionnalités spécifiques (...)

  • Configuration spécifique d’Apache

    4 février 2011, par

    Modules spécifiques
    Pour la configuration d’Apache, il est conseillé d’activer certains modules non spécifiques à MediaSPIP, mais permettant d’améliorer les performances : mod_deflate et mod_headers pour compresser automatiquement via Apache les pages. Cf ce tutoriel ; mode_expires pour gérer correctement l’expiration des hits. Cf ce tutoriel ;
    Il est également conseillé d’ajouter la prise en charge par apache du mime-type pour les fichiers WebM comme indiqué dans ce tutoriel.
    Création d’un (...)

Sur d’autres sites (3522)

  • Using ImageMagick to efficiently stitch together a line scan image

    2 octobre 2018, par rkantos

    I’m looking for alternatives for line scan cameras to be used in sports timing, or rather in the part where placing needs to be figured out. I found that common industrial cameras can readily match the speed of commercial camera solutions at >1000 frames per second. For my needs, usually the timing accuracy is not important, but the relative placing of athletes. I figured I could use one of the cheapest Basler, IDS or any other area scan industrial cameras for this purpose. Of course there are line scan cameras that can do a lot more than a few thousand fps (or hz), but it is possible to get area scan cameras that can do the required 1000-3000fps for less than 500€.

    My holy grail would of course be the near-real time image composition capabilities of FinishLynx (or any other line scan system), basically this part : https://youtu.be/7CWZvFcwSEk?t=23s

    The whole process I was thinking for my alternative is :

    • Use Basler Pylon Viewer (or other software) to record 2px wide images at the camera’s fastest read speed. For the camera I am
      currently using it means it has to be turned on it’s side and the
      height needs to be reduced, since it is the only way it will read
      1920x2px frames @ >250fps
    • Make a program or batch script that then stitches these 1920x2px frames together to, for example one second of recording 1000*1920x2px
      frames, meaning a resulting image with a resolution of 1920x2000px
      (Horizontal x Vertical).
    • Finally using the same program or another way, just rotate the image so it reflects how the camera is positioned, thus achieving an image
      with a resolution of 2000x1920px (again Horizontal x Vertical)
    • Open the image in an analyzing program (currently ImageJ) to quickly analyze results

    I am no programmer, but this is what I was able to put together just using batch scripts, with the help of stackoverflow of course.

    • Currently recording a whole 10 seconds for example to disk as a raw/mjpeg(avi/mkv) stream can be done in real time.
    • Recording individual frames as TIFF or BMP, or using FFMPEG to save them as PNG or JPG takes 20-60 seconds The appending and rotation
      then takes a further 45-60 seconds
      This all needs to be achieved in less than 60 seconds for 10 seconds of footage(1000-3000fps @ 10s = 10000-30000 frames) , thus why I need something faster.

    I was able to figure out how to be pretty efficient with ImageMagick :

    magick convert -limit file 16384 -limit memory 8GiB -interlace Plane -quality 85 -append +rotate 270 “%folder%\Basler*.Tiff” “%out%”

    #%out% has a .jpg -filename that is dynamically made from folder name and number of frames.

    This command works and gets me 10000 frames encoded in about 30 seconds on a i5-2520m (most of the processing seems to be using only one thread though, since it is working at 25% cpu usage). This is the resulting image : https://i.imgur.com/OD4RqL7.jpg (19686x1928px)

    However since recording to TIFF frames using Basler’s Pylon Viewer takes just that much longer than recording an MJPEG video stream, I would like to use the MJPEG (avi/mkv) file as a source for the appending. I noticed FFMPEG has “image2pipe” -command, which should be able to directly give images to ImageMagick. I was not able to get this working though :

      $ ffmpeg.exe -threads 4 -y -i "Basler acA1920-155uc (21644989)_20180930_043754312.avi" -f image2pipe - | convert - -interlace Plane -quality 85 -append +rotate 270 "%out%" >> log.txt
       ffmpeg version 3.4 Copyright (c) 2000-2017 the FFmpeg developers
         built with gcc 7.2.0 (GCC)
         configuration: –enable-gpl –enable-version3 –enable-sdl2 –enable-bzlib –enable-fontconfig –enable-gnutls –enable-iconv –enable-libass –enable-libbluray –enable-libfreetype –enable-libmp3lame –enable-libopenjpeg –enable-libopus –enable-libshine –enable-libsnappy –enable-libsoxr –enable-libtheora –enable-libtwolame –enable-libvpx –enable-libwavpack –enable-libwebp –enable-libx264 –enable-libx265 –enable-libxml2 –enable-libzimg –enable-lzma –enable-zlib –enable-gmp –enable-libvidstab –enable-libvorbis –enable-cuda –enable-cuvid –enable-d3d11va –enable-nvenc –enable-dxva2 –enable-avisynth –enable-libmfx
         libavutil      55. 78.100 / 55. 78.100
         libavcodec     57.107.100 / 57.107.100
         libavformat    57. 83.100 / 57. 83.100
         libavdevice    57. 10.100 / 57. 10.100
         libavfilter     6.107.100 /  6.107.100
         libswscale      4.  8.100 /  4.  8.100
         libswresample   2.  9.100 /  2.  9.100
         libpostproc    54.  7.100 / 54.  7.100
       Invalid Parameter - -interlace
       [mjpeg @ 000000000046b0a0] EOI missing, emulating
       Input #0, avi, from 'Basler acA1920-155uc (21644989)_20180930_043754312.avi’:
         Duration: 00:00:50.02, start: 0.000000, bitrate: 1356 kb/s
           Stream #0:0: Video: mjpeg (MJPG / 0x47504A4D), yuvj422p(pc, bt470bg/unknown/unknown), 1920x2, 1318 kb/s, 200 fps, 200 tbr, 200 tbn, 200 tbc
       Stream mapping:
         Stream #0:0 -> #0:0 (mjpeg (native) -> mjpeg (native))
       Press [q] to stop, [?] for help
       Output #0, image2pipe, to ‘pipe:’:
         Metadata:
           encoder         : Lavf57.83.100
           Stream #0:0: Video: mjpeg, yuvj422p(pc), 1920x2, q=2-31, 200 kb/s, 200 fps, 200 tbn, 200 tbc
           Metadata:
             encoder         : Lavc57.107.100 mjpeg
           Side data:
             cpb: bitrate max/min/avg: 0/0/200000 buffer size: 0 vbv_delay: -1
       av_interleaved_write_frame(): Invalid argument
       Error writing trailer of pipe:: Invalid argument
       frame=    1 fps=0.0 q=1.6 Lsize=       0kB time=00:00:00.01 bitrate= 358.4kbits/s speed=0.625x
       video:0kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.000000%
       Conversion failed!

    If I go a bit higher for the height, I no longer get the “[mjpeg @ 000000000046b0a0] EOI missing, emulating” -error. However the whole thing will only work with <2px high/wide footage.

    edit : Oh yes, I can also use ffmpeg -i file.mpg -r 1/1 $filename%03d.bmp or ffmpeg -i file.mpg $filename%03d.bmp to extract all the frames from the MJPEG/RAW stream. However this is an extra step I do not want to take. (just deleting a folder of 30000 jpgs takes 2 minutes alone…)

    Can someone think of a working solution for the piping method or a totally different alternative way of handling this ?

  • Overthinking My Search Engine Problem

    31 décembre 2013, par Multimedia Mike — General

    I wrote a search engine for my Game Music Appreciation website, because the site would have been significantly less valuable without it (and I would eventually realize that the search feature is probably the most valuable part of this endeavor). I came up with a search solution that was a bit sketchy, but worked… until it didn’t. I thought of a fix but still searched for more robust and modern solutions (where ‘modern’ is defined as something that doesn’t require compiling a C program into a static CGI script and hoping that it works on a server I can’t debug on).

    Finally, I realized that I was overthinking the problem– did you know that a bunch of relational database management systems (RDBMSs) support full text search (FTS) ? Okay, maybe you did, but I didn’t know this.

    Problem Statement
    My goal is to enable users to search the metadata (title, composer, copyright, other tags) attached to various games. To do this, I want to index a series of contrived documents that describe the metadata. 2 examples of these contrived documents, interesting because both of these games have very different titles depending on region, something the search engine needs to account for :

    system : Nintendo NES
    game : Snoopy’s Silly Sports Spectacular
    author : None ; copyright : 1988 Kemco ; dumped by : None
    additional tags : Donald Duck.nsf Donald Duck
    

    system : Super Nintendo
    game : Arcana
    author : Jun Ishikawa, Hirokazu Ando ; copyright : 1992 HAL Laboratory ; dumped by : Datschge
    additional tags : card.rsn.gamemusic Card Master Cardmaster

    The index needs to map these documents to various pieces of game music and the search solution needs to efficiently search these documents and find the various game music entries that match a user’s request.

    Now that I’ve been looking at it for long enough, I’m able to express the problem surprisingly succinctly. If I had understood that much originally, this probably would have been simpler.

    First Solution & Breakage
    My original solution was based on SWISH-E. The CGI script was a C program that statically linked the SWISH-E library into a binary that miraculously ran on my web provider. At least, it ran until it decided to stop working a month ago when I added a new feature unrelated to search. It was a very bizarre problem, the details of which would probably bore you to tears. But if you care, the details are all there in the Stack Overflow question I asked on the matter.

    While no one could think of a direct answer to the problem, I eventually thought of a roundabout fix. The problem seemed to pertain to the static linking. Since I couldn’t count on the relevant SWISH-E library to be on my host’s system, I uploaded the shared library to the same directory as the CGI script and used dlopen()/dlsym() to fetch the functions I needed. It worked again, but I didn’t know for how long.

    Searching For A Hosted Solution
    I know that anything is possible in this day and age ; while my web host is fairly limited, there are lots of solutions for things like this and you can deploy any technology you want, and for reasonable prices. I figured that there must be a hosted solution out there.

    I have long wanted a compelling reason to really dive into Amazon Web Services (AWS) and this sounded like a good opportunity. After all, my script works well enough ; if I could just find a simple Linux box out there where I could install the SWISH-E library and compile the CGI script, I should be good to go. AWS has a free tier and I started investigating this approach. But it seems like a rabbit hole with a lot of moving pieces necessary for such a simple task.

    I had heard that AWS had something in this area. Sure enough, it’s called CloudSearch. However, I’m somewhat discouraged by the fact that it would cost me around $75 per month to run the smallest type of search instance which is at the core of the service.

    Finally, I came to another platform called Heroku. It’s supposed to be super-scalable while having a free tier for hobbyists. I started investigating FTS on Heroku and found this article which recommends using the FTS capabilities of their standard hosted PostgreSQL solution. However, the free tier of Postgres hosting only allows for 10,000 rows of data. Right now, my database has about 5400 rows. I expect it to easily overflow the 10,000 limit as soon as I incorporate the C64 SID music corpus.

    However, this Postgres approach planted a seed.

    RDBMS Revelation
    I have 2 RDBMSs available on my hosting plan– MySQL and SQLite (the former is a separate service while SQLite is built into PHP). I quickly learned that both have FTS capabilities. Since I like using SQLite so much, I elected to leverage its FTS functionality. And it’s just this simple :

    CREATE VIRTUAL TABLE gamemusic_metadata_fts USING fts3
    ( content TEXT, game_id INT, title TEXT ) ;
    

    SELECT id, title FROM gamemusic_metadata_fts WHERE content MATCH "arcana" ;
    479|Arcana

    The ‘content’ column gets the metadata pseudo-documents. The SQL gets wrapped up in a little PHP so that it queries this small database and turns the result into JSON. The script is then ready as a drop-in replacement for the previous script.

  • Parallelize Youtube video frame download using yt-dlp and cv2

    4 mars 2023, par zulle99

    My task is to download multiple sequences of successive low resolution frames of Youtube videos.

    &#xA;

    I summarize the main parts of the process :

    &#xA;

      &#xA;
    • Each bag of shots have a dimension of half a second (depending on the current fps)
    • &#xA;

    • In order to grab useful frames I've decided to remove the initial and final 10% of each video since it is common to have an intro and outro. Moreover
    • &#xA;

    • I've made an array of pair of initial and final frame to distribute the load on multiple processes using ProcessPoolExecutor(max_workers=multiprocessing.cpu_count())
    • &#xA;

    • In case of failure/exception I completly remove the relative directory
    • &#xA;

    &#xA;

    The point is that it do not scale up, since while running I noticesd that all CPUs had always a load lower that the 20% more or less. In addition since with these shots I have to run multiple CNNs, to prevent overfitting it is suggested to have a big dataset and not a bounch of shots.

    &#xA;

    Here it is the code :

    &#xA;

    import yt_dlp&#xA;import os&#xA;from tqdm import tqdm&#xA;import cv2&#xA;import shutil&#xA;import time&#xA;import random&#xA;from concurrent.futures import ProcessPoolExecutor&#xA;import multiprocessing&#xA;import pandas as pd&#xA;import numpy as np&#xA;from pathlib import Path&#xA;import zipfile&#xA;&#xA;&#xA;# PARAMETERS&#xA;percentage_train_test = 50&#xA;percentage_bag_shots = 20&#xA;percentage_to_ignore = 10&#xA;&#xA;zip_f_name = f&#x27;VideoClassificationDataset_{percentage_train_test}_{percentage_bag_shots}_{percentage_to_ignore}&#x27;&#xA;dataset_path = Path(&#x27;/content/VideoClassificationDataset&#x27;)&#xA;&#xA;# DOWNOAD ZIP FILES&#xA;!wget --no-verbose https://github.com/gtoderici/sports-1m-dataset/archive/refs/heads/master.zip&#xA;&#xA;# EXTRACT AND DELETE THEM&#xA;!unzip -qq -o &#x27;/content/master.zip&#x27; &#xA;!rm &#x27;/content/master.zip&#x27;&#xA;&#xA;DATA = {&#x27;train_partition.txt&#x27;: {},&#xA;        &#x27;test_partition.txt&#x27;: {}}&#xA;&#xA;LABELS = []&#xA;&#xA;train_dict = {}&#xA;test_dict = {}&#xA;&#xA;path = &#x27;/content/sports-1m-dataset-master/original&#x27;&#xA;&#xA;for f in os.listdir(path):&#xA;  with open(path &#x2B; &#x27;/&#x27; &#x2B; f) as f_txt:&#xA;    lines = f_txt.readlines()&#xA;    for line in lines:&#xA;      splitted_line = line.split(&#x27; &#x27;)&#xA;      label_indices = splitted_line[1].rstrip(&#x27;\n&#x27;).split(&#x27;,&#x27;) &#xA;      DATA[f][splitted_line[0]] = list(map(int, label_indices))&#xA;&#xA;with open(&#x27;/content/sports-1m-dataset-master/labels.txt&#x27;) as f_labels:&#xA;  LABELS = f_labels.read().splitlines()&#xA;&#xA;&#xA;TRAIN = DATA[&#x27;train_partition.txt&#x27;]&#xA;TEST = DATA[&#x27;test_partition.txt&#x27;]&#xA;print(&#x27;Original Train Test length: &#x27;, len(TRAIN), len(TEST))&#xA;&#xA;# sample a subset percentage_train_test&#xA;TRAIN = dict(random.sample(TRAIN.items(), (len(TRAIN)*percentage_train_test)//100))&#xA;TEST = dict(random.sample(TEST.items(), (len(TEST)*percentage_train_test)//100))&#xA;&#xA;print(f&#x27;Sampled {percentage_train_test} Percentage  Train Test length: &#x27;, len(TRAIN), len(TEST))&#xA;&#xA;&#xA;if not os.path.exists(dataset_path): os.makedirs(dataset_path)&#xA;if not os.path.exists(f&#x27;{dataset_path}/train&#x27;): os.makedirs(f&#x27;{dataset_path}/train&#x27;)&#xA;if not os.path.exists(f&#x27;{dataset_path}/test&#x27;): os.makedirs(f&#x27;{dataset_path}/test&#x27;)&#xA;

    &#xA;

    Function to extract a sequence of continuous frames :

    &#xA;

    def extract_frames(directory, url, idx_bag, start_frame, end_frame):&#xA;  capture = cv2.VideoCapture(url)&#xA;  count = start_frame&#xA;&#xA;  capture.set(cv2.CAP_PROP_POS_FRAMES, count)&#xA;  os.makedirs(f&#x27;{directory}/bag_of_shots{str(idx_bag)}&#x27;)&#xA;&#xA;  while count &lt; end_frame:&#xA;&#xA;    ret, frame = capture.read()&#xA;&#xA;    if not ret: &#xA;      shutil.rmtree(f&#x27;{directory}/bag_of_shots{str(idx_bag)}&#x27;)&#xA;      return False&#xA;&#xA;    filename = f&#x27;{directory}/bag_of_shots{str(idx_bag)}/shot{str(count - start_frame)}.png&#x27;&#xA;&#xA;    cv2.imwrite(filename, frame)&#xA;    count &#x2B;= 1&#xA;&#xA;  capture.release()&#xA;  return True&#xA;

    &#xA;

    Function to spread the load along multiple processors :

    &#xA;

    def video_to_frames(video_url, labels_list, directory, dic, percentage_of_bags):&#xA;  url_id = video_url.split(&#x27;=&#x27;)[1]&#xA;  path_until_url_id = f&#x27;{dataset_path}/{directory}/{url_id}&#x27;&#xA;  try:   &#xA;&#xA;    ydl_opts = {&#xA;        &#x27;ignoreerrors&#x27;: True,&#xA;        &#x27;quiet&#x27;: True,&#xA;        &#x27;nowarnings&#x27;: True,&#xA;        &#x27;simulate&#x27;: True,&#xA;        &#x27;ignorenoformatserror&#x27;: True,&#xA;        &#x27;verbose&#x27;:False,&#xA;        &#x27;cookies&#x27;: &#x27;/content/all_cookies.txt&#x27;,&#xA;        #https://stackoverflow.com/questions/63329412/how-can-i-solve-this-youtube-dl-429&#xA;    }&#xA;    ydl = yt_dlp.YoutubeDL(ydl_opts)&#xA;    info_dict = ydl.extract_info(video_url, download=False)&#xA;&#xA;    if(info_dict is not None and  info_dict[&#x27;fps&#x27;] >= 20):&#xA;      # I must have a least 20 frames per seconds since I take half of second bag of shots for every video&#xA;&#xA;      formats = info_dict.get(&#x27;formats&#x27;, None)&#xA;&#xA;      # excluding the initial and final 10% of each video to avoid noise&#xA;      video_length = info_dict[&#x27;duration&#x27;] * info_dict[&#x27;fps&#x27;]&#xA;&#xA;      shots = info_dict[&#x27;fps&#x27;] // 2&#xA;&#xA;      to_ignore = (video_length * percentage_to_ignore) // 100&#xA;      new_len = video_length - (to_ignore * 2)&#xA;      tot_stored_bags = ((new_len // shots) * percentage_of_bags) // 100   # ((total_possbile_bags // shots) * percentage_of_bags) // 100&#xA;      if tot_stored_bags == 0: tot_stored_bags = 1 # minimum 1 bag of shots&#xA;&#xA;      skip_rate_between_bags = (new_len - (tot_stored_bags * shots)) // (tot_stored_bags-1) if tot_stored_bags > 1 else 0&#xA;&#xA;      chunks = [[to_ignore&#x2B;(bag*(skip_rate_between_bags&#x2B;shots)), to_ignore&#x2B;(bag*(skip_rate_between_bags&#x2B;shots))&#x2B;shots] for bag in range(tot_stored_bags)]&#xA;      # sequence of [[start_frame, end_frame], [start_frame, end_frame], [start_frame, end_frame], ...]&#xA;&#xA;&#xA;      # ----------- For the moment I download only shots form video that has 144p resolution -----------&#xA;&#xA;      res = {&#xA;          &#x27;160&#x27;: &#x27;144p&#x27;,&#xA;          &#x27;133&#x27;: &#x27;240p&#x27;,&#xA;          &#x27;134&#x27;: &#x27;360p&#x27;,&#xA;          &#x27;135&#x27;: &#x27;360p&#x27;,&#xA;          &#x27;136&#x27;: &#x27;720p&#x27;&#xA;      }&#xA;&#xA;      format_id = {}&#xA;      for f in formats: format_id[f[&#x27;format_id&#x27;]] = f&#xA;      #for res in resolution_id:&#xA;      if list(res.keys())[0] in list(format_id.keys()):&#xA;          video = format_id[list(res.keys())[0]]&#xA;          url = video.get(&#x27;url&#x27;, None)&#xA;          if(video.get(&#x27;url&#x27;, None) != video.get(&#x27;manifest_url&#x27;, None)):&#xA;&#xA;            if not os.path.exists(path_until_url_id): os.makedirs(path_until_url_id)&#xA;&#xA;            with ProcessPoolExecutor(max_workers=multiprocessing.cpu_count()) as executor:&#xA;              for idx_bag, f in enumerate(chunks): &#xA;                res = executor.submit(&#xA;                  extract_frames, directory = path_until_url_id, url = url, idx_bag = idx_bag, start_frame = f[0], end_frame = f[1])&#xA;                &#xA;                if res.result() is True: &#xA;                  l = np.zeros(len(LABELS), dtype=int) &#xA;                  for label in labels_list: l[label] = 1&#xA;                  l = np.append(l, [shots]) # appending the number of shots taken in the list before adding it on the dictionary&#xA;&#xA;                  dic[f&#x27;{directory}/{url_id}/bag_of_shots{str(idx_bag)}&#x27;] = l.tolist()&#xA;&#xA;&#xA;  except Exception as e:&#xA;    shutil.rmtree(path_until_url_id)&#xA;    pass&#xA;

    &#xA;

    Download of TRAIN bag of shots :

    &#xA;

    start_time = time.time()&#xA;pbar = tqdm(enumerate(TRAIN.items()), total = len(TRAIN.items()), leave=False)&#xA;&#xA;for _, (url, labels_list) in pbar: video_to_frames(&#xA;  video_url = url, labels_list = labels_list, directory = &#x27;train&#x27;, dic = train_dict, percentage_of_bags = percentage_bag_shots)&#xA;&#xA;print("--- %s seconds ---" % (time.time() - start_time))&#xA;

    &#xA;

    Download of TEST bag of shots :

    &#xA;

    start_time = time.time()&#xA;pbar = tqdm(enumerate(TEST.items()), total = len(TEST.items()), leave=False)&#xA;&#xA;for _, (url, labels_list) in pbar: video_to_frames(&#xA;  video_url = url, labels_list = labels_list, directory = &#x27;test&#x27;, dic = test_dict, percentage_of_bags = percentage_bag_shots)&#xA;&#xA;print("--- %s seconds ---" % (time.time() - start_time))&#xA;

    &#xA;

    Save the .csv files

    &#xA;

    train_df = pd.DataFrame.from_dict(train_dict, orient=&#x27;index&#x27;, dtype=int).reset_index(level=0)&#xA;train_df = train_df.rename(columns={train_df.columns[-1]: &#x27;shots&#x27;})&#xA;train_df.to_csv(&#x27;/content/VideoClassificationDataset/train.csv&#x27;, index=True)&#xA;&#xA;test_df = pd.DataFrame.from_dict(test_dict, orient=&#x27;index&#x27;, dtype=int).reset_index(level=0)&#xA;test_df = test_df.rename(columns={test_df.columns[-1]: &#x27;shots&#x27;})&#xA;test_df.to_csv(&#x27;/content/VideoClassificationDataset/test.csv&#x27;, index=True)&#xA;

    &#xA;