ページ 1 / 1
C++でファイル名を取得して動画を再生したい
Posted: 2017年2月09日(木) 16:03
by tinotina
動画ファイルのみがあると仮定して フォルダの一覧を取得 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;
}
Re: C++でファイル名を取得して動画を再生したい
Posted: 2017年2月09日(木) 18:46
by みけCAT
素人考えとしては、素直に
string()メンバ関数でstd::stringに変換すればよさそうな気がしますが、そんな単純な話ではないのでしょうか?
【追記】
あー、よく見たらこれはstd::experimental::filesystem::v1::path じゃなくてstd::experimental::filesystem::pathですね。
でも、
std::experimental::filesystem::v1::pathにもstring()関数はありそうですね。
tinotina さんが書きました:検索しても上手く解決策が見つかりません。
何をどのように検索しましたか?
私は「std::experimental::filesystem::v1::path」でググりました。
Re: C++でファイル名を取得して動画を再生したい
Posted: 2017年2月09日(木) 20:52
by inemaru
解決方法は、既に書かれているので環境について。
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します。
Re: C++でファイル名を取得して動画を再生したい
Posted: 2017年2月09日(木) 22:58
by Math
[雑談]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]
Re: C++でファイル名を取得して動画を再生したい
Posted: 2017年2月10日(金) 17:22
by tinotina
みけCATさま
『std::experimental::filesystem::v1::path 型を変換』で検索しました。
https://msdn.microsoft.com/ja-jp/librar ... .aspxで見たのが
『パスと文字列型の間の変換
path オブジェクトは std::wstring または std::string に暗黙的に変換できます。』
という文章でした。
おっしゃる通り 基本的には変換できるようです。 「.string」もインテリジェンスで表示されます。
大変ありがとうございました。
Re: C++でファイル名を取得して動画を再生したい
Posted: 2017年2月10日(金) 17:26
by tinotina
inumaruさま
環境を申し上げ忘れていました。
WINDOWS10
VS2015 C++
nuget OPENCV3.1
です。
VS2013 と VS2015 では 扱いが違うんですね。
filesystemは、正式リリースではない ことと併せて
すごく勉強になりました。
本当にありがとございます。
実は今日 書き足して頂く前の文章を読んだ後
不幸なことにVS2012にハマっておりました。不覚です。
opencv3base
opencvsample
のテンプレをみて テンション上がりましたが
やはり動作はしませんでした。
それから VB2015に戻って
nugetでない opencv2.4.11 opencv3.1を試したものの
それもだめでここに戻ってきたところ
書き足していただいた vs2013の記述を拝見して
今 VS2013をインストールしているところです。
でき次第、確認してみようと思います。
ありがとうございました。
Re: C++でファイル名を取得して動画を再生したい
Posted: 2017年2月10日(金) 17:27
by tinotina
Math さま
filesystemについて ご教授ありがとうございました。
あと、サンプルコードも大変感謝しております。
cout<<"ファイル名:"<<path.basename()<<endl;
このコードはオーバーロードされて表示できるんですよね・・・
filesystemを使うと コードがすごくきれいだったので
使ってみたかったんですが、私には荷が勝ちすぎたようです(汗
正式リリースの際には 使いこなせるように
スキルを磨きたいと思います。
Re: C++でファイル名を取得して動画を再生したい
Posted: 2017年2月10日(金) 17:28
by tinotina
VB歴だけは長いのですがC++は数か月前からなもので
扱うのはものすごく大変なんですが面白いです。
どうしてもOPENCVで遊んでみたくてC+++に入ってきました。
これからもどうぞよろしくお願いいたします。
Re: C++でファイル名を取得して動画を再生したい
Posted: 2017年2月11日(土) 14:56
by tinotina
動作したコードを残しておきます。
結局 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;
}
})
;
}
Re: C++でファイル名を取得して動画を再生したい
Posted: 2017年2月11日(土) 20:34
by みけCAT
tinotina さんが書きました:
結局 string b = p.filename(); はエラーが出たままでしたが
p.string() だと キャストできるんですね。
よく考えたら ファイル名じゃなくってフルパスが必要ですし。
これはこれでいいんですが .filenameがだめで .stringはキャストできる不思議さが残りました。
std::experimental::filesystem::v1::path::filename()はpathを返すので、
コード:
string b = p.filename().string();
とするとどうでしょうか?
Re: C++でファイル名を取得して動画を再生したい
Posted: 2017年2月18日(土) 13:13
by tinotina
ありがとうございます。ファイル名が帰ってきました。
...p.filename. と記述したところでインテリジェンスが働いて .以下の選択がコンテキストメニューのように表示されるようになるので
p.filename(). という表現ができるということに今まで気づきませんでした。
c++ まだまだ勉強させていただきます。ありがとうございました。