コンピューターグラフィックス

2017年11月28日 (火)

開発費用ゼロ コンピューターグラフィックスによる動画制作 (2) Java OpenCV3 Eclipse を使って

先日、下記のコンテンツを発表しました。

開発費用ゼロ コンピューターグラフィックスによる動画制作 Java OpenCV3 Eclipse を使って

上記に述べたように、私が使用しているコンピューター上に、[Java , OpenCV3 , Eclipse]の3点セットを使って動画制作を行う基盤を整備することができたので、別のプログラムを制作してみました。

上記で記述したプログラムは、

 動画の中に、静止画を埋め込む

というものでしたが、この1歩先へ行ってみよう、ということで、今回制作するプログラムを、以下のようなものに目標設定しました。

 動画Aの中に、別の動画Bを埋め込む
 動画Bを埋め込む際に、動画Bの各フレーム中の、
  [ある条件]を満たすようなピクセルだけを選択して、
  動画Aのフレームの中に、埋め込む

[ある条件]の内容を、文章でうまく表現するのは困難なので、後述のプログラム・ソースリスト記述の所で、述べます。

制作作業の結果、できたのが、下記の動画です。(ユーテューブ上にアップロードしてあります。)

映像を、この自作のコンピュータープログラムにより、制作しました。

バックグラウンド音楽には、自作曲 [だがっきだだがっきだ, Op.21]を、使用しました。
  (短い動画なので、この曲の一部だけを用いています。)

制作した動画を、下記でご覧になることができます。

この動画の格納先URLは、下記です。

https://youtu.be/WvNAgGxZ7Eg

----------------
今回の制作で、[OpenCV3]に関して、今まで知らなかった事を、新たに知りました。

制作し始めた段階では、動画Aの中に、別の動画Bを埋め込む、ということで、下記のような処理を繰り返すような、プログラミングをしていました。

  (1) 動画Bの1フレームを読みこむ
  (2) 動画Aの1フレームを読みこむ
  以下の(3)~(7)を繰り返す
   (3) 読みこまれた動画Aの1フレームを、出力側の動画の1フレームに、コピーし
   (4) コピーされたそのフレームを、動画Bの読みこまれているフレームの内容に従って、加工する
   (5) 加工がすんだフレームを、出力側の動画格納ファイル中に、書き込む
   (6) 動画Bの次の1フレームを読みこむ
   (7) 動画Aの次の1フレームを読みこむ

「(3) 読みこまれた動画Aの1フレームを、出力側の動画の1フレームに、コピーし」の所では、

 Matクラスのcloneメソッド

を使用するようにしていました。

ところが、このプログラムを実行すると、大問題が発生してしまいました。

処理が相当進んで行った段階で、コンピューターの動きが、なんだかおかしくなってきたのです。プログラムの進行が止まってしまったり、ハードウェア・アクセスランプが点灯し続けたり・・・。

(Windows10のタスクマネージャーを起動して、処理を強制的にストップしようともしましたが、タスクマネージャーの画面が、なかなか現れてくれない・・・)

これまでのプログラム制作の経験から、「メモリー不足」という言葉が、脳裏に浮かびました。

もしかしたら、プログラムのいずれかの箇所で、メモリー確保がバンバン行われしまっていて、ついには、メモリー不足に陥って、と、このような事が原因なのでは、と思いました。

そこで、ネットで調べて、[copyTo]というメソッドが、Matクラスに備わっていることを知り、[clone]ではなく、[copyTo]を使うようにしてみました。

しかし、問題の解決には至りませんでした。

ついには、[copyTo]の使用もやめ、読みこまれたフレームの内容が含まれている Matインスタンスを、別のMatインスタンス にコピーすることなく、直接、その内容を加工する、というように、してみました。

しかし、問題の解決には至りませんでした。

そしてついに、出力側の動画を複数個出力するようにしてみました。

 一定数の出力側の動画のフレームが出力された後、
 VideoWiterインスタンスに、releaseを行わせ
 ファイル名を変えて、新たなVideoWriterをコンストラクトして、
 そこに、続きを出力していく

というような動作をするように、プログラムを変えました。

更に、動画Bを複数個の動画ファイルに分割し、それぞれの分割後の動画(情報量が、分割前の動画よりも少ない)に対して、このプログラムを実行する、というように、コンピューターへの負荷を低減するようにしてみました。

すると、ようやく、問題が解消して、コンピューターが安定的に動作するようになりました。

そのようにして、生成された多数の出力側動画ファイルを、動画編集ソフトを使って、1個の動画にまとめあげました。この作業には、手間がかかりました。もっとスマートなやり方があるのかもしれません。

[clone]、[copyTo]については、下記のキーワードを用いてネット検索して、関連する情報を得ることができました。

 [OpenCV Mat clone]
 [OpenCV Mat copyTo]

-------------------------------------------

どのようなプログラムを制作して、今回の動画制作を行ったのか、今、その作業の記憶が頭の中に残っているうちに、記録しておこう、将来、再び、同じような動画の制作を行う際に困らないように、と思い、その内容を下記に記述しました。

下記の記述をお読みになった方が、それを単に参考にしていただく分には、問題は無いと思われます。

しかし、記述されている内容に沿って、その方がそこに記されているのと同様のプログラムを制作して、コンピューター上で実行された際に、その作業の結果、作業に使用されたコンピューター等、様々な方面において、何らかの問題が発生しないという保証は、全くありません。

その作業の結果、その方や、その方が使用された様々な器機、インフラ等の身の上にどのような事が起ころうとも、私は一切、責任を負いません。

今回の制作作業において、私が使用したコンピューターは、以下のような仕様になっています。

 CPU : Core i3-3110M 2.40GHz
 メモリー : 4GB
 Operating System : Windows 10 Home, 64ビットオペレーティングシステム

後述のプログラム・ソースリストは、私が実際に制作したものと、以下の点で、異なった内容になっています。

(1)フォルダー名が異なっている

    String path_string_1 = "C:\\Users\\Xyyyyy\\Documents\\" ;
    String path_string_2 = "10\\J\\T\\" ;

となっていますが、実際に使用したフォルダー名は、上記とは異なります。

(2)記述省略 色の範囲を指定するテーブル

 mv_table_of_color_value の内容を全て記述すると、長くなるので、一部、記述を省略しています。

 このエリアは、上記中の「[ある条件]を満たすようなピクセルだけを選択して」の、[ある条件]に関係している記述です。ピクセルの色(BGR値)を、L*a*b* 形式の値に変換し、その値に対して、このエリア中の記述を用いて、範囲チェックを行うようにしました。

 mv_table_of_color_value [ * ] [ 6 ] にセットされる値が、-1.0 の場合は、この範囲内にある色であれば、[ある条件]を満たさない、とする(なので、調べているピクセルの色を、出力側の動画のフレーム上には、コピーしない)

 [ * ] [ 6 ] にセットされる値が、1.0 の場合は、この範囲内にある色であれば、[ある条件]を満たすとする

ソースリストの最後の方にある、detect_color_value メソッドの中で、上記に沿ってのプログラミングを行っています。

(3)記述省略 WaitEntKeyクラス

ソースリスト中にある、

 WaitEntKey.wait_ent_key () ;

は、自作の別クラスのメソッドを呼び出しているものです。

[wait_ent_key ()]メソッドが実行されると、Enterキーが押されるまで、じっと待つ、という動作になります。WaitEntKeyクラスは、この動画を行わせるためだけに、制作したクラスです。簡単なプログラムだし、今回発表のテーマとはあまり関係ないような内容なので、そのクラスのソースリストに関する記述を省略しました。

以下、今回制作したプログラムのソースリストです。   

-------
        //for using OpenCV3
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.Size;
import org.opencv.videoio.VideoCapture;
import org.opencv.videoio.VideoWriter;
import org.opencv.imgproc.Imgproc ;
        //for using Calendar class
import java.util.Calendar;

public class Test2 {

