Это проблема XY: вы не должны связываться с эфемерными связями, поскольку они не предназначены для такого использования.На ум приходит несколько решений.
Вы можете кэшировать изображение с камеры и сохранить кэшированное значение:
Q_DECLARE_METATYPE(cv::Mat)
const char kImageCache[] = "imageCache";
// connect once, as soon as you have the camera available
connect(camera, &Camera::sendImage, [camera](const cv::Mat &image){
camera->setProperty(kImageCache, image);
});
connect(saveAction, &QAction::triggered, camera, [camera]{
auto const image = camera->property(kImageCache).value<cv::Mat>();
cv::imshow("Saved Image", image);
QtConcurrent::run([image]{
static std::atomic_bool saving;
static bool not_saving;
if (saving.compare_exchange_strong(not_saving, true)) {
cv::imwrite("foo", image);
saving.store(not_saving);
}
});
});
У вас также может быть конечный автомат, который реагирует на изображения в s_waiting
государство.Конечный автомат позволяет сохранять изображение только тогда, когда это необходимо для сохранения: в противном случае копия не сохраняется.
Приятная особенность конечных автоматов состоит в том, что они позволяют вам выразить сложные шаблоны поведения в ясной и понятной форме.стандартизированный способ.Они определенно недостаточно используются во многих интерфейсах.
class MyWindow : public QWidget {
…
QStateMachine m_machine{this};
QState s_idle{&m_machine}, s_waiting{&m_machine}, s_saving{&m_machine};
cv::Mat m_saveImage;
Q_SIGNAL void saved();
};
MyWindow::MyWindow(…):… {
m_machine.setInitialState(&s_idle);
m_machine.start();
s_idle.addTransition(saveAction, &QAction::triggered, &s_waiting);
s_waiting.addTransition(camera, &Camera::sendImage, &s_saving);
s_saving.addTransition(this, &decltype(*this)::saved, &s_idle);
connect(camera, &Camera::sendImage, &s_waiting, [this](const auto &image){
if (s_waiting.isActive())
m_saveImage = image;
});
connect(&s_saving, &QState::entered, [this]{
cv::imshow(…, m_saveImage);
QtConcurrent::run([image = m_saveImage, this]{
cv::imwrite(…, image);
emit saved();
});
m_saveImage = {};
});
}
Хорошая идея - одновременное сохранение изображения: в противном случае пользователь убивает работу пользователя, выполняя медленный дисковый ввод-вывод в потоке графического интерфейса.
Наконец: клонирование cv::Mat
обычно не требуется: весь смысл этого типа в том, что он подсчитывает ссылки и неявно разделяет их - это тип копирования при записи.Это как QImage
в этом отношении.