카메라로부터 16비트 이미지 버퍼를 받아서 WPF의 ImageSource로 이미지를 출력하는 중입니다.
이런 글을 쓰는게 익숙하지 않아서… 작성이 이쁘지 못한점 죄송합니다.
속도 때문에 해당 링크와 같게 작성했습니다.
rtsp 카메라 영상 이미지로 출력 - UI/UX 프로그래밍 Q&A / WPF Q&A - 닷넷데브 (dotnetdev.kr)
DisplayImage(ushort[] frame, ushort width, ushort height)
{
System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(() => AllocImgBuf(width, height)), DispatcherPriority.Normal);
WriteableBitmap buffer = null;
ushort pixelValue = 0;
lock (_bufferLock)
{
if (_lastWritten == _bufferPtr) // 이전 버퍼가 아직 사용되지 않았다면 스킵
{
return;
}
//고정된 배열로부터 포인터 얻기
GCHandle handle = GCHandle.Alloc(frame, GCHandleType.Pinned);
IntPtr pPixelData = handle.AddrOfPinnedObject();
CopyMemory(_bufferPtr, pPixelData, (uint)((uint)width * (uint)height * 2));
_lastWritten = _bufferPtr;
buffer = _freeBuffer;
handle.Free();
}
System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(() => SwitchBuffer(buffer)), DispatcherPriority.Render);
}
private void AllocImgBuf(int width, int height)
{
if (_buffer1 == null || ((width * height) != (_buffer1.Width * _buffer1.Height)))
{
_buffer1 = new WriteableBitmap(width, height, 96, 96, PixelFormats.Gray16, null);
_buffer2 = new WriteableBitmap(width, height, 96, 96, PixelFormats.Gray16, null);
_freeBuffer = _buffer2;
_freeBuffer.Lock();
_bufferPtr = _freeBuffer.BackBuffer;
}
}
private void SwitchBuffer(WriteableBitmap buffer)
{
// CountFPS();
ushort pixelValue = 0;
lock (_bufferLock)
{
_freeBuffer = buffer == _buffer2 ? _buffer1 : _buffer2;
_freeBuffer.Lock();
_bufferPtr = _freeBuffer.BackBuffer;
}
buffer.AddDirtyRect(new System.Windows.Int32Rect(0, 0, buffer.PixelWidth, buffer.PixelHeight));
buffer.Unlock();
Image = buffer;
}
Image는 ObservableProperty로 Binding 되어있습니다.
위의 코드로 프로그램을 실행할 경우, 아래의 이미지와 같이 Stride나 이미지 형식이 잘못된 것처럼 출력됩니다.
// System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(() => SwitchBuffer(buffer)), DispatcherPriority.Render);
//위의 코드 대신에
System.Windows.Application.Current.Dispatcher.BeginInvoke((Action)(() =>
{
if (frame is not null && frame.Length != 0)
Image = BitmapSource.Create(width, height, 96, 96, PixelFormats.Gray16, null, frame, width * 2);
else
Image = null;
}));
BackBuffer를 Copy하는 방식이 아닌 BitmapSource.Create 방식으로 할 경우, 아래의 이미지와 같이 정상적으로 나옵니다.
위의 CopyMemory 방식 이후, SwitchBuffer 방식이 BitmapSource.Create 방식과 다르게 이미지가 이상하게 나오는 이유를 모르겠습니다… ㅠㅠ…
이것 저것 확인해본다고, 메모리 주소에 있는 값도 전부 긁어와서 비교해봤는데 똑같은 것을 확인했습니다.
속도가 중요해서 그런데 SwitchBuffer 방식을 사용했을 때 이미지가 정상적으로 출력될 수 있는 방법을 알수있을까요…