Моя обработка изображений полностью выполнена на C++. Использовал MFC, сейчас изучаю возможность обновления до WPF. Сторона WPF будет в основном пользовательским интерфейсом, я передаю указатели изображений из неуправляемого в управляемое для отображения. Я обнаружил, что если я использую поток для зацикливания вектора бэкэнда, он ничего не отобразит, но если я изменю его на триггер кнопки один за другим, он будет работать. С теми же функциями понятия не имею, что происходит.
WPF владеет моим объектом CppCli, который может напрямую вызывать любую функцию в c++/cli. Что здесь может быть не так.
код wpf cs:
private CppCli cli;
public MainWindow() {
cli = new CppCli();
cli.ImageUpdated += Cli_ImageUpdated; // delegate and event to call method Cli_ImageUpdated
InitializeComponent();
}
private void Cli_ImageUpdated(object sender, ImageUpdateEventArgs e)
{
Dispatcher.Invoke(() =>
{
MyImageControl.Source = e.img;
});
}
private void LiveToggle_Click(object sender, RoutedEventArgs e) {
cli.LiveToggle();
}
CPP-код CLI:
public ref class ImageUpdateEventArgs : EventArgs {
public: BitmapSource^ img;
ImageUpdateEventArgs(BitmapSource^ bitmap) {
img = bitmap;
}
};
void CppCli::LiveToggle() {
running = !running;
if (running) {
liveThread = gcnew Thread(gcnew ThreadStart(this, &MathFunctions::UpdateDisplay));
liveThread->IsBackground = true;
liveThread->Start();
}
//UpdateDisplay() // This works if replace the whole thing above.
}
void CppCli::UpdateDisplay() {
while (running) { // Remove this while loop and it works.
int stride, rows, cols, bufferSize;
stride = cvObj->images[imageIndex].step[0];
rows = cvObj->images[imageIndex].rows;
cols = cvObj->images[imageIndex].cols;
bufferSize = cvObj->images[imageIndex].total() * cvObj->images[imageIndex].elemSize();
IntPtr ptr(cvObj->images[imageIndex].ptr());
ImageUpdated(this, gcnew ImageUpdateEventArgs(BitmapSource::Create(cols, rows, 96, 96, PixelFormats::Bgra32, nullptr, ptr, bufferSize, stride)));
Thread::Sleep(100);
imageIndex++;
if (imageIndex >= cvObj->images.size())
{
imageIndex = 0;
}
}
}
Плохо, я не знал о формате stackoverflow, пока он не стал доступен для чтения. Я также тестирую WriteableBitmap. Есть ли способ указать с его помощью разные указатели? Это означает, что я просто меняю указатели на буферы изображений.
Вы должны скопировать в BackBuffer.
liveThread — это новый поток для вызова UpdateDisplay(). Это не основная тема, верно?
Поскольку BitmapSource создается в потоке, отличном от потока пользовательского интерфейса, его необходимо заморозить перед присвоением свойству Source элемента Image в потоке пользовательского интерфейса:
private void Cli_ImageUpdated(object sender, ImageUpdateEventArgs e)
{
e.img.Freeze(); // call here or in the ImageUpdateEventArgs constructor
Dispatcher.Invoke(() => MyImageControl.Source = e.img);
}
Подробную информацию см. в разделе «Примечания» в Freezable.Freeze и Freezable.IsFrozen.
Это действительно решено. Однако у меня есть несколько вопросов: поскольку я сделал новую копию BitmapSource, и она взята из другого фонового потока, вызывающего диспетчеризацию... почему нам нужно ее заморозить, чтобы она была потокобезопасной? Я удалил спящий режим и заметил, что частота кадров невысокая. Однако с WriteableBitmap еще не удалось справиться.
Да, замораживание делает его доступным для всех потоков. Пожалуйста, прочитайте связанную документацию.
ирония заключается в том, что замечание никогда не предполагает совместного использования/цели: «Чтобы избежать возможности возникновения исключения InvalidOperationException при вызове этого метода, проверьте свойство CanFreeze, чтобы определить, можно ли сделать Freezable неизменяемым перед вызовом этого метода».
Кстати, при назначении свойства Source у вас должно было возникнуть исключение InvalidOperationException.
Интересная часть: вообще этого не видел.
Возможно, вы захотите использовать WritaableBitmap вместо создания новых BitmapSources при каждом вызове ImageUpdated. BackBuffer объекта WritableBitmap можно заблокировать, чтобы он был доступен из потока, отличного от потока пользовательского интерфейса.