OpenCV USBカメラをキャプチャして動画を作成する(C++)
C++でUSBカラメをキャプチャしてAVIを作成する。
OpenCV 3.4.1
#include <opencv2/opencv.hpp> int main() { using std::cout; using std::endl; int camera_id = 0; double fps = 30.0; double width = 640.0; double height = 480.0; // DirectShowでキャプチャ cv::VideoCapture cap(cv::CAP_DSHOW + camera_id); if (!cap.isOpened()) { cout << "camera open error" << endl; return; } if (!cap.set(cv::CAP_PROP_FPS, fps)) cout << "camera set fps error" << endl; if (!cap.set(cv::CAP_PROP_FRAME_WIDTH, width)) cout << "camera set width error" << endl; if (!cap.set(cv::CAP_PROP_FRAME_HEIGHT, height)) cout << "camera set height error" << endl; // モーションJPEGで保存する int fourcc = cv::VideoWriter::fourcc('M', 'J', 'P', 'G'); bool isColor = true; cv::VideoWriter writer("test.avi", fourcc, fps, cv::Size(width, height), isColor); cv::namedWindow("framewin", CV_WINDOW_AUTOSIZE | CV_WINDOW_FREERATIO); cv::Mat frame; std::vector<uchar> jpeg_buff; std::vector<int> param(2); param[0] = CV_IMWRITE_JPEG_QUALITY; param[1] = 95; while (true) { // 1フレームキャプチャする cap >> frame; if (frame.empty()) break; // 水平反転 cv::flip(frame, frame, 1); // JPEG変換 // libjpeg-turboを使っているので(不要?) cv::imencode(".jpg", frame, jpeg_buff, param); cv::Mat jpeg_image = cv::imdecode(cv::Mat(jpeg_buff), CV_LOAD_IMAGE_COLOR); // AVIに書き込み writer << jpeg_image; cv::imshow("framewin", jpeg_image); if (cv::waitKey(1) >= 0) break; } cap.release(); writer.release(); cv::destroyAllWindows(); return 0; }
C++/CLIでString^(UTF-16)とchar*(UTF-8)の相互変換を調べたのでメモ。
久し振りに仕事でちょっとしたフレームワーク作ってます。
昔を思い出すこの感じ。嫌いじゃないです。
※Shift-JISは一切考慮してません
#include "msclr/marshal.h" #include "msclr/marshal_windows.h" #include "msclr/marshal_cppstd.h" #include "msclr/marshal_atl.h" #include <cstdint> #include <iostream> #include <string> // string, wstring #include <codecvt> // wstring_convert, codecvt_utf8_utf16 #include <memory> using namespace System; namespace convutil { inline std::wstring utf8_to_utf16(const std::string& from) { std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> conv; return conv.from_bytes(from); } std::string utf16_to_utf8(const std::wstring& from) { std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> conv; return conv.to_bytes(from); } inline String^ ToCliString(const std::string& from) { return msclr::interop::marshal_as<String^>(utf8_to_utf16(from)); } inline String^ ToCliString(const char* from) { return msclr::interop::marshal_as<String^>(utf8_to_utf16(from)); } inline std::string ToStlString(String^ from) { return msclr::interop::marshal_as<std::string>(from); } template<size_t toSize> inline const char* ToCharArray(String^ from, char(&to)[toSize]) { auto context = gcnew msclr::interop::marshal_context(); try { // 一度 std::wstring に変換してから std::string(utf-8)に変換 // ムダがあるような気もする auto temp = context->marshal_as<std::wstring>(from); auto temp2 = utf16_to_utf8(temp); strncpy_s(to, toSize, temp2.c_str(), _TRUNCATE); return to; } finally{ // 確実に削除。ぶっちゃけ例外でない気がするのでムダtryかも。 delete context; } } } // namespace convutil // Native struct Employee { int32_t id; char name[64]; char address[256]; }; // Managed ref struct ST_Employee { Int32 id; String^ name; String^ address; }; namespace msclr { namespace interop { // Native → Managed 変換 template<> inline ST_Employee^ marshal_as<ST_Employee^, Employee>(const Employee& from) { auto to = gcnew ST_Employee(); to->id = from.id; to->name = convutil::ToCliString(from.name); to->address = convutil::ToCliString(from.address); return to; } // Managed → Native 変換 template<> ref class context_node<Employee*, ST_Employee^> : public context_node_base { public: context_node(Employee*& to_obj, ST_Employee^ from_obj) { if (toPtr_ != nullptr) { delete toPtr_; } // toPtr_ に値をコピーする toPtr_ = new Employee(); toPtr_->id = from_obj->id; convutil::ToCharArray(from_obj->name, toPtr_->name); convutil::ToCharArray(from_obj->address, toPtr_->address); to_obj = toPtr_; } ~context_node() { this->!context_node(); } protected: !context_node() { // メモリはちゃんと開放しましょう if (toPtr_ != nullptr) { delete toPtr_; toPtr_ = nullptr; } } private: Employee * toPtr_; marshal_context context_; }; } // namespace interop } // namespace msclr using namespace msclr::interop; int main(array<System::String ^> ^args) { // native to managed { Employee native_emp; native_emp.id = 1; strcpy_s(native_emp.name, u8"私です!!"); strcpy_s(native_emp.address, "nihon no dokokadayo"); auto managed_emp = marshal_as<ST_Employee^>(native_emp); Console::WriteLine("managed id = {0}", managed_emp->id); Console::WriteLine("managed name = {0}", managed_emp->name); Console::WriteLine("managed address = {0}", managed_emp->address); } // managed to native { auto managed_emp = gcnew ST_Employee(); managed_emp->id = 100; managed_emp->name = "私はだれ??"; managed_emp->address = "iega naidesu..."; marshal_context context; auto native_emp = context.marshal_as<Employee*>(managed_emp); using std::cout; using std::endl; cout << "native id = " << native_emp->id << endl; cout << "native name = " << native_emp->name << endl; // UTF-8だから文字化けするよ! cout << "native address = " << native_emp->address << endl; } return 0; }
Google Chrome のキャッシュ格納場所を変更する
最近会社のPCがSSD+HDDになったので、一時ファイル関係はHDD側に格納するように変更した。
その時に Google Chrome のキャッシュ格納場所を移動したのでやり方をメモ。
1.移動先のキャッシュフォルダを作成する
例:E:\Cache
2.現在のキャッシュフォルダを確認する
C:\Users\ユーザー名\AppData\Local\Google\Chrome\User Data\Default\Cache
※DefaultはProfile1、Profile2…などになっている場合がある
一度chromeで適当なサイトを開いてみて、更新されたフォルダがどれかで判断する
3.上記で見つけたキャッシュフォルダを削除する
4.次のコマンドを実行する
mklink /d "C:\Users\ユーザー名\AppData\Local\Google\Chrome\User Data\Default\Cache" "E:\Cache"
これでシンボリックリンクが作成され、キャッシュの格納場所が変更される
ListのTがクラスか構造体かでメモリ使用量が大きく異なる?
そんなことはないだろうと思ったが、気になったので試してみた。
ListにAddし続けてOutOfMemoryがでるタイミングを見てみたがやっぱり大きな差はなかった。
[ListにクラスをAddし続けた場合]
・開始時点
プライベートメモリ使用量: 30MB
物理メモリ使用量: 41MB
仮想メモリ使用量: 621MB
・終了時点
プライベートメモリ使用量: 6,297MB
物理メモリ使用量: 882MB
仮想メモリ使用量: 6,870MB
[Listに構造体をAddし続けた場合]
・開始時点
プライベートメモリ使用量: 30MB
物理メモリ使用量: 41MB
仮想メモリ使用量: 613MB
・終了時点
プライベートメモリ使用量: 6,289MB
物理メモリ使用量: 955MB
仮想メモリ使用量: 6,862MB
以下、テストで使用したコード
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Runtime.InteropServices; namespace MemoryCheck { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { const string title = "ListにクラスをAddし続けた場合"; // 自プロセスを取得 var process = System.Diagnostics.Process.GetCurrentProcess(); var list = new List<TestClass>(); using (var sw = new System.IO.StreamWriter(process.ProcessName + "_" + title + ".txt")) { try { sw.WriteLine(title); sw.WriteLine("プロセスID: {0}", process.Id); sw.WriteLine("プロセス名: {0}", process.ProcessName); int count = 1; while (true) { sw.WriteLine("Count = {0}", count++); WriteMemoryLog(process, sw); var data = new TestClass(); data.Init(); list.Add(data); sw.WriteLine(); } } catch (Exception ex) { sw.WriteLine(); sw.WriteLine(ex.ToString()); this.Close(); } } } private void button2_Click(object sender, EventArgs e) { const string title = "Listに構造体をAddし続けた場合"; // 自プロセスを取得 var process = System.Diagnostics.Process.GetCurrentProcess(); var list = new List<TestStruct>(); using (var sw = new System.IO.StreamWriter(process.ProcessName + "_" + title + ".txt")) { try { sw.WriteLine(title); sw.WriteLine("プロセスID: {0}", process.Id); sw.WriteLine("プロセス名: {0}", process.ProcessName); int count = 1; while (true) { sw.WriteLine("Count = {0}", count++); WriteMemoryLog(process, sw); var data = new TestStruct(); data.Init(); list.Add(data); sw.WriteLine(); } } catch (Exception ex) { sw.WriteLine(); sw.WriteLine(ex.ToString()); this.Close(); } } } private void WriteMemoryLog(System.Diagnostics.Process process, System.IO.StreamWriter sw) { // リフレッシュしないとプロセスの各種情報が最新情報に更新されない process.Refresh(); // 各種プロセス情報を出力する const int mb = 1024 * 1024; sw.WriteLine("プライベートメモリ使用量: {0:#,0}MB", process.PrivateMemorySize64 / mb); sw.WriteLine("物理メモリ使用量: {0:#,0}MB", process.WorkingSet64 / mb); sw.WriteLine("仮想メモリ使用量: {0:#,0}MB", process.VirtualMemorySize64 / mb); sw.Flush(); } } [StructLayout(LayoutKind.Sequential, Size = 4)] public struct TestStruct { // 1MBの配列 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1024 * 1024)] public byte[] array01; public void Init() { array01 = new byte[1024 * 1024]; } } public class TestClass { // 1MBの配列 public byte[] array01; public void Init() { array01 = new byte[1024 * 1024]; } } }
C#で簡単な画像のトリミングをやってみた
引数で指定された画像をトリミングする
using System.Drawing; namespace TrimImage { class Program { static void Main(string[] args) { string srcFile = args[0]; int x = int.Parse(args[1]); int y = int.Parse(args[2]); int width = int.Parse(args[3]); int height = int.Parse(args[4]); using (var srcImage = new Bitmap(srcFile)) using (var desImage = new Bitmap(width, height, srcImage.PixelFormat)) using (var g = Graphics.FromImage(desImage)) { var srcRect = new Rectangle(x, y, width, height); var desRect = new Rectangle(0, 0, desImage.Width, desImage.Height); g.DrawImage(srcImage, desRect, srcRect, GraphicsUnit.Pixel); string desFile = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(srcFile), "trim_" + System.IO.Path.GetFileName(srcFile)); desImage.Save(desFile, System.Drawing.Imaging.ImageFormat.Png); } } } }
C++でファイルサイズ取得
C++でファイルサイズを取得する
// for win32api #include <Windows.h> // for ifstream #include <fstream> // for stat #include <sys/types.h> #include <sys/stat.h> int main(int argc, char* argv[]) { const char* filepath = "C:\\Windows\\Media\\Windows Shutdown.wav"; // for win32api HANDLE hFile = CreateFile(filepath, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); DWORD size1 = GetFileSize(hFile, NULL); CloseHandle(hFile); printf("GetFileSize :%ld\n", size1); // for ifstream std::ifstream ifs(filepath, std::ios::binary); ifs.seekg(0, std::ios::end); auto eofpos = ifs.tellg(); ifs.clear(); ifs.seekg(0, std::ios::beg); auto begpos = ifs.tellg(); auto size2 = eofpos - begpos; printf("ifstream :%ld\n", size2); ifs.close(); // for stat struct _stat buf; int result = _stat(filepath, &buf); if (result == 0) { printf("stat :%ld\n", buf.st_size); } return 0; } 結果 GetFileSize :169444 ifstream :169444 stat :169444