  private static String mv_this_Class_name = "Test2" ;

  private static double [ ] [ ] mv_table_of_color_value  ;
  private static int mv_number_of_table_of_color_value ;
  private static String [ ] mv_table_of_filename_BVF ;

              //for reading BackGroundVideo
  private static int mv_index_of_current_using_BackGroundVideo ;

  private static String mv_dir_of_input_video ;
  private static String mv_dir_of_output_video ;

  private static int mv_index_of_VideoWriter = 0 ;

  public static void main ( String[] args ) {

    make_output_video ( ) ;
   }

  //--------------------------
  // make_output_video
  //--------------------------
  private static char make_output_video ( ) {

    String this_methode_name = "make_output_video" ; 

    Calendar ins_calendar_at_start = Calendar.getInstance ( ) ;

    String path_string_1 = "C:\\Users\\Xyyyyy\\Documents\\" ;
    String path_string_2 = "10\\J\\T\\" ;
    String path_string_4 = "VideoInput\\" ;
    String path_string_5 = "VideoOutput\\" ;

    mv_dir_of_input_video
         = path_string_1 + path_string_2 + path_string_4 ;
    mv_dir_of_output_video
         = path_string_1 + path_string_2 + path_string_5 ;

//==============================================
                 //prepare table for selecting pixel by color value
    mv_number_of_table_of_color_value = 9 ;
    mv_table_of_color_value =
            new double [ mv_number_of_table_of_color_value ]
                                   [ 7 ] ;
        //gray for pine movie
    mv_table_of_color_value [ 0 ] [ 0 ] = 0.0 ;   //L* value : From                        
    mv_table_of_color_value [ 0 ] [ 1 ] = 300.0 ;   //L* value : To
    mv_table_of_color_value [ 0 ] [ 2 ] = 124.0 ;   //a* value : From
    mv_table_of_color_value [ 0 ] [ 3 ] = 136.0 ;   //a* value : To
    mv_table_of_color_value [ 0 ] [ 4 ] = 117.0 ;   //b* value : From
    mv_table_of_color_value [ 0 ] [ 5 ] = 136.0 ;   //b* value : To
    mv_table_of_color_value [ 0 ] [ 6 ] = -1.0 ;
        //[ * ] [ 6 ] = -1.0 : if color value is in area defined above
        //    , do not get the pixel
                  //yellow ( pineapple )
    mv_table_of_color_value [ 1 ] [ 0 ] = 50.0 ;   //L* value : From                        
    mv_table_of_color_value [ 1 ] [ 1 ] = 290.0 ;   //L* value : To
    mv_table_of_color_value [ 1 ] [ 2 ] = 125.0 ;   //a* value : From
    mv_table_of_color_value [ 1 ] [ 3 ] = 150.0 ;   //a* value : To
    mv_table_of_color_value [ 1 ] [ 4 ] = 170.0 ;   //b* value : From
    mv_table_of_color_value [ 1 ] [ 5 ] = 205.0 ;   //b* value : To
    mv_table_of_color_value [ 1 ] [ 6 ] = 1.0 ;
            //[ * ] [ 6 ] = 1.0 : if color value is in area defined above
            //    , get the pixel

            ・・・記述省略
//==============================================

//==============================================
            //prepare table for path of loading backgound video file
    mv_table_of_filename_BVF = new String [ 6 ]  ;
    mv_table_of_filename_BVF [ 0 ] = "M03.mp4" ;                        
    mv_table_of_filename_BVF [ 1 ] = "M02.mp4" ;   
    mv_table_of_filename_BVF [ 2 ] = "M01.mp4" ;
    mv_table_of_filename_BVF [ 3 ] = "M04.mp4" ;
    mv_table_of_filename_BVF [ 4 ] = "M05.mp4" ;
    mv_table_of_filename_BVF [ 5 ] = "M06.mp4" ;

    mv_index_of_current_using_BackGroundVideo = (-1) ;
//==============================================

              //prepare for using OpenCV3
    System.loadLibrary ( Core.NATIVE_LIBRARY_NAME ) ;

             //prepare for reading video file
                    //BackGround Video
    String path_of_InputVideoFile_BG =
        mv_dir_of_input_video
          + mv_table_of_filename_BVF [ 0 ] ;
                   //ForeGround Video   
    String path_of_InputVideo_FG =
         mv_dir_of_input_video
         //=====================================
              + "PMikan_60_End.mp4" ;
         //=====================================

        //construct instance of VideoCapture for ForeGround Video            
    System.out.println ( "path_of_InputVideo_FG = "
                + path_of_InputVideo_FG ) ;
    VideoCapture ins_VideoCapture_FGV
          = new VideoCapture ( path_of_InputVideo_FG ) ;
    if ( ins_VideoCapture_FGV == null ) {
      System.out.println ( "can not access InputVideo_FG" ) ;
      return '1' ;   
     }
    if ( ins_VideoCapture_FGV.isOpened ( ) != true ) {
      System.out.println ( "can not open InputVideo_FG" ) ;
      return '2' ; 
     }
        //construct instance of Mat for ForeGround Video
    Mat ins_Mat_contain_one_frame_of_InputVideo_FG
               = new Mat () ;
        //read first frame of InputVideo_FG
    long number_of_readed_frame = 0 ;
    char read_status_1 = 'N' ;
    if ( ins_VideoCapture_FGV
             .read ( ins_Mat_contain_one_frame_of_InputVideo_FG )
       ) {
      read_status_1 = 'Y' ;
     }
    if ( read_status_1 == 'N') {
      System.out.println ( "can not read first frame Video_FG" ) ;
      return '3' ; 
     }
       //have read first frame of InputVideo_FG
    System.out.println ( "can read first frame Video_FG" ) ;
    number_of_readed_frame ++ ;

        //construct instance of VideoCapture for BackGround Video
    System.out.println ( "path_of_InputVideoFile_BG = "
            + path_of_InputVideoFile_BG ) ;
    VideoCapture ins_VideoCapture_BGV_kariOpen
            = new VideoCapture ( path_of_InputVideoFile_BG ) ;
    if ( ins_VideoCapture_BGV_kariOpen == null ) {
      System.out.println ( "can not access InputVideoFile_BG" ) ;
      return '4' ; 
     }
    if ( ins_VideoCapture_BGV_kariOpen.isOpened ( ) != true ) {
      System.out.println ( "can not open InputVideoFile_BG" ) ;
      return '5' ; 
     }
             //construct instance of Mat for BackGround Video
    Mat ins_Mat_contain_one_frame_of_BGV_kariOpen
                = new Mat () ;
            //read first frame of InputVideo_BG
    char read_status_2 = 'N' ;
    if ( ins_VideoCapture_BGV_kariOpen
             .read ( ins_Mat_contain_one_frame_of_BGV_kariOpen )
       ) {
      read_status_2 = 'Y' ;
     }
    if ( read_status_2 == 'N') {
      System.out.println ( "can not read first frame Video_BG" ) ;
      return '6' ; 
     }
              //have read first frame of InputVideo_BG
    System.out.println ( "can read first frame Video_BG" ) ;

          //know information about frame_of_InputVideo_BG
    Size size_of_Mat_I
       = ins_Mat_contain_one_frame_of_BGV_kariOpen.size ( ) ;
    int width_of_frame_InputVideo_BG = (int) size_of_Mat_I.width ;
    int height_of_frame_InputVideo_BG =(int) size_of_Mat_I.height ;
    int type_of_Mat
       = ins_Mat_contain_one_frame_of_BGV_kariOpen.type ( ) ;
    System.out.println( "width and height of frame_of_InputVideo_BG = "
                + width_of_frame_InputVideo_BG
        + " , " + height_of_frame_InputVideo_BG ) ;
    System.out.println( "type_of_Mat = " + type_of_Mat ) ;

          //prepare OutputVideo
       //FPS
    int fps_value = 30 ;
       //forucc : MP4V format
    int fourcc_value = VideoWriter.fourcc ( 'm', 'p' , '4', 'v' ) ;
       //Size
    int width_of_frame_OutputVideo = width_of_frame_InputVideo_BG ;
    int height_of_frame_OutputVideo = height_of_frame_InputVideo_BG ;
    System.out.println( "width_of_frame_OutputVideo = "
       + width_of_frame_OutputVideo ) ;
    System.out.println( "height_of_frame_OutputVideo = "
       + height_of_frame_OutputVideo ) ;
    Size ins_Size_of_VideoWriter
       = new Size ( width_of_frame_OutputVideo
         , height_of_frame_OutputVideo ) ;

         //construct instance of VideoWriter class
    VideoWriter ins_VideoWriter_OutputVideo
          = new VideoWriter(
                  //path of output video
            ( mv_dir_of_output_video +
              "out" + 0 + ".m4v" )
         , fourcc_value
         , fps_value
         , ins_Size_of_VideoWriter
                   ) ;
    System.out.println( "prepared OutputVideo" ) ;

           //prepare area for handling image data   
    Mat ins_Mat_contain_one_frame
        = new Mat ( size_of_Mat_I , type_of_Mat ) ;

    ins_VideoCapture_BGV_kariOpen.release ( ) ;

    VideoCapture ins_VideoCapture_of_BGV = null ;
    VideoWriter ins_VideoWriter_new ;

           //until this value , writing will be continue
    long max_number_of_output_frame
           = ( long ) ( fps_value * 40.0 ) ;

           //for changing BGVideo
    int timing_of_chage_BGV = fps_value * 40 ;
    int counter_for_reading_BGV = timing_of_chage_BGV + 1 ;
           //for changing VideoWriter
    int timing_of_chage_VideoWriter = fps_value * 3 ;
    int counter_for_writing_OutputVideo = 0 ;

    mv_index_of_VideoWriter = 0 ;

    char reached_to_end_of_InputVideo_FG = 'N' ;
    int w1 = 0 ;

     //repeat :
     //      modify contents of the frame of inputVideo BackGround
     //      write the frame modified into OutputVideo file
     //      read next frame of inputVideo
    char reached_to_end_of_process = 'N' ;
    while ( reached_to_end_of_process == 'N' ) {

                       //display frame number
      System.out.println ( "----------------------------------" ) ;
      System.out.println ( "Class = " + mv_this_Class_name +
              " : methode = " + this_methode_name ) ;
      System.out.print ( "number_of_readed_frame = "
              + number_of_readed_frame ) ;
      System.out.println ( ", max_number_of_output_frame = "
             + max_number_of_output_frame ) ;
      System.out.print ( "counter_for_reading_BGV = "
               + counter_for_reading_BGV ) ;
      System.out.println ( ", timing_of_chage_BGV = "
              + timing_of_chage_BGV ) ;
      System.out.println ( "mv_index_of_current_using_BackGroundVideo = "
                + mv_index_of_current_using_BackGroundVideo ) ;
      System.out.print ( "counter_for_writing_OutputVideo = "
                + counter_for_writing_OutputVideo ) ;      
      System.out.println ( ", timing_of_chage_VideoWriter = "
                + timing_of_chage_VideoWriter ) ;      

      if ( number_of_readed_frame
               >  max_number_of_output_frame ) {
                   //reached to process end
        reached_to_end_of_process = 'Y' ;
        break ;
       }
      w1 = counter_for_reading_BGV ;
      if ( w1 >= timing_of_chage_BGV ) {
                   //it is the timing of changing BGV
        ins_VideoCapture_of_BGV
              = change_VideoCapture_of_BGV (
                      mv_dir_of_input_video
                    , mv_table_of_filename_BVF
                                           ) ;
        read_one_frame_of_BGV (
                 ins_VideoCapture_of_BGV
               , ins_Mat_contain_one_frame
                               ) ;
        counter_for_reading_BGV = 0 ;
       }
             //modify contents of frame
      modify_contents_of_frame (
               ins_Mat_contain_one_frame
             , ins_Mat_contain_one_frame_of_InputVideo_FG
             , mv_table_of_color_value
             , mv_number_of_table_of_color_value
                                 ) ;
      System.out.println ( "passed : modify_contents_of_frame" ) ;

      w1 = counter_for_writing_OutputVideo ;
      if ( w1 >= timing_of_chage_VideoWriter ) {
                      //it is the timing of changing VideoWriter
          ins_VideoWriter_new =
               change_VideoWriter (
                      ins_VideoWriter_OutputVideo
                      , width_of_frame_OutputVideo
                      , height_of_frame_OutputVideo
                                    ) ;
          ins_VideoWriter_OutputVideo
                  = ins_VideoWriter_new ;
          counter_for_writing_OutputVideo = 0 ;
       }

               //write the frame modified into OutputVideo file
      ins_VideoWriter_OutputVideo
                .write (
                        ins_Mat_contain_one_frame                        
                        ) ;
        counter_for_writing_OutputVideo ++ ;
      System.out.println ( "passed : ins_VideoWriter_OutputVideo.write" ) ;

                   //read next frame of ForeGroundVideo
      read_status_1 = 'N' ;
      if ( ins_VideoCapture_FGV
                   .read ( ins_Mat_contain_one_frame_of_InputVideo_FG )
         ) {
        read_status_1 = 'Y' ;
       }
      if ( read_status_1 == 'N') {
        System.out.println ( "have reached to end of InputVideo_FG file" ) ;
        WaitEntKey.wait_ent_key () ;
        reached_to_end_of_InputVideo_FG = 'Y' ;
        reached_to_end_of_process = 'Y' ;
        break ;
       }
      else {
        number_of_readed_frame ++ ;
       }          
               //read next frame of BackGroundVideo          
      read_one_frame_of_BGV (
                  ins_VideoCapture_of_BGV
                , ins_Mat_contain_one_frame 
                             ) ;
      counter_for_reading_BGV ++ ;
     }
                //release VideoWriter
    ins_VideoWriter_OutputVideo.release ( ) ;
    System.out.println ( "passed : ins_VideoWriter_OutputVideo.release ( )" ) ;

    System.out.println ( "======================" ) ;
    System.out.println ( "terminated" ) ;
    Calendar ins_calendar_at_end = Calendar.getInstance ( ) ;
    System.out.println ( "Start Time = " +
                ins_calendar_at_start.get ( Calendar.HOUR_OF_DAY )
        + " : " + ins_calendar_at_start.get ( Calendar.MINUTE )
        + " : " + ins_calendar_at_start.get ( Calendar.SECOND )
                       ) ;
    System.out.println ( "End Time =   " +
            ins_calendar_at_end.get ( Calendar.HOUR_OF_DAY )
        + " : " + ins_calendar_at_end.get ( Calendar.MINUTE )
        + " : " + ins_calendar_at_end.get ( Calendar.SECOND )
                       ) ;

    return 'Y' ; 
   }

//---------------------
//change Output VideoWriter
//--------------------- 
  private static VideoWriter change_VideoWriter (
                  VideoWriter para_ins_VideoWriter_current
                , int para_width_of_frame_InputVideo_BG
               ,  int para_height_of_frame_InputVideo_BG
                                       ) {

    String this_methode_name = "change_VideoWriter" ; 

            //release current VideoWriter
    para_ins_VideoWriter_current.release ( ) ;
    para_ins_VideoWriter_current = null ;

    System.out.println( "Class = " + mv_this_Class_name
             + " , " + this_methode_name ) ;
    System.out.println( "released current VideoWriter" ) ;

            //prepare new OutputVideo
    //=====================================   
    mv_index_of_VideoWriter ++ ;
    //=====================================       
      //FPS
    int fps_value = 30 ;
     //forucc : MP4V format
    int fourcc_value = VideoWriter.fourcc ( 'm', 'p' , '4', 'v' ) ;
     //Size
    int width_of_frame_OutputVideo = para_width_of_frame_InputVideo_BG ;
    int height_of_frame_OutputVideo = para_height_of_frame_InputVideo_BG ;
    System.out.println( "width_of_frame_OutputVideo = "
           + width_of_frame_OutputVideo ) ;
    System.out.println( "height_of_frame_OutputVideo = "
           + height_of_frame_OutputVideo ) ;
    Size ins_Size_of_VideoWriter
      = new Size ( width_of_frame_OutputVideo
                 , height_of_frame_OutputVideo ) ;
         //construct instance of VideoWriter class
    String path_of_output =
        mv_dir_of_output_video +
             "out" + mv_index_of_VideoWriter + ".m4v" ;
    VideoWriter ins_new_VideoWriter
          = new VideoWriter(
                      //path of new output video file
                path_of_output
              , fourcc_value
              , fps_value
              , ins_Size_of_VideoWriter
                           ) ;
    System.out.println( "new instance of VideoWriter constructed") ;
    System.out.println( "path_of_output = "
                 + path_of_output ) ;

//    WaitEntKey.wait_ent_key () ;

    return ins_new_VideoWriter ;
   } 

//----------------------
// change VideoCapture of BackGoundVideo
//---------------------- 
  private static VideoCapture change_VideoCapture_of_BGV (
         String para_dir_of_input_video
       , String [ ] para_table_of_path_BVF
                                     ) {

    String this_methode_name = "change_VideoCapture_of_BGV" ;

    VideoCapture ins_VideoCapture_return = null ;

    //====================================
    mv_index_of_current_using_BackGroundVideo ++ ;
    //===================================
    String filename_of_BackGoundVideo
           = para_table_of_path_BVF
        [ mv_index_of_current_using_BackGroundVideo ] ;
    String path_of_BackGoundVideo =
            para_dir_of_input_video +
            filename_of_BackGoundVideo ;   

    VideoCapture ins_VideoCapture_BGV
            = new VideoCapture ( path_of_BackGoundVideo ) ;
    if ( ins_VideoCapture_BGV == null ) {
      System.out.println ( "    Class = " + mv_this_Class_name +
                " : methode = " + this_methode_name ) ;
      System.out.println ( "    can not access Background Video File" ) ;
      System.out.println ( "path_of_BackGoundVideo = "
                     + path_of_BackGoundVideo ) ;
      WaitEntKey.wait_ent_key () ;
      return ins_VideoCapture_return ;
     }
    if ( ins_VideoCapture_BGV.isOpened ( ) != true ) {
        System.out.println ( "    Class = " + mv_this_Class_name +
                " : methode = " + this_methode_name ) ;
      System.out.println ( "    can not open Background Video File" ) ;
      System.out.println ( "path_of_BackGoundVideo = "
                    + path_of_BackGoundVideo ) ;
      WaitEntKey.wait_ent_key () ;
      return ins_VideoCapture_return ;
     }

    ins_VideoCapture_return = ins_VideoCapture_BGV ;
    return ins_VideoCapture_return ;
  }

//--------------------
//read one frame of InputVideo_BGV
//--------------------
  private static Mat read_one_frame_of_BGV (
              VideoCapture para_ins_VideoCapture
            , Mat para_ins_Mat_contain_read_imageData
                                           ) {

    String this_methode_name = "read_one_frame_of_BGV" ;

    char read_status_2 = 'N' ;
    if ( para_ins_VideoCapture
             .read ( para_ins_Mat_contain_read_imageData )
       ) {
      read_status_2 = 'Y' ;
     }
    if ( read_status_2 == 'N') {
      System.out.println ( "    Class = " + mv_this_Class_name +
                " : methode = " + this_methode_name ) ;
      System.out.println ( "can not read frame Video_BG" ) ;
      WaitEntKey.wait_ent_key () ;
     }

    return para_ins_Mat_contain_read_imageData ;   
   }

//---------------------
//modify contents of frame
//---------------------      
  private static void modify_contents_of_frame (
               Mat para_ins_Mat_contain_one_frame_of_InputVideo_BG
             , Mat para_ins_Mat_contain_one_frame_of_InputVideo_FG
             , double [ ] [ ] para_table_of_color_value
             , int para_number_of_table_of_color_value
                                           ) {

    String this_methode_name = "modify_contents_of_frame" ;

    Size size_of_Mat_I = para_ins_Mat_contain_one_frame_of_InputVideo_FG.size ( ) ;
    int width_of_frame_InputVideo_FG = (int) size_of_Mat_I.width ;
    int height_of_frame_InputVideo_FG =(int) size_of_Mat_I.height ;
//    System.out.println( "width and height of frame_of_InputVideo_FG = "
//                    + width_of_frame_InputVideo_FG
//            + " , " + height_of_frame_InputVideo_FG ) ;

    double [ ] color_Lab_of_one_pixel ;
    double [ ] color_BGR_of_one_pixel ;
    char return_status ;

          //make instance of Mat that contain
          //  color value of L*a*b* converted from BGR
    Mat ins_Mat_converted = new Mat ( ) ;
    Imgproc.cvtColor (
             para_ins_Mat_contain_one_frame_of_InputVideo_FG
           , ins_Mat_converted
           , Imgproc.COLOR_BGR2Lab ) ;

    int put_location_X = 0 ;
    int put_location_Y = 0 ;
    long counter_of_put_pixel = 0 ;

    char debug_mode = 'N' ;

    for ( int get_location_X = 0
               ; get_location_X < width_of_frame_InputVideo_FG
               ; get_location_X ++ ) {
      for ( int get_location_Y = 0
                 ; get_location_Y < height_of_frame_InputVideo_FG
                 ; get_location_Y ++ ) {

                 //get the color value (L*a*b*) of one pixel in Photo Image
        color_Lab_of_one_pixel
              = ins_Mat_converted
                  .get ( get_location_Y, get_location_X ) ;

//        if ( ( get_location_X == 964 )
//             &&
//             ( get_location_Y == 166 )
//         ) {
//           debug_mode = 'Y' ;
//          }
//        else {
//           debug_mode = 'N' ;
//         }            

        if ( debug_mode == 'Y' ) {
            System.out.println ( "Class = " + mv_this_Class_name
                      + " , " + this_methode_name ) ;
          System.out.println ( "get_location_X = "
                        + get_location_X
                        + " , get_location_Y = "
                        + get_location_Y ) ;
          System.out.println ( "color_Lab_of_one_pixel = "
                            + color_Lab_of_one_pixel [ 0 ]
                    + " , " + color_Lab_of_one_pixel [ 1 ]
                    + " , " + color_Lab_of_one_pixel [ 2 ]
                            ) ;
          WaitEntKey.wait_ent_key () ;
         }
                 //detect the color
        return_status = detect_color_value (
                           color_Lab_of_one_pixel
                         , para_table_of_color_value
                         , para_number_of_table_of_color_value
                         , debug_mode
                                           ) ;

        if ( debug_mode == 'Y' ) {
          System.out.println ( "Class = " + mv_this_Class_name
                        + " , " + this_methode_name ) ;
          System.out.println ( "get_location_X = "
                            + get_location_X
                            + " , get_location_Y = "
                            + get_location_Y ) ;
          System.out.println ( "return_status = "
                        + return_status    ) ;
          WaitEntKey.wait_ent_key () ;
         }

        if ( return_status == 'Y' ) {
                //this pixel have the color in condition
                //so , this pixel have to be copied into frame of output video
          color_BGR_of_one_pixel
              = para_ins_Mat_contain_one_frame_of_InputVideo_FG
                  .get ( get_location_Y, get_location_X ) ;             
          put_location_X = get_location_X ;
          put_location_Y = get_location_Y ;
          para_ins_Mat_contain_one_frame_of_InputVideo_BG
                .put (
                        put_location_Y , put_location_X
                      , color_BGR_of_one_pixel
                              ) ;
          counter_of_put_pixel ++ ;
         }
       }
     }

    System.out.println ( "    Class = " + mv_this_Class_name +
                        " : methode = " + this_methode_name ) ;
    System.out.println( "        counter_of_put_pixel = "
                        + counter_of_put_pixel ) ;
//    WaitEntKey.wait_ent_key ( ) ;
   }

//----------------------
//detect the color
//-----------------------
  private static char detect_color_value (
         double [ ]  para_color_Lab_of_one_pixel
       , double [ ] [ ] para_table_of_color_value
       , int para_number_of_table_of_color_value
       , char para_debug_mode
                                      ) {

    String this_methode_name = "detect_color_value" ;

    char display_do = 'N' ;

    char return_status = ' ' ;                                 
    for ( int i = 0 ; i < para_number_of_table_of_color_value
                        ; i ++ ) {      
      if ( para_debug_mode == 'Y' ) {
        System.out.println ( "    Class = " + mv_this_Class_name +
                    " : methode = " + this_methode_name ) ;
        System.out.println( "return_status = "
                       + return_status ) ;
        System.out.println( "para_number_of_table_of_color_value = "
                    + para_number_of_table_of_color_value ) ;
        System.out.println ( "i = " + i ) ;
        System.out.println ( "para_table_of_color_value [ i ] = "
             + para_table_of_color_value [ i ][0]
            + " , " + para_table_of_color_value [ i ][1]
                    + " , " + para_table_of_color_value [ i ][2] 
                    + " , " + para_table_of_color_value [ i ][3] 
                    + " , " + para_table_of_color_value [ i ][4] 
                    + " , " + para_table_of_color_value [ i ][5]            
                     ) ;
        System.out.println ( "para_color_Lab_of_one_pixel = "
                  + para_color_Lab_of_one_pixel[0]
                 + " , " + para_color_Lab_of_one_pixel [1]
                 + " , " + para_color_Lab_of_one_pixel [2] 
                          ) ;
          WaitEntKey.wait_ent_key ( ) ;
       }

      if ( ( para_color_Lab_of_one_pixel [ 0 ]   //L*                
                  > para_table_of_color_value [ i ] [ 0 ] ) //L* From )
            &&
            ( para_color_Lab_of_one_pixel [ 0 ]   //L*                
                  < para_table_of_color_value [ i ] [ 1 ] ) //L* To )
            &&                  
            ( para_color_Lab_of_one_pixel [ 1 ]   //a*                
                  > para_table_of_color_value [ i ] [ 2 ] )//a* From )
            &&                  
            ( para_color_Lab_of_one_pixel [ 1 ]   //a*                
                  < para_table_of_color_value [ i ] [ 3 ] ) //a* To )
            &&                  
            ( para_color_Lab_of_one_pixel [ 2 ]   //b*                
                  > para_table_of_color_value [ i ] [ 4 ] ) //b* From )
            &&                  
            ( para_color_Lab_of_one_pixel [ 2 ]   //b*                
                  < para_table_of_color_value [ i ] [ 5 ] ) //b* To )
          ) {
        if ( para_table_of_color_value [ i ] [ 6 ] < 0.0 ) {
            //[ * ] [ 6 ] = -1.0 : if color value is in area defined above
            //    , do not get the pixel            
          return_status = 'N' ;

          if ( para_debug_mode == 'Y' ) {
              System.out.println ( "i = " + i ) ;
              System.out.println ( "return_status = "
                      + return_status ) ;             
               WaitEntKey.wait_ent_key ( ) ;
           }             
          return return_status ;            
         }
        else {
            //[ * ] [ 6 ] = 1.0 : if color value is in area defined above
            //    , get the pixel
             return_status = 'Y'  ;
         }

        if ( para_debug_mode == 'Y' ) {
           System.out.println ( "    Class = " + mv_this_Class_name +
                     " : methode = " + this_methode_name ) ;
          System.out.println( "return_status = "
                        + return_status ) ;
          WaitEntKey.wait_ent_key ( ) ; 
         }    
       }         
    }
   return return_status ;                                     
  }

}

