Garmin FITファイルをCSVに変換するツール

 Garminのフィットネスデータ(ランニングやサイクリング)のFIT形式のファイルをCSVに変換するツールを公開します。CSVに変換すれば手持ちのソフトで分析したり、動画に合成することが可能です。是非以下からダウンロードして使ってください。インストールはファイルを解凍後、好きなフォルダにコピーしてください。実行するとファイルを聞かれますので、FITファイルを選んでください。その後にCSVファイル出力先を選べばファイルが作成されます。

http://tool.toyokawa.jp/software/fitCSVW.zip


CSVは左から、タイムスタンプ、速度、高度、斜度、心拍、ケイデンス、距離、パワーと並んでいます。パワーに関してはパワーメーターを所有していないので動作確認は出来ていません。 動画にサイコン情報を重ねるなどの処理の助けになれば良いと考えています。

C++でAVIを出力する実験 60fps 簡易アニメーション

 C++でAVIを出力する実験をしています。無圧縮なので高解像度の本編では使えないですが、動画内のアクセントとなるアニメーションや特殊効果程度なら応用例があると考えます。WindowsのGDIでグラフなどを描画するスキルが有ればそれをそのまま動画制作に応用可能です。以下のソースはG++でコンパイルできます。(Windows APIを使ってるので残念ながらWindows専用です。)



  1. #define _UNICODE    //ワイド文字列 (Unicode) 対応
  2. #include <windows.h>
  3. #include <vfw.h>
  4. #include <sstream>
  5. #include <string>
  6. /********************************************************************
  7. 実行すると100までカウントアップするAVI動画を作成します。以下のコマンドラインでビルドしてください。
  8. g++ .\avisample001.cpp -mwindows -lvfw32 -municode -o avisample001
  9. *********************************************************************/
  10. int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hinstPrev, LPWSTR lpszCmdLine, int nCmdShow)
  11. {
  12.     const int width = 640; //画面サイズフレームレートなどを設定
  13.     const int height = 560;
  14.     const int fps = 60;
  15.     const int frames = 1200;
  16.     
  17.     PAVIFILE pfile;
  18.     PAVISTREAM pavi;
  19.     AVISTREAMINFO si;
  20.     LPAVISTREAMINFO lpsi = &si;
  21.     LPVOID lpBits;
  22.     BITMAPINFOHEADER bmiHeader;    
  23.     
  24.     AVIFileInit();
  25.     if (AVIFileOpen(&pfile, L"video.avi", OF_CREATE | OF_WRITE, NULL) != 0) {
  26.         MessageBox(NULL, L"Fail file open.", L"OK", MB_OK);
  27.         AVIFileExit();
  28.         return 0;}
  29.     ZeroMemory(&si, sizeof(AVISTREAMINFO));
  30.     si.fccType = streamtypeVIDEO;
  31.     si.fccHandler = comptypeDIB;
  32.     si.dwScale = 1;
  33.     si.dwRate = fps;
  34.     si.dwLength = 0;
  35.     si.dwQuality = (DWORD)-1;
  36.     SetRect(&si.rcFrame, 0, 0, width, height);
  37.     if (AVIFileCreateStream(pfile, &pavi, &si) != 0) {
  38.         MessageBox(NULL, TEXT("Fail open stream."), TEXT("OK"), MB_OK);
  39.         AVIFileRelease(pfile);
  40.         AVIFileExit();
  41.         return 0;}
  42.     ZeroMemory(&bmiHeader, sizeof(BITMAPINFOHEADER));
  43.     bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  44.     bmiHeader.biWidth = lpsi->rcFrame.right;
  45.     bmiHeader.biHeight = lpsi->rcFrame.bottom;
  46.     bmiHeader.biPlanes = 1;
  47.     bmiHeader.biBitCount = 24;
  48.     bmiHeader.biCompression = BI_RGB;
  49.     bmiHeader.biSizeImage = bmiHeader.biHeight * ((3 * bmiHeader.biWidth + 3) / 4) * 4;
  50.     AVIStreamSetFormat(pavi, 0, &bmiHeader, sizeof(BITMAPINFOHEADER));
  51.     //ここにHDCへ描画し、AVIStreamWriteを呼び出し一コマ書き出す。これを繰り返す。
  52.     HDC hdc = CreateCompatibleDC(NULL);
  53.     HBITMAP hbmpMem = CreateDIBSection(NULL, (LPBITMAPINFO)&bmiHeader, DIB_RGB_COLORS, &lpBits, NULL, 0);
  54.     HBITMAP hbmpMemPrev = (HBITMAP)SelectObject(hdc, hbmpMem);
  55.     
  56.     SetTextColor(hdc, RGB(255, 255, 255));
  57.     HGDIOBJ hFont = CreateFontW(100, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_OUTLINE_PRECIS,
  58.         CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"UI Gothic");
  59.     HGDIOBJ hFontOld = SelectObject(hdc, hFont);
  60.     
  61.     HBRUSH hBrush = CreateSolidBrush(RGB(255, 255, 255));
  62.     HBRUSH hPrevBrush =(HBRUSH)SelectObject(hdc,hBrush);
  63.     
  64.     SetBkMode(hdc, TRANSPARENT);
  65.     
  66.     bool isTop = true; //裏表フラグ
  67.     for (int fCnt = 0; fCnt < frames; fCnt++) {
  68.         FillRect(hdc, &lpsi->rcFrame, (HBRUSH)GetStockObject(BLACK_BRUSH)); //背景を黒で塗る
  69.         
  70.         std::wstringstream wss;
  71.         wss << fCnt;
  72.         std::wstring buf = wss.str();
  73.         const int size = width < height?width:height; //高さと幅の短い方を選ぶ
  74.         const int c_width = size/10; //円の幅を調整
  75.         const int div = 59; //円を分割する数
  76.         const float step = (float)360 / div; //分割された度数
  77.         const float seg = step / 2; //空白部と実部の割合(数字が大きいほど実部が減る)
  78.         const int c_x = width / 2; //円の中心座標
  79.         const int c_y = height /2;
  80.         const int radius = size / 2 - size / 20; //余白
  81.         const int l_begin = isTop?0:fCnt%(div+1);
  82.         const int l_end = isTop?fCnt%(div+1):div;
  83.         for (int j = l_begin;j<l_end;j++){
  84.             BeginPath(hdc);
  85.             AngleArc(hdc,c_x,c_y,radius,step*j,0);
  86.             EndPath(hdc);    
  87.             BeginPath(hdc);
  88.             AngleArc(hdc,c_x,c_y,radius,step*j,seg);
  89.             AngleArc(hdc,c_x,c_y,radius-c_width,step*j+seg,-seg);
  90.             CloseFigure(hdc);
  91.             EndPath(hdc);    
  92.             FillPath(hdc);
  93.         }
  94.         
  95.         DrawText(hdc, buf.c_str(), -1, &lpsi->rcFrame, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  96.         AVIStreamWrite(pavi, fCnt, 1, lpBits, bmiHeader.biSizeImage, AVIIF_KEYFRAME, NULL, NULL); //一コマ書き出し
  97.         
  98.         if(fCnt%(div+1) == div){
  99.             isTop = !isTop; //裏表逆転
  100.         }
  101.     }
  102.     
  103.     
  104.     SelectObject(hdc,hPrevBrush);
  105.     DeleteObject(hBrush);
  106.     SelectObject(hdc, hFontOld);
  107.     DeleteObject(hFont);
  108.     SelectObject(hdc, hbmpMemPrev);
  109.     DeleteObject(hbmpMem);
  110.     DeleteDC(hdc);
  111.     AVIStreamRelease(pavi);
  112.     AVIFileRelease(pfile);
  113.     AVIFileExit();
  114.     MessageBox(NULL, L"Done.", L"OK", MB_OK);
  115.     return 0;
  116. }

簡易アニメをAVI出力するコード C++ でAVI出力

 C++で作成する簡易アニメをAVI出力するコードです。G++でビルドできます。WindowsのAPIを使っているのでWindows専用だと考えます。既にGDIで出力できるスキルが有れば簡単にAVI形式でアニメ(動画)を出力できます。実験結果を簡易的にCGにするなどの目的に使えそうです。 以下のコードをUTF-8で保存してコンパイルしてください。サンプルコードでは320x240ですが、ストレステストとしてFullHD(1920x1080)や4Kでの出力もテストしています。8Kも出力しましたが再生環境が無いので出力確認は出来ていません。




  1. #define _UNICODE    //ワイド文字列 (Unicode) 対応
  2. #include <windows.h>
  3. #include <vfw.h>
  4. #include <sstream>
  5. #include <string>
  6. /********************************************************************
  7. 実行すると100までカウントアップするAVI動画を作成します。以下のコマンドラインでビルドしてください。
  8. g++ .\avisample001.cpp -mwindows -lvfw32 -municode -o avisample001
  9. *********************************************************************/
  10. int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hinstPrev, LPWSTR lpszCmdLine, int nCmdShow)
  11. {
  12.     const int width = 320; //画面サイズフレームレートなどを設定
  13.     const int height = 240;
  14.     const int fps = 2;
  15.     
  16.     PAVIFILE pfile;
  17.     PAVISTREAM pavi;
  18.     AVISTREAMINFO si;
  19.     LPAVISTREAMINFO lpsi = &si;
  20.     LPVOID lpBits;
  21.     BITMAPINFOHEADER bmiHeader;    
  22.     
  23.     AVIFileInit();
  24.     if (AVIFileOpen(&pfile, L"video.avi", OF_CREATE | OF_WRITE, NULL) != 0) {
  25.         MessageBox(NULL, L"Fail file open.", L"OK", MB_OK);
  26.         AVIFileExit();
  27.         return 0;}
  28.     ZeroMemory(&si, sizeof(AVISTREAMINFO));
  29.     si.fccType = streamtypeVIDEO;
  30.     si.fccHandler = comptypeDIB;
  31.     si.dwScale = 1;
  32.     si.dwRate = fps;
  33.     si.dwLength = 0;
  34.     si.dwQuality = (DWORD)-1;
  35.     SetRect(&si.rcFrame, 0, 0, width, height);
  36.     if (AVIFileCreateStream(pfile, &pavi, &si) != 0) {
  37.         MessageBox(NULL, TEXT("Fail open stream."), TEXT("OK"), MB_OK);
  38.         AVIFileRelease(pfile);
  39.         AVIFileExit();
  40.         return 0;}
  41.     ZeroMemory(&bmiHeader, sizeof(BITMAPINFOHEADER));
  42.     bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  43.     bmiHeader.biWidth = lpsi->rcFrame.right;
  44.     bmiHeader.biHeight = lpsi->rcFrame.bottom;
  45.     bmiHeader.biPlanes = 1;
  46.     bmiHeader.biBitCount = 24;
  47.     bmiHeader.biCompression = BI_RGB;
  48.     bmiHeader.biSizeImage = bmiHeader.biHeight * ((3 * bmiHeader.biWidth + 3) / 4) * 4;
  49.     AVIStreamSetFormat(pavi, 0, &bmiHeader, sizeof(BITMAPINFOHEADER));
  50.     //ここにHDCへ描画し、AVIStreamWriteを呼び出し一コマ書き出す。これを繰り返す。
  51.     HDC hdc = CreateCompatibleDC(NULL);
  52.     HBITMAP hbmpMem = CreateDIBSection(NULL, (LPBITMAPINFO)&bmiHeader, DIB_RGB_COLORS, &lpBits, NULL, 0);
  53.     HBITMAP hbmpMemPrev = (HBITMAP)SelectObject(hdc, hbmpMem);
  54.     
  55.     SetTextColor(hdc, RGB(255, 255, 255));
  56.     HGDIOBJ hFont = CreateFontW(100, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_OUTLINE_PRECIS,
  57.         CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"UI Gothic");
  58.     HGDIOBJ hFontOld = SelectObject(hdc, hFont);
  59.     
  60.     HBRUSH hBrush = CreateSolidBrush(RGB(255, 255, 255));
  61.     HBRUSH hPrevBrush =(HBRUSH)SelectObject(hdc,hBrush);
  62.     
  63.     SetBkMode(hdc, TRANSPARENT);
  64.     for (int fCnt = 0; fCnt < 100; fCnt++) {
  65.         FillRect(hdc, &lpsi->rcFrame, (HBRUSH)GetStockObject(BLACK_BRUSH)); //背景を黒で塗る
  66.         
  67.         std::wstringstream wss;
  68.         wss << fCnt;
  69.         std::wstring buf = wss.str();
  70.         const int c_width = 30;
  71.         const int div = 8;
  72.         const int step = 360 / div;
  73.         const int seg = step / 2;
  74.         BeginPath(hdc);
  75.         AngleArc(hdc,width/2,height/2,height/2-20,0,0);
  76.         EndPath(hdc);        
  77.         
  78.         for (int j = 0;j<fCnt%(div+1);j++){ //区切りの数+1がアニメのコマ数になる
  79.             BeginPath(hdc);
  80.             AngleArc(hdc,width/2,height/2,height/2-20,step*j,0);
  81.             EndPath(hdc);    
  82.             BeginPath(hdc);
  83.             AngleArc(hdc,width/2,height/2,height/2-20,step*j,seg);
  84.             AngleArc(hdc,width/2,height/2,height/2-20-c_width,step*j+seg,-seg);
  85.             CloseFigure(hdc);
  86.             EndPath(hdc);    
  87.             FillPath(hdc);
  88.         }
  89.         
  90.         DrawText(hdc, buf.c_str(), -1, &lpsi->rcFrame, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  91.         AVIStreamWrite(pavi, fCnt, 1, lpBits, bmiHeader.biSizeImage, AVIIF_KEYFRAME, NULL, NULL); //一コマ書き出し
  92.     }
  93.     
  94.     
  95.     SelectObject(hdc,hPrevBrush);
  96.     DeleteObject(hBrush);
  97.     SelectObject(hdc, hFontOld);
  98.     DeleteObject(hFont);
  99.     SelectObject(hdc, hbmpMemPrev);
  100.     DeleteObject(hbmpMem);
  101.     DeleteDC(hdc);
  102.     AVIStreamRelease(pavi);
  103.     AVIFileRelease(pfile);
  104.     AVIFileExit();
  105.     MessageBox(NULL, L"Done.", L"OK", MB_OK);
  106.     return 0;
  107. }


簡単に手持ちのC,C++の処理に進捗バーを実装する方法

 C言語やC++で何か処理を書ける人は多いですが、Windowプログラムとなると実装方法が難しいです。VisualStudioのプロジェクトの雛形にボタンを配置し、そこから手持ちのコードを起動すれば動きそうです。

しかし、その方法では「未応答」状態になったり、ウィンドウの操作すらできなくなります。もちろん処理が終われば正常に動きはしますが、見た目は悪いです。

進捗バーを表示しようと配置しても、当然それを動かすためのコードも必要です。

メッセージループを処理しながら、自前のコードを動かしたり、「状態機械」にコードを移植した後でメッセージループに組み込むなど方法はありますが、非常に可読性が悪くなります。

今回は、スレッドを一本発行することで手持ちのコードを動作させます。完全に無改造では動かないですが、手持ちの関数に2つの処理を埋め込むだけで対応できます。

1つ目は進捗バーに状態を知らせるためのグローバル変数を更新することです。処理に応じて増分させた数値を定期的に書き込んでください。

2つ目は強制終了フラグを監視し、検出したら処理ループを安全に停止させる処理を行うことです。外部からスレッドを停止させる方法は、処理中のファイルやリソースのクローズがされないので問題があります。 強制終了フラグを検知したら、区切りの良い場所まで処理して、その後クロージング処理などが出来ます。

このように簡単に手持ちのC,C++コードを今風に作り上げることが出来ます。個人的に、仕事で変換プログラムなどを持っている人はリニューアルしてみてください。

AmazonでC++関連の書籍を買います

  1. /*******************************************************
  2. G++ .\progress2.cpp -mwindows -lvfw32 -municode -o progress2 でコンパイルしてください。
  3. 手持ちのC言語やC++で作成した時間がかかる変換プログラムも簡単にウィンドウアプリに出来ます。
  4. Tiktok @pistalove 好きなことをやらない人生は最高 も御覧ください。
  5. ********************************************************/
  6. #include <windows.h>
  7. #include <commctrl.h>
  8. HWND hWnd; //メインウィンドウハンドル
  9. HWND hProgress; //進捗表示用ハンドル
  10. HWND hButton; //ボタン表示用ハンドル
  11. HWND hText; //文字表示用ハンドル
  12. int iProgress = 0; //進捗状態
  13. int bAbort = false; //強制終了フラグ
  14. /******************************************
  15. ここに時間がかかる手持ちのコードを書きます。仕様は
  16. ・bAbortがtrueになったら親ウィンドウの停止ボタンが押されています。安全に処理を終了してください。
  17. ・iProgressに進捗状況をパーセントで書き込んでください。進捗バーが動きます。
  18. ・処理が完全に終了したら SendMessageで親ウィンドウを閉じてください。
  19. ・手持ちのGUIに対応していないプログラムをコピペすれば進捗バーと停止ボタンが付いて見た目が良いです。
  20. ********************************************/
  21. DWORD WINAPI MyThreadFunction( LPVOID lpParam ){
  22.      for (int i = 0; i <= 100; ++i) {
  23.             
  24.                 if(bAbort) break; //強制終了指示が出たら終了する
  25.                 iProgress = i;
  26.                  Sleep(500); //試験的に待っています。
  27.             }
  28.  
  29.     SendMessage(hWnd, WM_DESTROY, 0, 0);
  30.     return 0;
  31. }
  32. //以下のコードは基本的にそのままで動きます。表示される文字やウィンドウの体裁だけ整えてください。
  33. //ウィンドウプロシージャ
  34. LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
  35.     switch (message) {
  36.     case WM_CREATE:
  37.         // プログレスバーの作成
  38.         hProgress = CreateWindowEx(0, PROGRESS_CLASS, NULL,WS_CHILD | WS_VISIBLE | PBS_SMOOTH,10,40,280,10,hWnd,NULL,NULL,NULL);
  39.         SendMessage(hProgress, PBM_SETRANGE, 0, MAKELPARAM(0, 100));
  40.         SendMessage(hProgress, PBM_SETSTEP, 1, 0);
  41.         hText = CreateWindowEx(0,L"STATIC",
  42.                 L"Tiktok @pistalove", // 表示するテキスト
  43.                 WS_VISIBLE | WS_CHILD | SS_CENTER,10, 10,280, 20,hWnd,NULL,NULL,NULL);
  44.     hButton = CreateWindow(L"BUTTON",L"停止",WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,230,55,60,30,hWnd,(HMENU)1,NULL,NULL);
  45.     
  46.     SetTimer(hWnd, 1, 100, NULL);//進捗画面更新用タイマー設定100ミリ秒に一回
  47.         CreateThread(NULL, 0, MyThreadFunction, NULL, 0, NULL); //手持ちのコードの関数が実行されます。
  48.         return 0;
  49.     case WM_COMMAND:
  50.         if (LOWORD(wParam) == 1) { //ボタンクリック
  51.             bAbort = true; //停止フラグを設定
  52.         }
  53.         return 0;
  54.     case WM_TIMER:
  55.     SendMessage(hProgress, PBM_SETPOS, iProgress, 0);
  56.     
  57.     return 0;
  58.     
  59.     case WM_CLOSE:
  60.      return 0;
  61.     
  62.     case WM_DESTROY:
  63.      KillTimer(hWnd, 1);
  64.         PostQuitMessage(0);
  65.         return 0;
  66.     default:
  67.         return DefWindowProc(hWnd, message, wParam, lParam);
  68.     }
  69. }
  70. int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hinstPrev, LPWSTR lpCmdLine, int nCmdShow){
  71.     WNDCLASS wc = {};
  72.     wc.lpfnWndProc = WindowProc;
  73.     wc.hInstance = hInstance;
  74.     wc.lpszClassName = L"ProgressDemo";
  75.     
  76.     RegisterClass(&wc);
  77.     
  78.     hWnd = CreateWindowEx(0, L"ProgressDemo", L"Tiktok @Pistalove",    WS_OVERLAPPEDWINDOW ^ (WS_THICKFRAME|WS_MAXIMIZEBOX) | WS_VISIBLE,CW_USEDEFAULT, CW_USEDEFAULT, 320, 200, NULL,NULL,hInstance, NULL);
  79.     
  80.     MSG msg;
  81.     while (GetMessage(&msg, NULL, 0, 0)) {
  82.         TranslateMessage(&msg);
  83.         DispatchMessage(&msg);
  84.     }
  85.     return 0;
  86. }

劇遅 メモリ交換だけで古いセレロンパソコンを使えるレベルにアップグレード esprimo FH52/W 2950M SP016GLSTU160N22

Amazonでメモリを購入します ウチにある古いパソコンの富士通ESPRIMO FH52/W が酷く遅くなりました。OSの起動も遅く、アプリの起動も遅いです。さらにブラウザや事務ソフト程度の軽いソフトも突然固まります。30秒くらい待っていればまた使えるようになりますがストレスはあ...