質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.34%

  • JavaScript

    17590questions

    JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

  • HTML5

    4318questions

    HTML5 (Hyper Text Markup Language、バージョン 5)は、マークアップ言語であるHTMLの第5版です。

  • Firefox

    216questions

    Mozilla Foundationによって作られた無料、オープンソース、クロスプラットフォームなウェブブラウザ

canvas上で動画の合成

受付中

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 876

west826

score 6

前提・実現したいこと

canvas上で動画を重ねて表示したいと考えています。
何の処理もしていない動画(#v)の上に
クロマキー処理をした動画(#v2)を表示したいと思っています。

発生している問題

個々の操作はできるのですが、組合わせ方がわかりません。

HTML クロマキー処理

<<!DOCTYPE html>
<html lang="ja">
    <head>
      <meta charset="utf-8">
      <title>Chroma key</title>
        <style type="text/css">
          #v{
            display:none;
          }
      </style>
 </head>
  <body>
    <video controls id="v" width="480" height="270">
      <source src="movie.mp4" width="480" height="270">
    </video>

    <div id="screen">
      <canvas id="c" width="480" height="270"></canvas>
    </div>
    <div class="kouka">
      <button onClick="playVideo()">play/stop</button>
      <button onClick="restart()">restart</button>
    </div>
    <div>
      <video id="v2" width="160px" height="90px" autoplay src="m1.mp4.mp4" loop ></video>
      <span>不透明度</span>
      <input type="range" id="opacity1" min="0" max="100" step="1" >
      <span id="opacityvalue1"></span>
    </div>
   <script type="text/javascript" >

      var video = document.getElementById("v2");
      var canvas = document.getElementById("c");
      var context = canvas.getContext('2d');

      //opacity値の出力
      opacity1.oninput = e => opacityvalue1.textContent = opacity1.value;
      // r,g,bというkeyを持ったobjectが第一引数と第二引数に渡される想定
      function getColorDistance(rgb1, rgb2) {
        // 三次元空間の距離が返る
        return Math.sqrt(
            Math.pow((rgb1.r - rgb2.r), 2) +
            Math.pow((rgb1.g - rgb2.g), 2) +
            Math.pow((rgb1.b - rgb2.b), 2)
        );
    };
    // videoの映像をcanvasに描画する
      function draw() {
        //グラフィックをクリア
        context.clearRect(0, 0, canvas.width, canvas.height);
        //opacity(alpha)値を設定
        context.globalAlpha = opacity1.value/100;
        context.drawImage(video, 0, 0, canvas.width, canvas.height);
        // ここでクロマキー処理をする
        chromaKey();
        requestAnimationFrame(draw);
    };
      // 消す色と閾値
      var chromaKeyColor = {r: 0, g: 0, b: 0},
          colorDistance = 30;
      // クロマキー処理
      function chromaKey() {
        var imageData = context.getImageData(0, 0, canvas.width, canvas.height),
            data = imageData.data;

        // dataはUint8ClampedArray
        // 長さはcanvasの width * height * 4(r,g,b,a)
        // 先頭から、一番左上のピクセルのr,g,b,aの値が順に入っており、
        // 右隣のピクセルのr,g,b,aの値が続く
        // n から n+4 までが1つのピクセルの情報となる
        for (var i = 0, l = data.length; i < l; i += 4) {
            var target = {
                    r: data[i],
                    g: data[i + 1],
                    b: data[i + 2]
                };
            // chromaKeyColorと現在のピクセルの三次元空間上の距離を閾値と比較する
            // 閾値より小さい(色が近い)場合、そのピクセルを消す
            if (getColorDistance(chromaKeyColor, target) < colorDistance) {
                // alpha値を0にすることで見えなくする
                data[i + 3] = 0;
            }
        }
        // 書き換えたdataをimageDataにもどし、描画する
        imageData.data = data;
        context.putImageData(imageData, 0, 0);
    };
    draw();          
    </script>
  </body>
</html>

HTML 動画のの再生処理

//play/stopボタンの設定
function playVideo(){    
    var video = document.getElementById("v");
    if(video.paused){
        video.play();
    }else{
        video.pause();
    }
    setInterval(function(){
        var canvas = document.getElementById("c");
        canvas.getContext("2d").drawImage(video, 0, 0, 480, 270);
    }, 1000/30);
}


//restartボタンの設定
function restart() {
    var video = document.getElementById("v");
    video.currentTime = 0;
}

補足情報(言語/FW/ツール等のバージョンなど)

わかる方がいらっしゃいましたら教えていただけると幸いです。
よろしくお願い致します。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

+1

どのように映像を重ねたいのかが明らかでないため, ここではその実現方法についてのヒントを提示します. 


canvas要素で加工したビデオ映像を重ねる場合, 次の二つの方法が考えられます.

  • CSSを使って二つのcanvas要素を重ねてしまう
  • 別途ビデオ加工用のcanvas要素を用意し, 二つの映像を最終的に一つにまとめる

NOTE:
drawImageに渡す画像ソースとして, HTMLImageElement(img要素/Image), HTMLVideoElement(video要素)オブジェクトの他にHTMLCanvasElement(canvas要素)オブジェクトが使えます.

以下は後者におけるコードの雛形です.

//重ねたいvideo映像
const video1 = document.getElementById("video1");
const video2 = document.getElementById("video2");

//合成したvideo映像の出力先
const canvas = document.getElementById("canvas");
//video映像の一次加工用のcanvas要素(インメモリcanvas)
const canvas1 = document.createElement("canvas");
const canvas2 = document.createElement("canvas");

//canvas要素群のサイズを揃える
[canvas.width, canvas.height] 
    = [canvas1.width, canvas1.height] 
    = [canvas2.width, canvas2.height] 
    = [200, 200];

const ctx = canvas.getContext("2d");
const ctx1 = canvas1.getContext("2d");
const ctx2 = canvas2.getContext("2d");

(function draw(){
    //グラフィックの内容をクリア
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx1.clearRect(0, 0, canvas1.width, canvas1.height);
    ctx2.clearRect(0, 0, canvas2.width, canvas2.height);

    //video1の加工
    ctx1.drawImage(video1, 0, 0, canvas1.width, canvas1.height);
    //何らかの処理(例えば輪郭抽出)

    //video2の加工
    ctx2.drawImage(video2, 0, 0, canvas2.width, canvas2.height);
    //何らかの処理(例えばクロマキー処理)

    //加工済みのビデオ映像を重ねる
    ctx.drawImage(canvas1, 0, 0);
    ctx.drawImage(canvas2, 0, 0);

    //次フレームの描画時に処理を呼び出す
    requestAnimationFrame(draw);
})();

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/01/10 11:14

    ご回答ありがとうございます。
    動画を再生するための処理の
    function playVideo
    を//何らかの処理と書いてある後の部分に入れてみたのですが
    playVideo is not defined
    というエラーが出ました。
    これはどうしたら直すことが出来るのでしょうか
    教えていただけると幸いです。
    よろしくお願い致します。

    キャンセル

  • 2018/01/10 11:50

    > を//何らかの処理と書いてある後の部分に入れてみたのですが
    の時点であなたはスクリプトを理解していない(もしくは読んでいない)ように見受けられます.
    同様に「playVideo is not defined」についても「関数playVideoが見つからない」という初歩的なエラーであり, エラーメッセージすら読んでいないのでは無いでしょうか?
    これではいかな有用なアドバイスを得てもそれを切り貼りしているだけでご自身のスキルアップには到底繋がりません.
    ---
    エラーの発生原因はコード全体を見ない限り突き止められません. どのように書き換えたか等を質問に追記するなりして下さい.

    キャンセル

+1

1つのcanvasではなく、#v用,#v2用、クロマキー描画用の3つ用意してレンダリングすれば、混乱しにくいかと
サンプル

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

同じタグがついた質問を見る

  • JavaScript

    17590questions

    JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

  • HTML5

    4318questions

    HTML5 (Hyper Text Markup Language、バージョン 5)は、マークアップ言語であるHTMLの第5版です。

  • Firefox

    216questions

    Mozilla Foundationによって作られた無料、オープンソース、クロスプラットフォームなウェブブラウザ