------------------------------------------------

2017年11月21日 (火)

開発費用ゼロ コンピューターグラフィックスによる動画制作 Java OpenCV3 Eclipse を使って

先日、下記のコンテンツを発表したのですが、

コンピューターグラフィックスによる動画制作をやってみました ( Python と OpenCV を使って )

その中で、下記のように記しました。

----------------
 [Python]、もっと速く動いてほしいなぁ

という感じです。

将来、時間的余裕があれば、今回、Python で記述したコンピュータープログラムを、Java言語を使って書き直してみようかな、というような事も思っています。
----------------

で、「時間的余裕」が少し生じたので、調べてみました、

下記の3点セットを使って、
 コンピューターグラフィックス による 動画制作 を
  行えるかどうか

という事について。  

3点セット
 OpenCV3
 Java言語
 Eclipse

上記3点セット中のいずれをも、ネットを経由して、新たに費用を出費することなく、入手することができます。

なので、この3点セットを使って、動画の制作を行うことができるのであれば、「開発費用ゼロ」での動画の制作を、私は行うことができるようになるであろうと、と考えました。

調べてみた結果は、

 「なんとかできそうだ」

でした。

しかし、その結論に達するまでの道程は、様々な障害を乗り越えていくものでした。

どのような手順で、様々な作業を行って、上記の結論に達しえたのか、今、その作業の記憶が頭の中に残っているうちに、記録しておこう、将来、再び、動画の制作を行う際に困らないように、と思い、その内容を下記に記述しました。

