성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] VT sequences to "CONOUT$" vs. STD_O...
[정성태] NetCoreDbg is a managed code debugg...
[정성태] Evaluating tail call elimination in...
[정성태] What’s new in System.Text.Json in ....
[정성태] What's new in .NET 9: Cryptography ...
[정성태] 아... 제시해 주신 "https://akrzemi1.wordp...
[정성태] 다시 질문을 정리할 필요가 있을 것 같습니다. 제가 본문에...
[이승준] 완전히 잘못 짚었습니다. 댓글 지우고 싶네요. 검색을 해보...
[정성태] 우선 답글 감사합니다. ^^ 그런데, 사실 저 예제는 (g...
[이승준] 수정이 안되어서... byteArray는 BYTE* 타입입니다...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <h1 style='font-family: Malgun Gothic, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>C# - OpenCvSharp을 이용한 동영상(avi, mp4, ...) 처리</h1> <p> OpenCvSharp을 이용해,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > OpenCV 응용 프로그램을 C#으로 구현 - OpenCvSharp ; <a target='tab' href='http://www.sysnet.pe.kr/2/0/11402'>http://www.sysnet.pe.kr/2/0/11402</a> </pre> <br /> 동영상 처리하는 것도 다음과 같이 간단합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > [Cpp] Capturing Video ; <a target='tab' href='https://github.com/shimat/opencvsharp/wiki/%5BCpp%5D-Capturing-Video'>https://github.com/shimat/opencvsharp/wiki/%5BCpp%5D-Capturing-Video</a> </pre> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > using OpenCvSharp; using System; namespace ConsoleApp1 { class Program { static void Main(string[] args) { <span style='color: blue; font-weight: bold'>VideoCapture capture = new VideoCapture</span>("c:\\temp\\test.avi"); int sleepTime = (int)Math.Round(1000 / capture.Fps); using (Window window = new Window("capture")) using (Mat image = new Mat()) // Frame image buffer { // When the movie playback reaches end, Mat.data becomes NULL. while (true) { capture.Read(image); // same as cvQueryFrame if (image.Empty()) break; window.ShowImage(image); Cv2.WaitKey(sleepTime); } } } } } </pre> <br /> 참고로 Cv2.WaitKey를 Thread.Sleep으로 바꾸면 동영상 출력이 안됩니다. (아마도 Cv2.WaitKey 내부 로직에는 OpenCvSharp.Window의 메시지 처리 등도 포함이 된 것 같습니다.)<br /> <br /> <hr style='width: 50%' /><br /> <br /> 그런데, Windows Forms로 올려서 OpenCvSharp.Window 없이 처리하려면 어떻게 해야 할까요? 이를 위해 다음과 같은 식으로 처리를 해봤는데요.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > using OpenCvSharp; using OpenCvSharp.Extensions; using System; using System.Collections.Concurrent; using System.Diagnostics; using System.Drawing; using System.Threading; using System.Windows.Forms; namespace WindowsFormsApp1 { public partial class Form1 : Form { public Form1() { InitializeComponent(); } protected override void OnPaintBackground(PaintEventArgs e) { // base.OnPaintBackground(e); } protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); var g = e.Graphics; while (true) { if (_q.TryTake(out Bitmap item) == true) { <span style='color: blue; font-weight: bold'>g.DrawImage(item, new PointF(0, 0));</span> item.Dispose(); } else { break; } } } BlockingCollection<Bitmap> _q = new BlockingCollection<Bitmap>(); private Thread camera; private void CaptureCameraCallback() { <span style='color: blue; font-weight: bold'>VideoCapture capture = new VideoCapture("c:\\temp\\test.avi");</span> if (capture.IsOpened() == false) { return; } int fps = (int)capture.Fps; int expectedProcessTimePerFrame = 1000 / fps; Stopwatch st = new Stopwatch(); st.Start(); using (Mat image = new Mat()) { while (true) { long started = st.ElapsedMilliseconds; <span style='color: blue; font-weight: bold'>capture.Read(image);</span> if (image.Empty() == true) { break; } <span style='color: blue; font-weight: bold'>_q.Add(BitmapConverter.ToBitmap(image));</span> this.Invoke((Action)(() => this.Invalidate())); int elapsed = (int)(st.ElapsedMilliseconds - started); int delay = expectedProcessTimePerFrame - elapsed; if (delay > 0) { Thread.Sleep(delay); } } } } private void Form1_Load(object sender, EventArgs e) { camera = new Thread(CaptureCameraCallback); camera.IsBackground = true; camera.Start(); } } } </pre> <br /> 이전의 OpenCvSharp.Window를 이용했던 예제와 비교해 성능이 심각하게 하락했습니다. 예를 들어 1280 * 720 해상도의 24 fps 동영상도 화면이 뚝뚝 끊기면서 나오고 CPU 사용량도 늘었습니다. 단순히 OpenCvSharp.Window를 출력할 때는 CPU가 거의 0에 가깝게 소비하고 있었는데 위와 같이 바꾸니까 항상 7 ~ 12% 이상을 소비합니다. (4Core 기준)<br /> <br /> 물론 OpenCvSharp.Window를 사용할 때와는 다르게 ToBitmap의 호출로 인한 버퍼 복사에 대한 부하가 있겠지만 가장 병목이 되는 지점은 Graphics.DrawImage였습니다. DrawImage 호출에 20ms ~ 50ms까지 부하가 나오므로 24fps를 위한 최소 기준인 41ms를 심심치 않게 초과하는 것입니다.<br /> <br /> Graphics.DrawImage에 대해 검색해 봐도 비슷한 의견을 많이 볼 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Is Graphics.DrawImage too slow for bigger images? ; <a target='tab' href='https://stackoverflow.com/questions/11020710/is-graphics-drawimage-too-slow-for-bigger-images'>https://stackoverflow.com/questions/11020710/is-graphics-drawimage-too-slow-for-bigger-images</a> </pre> <br /> 그러니까, 혹시나 GDI로 영상 처리를 한다면 단일 프레임은 그나마 상관없겠지만 다중 프레임을 처리해야 하는 상황이라면 이런 성능 차이를 고려해 OpenCvSharp.Window로 처리하는 것이 권장됩니다.<br /> <br /> (<a target='tab' href='http://www.sysnet.pe.kr/bbs/DownloadAttachment.aspx?fid=1198&boardid=331301885'>첨부한 파일은 이 글의 예제 코드를 포함</a>합니다.)<br /> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
2467
(왼쪽의 숫자를 입력해야 합니다.)