Gige 카메라를 사용해 이미지 프레임을 받았습니다.
Winform 데모 프로그램에서는 정상적으로 프레임을 받아
뷰어에 표시 합니다.
그런데 wpf 이미지 컨트롤에 넣는데 나타나질 않네요
아래는 윈폼 데모 소스 코드

private void mCam1_OnFrameReceived(Image image)
{
if (InvokeRequired == true)
{
BeginInvoke(new ImageReceivedHandler(this.mCam1_OnFrameReceived), image);
return;
}
m_PictureBox.Image = image;
m_Frames_Cam1++;
labelFramesCam1.Text = m_Frames_Cam1.ToString();
}
이 소스 형식을 그대로 wpf 로 옮겨 만들고 있습니다.
wpf 코드

private void Cam_OnFrameReceived(Image image)
{
Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() =>
{
Dispatcher.BeginInvoke(new ImageReceivedHandler(this.Cam_OnFrameReceived), image);
return;
}));
ImgCamView_Before[0].Source = ToImageSource(image, ImageFormat.Bmp);
}
System.Drawing.Image 를 System.Windows.Media.ImageSource 로 변환하는 함수
![image]()
public static ImageSource ToImageSource(Image image, ImageFormat imageFormat)
{
using MemoryStream stream = new();
// Save to the stream
image.Save(stream, imageFormat);
// Rewind the stream
stream.Seek(0, SeekOrigin.Begin);
// Tell the WPF BitmapImage to use this streamtreeze
var BitmapImg = new BitmapImage();
BitmapImg.BeginInit();
BitmapImg.CacheOption = BitmapCacheOption.OnLoad;
BitmapImg.StreamSource = stream;
BitmapImg.EndInit();
return BitmapImg;
}
카메라에서 넘겨온 이미지도 정상이고

변환 함수에서 리턴도 정상같아요
![image]()
그런데 왜 나타나질 않는건지 모르겠어요

private void Cam_OnFrameReceived(Image image)
{
Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() =>
{
Dispatcher.BeginInvoke(new ImageReceivedHandler(this.Cam_OnFrameReceived), image);
return;
}));
ImgCamView_Before[0].Source = ToImageSource(image, ImageFormat.Bmp);
}
위 코드는 메인 스레드에서 이미지를 할당하는 것을 의도하신 것 같은데 첫 번째 BeginInvoke 부분에서 실수를 하신 것 같네요. 그래서 마지막 줄의 ImgCamView_Before[0].Source를 Set하는 코드가 메인 스레드와 카메라 프레임 수신 스레드에서 교차로 호출되고, 또 무한 반복되고 있는 듯 합니다.
함수의 첫 줄을 아래와 같이 수정해보세요.
private void Cam_OnFrameReceived(Image image)
{
if (!Dispatcher.CheckAccess())
{
Dispatcher.BeginInvoke(new ImageReceivedHandler(this.Cam_OnFrameReceived), image);
return;
}
ImgCamView_Before[0].Source = ToImageSource(image, ImageFormat.Bmp);
}
그리고 Cam_OnFrameReceived 함수로 넘어오는 Image 객체에 대해서 Dispose()를 호출하지 않아도 되는지 확인이 필요할 것 같습니다. 이전 코드에서 BeginInvoke로 호출해서 잘 동작했다면 Cam 라이브러리가 Bitmap 리소스를 Release 하지 않을 가능성이 큽니다. 메모리 누수가 없는지 확인해보시고 메모리가 계속 증가한다면 ToImageSource함수에서 image.Save 후 image 객체를 Dispose하세요.
4개의 좋아요
바로 해결되었습니다! 감사합니다.
스레딩에 대한 이해와 활용이 부족한게 원인이였네요.
언급해주신 객체 디스포즈를 했음에도 cpu, 메모리 부하가 크고
대략 30초 이내에 이벤트가 죽어버리네요,
이 부분은 데모 코드를 잘 파악해서 수정해 수정해나아가야 겠습니다.
많은 도움과 배움이 되었습니다.
감사합니다!
MemoryStream을 이용한 BitmapSource 변환은 성능 이슈와 메모리 누수 이슈가 있다고 합니다. (메모리 누수는 솔루션이 있지만 테스트 해보지 않았습니다.)
https://www.google.com/search?q=bitmapimage+streamsource+memory+leak
관련 내용은 참고하시고 아래 코드를 사용해 보세요. 메모리 누수 없이 안정적으로 동작했던 코드입니다.
[DllImport("gdi32")]
private static extern int DeleteObject(IntPtr o);
public static BitmapSource ToBitmapSource(Bitmap bitmap)
{
var ptr = bitmap.GetHbitmap(); //obtain the Hbitmap
try
{
return System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
ptr,
IntPtr.Zero,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
}
finally
{
DeleteObject(ptr); //release the HBitmap
bitmap.Dispose();
}
}
3개의 좋아요
추가 도움까지 아낌없이 주시네요!
바로 적용해서 비교해봤습니다.
아래와 같은 결과가 나왔는데요.
![image]()
알려주신 함수형식이 메모리 부하를 낮춰주었으나
Cpu 부하가 올라가는 현상이 나타났습니다.
이는 완벽한 결과가 아니기에 카메라 라이브러리의 데모 코드를 손 보면
더욱 효과가 뚜렷해질 것 같습니다.
코드를 개선 해서 추가 결과로 보답해드리겠습니다
도움에 감사드립니다
즐거운 하루 되세요!
2개의 좋아요
BitmapImg.EndInit() 다음에 아래 함수 한번 추가해 보세요.
///////////////////////////////////////////////
BitmapImg.EndInit();
BitmapImg.Freeze(); //Important to freeze it, otherwise it will still have minor leaks
///////////////////////////////////////////////
2개의 좋아요
도움 감사합니다! 적용해보고 계속 결과로 남겨둘게요! 즐거운 금요일 되세요!
1개의 좋아요