その内容は、このような手順で、このような作業を行ったら、このようになった、という事を、ただ、淡々と述べているに過ぎません。

下記の記述をお読みになった方が、それを単に参考にしていただく分には、問題は無いと思われます。

しかし、記述されている内容に沿って、その方がそこに記されているのと同様の作業を行われた際に、その作業の結果、作業に使用されたコンピューター等、様々な方面において、何らかの問題が発生しないという保証は、全くありません。

その作業の結果、その方や、その方が使用された様々な器機、インフラ等の身の上にどのような事が起ころうとも、私は一切、責任を負いません。

-------

どのような手順でもって、どのような作業を行った末に、上記3点セットを使用しての動画制作、なんとかできそうだ、という結論に達したのか

について、以下に記します。

以下のような手順で、作業を行いました。

1. prepare computer
     使用するコンピューターを用意

 CPU : Core i3-3110M 2.40GHz
 メモリー : 4GB
 Operating System : Windows 10 Home, 64ビットオペレーティングシステム

2.  OpenCV3 関連の作業を行いました

2.1 install OpenCV3

OpenCV

から、[opencv-3.3.1-vc14.exe] をダウンロードし、上記1.に記述されているコンピューターの中に、インストールしました。

これ以降の、OpenCV3に関する記述において、[OpenCV_3_3_1_vc14]という文字列が出現した場合には、、これは、上記の作業の結果、OpenCV3がインストールされた先のフォルダーを表すものと、考えてください。

