らくの遊び場

プログラムでやったことを自由に描いていきます。C++/C#/Python/OpenCV/Tensorflow/Unity

【C#】DateTimeで現在時刻を取得しファイル名にしたい

概要

プログラムでファイルを書き出す時に、ファイル名を現在時刻にしたくなったためやり方をメモする。

実装

DateTime dt = DateTime.Now;
String name = dt.ToString($"{dt:yyyyMMddHHmmss}");

これで年~秒単位の数字の羅列で時刻を入手することができる。 そのままdtを使用すると、/や:やスペース等が入っているため注意。

yyyyMMddHHmmss の部分を変更することにより、内容を変更可能。

【C#】System.Speechを使用し、テキストを読み上げ、音声を保存する

概要

System.Speech.Synthesisを使用して、テキストを読み上げ保存する

環境

実装

using System.Speech.Synthesis;    
using System.Windows.Forms;
using System.Globalization;
using System.Collections.ObjectModel;

public void CreateVoice(string filename, int volume, int speed, string text)
{
    SpeechSynthesizer sz = new SpeechSynthesizer();
    // 設定
    sz.Volume = volume;
    sz.Rate = speed;

    // 使用できる音声合成エンジンを探す
    CultureInfo cultureInfo = Application.CurrentCulture;
    // voicesに使用でききる音声合成エンジンが格納される
    ReadOnlyCollection<InstalledVoice> voices = sz.GetInstalledVoices(cultureInfo);                      
    sz.SelectVoice(voices[0].VoiceInfo.Name);

    sz.SetOutputToWaveFile(filename);
    sz.Speak(text);
}        

解説

SpeechSynthesizer s = new SpeechSynthesizer();
// 設定
s.Volume = volume;
s.Rate = speed;        

で、SpeechSynthesizerの定義と設定を行っています。
次に、どの合成音声エンジンを使用するかですが、まずPCに何がインストールされているかを調べます。

// 使用できる音声合成エンジンを探す
CultureInfo cultureInfo = Application.CurrentCulture;
// voicesに使用でききる音声合成エンジンが格納される
ReadOnlyCollection<InstalledVoice> voices = sz.GetInstalledVoices(cultureInfo);                      

voicesへ情報が格納されるので、中身を見てみると何が使用できるかがわかります。

s.SelectVoice(voices[0].VoiceInfo.Name);

でどのエンジンを使用するか、名前で指定することができます。

また、特に気にせずに初期のまま使用したい場合は

s.SelectVoiceByHints(VoiceGender.Female, VoiceAge.Adult); 

等で性別や年齢を設定できます。

s.SetOutputToWaveFile(filename);
s.Speak(text);

で指定したfilenameで保存することができます。

s.SetOutputToWaveFile(filename);

コメントアウトすると、

s.Speak(text);

単体で、音声を鳴らすことができます。

s.SpeakAsync(text);

とすることで、非同期で再生することも可能です。

問題

アプリが落ちるまで完全に出力されていないのか、サイズが0のままで開くことができません。

追記 2018/12/20

上記問題を以下のように修正することで解決できました。

s.Speak(text);

これを

PromptBuilder builder = new PromptBuilder();
builder.AppendText(text);
sz.Speak(builder);
sz.Dispose();
sz = null;

こう。
PromptBuilderを使用せずにDiposeするとファイルが上手く作成できませんでした。

【OpenCVSharp】VideoWriterを使用して動画をカットして書き出す

概要

OpenCVSharpを使用して読み込んだ動画の一部をカットして書き出す必要があったので メモとして

環境

  • Windows 10
  • OpenCVSharp3 4.0.0
  • VisualStudio2017

実装

    string path = "パス";
    int startFrame = 0;
    int endFrame = 500;

    public void Start(MovieInfo info)
    {
        Thread.CurrentThread.IsBackground = false;
        ThreadPool.QueueUserWorkItem(this.WriteMovie);
    }

    private void WriteMovie(object state)
    {
        // 動画を開く
        var capture = new VideoCapture(path);
        // whileで回して切り分ける
        using (VideoWriter vw = new VideoWriter("test.avi", FourCC.XVID, 30, new Size(capture.FrameWidth, capture.FrameHeight)))
        using (var img = new Mat())
        {
            capture.PosFrames = startFrame;
            for (int i = 0; i < endFrame - startFrame; i++)
            {
                // 動画を読み込む
                capture.Read(img);
                if (img.Empty())
                    break;
                 vw.Write(img);
            }
        }
    }

解説

動画を書き出す関数 WriteMovieをThredPoolで読み出しています。

using (VideoWriter vw = new VideoWriter("test.avi", FourCC.XVID, 30, new Size(capture.FrameWidth, capture.FrameHeight)))

でVideoWriterを定義しています。 第一引数が書き出す動画のファイルネーム 第二引数が圧縮方法 第三引数がFPS 第四引数が書き出しの動画サイズ になっています。

vw.Write(img);

が呼ばれるたびに、動画の最後尾にフレームが追加されていきます。

【Unity】【C#】処理時間を計測する

環境

  • Unity 2017.2
  • VisualStudio 2015
  • Windows 10 64bit

実装

UnityにはSystem.Diagnostics.Stopwatchというクラスが用意されています。 これを使用し、時間を計測します。

今回はnamespaceをusingで呼び出した場合、Debugというクラスが重複してしまうようで、エラーが出てしまいました。 ですので以下のように記述します。

System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
sw.Start();
for(int i = 0; i < 60000; i ++){
    for(int j = 0; j < 60000; j++){
    }
}
sw.Stop();
Debug.Log(sw.ElapsedMilliseconds + "ms")

これでコンソールに処理時間が表示されます。 ElapsedMillisecondsの戻値はlongです。

【C#】古いログファイルを削除する

古いログファイルを削除していく必要があったため メモとして

今回はCreateTimeだとコピーも反応してしまうため、LastWriteTimeで比較している。

// 古いログファイルの削除
static void CheckOldLogfile()
{
    uint logLifespan = 7; //     ログの寿命(日)

    string dirPath = "./log";     // ディレクトリのパスを入力
    DirectoryInfo dyInfo = new DirectoryInfo(dirPath);
    // フォルダのファイルを取得
    var target = DateTime.Today.AddDays(-logLifespan);
    foreach(FileInfo fInfo in dyInfo.GetFiles())
    {
        // 日付の比較
        if (fInfo.LastWriteTime < target) {
            fInfo.Delete();
        }
    }
}

【C#】ショートカットから起動するとDirectoryクラスのカレントディレクトリが違う問題

概要

アプリは実行すると基本的にexeのある場所をカレントディレクトリとし実行されますが、ショートカットから実行した場合その限りではありません。 相対パスで実行するショートカットに

%windir%\explorer.exe "

を使用していると

Directory.GetCurrentDirectory()
System.Environment.CurrentDirectory    

でパスを取得すると、上記のパスになってしまいます。 これではDirectoryクラスを相対パスで使用することが出来ません。 ですのでカレントディレクトリの移動を行う必要があります。

対策

System.AppDomain.CurrentDomain.BaseDirectory

でパスを取得すると、実行ファイルのパスが取得できるみたいです。 ですのでこのパスを使用してDirectoryクラスのカレントディレクトリを移動します。

string dir = System.AppDomain.CurrentDomain.BaseDirectory;
Directory.SetCurrentDirectory(dir);

これでDirectoryクラスで相対パスが普段と同じように使用することが出来ました。