C++でファイル名を取得して動画を再生したい

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
tinotina
記事: 7
登録日時: 8年前

C++でファイル名を取得して動画を再生したい

#1

投稿記事 by tinotina » 8年前

動画ファイルのみがあると仮定して フォルダの一覧を取得 opencvで動画再生をしようと思い

http://qiita.com/episteme/items/0e3c2ee8a8c03780f01e

http://nonbiri-tereka.hatenablog.com/en ... /15/094559
で得た サンプルコードを繋いでみました。

ところが
string a = p.filename(); でエラーが発生します。

エラーメッセージを読むと
"std::experimental::filesystem::v1::path" から "std::string" へ変換ができないそうなのですが
検索しても上手く解決策が見つかりません。

どう変換したらいいのか、あるいはどのように修正したらいいのかを
お教え頂けたら幸いです。

どうぞよろしくお願いいたします。

コード:

#include <iostream>
#include <algorithm>
#include <filesystem>

#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>

using namespace std;
using namespace cv;

//http://qiita.com/episteme/items/0e3c2ee8a8c03780f01e

int main() 
{
	namespace sys = std::tr2::sys;
	sys::path p("."); // 列挙の起点 
	
	std::for_each(sys::directory_iterator(p), sys::directory_iterator(),
		//  再帰的に走査するならコチラ↓
		//  std::for_each(sys::recursive_directory_iterator(p), sys::recursive_directory_iterator(),
		[](const sys::path& p) {
		if (sys::is_regular_file(p)) { // ファイルなら...

			//http://nonbiri-tereka.hatenablog.com/entry/2014/04/15/094559
			
			string a = p.filename();

			cout << "file: " << p.filename() << endl;

			//動画の読み込み
			VideoCapture video(a);

			//動画を再生する。
			namedWindow("hoge");
			while (1) {
				Mat frame;
				video >> frame;
				//フレームが空か、ボタンが押された時か一周したときに出る。
				if (frame.empty() || waitKey(30) >= 0 || video.get(CV_CAP_PROP_POS_AVI_RATIO) == 1) {
					break;
				}
				imshow("hoge", frame);
			}
		}
		else if (sys::is_directory(p)) { // ディレクトリなら...
			cout << "dir.: " << p.string() << endl;
		}
	});

	cv::destroyAllWindows();
	return 0;
}

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: C++でファイル名を取得して動画を再生したい

#2

投稿記事 by みけCAT » 8年前

素人考えとしては、素直にstring()メンバ関数でstd::stringに変換すればよさそうな気がしますが、そんな単純な話ではないのでしょうか?

【追記】
あー、よく見たらこれはstd::experimental::filesystem::v1::path じゃなくてstd::experimental::filesystem::pathですね。
でも、std::experimental::filesystem::v1::pathにもstring()関数はありそうですね。
tinotina さんが書きました:検索しても上手く解決策が見つかりません。
何をどのように検索しましたか?
私は「std::experimental::filesystem::v1::path」でググりました。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

inemaru
記事: 108
登録日時: 9年前

Re: C++でファイル名を取得して動画を再生したい

#3

投稿記事 by inemaru » 8年前

解決方法は、既に書かれているので環境について。
VS2013環境では、該当箇所でエラーしないので環境依存の問題の様です。
開発環境は、明記した方がよさそうです。

環境:VS2013

コード:

// VS2013だと filename() はstring型
string a = p.filename();
環境:VS2015

コード:

// VS2015だと filename() はpath型 → エラー
string a = p.filename();
filesystemは、正式リリースではないので
使用する際は、仕様変更されることを考慮した方が良いです。
https://msdn.microsoft.com/ja-jp/library/hh874694.aspx
Visual Studio 2015 のリリース以降、ヘッダーが、まだ C++ 標準。 Visual C 2015 には、標準の最終的な下書きが実装されているが、記載ISO/IEC JTC SC 1/22/WG 21 N4100します。

Math

Re: C++でファイル名を取得して動画を再生したい

#4

投稿記事 by Math » 8年前

[雑談]2017年中に改訂される予定のC++14の次のバージョン、仮称C++1zの話のようですね。
正式名称はISO/IEC 14882:2017、通称C++17になる予定の様です。

C++11がメジャーアップデート、C++14がC++11に対するバグ修正&マイナーアップデートというもので、C++17は、C++14に対するメジャーアップデートになる様です。

MSDNhttps://msdn.microsoft.com/ja-jp/library/dn986850.aspxにVisual Studio 2017 RC の最新のドキュメントの詳細については、Visual Studio 2017 RC ドキュメントをご参照ください。
とあって
”<filesystem> ヘッダーは、ドラフトの File System Technical Specification (ISO/IEC JTC 1/SC 22/WG 21 N4100) を実装し、型および関数により、ファイル システムを移動するためのプラットフォームに依存しないコードを記述できます。 それはクロス プラットフォームなので、Windows システムに関連しない API が含まれます。 たとえば、Windows では is_fifo(const path&) は常に false を返します。 ヘッダーは、Visual Studio 2015 RTM の段階で C++17 標準には認められていないドラフトの技術仕様に基づいています。 そのメンバーは std::experimental::filesystem::v1 名前空間にあります。”と書いてあります。