例えば、

  OpenCV_3_3_1_vc14
    opencv
      build

というような記述が行われている場合には、これは、下記のようなフォルダーの階層構造になっていることを意味します。

ドライブC
  XXXXXXXX
    YYYYYYYYY
      OpenCV_3_3_1_vc14
        opencv
          build

2.2 copy opencv_ffmpeg331_64.dll

  OpenCV_3_3_1_vc14
    opencv
      build
        bin

の下にある、opencv_ffmpeg331_64.dll を、

  OpenCV_3_3_1_vc14
    opencv
      build
     java
       x64

の下に、コピーしました。

その結果、このフォルダー中には、

  OpenCV_3_3_1_vc14
    opencv
      build
     java
       x64
         opencv_ffmpeg331_64.dll
         opencv_java331.dll

というように、2個の dll が存在する状態になりました。 

このような、OpenCV3 の内部の構造を改変するような事を、してもよいのかどうか、よく分かりませんが、このような作業が必要でした。他に、もっとスマートな解決方法があるのかもしれません。

3  Java 関連の作業を行いました

3.1 install Java SE Development Kit 8

[Java SE Development Kit 8u152] を、ダウンロードし、上記1.に記述されているコンピューター中に、インストールしました。

3.2 環境変数の設定変更

上記1.に記述されているコンピューターに対して、環境変数の設定変更を行いました。

 [JAVA_HOME] を追加
 [Path]に、[%JAVA_HOME%\bin;]を追記

