0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

世のお父さんのために子供のスポーツ動画にクロマキー合成するタイマーを作りました

Last updated at Posted at 2018-09-30

概要

スポーツシーズンですが、世のお父さん方は、子供達が活躍する所をせっせとビデオ撮影し、寝る間も惜しんで編集作業に勤しんでいることと思います。同情します。

そんなお父さんの動画クオリティーをアップさせるタイマーを用意しました。
https://www.exabugs.com/timer/index.html

スクリーンショット 2018-09-30 11.08.33.png

これでカッコいい動画を作成すれば、嫁や子供達から「パパ素敵!」と言われること間違いなし!やったね!

なお、本記事では iMovie と QuickTime を使用します

利用方法

タイマー使い方

  • ブラウザで上記URLにアクセス。(Chrome/Safariは動作確認済み)
  • 「リセット」でタイマーが出現し、「スタート」で開始します。
  • 設定はローカルに保存されますが、「クリア」を押すと初期化されます。
  • 緑色背景はアスペクト比 16:9 です。
  • 設定項目(左から)
    • 試合時間を「分」単位で指定
    • cd : カウントダウンかどうか。ONの場合は試合時間をカウントダウンします。
    • abs : 円形プログレスバーの一周(360度)を60分とする(サッカー方式?)か、試合時間とするか。
    • タイマーの大きさを画面幅との比率で指定
    • プログレスバーの色を指定。RGB値かred,blueのようなウェブカラー名。
      WEB色見本 https://www.colordic.org/
    • プログレスバーの前景の幅を指定
    • プログレスバーの背景の幅を指定
    • 背景色を指定。クロマキー用途には緑か青。LT大会で使うには白がいいでしょう。
    • タイマーのフォント。
      Googleウェブフォントを使用しています。
    • タイマーのフォントサイズ
    • タイマーの水平位置
    • タイマーの垂直位置
    • 緑色部分の幅と高さ。アスペクト比16:9になっています。

タイマー動画作成

  • Mac の場合は QuickTime Player を起動し、ファイル - 新規画面収録 でタイマー動画を収録します。
  • 収録開始すると以下が表示されるので、緑色部分に収録範囲を合わせて下さい。
    スクリーンショット 2018-09-30 12.15.31.png

動画編集

1. タイマーの合成

  • iMovie を起動して、スポーツ動画とタイマー動画の両方をマイメディアに取り込みます
  • 「グリーン/ブルースクリーン」を選択すると、クロマキー合成されます。

スクリーンショット_2018-09-30_12_29_24.jpg

  • タイムや怪我人の救護等で時計の進行が止まる場合は、iMovieでは「フリーズフレーム」でタイマー動画を止めるとよいでしょう。
  • ここまでで一旦、合成された動画をエクスポートします。

2. ハイライトシーンの編集

  • 1.の動画を開いて、ハイライトシーンを編集します。

プログラム

  • 一応コードも貼っておきます。
  • 簡単のため一つのHTMLに内包しています。
  • 肝心の円形プログレスバーの部分はcirclifulを使わせて頂きました。
    https://github.com/pguso/jquery-plugin-circliful