C++17情報:
策定体制として、Study Group (SG)と呼ばれる専門家グループがたくさん作られ、そこで同時並行に議論、策定が進められていた仕様のうち、固まったものがいくつかC++1zで導入されます。

それぞれの専門家グループで考えられた仕様はTechnical Specification (TS)という単位で個別に各国の承認をとっており、コンパイラでもstd::exprerimental名前空間以下などで実験的に実装されていました。C++1zでは専門家グループで進められた仕様のうち、以下のものが入ります:
•Library Fundamentals TS (基本的なライブラリ機能) •any, optional, string_view, メモリプール, 検索アルゴリズム, サンプリングアルゴリズム, タプルを展開して関数呼び出しするapply関数, shared_ptrの配列対応, 最大公約数と最小公倍数など

•Filesystem TS (ファイルシステムのライブラリ)
•Parallelism TS (並列ライブラリ) •並列アルゴリズム

C++1zでは間に合わないですが、継続して議論が進められているTSもまだまだあり、このあと仕様が固まったものは、C++1zの次のバージョンC++2x (2020年、C++20予定) に入る予定です。そのなかには、コンセプト、モジュールシステム、トランザクショナルメモリ、並行コンテナ、コルーチン、ネットワークなどがあります。

TS以外の機能としても、多くの便利な機能が入ります。構造化束縛やif constexpr文などは、とくに便利ですね。

それとこのサンプルをVC++2015でテストして見ました。

コード:

//・tr2::sys::path path("ファイルパス文字列");

//・と、tr2::sys::path クラスで初期化した時点で細かく分割してくれるようだ。
//・ 実験してみたところ、tr2::sys::pathには色々な関数があって、中には一見機能がかぶっているように見えるものもある。
//・ちょっと色々出力してみた。
//・その前にまとめると
//
//
//・ディレクトリの取得-parent_path() あるいは branch_path()
//・ファイル名の取得---basename()
//・拡張子の取得-------extenstion()
//・ドライブ名---------root_path()…rootと名のついたものはドライブ名のようだ。
//
//
#include <iostream>
#include <filesystem>//tr2::sys::pathに必要
using namespace std;

int main(){
    string filename="F:/SecondYear/VCproject/cloud/raw-format/data/cloud-velocity.exe";
    tr2::sys::path path(filename);
    cout<<"ドライブ名(root_path):"<<path.root_path()<<endl;
//    cout<<"ディレクトリ:"<<path.directory_string()<<endl;
//    cout<<"ファイル名:"<<path.basename()<<endl;
    cout<<"filename"<<path.filename()<<endl;
//    cout<<"file_string:"<<path.file_string()<<endl;
    cout<<"拡張子:"<<path.extension()<<endl;
    cout<<"root_name:"<<path.root_name()<<endl;
    cout<<"root_directory:"<<path.root_directory()<<endl;
    cout<<"フルパス:"<<path.string()<<endl;
 
    return 0;
}
//-----------------------------------------------------------------------------
/*
出力結果 
ドライブ名(root_path):F:/
...
拡張子:.exe
root_name:F:
root_directory:/
フルパス:F:/SecondYear/VCproject/cloud/raw-format/data/cloud-velocity.exe
...
*/
[/size]

tinotina
記事: 7
登録日時: 8年前

Re: C++でファイル名を取得して動画を再生したい

#5

投稿記事 by tinotina » 8年前

みけCATさま

『std::experimental::filesystem::v1::path 型を変換』で検索しました。

https://msdn.microsoft.com/ja-jp/librar ... .aspxで見たのが

『パスと文字列型の間の変換
path オブジェクトは std::wstring または std::string に暗黙的に変換できます。』

という文章でした。

おっしゃる通り 基本的には変換できるようです。 「.string」もインテリジェンスで表示されます。

大変ありがとうございました。

tinotina
記事: 7
登録日時: 8年前

Re: C++でファイル名を取得して動画を再生したい

#6

投稿記事 by tinotina » 8年前

inumaruさま

環境を申し上げ忘れていました。
WINDOWS10
VS2015 C++
nuget OPENCV3.1
です。

VS2013 と VS2015 では 扱いが違うんですね。
filesystemは、正式リリースではない ことと併せて
すごく勉強になりました。
本当にありがとございます。

実は今日 書き足して頂く前の文章を読んだ後
不幸なことにVS2012にハマっておりました。不覚です。
opencv3base
opencvsample
のテンプレをみて テンション上がりましたが
やはり動作はしませんでした。

それから VB2015に戻って
nugetでない opencv2.4.11 opencv3.1を試したものの
それもだめでここに戻ってきたところ
書き足していただいた vs2013の記述を拝見して
今 VS2013をインストールしているところです。