この際に、とまどったのが、Win10の[システムの詳細設定]の操作でした。

詳細設定の画面をどうやって表示させたらよいのか?

下記の手順に従ってやったら、できました。

 [窓枠アイコン](画面の左下角)を、左クリック
 [設定アイコン](歯車のような形)を、左クリック
 [Windowsの設定]の画面が開いたので、[システム]のアイコンを、左クリック
 [設定の検索]の箱の中に、[詳細設定]の4文字を入力すると、その箱の下に、
 [システムの詳細設定の表示]という文字列が表示されたので、そこを、左クリック
 [システムのプロパティ]画面が表示されたので、[詳細設定]タブを、左クリック
 [環境変数(N)...]ボタンを、左クリック

上記のようにして、環境変数の設定変更の処理を行うことができるようになりました。もっとスマートな(簡単な)やり方があるのかもしれません。

将来、Win10のバージョンアップに伴い、別のやり方によってやるようになるのかもしれません。

4  Eclipse 関連の作業を行いました

4.1 install eclipse-inst-win64.exe

Download Eclipse Technology that is right for you

にアクセスして、

[Get Eclipse OXYGEN] の下にある
  [DOWNLOAD 64 BIT]
   を、左クリックして、

eclipse-inst-win64.exe

をダウンロードして、
それを、左ボタン・ダブルクリックで起動して、インストールを行いました。

インストール対象としては、

 [Eclipse IDE for Java Developers]

を、選択しました。

4.2 動作確認

[TestOpenCV3]というプロジェクトを作成し、その中に、下記のプログラム(Java言語によって記述)を作成しました。

-----------------------------
public class Test1 {
  public static void main(String[] args) {
        System.out.println ( "AAA") ;
  }
}
-----------------------------

これを起動すると、Ecipseのコンソール上に

AAA

と表示されたので、

インストールした、[Ecipse] と [Java SE Development Kit 8] を用いて、Java言語を用いて記述されるプログラムを、制作、実行していく事が、私が使用するコンピューターを用いて可能となったことを、確認できました。

5. connect OpenCV3 and Eclipse

ここまでの作業により、私が使用するコンピューター上に、下記3点セットがインストールされた事になります。

3点セット
 [OpenCV3]
 [Java SE Development Kit 8u152]
 [Eclipse]

上記のうち、[Eclipse] と [Java SE Development Kit 8u152] とは、既に結合された状態になっています。

残るは、[OpenCV3] と [Eclipse] の結合であります。

5.1 opencv-331.jar

[Eclipse]を使用して、

プロジェクト[TestOpenCV3] の上で、右クリック
Build Path
Add External Archives で、下記を指定

  OpenCV_3_3_1_vc14
    opencv
      build
        java
          opencv-331.jar

5.2 Native library location

[Eclipse]を使用して、

プロジェクト[TestOpenCV3] の上で、右クリック
Build Path
Add Libraries
User Library を Select
・・・

で、[User Library] を1個作成して、

その後、

プロジェクト[TestOpenCV3] の上で、右クリック
Build Path
Configure Build Path

で、上記で作成された[User Library]を選択し、
それの、[Native library location] に、下記を登録しました。

  OpenCV_3_3_1_vc14
   opencv
    build
     java
       x64

2.2 に述べたように、上記のフォルダーの中には、

 opencv_ffmpeg331_64.dll
 opencv_java331.dll

が入っているのですが、これらの格納位置を、Eclipse に知らしめる事により、5.1に述べた処理とあいまって、[OpenCV3] と [Eclipse] の結合作業、完成、ということになったのかもしれません。

6. テスト・プログラム実行

後述のプログラムを、プロジェクト[TestOpenCV3] 中に記述し、実行してみました。

このプログラムは、

下記のようなイメージの動画

Bef
V_before  

の中に、

下記のようなイメージの写真画像を、埋め込んで

P
Inputphotoimage

下記のようなイメージの動画を新たに作成する

Aft
V_after

と、いうものです。

写真画像の埋め込みは、ただ単に埋め込む、というようなものではなく、

写真画像中の、赤成分が、緑成分、青成分よりも大きいようなピクセルだけを、埋め込む

というものです。

埋め込み先の位置も、動画が進んでいくにつれて変わっていくようにしてあります。

なので、写真画像のうち、緑色っぽい部分は埋め込まれておらず、黄色(花の部分)や茶色に近い部分だけが埋め込まれ、埋め込まれる先の位置も、徐々に変化していき、というような感じになっています。

このプログラムを制作してみて、今後に希望が出てきたような感じがしています。

PythonとOpenCVを使っての動画制作は、自分の使用しているコンピューターでは、処理に時間がかかりすぎるので、とてもムリのようですが、このプログラムのように、JavaとOpenCV3を使っての制作であれば、今後の更なる制作への希望が持てるような、短い時間で処理できることが、分かりました。

テスト・プログラムのソースリストを、以下に記します。

------------------------------------------------
//=====================================
//Exmpl1.java
//=====================================

           //for using OpenCV3
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.Size;
import org.opencv.imgcodecs.Imgcodecs ;
import org.opencv.videoio.VideoCapture;
import org.opencv.videoio.VideoWriter;

public class EXmpl1 {

          private static String mv_this_Class_name = " Exmpl1" ;

          public static void main ( String[] args ) {

            String this_methode_name = "main" ;

            System.out.println ( "----------------------------------" ) ;
              System.out.println ( "Enter into Class = " + mv_this_Class_name +
                          " : methode = " + this_methode_name ) ;

                        //prepare for using OpenCV3
            System.loadLibrary ( Core.NATIVE_LIBRARY_NAME ) ;

                        //load photo image data
            String path_of_InputPhotoImage = "E:Exmpl1\\InputPhotoImage.png" ;
                         //photo image data will be set to instance of Mat class
            Mat ins_Mat_contain_PhotoImage
                             //Using OpenCV3
                         = Imgcodecs.imread ( path_of_InputPhotoImage ) ;
            if ( ins_Mat_contain_PhotoImage == null ) {
              System.out.println ( "can not read InputPhotoImage" ) ;
             }
            else {
              System.out.println ( "can read InputPhotoImage" ) ;
              System.out.println ( "path_of_InputPhotoImage = "
                               + path_of_InputPhotoImage ) ;
              make_video ( ins_Mat_contain_PhotoImage ) ;
             }
          }