<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="UTF-8">
        <title>Timer</title>
        <link href="css/jquery.circliful.css" rel="stylesheet" type="text/css" />
        <link href='https://fonts.googleapis.com/css?family=Roboto:900,400' rel='stylesheet' type='text/css'>
        <link href='https://fonts.googleapis.com/css?family=Rajdhani:900,400' rel='stylesheet' type='text/css'>
        <script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
        <script src="js/jquery.circliful.min.js"></script>
        <style type="text/css">
            body {
                margin: 0;
                font-size: small;
            }

            div {
                margin: 3px;
            }

            button, input, select {
                font-size: 100%;
            }
        </style>
    </head>
    <body>

        <div id="container">
            <div id="header">
                <button id="RESET">リセット</button>
                <button id="START">スタート</button>

                <input id="total" size="2"><input id="countdown" type="checkbox">cd
                <input id="abs" type="checkbox">abs
                <input id="size" size="2">%
                <input id="color" size="9">
                <input id="fgborder" size="2">
                <input id="bgborder" size="2">

                <select id="bg">
                    <option value="#ffffff"></option>
                    <option value="#00ff00"></option>
                    <option value="#0000ff"></option>
                    <option value="#000000"></option>
                </select>

                <select id="font_family">
                    <option value="Roboto" selected>Roboto</option>
                    <option value="Rajdhani">Rajdhani</option>
                </select>
                <input id="font_size" size="3">px

                <select id="horizontal">
                    <option value="0"></option>
                    <option value="1"></option>
                    <option value="2"></option>
                </select>

                <select id="vertical">
                    <option value="0"></option>
                    <option value="1"></option>
                    <option value="2"></option>
                </select>

                <span id="divsize"></span>
                <button id="CLEAR">クリア</button>
            </div>
            <div id="contents">
                <div id="clock"></div>
            </div>
            <div id="footer">
            </div>
        </div>

        <script>

          function time(s) {
            var min = Math.floor(s / 60);
            var sec = Math.floor(s % 60);
            return ("0" + min).slice(-2) + ":" + ("0" + sec).slice(-2);
          }

          function disp(prog, total, countdown) {
            var _t = prog;
            if (total < prog) {
              _t = prog - total;
            } else if (countdown) {
              _t = total - prog;
            }
            return time(_t / 1000);
          }

          function percent(prog, total, abs) {
            var hour = 60 * 60 * 1000;
            var all = abs ? hour : total;
            return Math.max((total - prog) / all, 0);
          }

          function shadow(color) {
            return [
              [2, 0], [-2, 0], [0, -2], [0, 2],
              [2, 2], [-2, 2], [2, -2], [-2, -2],
              [1, 2], [-1, 2], [1, -2], [-1, -2],
              [2, 1], [-2, 1], [2, -1], [-2, -1]
            ].map(function(i) {
              return color + " " + i.map(function(j) {
                return j + "px"
              }).join(" ")
            }).join(",");
          }

          function conf(total, abs, countdown) {

            var font_size = $('#font_size').val();
            var font_family = $('#font_family').val();

            var textStyle = [
              ["font-size", font_size + "px"],
              ["font-family", font_family],
              ["text-shadow", shadow("black")]
            ].map(function(i) {
              return i[0] + ": " + i[1] + ";"
            }).join(" ");

            var prog = 0;
            return {
              percent: Math.floor(percent(prog, total, abs) * 100),
              replacePercentageByText: '',
              text: disp(prog, total, countdown),
              textStyle: textStyle,
              foregroundBorderWidth: $("#fgborder").val(),
              backgroundBorderWidth: $("#bgborder").val(),
              foregroundColor: $("#color").val(),
              textColor: "white",
              backgroundColor: "white",
            }
          }

          ///////////////////////////////////////////////////

          var storage = localStorage;

          function saveText(id) {
            storage.setItem(id, $("#" + id).val());
          }

          function saveCheck(id) {
            var val = $("#" + id).prop("checked");
            storage.setItem(id, val);
          }

          function loadText(id, def) {
            var val = storage.getItem(id);
            val = (val === null ? def : val);
            $("#" + id).val(val).change();
          }

          function loadCheck(id, def) {
            var val = storage.getItem(id);
            val = (val === null ? def : (val === "false" ? false : true));
            $("#" + id).prop("checked", val).change();
          }

          function save() {
            saveCheck("countdown");
            saveCheck("abs");
            saveText("total");
            saveText("size");
            saveText("color");
            saveText("bg");
            saveText("font_family");
            saveText("font_size");
            saveText("horizontal");
            saveText("vertical");
            saveText("fgborder");
            saveText("bgborder");
          }

          function load() {
            loadCheck("countdown", true);
            loadCheck("abs", true);
            loadText("total", 45);
            loadText("size", 15);
            loadText("color", "#3498DB");
            loadText("bg", "#00ff00");
            loadText("font_family", "Roboto");
            loadText("font_size", 36);
            loadText("horizontal", 0);
            loadText("vertical", 0);
            loadText("fgborder", 11);
            loadText("bgborder", 15);
          }

          function clear() {
            storage.clear();
            load();
          }

          ///////////////////////////////////////////////////

          var data = {};

          function stop() {
            clearInterval(data.timer);
            delete data.timer;
          }

          function reset() {
            stop();
            save();

            data.total = Number($("#total").val()) * 60 * 1000;
            data.countdown = $("#countdown").prop("checked");
            data.abs = $("#abs").prop("checked");

            var countdown = data.countdown;
            var total = data.total;
            var abs = data.abs;

            $('#clock').remove();
            $('#contents').append('<div id="clock"></div>');

            $('#clock').circliful(conf(total, abs, countdown));

            var svg = $("#clock").children("svg").eq(0);

            data.svg = {
              container: svg,
              text: svg.children("text").eq(0),
              circle: svg.children("circle").eq(1)
            };

            resize();
          }

          function start() {
            stop();

            data.start = Date.now();

            data.timer = setInterval(function() {
              var countdown = data.countdown;
              var total = data.total;
              var abs = data.abs;
              var prog = Date.now() - data.start;

              var degree = Math.floor(percent(prog, total, abs) * 360);

              data.svg.text.text(disp(prog, total, countdown));
              data.svg.circle.css("stroke-dasharray", degree + ", 20000");
            }, 200);
          }

          $('#RESET').click(reset);
          $('#START').click(start);
          $('#CLEAR').click(clear);

          ///////////////////////////////////////////////////

          $("#bg").change(function() {
            $("#contents").css('background-color', $(this).val());
          });

          function resize() {

            var contents = $("#contents");
            contents.height(Math.floor(contents.width() / 16 * 9));

            $("#divsize").text("(" + contents.width() + "x" + contents.height() + ")");

            if (data.svg) {
              var ratio = $("#size").val() / 100;

              var size = contents.width() * ratio;
              var left = (contents.width() - size) / 2 * $("#horizontal").val();
              var top = (contents.height() - size) / 2 * $("#vertical").val();

              var svg = data.svg.container;
              svg.css('width', size);
              svg.css('padding-left', left);
              svg.css('padding-top', top);
            }
          }

          $("#horizontal").change(resize);
          $("#vertical").change(resize);
          $(window).resize(resize);

          ///////////////////////////////////////////////////

          load();
          resize();

        </script>
    </body>
</html>
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?