でき次第、確認してみようと思います。

ありがとうございました。

tinotina
記事: 7
登録日時: 8年前

Re: C++でファイル名を取得して動画を再生したい

#7

投稿記事 by tinotina » 8年前

Math さま

filesystemについて ご教授ありがとうございました。
あと、サンプルコードも大変感謝しております。

cout<<"ファイル名:"<<path.basename()<<endl;
このコードはオーバーロードされて表示できるんですよね・・・

filesystemを使うと コードがすごくきれいだったので
使ってみたかったんですが、私には荷が勝ちすぎたようです(汗

正式リリースの際には 使いこなせるように
スキルを磨きたいと思います。

tinotina
記事: 7
登録日時: 8年前

Re: C++でファイル名を取得して動画を再生したい

#8

投稿記事 by tinotina » 8年前

VB歴だけは長いのですがC++は数か月前からなもので
扱うのはものすごく大変なんですが面白いです。
どうしてもOPENCVで遊んでみたくてC+++に入ってきました。

これからもどうぞよろしくお願いいたします。

tinotina
記事: 7
登録日時: 8年前

Re: C++でファイル名を取得して動画を再生したい

#9

投稿記事 by tinotina » 8年前

動作したコードを残しておきます。

結局 string b = p.filename(); はエラーが出たままでしたが
p.string() だと キャストできるんですね。

よく考えたら ファイル名じゃなくってフルパスが必要ですし。
これはこれでいいんですが .filenameがだめで .stringはキャストできる不思議さが残りました。

最終的には 動画再生部分をサブルーチンにしました。


コード:

#include <algorithm>
#include <filesystem>

#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>

using namespace std;
using namespace cv;

//http://qiita.com/episteme/items/0e3c2ee8a8c03780f01e

string aviname;

void movie()
{
	//動画の読み込み
	VideoCapture video(aviname);

	//動画を再生する。
	namedWindow("hoge");
	while (1) {
		Mat frame;
		video >> frame;
		//フレームが空か、ボタンが押された時か一周したときに出る。
		if (frame.empty() || waitKey(30) >= 0 || video.get(CV_CAP_PROP_POS_AVI_RATIO) == 1) {
			break;
		}
		imshow("hoge", frame);
	}
}

int main()
{
	namespace sys = std::tr2::sys;
	//sys::path p("."); // 列挙の起点 
	sys::path p("P:\DRV"); // 列挙の起点

	int i = 0, j = 0;
	std::for_each(sys::directory_iterator(p), sys::directory_iterator(),
		//  再帰的に走査するならコチラ↓
		//  std::for_each(sys::recursive_directory_iterator(p), sys::recursive_directory_iterator(),
		[](const sys::path& p) {
		if (sys::is_regular_file(p)) { // ファイルなら...

									   //http://nonbiri-tereka.hatenablog.com/entry/2014/04/15/094559

			/*string a = p.filename.string();*/

//			cout << "file: " << p.string() << endl;

			cout << "file: " << p.string() << endl;

			//string b = p.filename();
			//重大度レベル	コード	説明	プロジェクト	ファイル	行	抑制状態
			//	エラー(アクティブ)		"std::experimental::filesystem::v1::path" から "std::string" への適切なユーザー定義変換が存在しません	SrchDir2	c : \temp\c++\SrchDir2\Source.cpp	40

			//重大度レベル	コード	説明	プロジェクト	ファイル	行	抑制状態
			//	エラー	C2440	'初期化中': 'std::experimental::filesystem::v1::path' から 'std::basic_string<char,std::char_traits<char>,std::allocator<char>>' に変換できません。	SrchDir2	c : \temp\c++\srchdir2\source.cpp	40

			aviname = p.string();
			movie();
			;
		}
		else if (sys::is_directory(p)) { // ディレクトリなら...
			cout << "dir.: " << p.string() << endl;
		}
	})
		;
}



アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: C++でファイル名を取得して動画を再生したい

#10

投稿記事 by みけCAT » 8年前

tinotina さんが書きました: 結局 string b = p.filename(); はエラーが出たままでしたが
p.string() だと キャストできるんですね。

よく考えたら ファイル名じゃなくってフルパスが必要ですし。
これはこれでいいんですが .filenameがだめで .stringはキャストできる不思議さが残りました。
std::experimental::filesystem::v1::path::filename()はpathを返すので、

コード:

string b = p.filename().string();
とするとどうでしょうか?
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

tinotina
記事: 7
登録日時: 8年前

Re: C++でファイル名を取得して動画を再生したい

#11

投稿記事 by tinotina » 8年前

ありがとうございます。ファイル名が帰ってきました。

 ...p.filename. と記述したところでインテリジェンスが働いて .以下の選択がコンテキストメニューのように表示されるようになるので
p.filename(). という表現ができるということに今まで気づきませんでした。

c++ まだまだ勉強させていただきます。ありがとうございました。

閉鎖

“C言語何でも質問掲示板” へ戻る