        //------------------------
        // making of video
        //------------------------
          private static char make_video
               ( Mat para_ins_Mat_contain_PhotoImage ) {

            String this_methode_name = "make_video" ;

            System.out.println ( "----------------------------------" ) ;
            System.out.println ( "Enter into Class = " + mv_this_Class_name +
                    " : methode = " + this_methode_name ) ;

                   //know the size of PhotoImage
            Size size_of_loaded_PhotoImage
                      = para_ins_Mat_contain_PhotoImage.size() ;
            int width_of_PhotoImage =  (int) size_of_loaded_PhotoImage
                                                 .width ;
            int height_of_PhotoImage = (int) size_of_loaded_PhotoImage
                                                 .height ;
            System.out.println ( " width_of_PhotoImage = " +  width_of_PhotoImage ) ;
            System.out.println ( " height_of_PhotoImage = " +  height_of_PhotoImage ) ;

                            //set path of video
            String path_of_InputVideoFile = "E:Exmpl1\\BeforeVideo.mp4" ;
            String path_of_OutputVideoFile = "E:Exmpl1\\AfterVideo.m4v" ;
                            //access InputVideoFile using OpenCV3
            VideoCapture ins_VideoCapture_InputVideo
                = new VideoCapture ( path_of_InputVideoFile ) ;
            if ( ins_VideoCapture_InputVideo == null ) {
              System.out.println ( "can not access InputVideoFile" ) ;
              return 'N' ;
             }
            if ( ins_VideoCapture_InputVideo.isOpened ( ) != true ) {
              System.out.println ( "can not open InputVideoFile" ) ;
              return 'O' ;
             }
                  //we accesed and opened InputVideoFile
                  //Maybe, will be able to make output video

                           //define Mat for handling videos
            Mat ins_Mat_contain_one_frame_of_InputVideo
                        = new Mat () ;
            Mat ins_Mat_contain_one_frame_of_OutputVideo ;
                           //define and initialize counter for readed frame
            long number_of_readed_frame = 0 ;

                  //read first frame of InputVideo
            char read_status = 'N' ;
            if (ins_VideoCapture_InputVideo
                       .read ( ins_Mat_contain_one_frame_of_InputVideo )
               ) {
              read_status = 'Y' ;
             }
          if ( read_status == 'N') {
              System.out.println ( "can not read first frame" ) ;
              return 'F' ;
             }
                  //have read first frame of InputVideo
                  //Maybe, will be able to make output video
            System.out.println ( "can read first frame" ) ;
            number_of_readed_frame ++ ;

            Size size_of_Mat_I = ins_Mat_contain_one_frame_of_InputVideo.size ( ) ;
            int width_of_frame_InputVideo = (int) size_of_Mat_I.width ;
            int height_of_frame_InputVideo =(int) size_of_Mat_I.height ;
            System.out.println( "width and height of frame_of_InputVideo = "
                        + width_of_frame_InputVideo
                + " , " + height_of_frame_InputVideo ) ;

                    //prepare OutputVideo
                       //FPS
            int fps_value = 30 ;
                      //forucc : MP4V format
            int fourcc_value = VideoWriter.fourcc ( 'm', 'p' , '4', 'v' ) ;
                      //Size
            int width_of_frame_OutputVideo = width_of_frame_InputVideo ;
            int height_of_frame_OutputVideo = height_of_frame_InputVideo ;
            Size ins_Size_of_VideoWriter
                 = new Size ( width_of_frame_OutputVideo
                            , height_of_frame_OutputVideo ) ;
                      //construct instance of VideoWriter class
            VideoWriter ins_VideoWriter_OutputVideo
                 = new VideoWriter(
                          path_of_OutputVideoFile
                        , fourcc_value
                        , fps_value
                        , ins_Size_of_VideoWriter
                                  ) ;
             System.out.println( "prepared OutputVideo" ) ;

                    //repeat :
                    //      copy read frame of InputVideo to frame of OutputVideo
                    //        modify contents of copied frame
                    //      write the frame modified into OutputVideo file
                    //      read next frame of Inputvideo
              char reached_to_end_of_InputVideo = 'N' ;
              while ( reached_to_end_of_InputVideo == 'N' ) {

                           //display frame number
                System.out.println ( "----------------------------------" ) ;
                  System.out.println ( "Class = " + mv_this_Class_name +
                          " : methode = " + this_methode_name ) ;
                System.out.println ( "number_of_readed_frame = "
                             + number_of_readed_frame ) ;

                           //copy read frame of InputVideo to frame of OutputVideo
                ins_Mat_contain_one_frame_of_OutputVideo
                   = ins_Mat_contain_one_frame_of_InputVideo.clone() ;

                           //modify contents of copied frame ( by using PhotoImage )
                modify_contents_of_copied_frame (
                         ins_Mat_contain_one_frame_of_OutputVideo
                       , number_of_readed_frame
                       , para_ins_Mat_contain_PhotoImage
                       , width_of_PhotoImage
                       , height_of_PhotoImage
                                      ) ;
                System.out.println ( "passed : modify_contents_of_copied_frame" ) ;

                           //write the frame modified into OutputVideo file
                ins_VideoWriter_OutputVideo
                        .write ( ins_Mat_contain_one_frame_of_OutputVideo ) ;
                System.out.println ( "passed : ins_VideoWriter_OutputVideo.write" ) ;

                           //read next frame of Inputvideo
                read_status = 'N' ;
                if (ins_VideoCapture_InputVideo
                           .read ( ins_Mat_contain_one_frame_of_InputVideo )
                   ) {
                  read_status = 'Y' ;
                 }
                if ( read_status == 'N') {
                  System.out.println ( "have reached to end of InputVideo file" ) ;
                  reached_to_end_of_InputVideo = 'Y' ;
                  }
                else {
                   number_of_readed_frame ++ ;
                 }
               }

                        //release VideoWriter and VideoCapture
              ins_VideoWriter_OutputVideo.release ( ) ;
              ins_VideoCapture_InputVideo.release ( ) ;

              System.out.println ( "terminated" ) ;

              return ' ' ;
             }

        //-------------------------
        //modify contents of copied frame
        //-------------------------
          private static void modify_contents_of_copied_frame (
                         Mat para_ins_Mat_contain_one_frame_copied
                       , long para_number_of_readed_frame
                       , Mat para_ins_Mat_contain_PhotoImage
                       , int para_width_of_ins_Mat_contain_PhotoImage
                       , int para_height_of_ins_Mat_contain_PhotoImage
                                      ) {

            String this_methode_name = " modify_contents_of_copied_frame" ;

            System.out.println ( "    Class = " + mv_this_Class_name +
                        " : methode = " + this_methode_name ) ;
            System.out.println ( "    width and hieght of Mat_contain_PhotoImage = "
                       + para_width_of_ins_Mat_contain_PhotoImage
               + " , " + para_height_of_ins_Mat_contain_PhotoImage
                                ) ;

            int put_location_X = 0 ;
            int put_location_Y = 0 ;
            int w1 = 0 ;
            double [ ] color_value_of_one_pixel ;

            for ( int get_location_X = 0
                     ; get_location_X < para_width_of_ins_Mat_contain_PhotoImage
                     ; get_location_X ++ ) {
              for ( int get_location_Y = 0
                       ; get_location_Y < para_height_of_ins_Mat_contain_PhotoImage
                       ; get_location_Y ++ ) {

                       //get the color value of one pixel in Photo Image
                color_value_of_one_pixel
                    = para_ins_Mat_contain_PhotoImage
                         .get ( get_location_Y, get_location_X ) ;
                            //detect the color
                if ( ( color_value_of_one_pixel [ 0 ] < color_value_of_one_pixel [ 2 ] )
                     &&
                     ( color_value_of_one_pixel [ 1 ] < color_value_of_one_pixel [ 2 ] )
                   ) {
                           //modify the color value of one pixel in frame of video
                  w1 = ( int ) para_number_of_readed_frame % 100 ;
                  put_location_X = 30 + ( w1 * 2 ) + get_location_X ;
                  put_location_Y = 500 - w1 + get_location_Y ;
                  para_ins_Mat_contain_one_frame_copied
                             .put (
                        put_location_Y , put_location_X
                      , color_value_of_one_pixel
                              ) ;
                 }
               }
             }
           }

    }
------------------------------------------------

2017年11月 7日 (火)

コンピューターグラフィックスによる動画制作をやってみました ( Python と OpenCV を使って )

コンピューターグラフィックスによる動画制作をやってみました。

映像を、自作のコンピュータープログラムにより、制作しました。

バックグラウンド音楽には、自作曲 [だがっきだだがっきだ, Op.21]を、使用しました。
  (短い動画なので、この曲の序奏部だけ用いています。)

制作した動画を、下記でご覧になることができます。

この動画の格納先URLは、下記です。

https://youtu.be/sMQKNwl8LZA

----------

下記のような、動画制作の作業を行いたいと、思ったのです。

 動画は、静止画が集まったものである。
 よって、[動画・ビフォー]から、静止画を1枚ずつ、順に取り出しながら、
  その静止画に、何らかの加工を行った後
  その静止画を集めて、新たに、[動画・アフター]を作る
 このようにすることにより、[動画・ビフォー]に対して、何らかの加工を施した、[動画・アフター]を制作することができるであろう。

上記の自作の動画を例にとれば、

[動画・ビフォー]:背景にある、流れる川の様子を撮影した動画
 (この動画を、京都市内を流れる鴨川の川原に行って、撮影してきました)
[動画・アフター]:流れる川を撮影した動画と、左から右方向へ移動する物体を合成した動画
 (これらの物体の写真を、京都市内を流れる鴨川の川原に行って、撮影してきました) 

上記のような作業([動画・ビフォー]から、静止画を1枚ずつ、順に取り出しながら・・・)を、手作業でやっていたのでは、時間がいくらあっても足りませんので、コンピューターにやってもらおうと思いました。

そのようなコンピューター処理に関して、ネットでいろいろ調べて、[Python] と [OpenCV] を使って、そのような事をコンピューターにやらせることができそうだ、ということを知りました。(双方ともに、コンピューター・プログラミング言語)

なので、その方向でやってみました。

で、やってみた感想としては、

 このような動画の制作処理には、Python は、あまり向いてないのかもなぁ

という感じです。

下記に、それに関する詳細を述べますが、短期間での調査・制作だったので、私は、Pythonをまだうまく使いこなせていないのかもしれない、だから、下記のような結果になったのだ、という可能性があることを、ご理解した上で、何かの参考にしていただけたら、と思います。

-----

1. Python、使いにくいなぁ、と思ったところ

Java言語(かつて私が使用した)と比較してみると、以下のような点が、使いにくいなぁと感じました。

1.1 処理速度、もっと速くならないかなぁ

前記に述べたような動画の処理を行う際には、コンピューターに、多数回の、繰り返し処理を行わせることになります。

1個の動画は、大量の静止画からできています。

[フレームレート]という言葉があります。[fps]という表記がよく用いられているようですが、これは、[Frame Per Second]の略。すなわち、この動画を1秒間見続けると、人間の目には、何枚の静止画が飛び込んでくる事になるのか、ということを表す数値です。

例えば、FPS=30 の動画を、10秒間、見続けていると、300 ( = 30 × 10 ) 枚の静止画を見続けることになります。

FPS=30 の動画を、1分( = 60秒 )間、見続けていると、1800枚の静止画を見続けることになります。

すなわち、FPS=30 で 長さ 1分間 の動画は、1800枚 の静止画によって構成されている、ということになります。

この静止画1枚(動画を構成している)の中に、例えば、横120ピクセル、縦100ピクセルのサイズの別の静止画(例えば、木の葉を撮影したものとか)を埋め込むためには、その静止画のピクセルを1個ずつ順に調べていかねばなりません(そのピクセルがどのような色になっているのかを)。それを調べ、それと同じ色の点を、動画を構成している静止画の上の適切な位置に埋め込む、というような処理になります。

そのような処理を、12000 ( = 120 × 100 ) 回、繰り返していくことになります。(調べるピクセルの位置を、順に1ずつ、隣のピクセルへ、ずらしながら)

コンピューターは、このような処理を、動画を構成している全ての静止画に対して、エンエンと繰り返し、行ってくれるのであります。(疲れることなく)。

このような多数回の繰り返し処理をコンピューターに行わせのですから、処理時間が問題になってきます。朝、起動したけど、昼になっても終わらず、翌日の未明にようやく終了、なんてことになってしまうかもしれません。

そこで、重要になってくるのが、使用するコンピューターの選定と、使用するコンピューター・プログラム言語の選定です。

私の場合、今回のこの制作のために、新たに高速のコンピューターを買う、という選択肢はありえない、普段、使用しているパーソナル・コンピューターを使用するしか、ありませんでした。

ブログの制作、動画の制作、写真画像の処理等に、普段用いている、ノートパソコン(それほど高価なものではない)を使用するしか、ないのです。

なので、使用するコンピューター・プログラム言語の選択が、極めて重要であったのですが、

 [Python]、もっと速く動いてほしいなぁ

という感じです。

将来、時間的余裕があれば、今回、Python で記述したコンピュータープログラムを、Java言語を使って書き直してみようかな、というような事も思っています。

[Python 速度]、[Python for文 速度]等でネット検索すると、処理速度に関して様々な情報を得ることができるかと思います。

1.2 プログラムの記述量、少なくはならなかったような感じ

Pythonを使ってコンピュタープログラムを記述すると、他の言語を使ってやるよりも、少量の記述量にすることができる、というような情報が、ネット上にあったのですが、今回のこの処理に関しては、そのような事は、感じられませんでした。

Pythonでは、左や右のカッコ("{"  "}"を書かないでいい、それは事実でした。でもその代わりに、":"を、書かねばならないようです。(if文、while文、for文の中に)

動画からの(加工前の)静止画の読み込みや、加工された後の、最終的な動画の書き出しの処理部分は、少量の記述ですみました。しかし、その部分は、[OpenCV]を使用して記述したので、少量の記述ですんだのです、Pythonを使用したからではありません。

Pythonを使用して記述するので、記述量が増える、というような点もありました。行の継続を示すための記述("\")が、必須であるからです。

プログラムを読みやすくするために、数式を記述する際等に、記述の途中で、わざと、改行を施す、というような事を、私は行います。そのような時、各行の末尾に、"\"を必ず記述しなければなりませんでした。うっかり、付け忘れしちゃう事が、多かったです、Pythonにまだ、慣れ親しんでない状態だったので。

1.3 記述ミスしている箇所を、いっぺんに見つけてくれたらいいのになぁ

Pythonを使用してみて驚いたのが、複数の記述ミス箇所をいっぺんに、検出・表示してくれない、という点でした。

 プログラムを起動すると、記述ミスがある行で、ミスが検出されて、処理が止まり、記述ミスの内容を示すメッセージが表示される。

 で、その箇所の記述ミスを修正して、再度、プログラムを起動すると、今度は、別の記述ミスがある行で、ミスが検出されて、また、処理が止まり・・・

といった感じです。

Java言語だと、コンパイルすると、複数個所の記述ミスの内容を示すメッセージを表示してくれるので、それら全ての箇所を修正し、再度、コンパイル、という手順になります。その点において、Pythonを用いてのプログラム制作は、非効率になってしまう可能性があると感じました。修正しては実行、また修正しては実行、というような感じとなり。

1.4 for文、違う、他の言語とは

変数 x を、0 から 10 まで 1 ずつ、数値を増やしながら、処理Aを行う、というような処理をコンピューターに行わせたい時には、下記のように書いたらいいんだろうと思って、書いてみたのですが、

 for x in range ( 0 , 10 ) :
    処理A

処理結果がどうにも、おかしいのです、1回分処理が足りない、で、Pythonのfor文について調べてみたら、

 for x in range ( 0 , 11 ) :
    処理A

と、記述しなければならなかったのだ、という事が分かりました。

C言語や、Java言語での感覚を忘れて、新たなる気持ちでやらねばならない、という事になりましょうか。(ちょっと、大げさかな?)

1.5 メソッドの引数にself必須、まいるなぁ

メソッドの引数には、必ず、"self" を入れなければならない、これも驚きでした。

ついつい、これを入れ忘れ、処理起動したら、エラーで止まり、ということの頻発で、疲れました。(笑)

1.6 System.out.println みたいなのがあると便利なのになぁ

Java言語では、コンピューター画面に何か表示させたい時、

 System.out.println ( "value of var_X = " + var_X ) ;

といったように、手軽に書いてよかったのだけど、Pythonには、これに相当するような、手軽な書き方が無いようです。

-----

2. Python、使いやすいなぁ、と思ったところ

とりあえず、プログラムをちょこっと変えて、やってみる、というような作業には、とても便利だなと、思いました

Pythonを使用して記述したプログラムは、コンパイルしないで、そく、実行できましたので。

その他のカテゴリー

フォト
無料ブログはココログ