gpt4 book ai didi

c++ - 定期从 mexFile 向 MATLAB 发送数据

转载 作者:太空狗 更新时间:2023-10-29 21:39:36 25 4
gpt4 key购买 nike

我现在正在开发一个完全编写的数据采集工具在 MATLAB 中。我的同事希望我用 MATLAB 写这个东西以便他们可以扩展和修改它。

该软件需要从两个连接的 USB 摄像头抓取图片。这些相机的 API 是用 C++ 编写的,并记录在案 -> Here .

问题来了:当我写一个抓取图片的 mex 文件时,它包括相机的初始化和配置加载花费很长时间。当我想抓取图片时这样,MATLAB 需要超过 1 秒的时间来执行任务。一旦初始化,摄像机就能够记录和发送 100 fps。我需要的最低帧速率是 10 fps。我需要能够将每张录制的照片发回到 MATLAB。因为录制 session 需要采集工具大约需要 12 小时,我们需要一个带有一些轻微后处理的实时屏幕。

是否可以在 mex 文件中生成一个循环将数据发送到 MATLAB,然后等待来自 MATLAB 的返回信号并继续?这样我就可以初始化相机并定期发送图像到 MATLAB。

我是 C++ 的初学者,我很有可能不明白为什么会这样的基本概念不可能。

感谢您给我的任何建议或资源。

请在下面找到初始化相机的代码使用 Basler 提供的 Pylon API。

// Based on the Grab_MultipleCameras.cpp Routine from Basler
/*
This routine grabs one frame from 2 cameras connected
via two USB3 ports. It directs the Output to MATLAB.
*/

// Include files to use the PYLON API.
#include <pylon/PylonIncludes.h>
#include <pylon/usb/PylonUsbIncludes.h>
#include <pylon/usb/BaslerUsbInstantCamera.h>
#include <pylon/PylonUtilityIncludes.h>
// Include Files for MEX Generation
#include <matrix.h>
#include <mex.h>

// Namespace for using pylon objects.
using namespace Pylon;

// We are lazy and use Basler USB namespace
using namespace Basler_UsbCameraParams;

// Standard namespace
using namespace std;

// Define Variables Globally to be remembered between each call
// Filenames for CamConfig
const String_t filenames[] = { "NodeMapCam1.pfs","NodeMapCam2.pfs" };

// Limits the amount of cameras used for grabbing.
static const size_t camerasToUse = 2;

// Create an array of instant cameras for the found devices and
// avoid exceeding a maximum number of devices.
CBaslerUsbInstantCameraArray cameras(camerasToUse);

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
// Automagically call PylonInitialize and PylonTerminate to ensure the pylon runtime system.
// is initialized during the lifetime of this object
PylonAutoInitTerm autoInitTerm;

try
{
// Get the transport layer factory
CTlFactory& tlFactory = CTlFactory::GetInstance();

// Get all attached devices and exit application if no device or USB Port is found.
DeviceInfoList_t devices;
ITransportLayer *pTL = dynamic_cast<ITransportLayer*>(tlFactory.CreateTl(BaslerUsbDeviceClass));
if (pTL == NULL)
{
throw RUNTIME_EXCEPTION("No USB transport layer available.");
}

if (pTL->EnumerateDevices(devices) == 0)
{
throw RUNTIME_EXCEPTION("No camera present.");
}

// Create and attach all Pylon Devices. Load Configuration
for (size_t i = 0; i < cameras.GetSize(); ++i)
{
cameras[i].Attach(tlFactory.CreateDevice(devices[i]));
}

// Open all cameras.
cameras.Open();

// Load Configuration and execute Trigger
for (size_t i = 0; i < cameras.GetSize(); ++i)
{
CFeaturePersistence::Load(filenames[i], &cameras[i].GetNodeMap());
}
if (cameras[0].IsOpen() && cameras[1].IsOpen())
{
mexPrintf("\nCameras are fired up and configuration is applied\n");
// HERE I WOULD LIKE TO GRAB PICTURES AND SEND THEM
// PERIODICALLY TO MATLAB.
}
}
catch (GenICam::GenericException &e)
{
// Error handling
mexPrintf("\nAn exception occured:\n");
mexPrintf(e.GetDescription());
}

return;
}

最佳答案

您可以定期循环并将图像发送回 MATLAB,但您希望它在工作区中如何显示(多个 2D 图像、巨大的 3D/4D 阵列、单元格等)?我认为您正在寻找的解决方案是一个有状态的 MEX 文件,它可以通过 'init''new' 命令启动,然后用 'capture' 命令为已经初始化的相机重复调用。

有一个example of how to do this in my GitHub .从 class_wrapper_template.cpp 开始并根据您的命令修改它(newcapturedelete 等)。这是一个粗略且未经测试的示例,说明它的核心可能看起来如何(也是 mirrored on Gist.GitHub ):

// pylon_mex_camera_interface.cpp
#include "mex.h"
#include <vector>
#include <map>
#include <algorithm>
#include <memory>
#include <string>
#include <sstream>

//////////////////////// BEGIN Step 1: Configuration ////////////////////////
// Include your class declarations (and PYLON API).
#include <pylon/PylonIncludes.h>
#include <pylon/usb/PylonUsbIncludes.h>
#include <pylon/usb/BaslerUsbInstantCamera.h>
#include <pylon/PylonUtilityIncludes.h>

// Define class_type for your class
typedef CBaslerUsbInstantCameraArray class_type;

// List actions
enum class Action
{
// create/destroy instance - REQUIRED
New,
Delete,
// user-specified class functionality
Capture
};

// Map string (first input argument to mexFunction) to an Action
const std::map<std::string, Action> actionTypeMap =
{
{ "new", Action::New },
{ "delete", Action::Delete },
{ "capture", Action::Capture }
}; // if no initializer list available, put declaration and inserts into mexFunction

using namespace Pylon;
using namespace Basler_UsbCameraParams;

const String_t filenames[] = { "NodeMapCam1.pfs","NodeMapCam2.pfs" };
static const size_t camerasToUse = 2;
///////////////////////// END Step 1: Configuration /////////////////////////

// boilerplate until Step 2 below
typedef unsigned int handle_type;
typedef std::pair<handle_type, std::shared_ptr<class_type>> indPtrPair_type; // or boost::shared_ptr
typedef std::map<indPtrPair_type::first_type, indPtrPair_type::second_type> instanceMap_type;
typedef indPtrPair_type::second_type instPtr_t;

// getHandle pulls the integer handle out of prhs[1]
handle_type getHandle(int nrhs, const mxArray *prhs[]);
// checkHandle gets the position in the instance table
instanceMap_type::const_iterator checkHandle(const instanceMap_type&, handle_type);

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {

// static storage duration object for table mapping handles to instances
static instanceMap_type instanceTab;

if (nrhs < 1 || !mxIsChar(prhs[0]))
mexErrMsgTxt("First input must be an action string ('new', 'delete', or a method name).");

char *actionCstr = mxArrayToString(prhs[0]); // convert char16_t to char
std::string actionStr(actionCstr); mxFree(actionCstr);

for (auto & c : actionStr) c = ::tolower(c); // remove this for case sensitivity

if (actionTypeMap.count(actionStr) == 0)
mexErrMsgTxt(("Unrecognized action (not in actionTypeMap): " + actionStr).c_str());

// If action is not 'new' or 'delete' try to locate an existing instance based on input handle
instPtr_t instance;
if (actionTypeMap.at(actionStr) != Action::New && actionTypeMap.at(actionStr) != Action::Delete) {
handle_type h = getHandle(nrhs, prhs);
instanceMap_type::const_iterator instIt = checkHandle(instanceTab, h);
instance = instIt->second;
}

//////// Step 2: customize each action in the switch in mexFuction ////////
switch (actionTypeMap.at(actionStr))
{
case Action::New:
{
if (nrhs > 1 && mxGetNumberOfElements(prhs[1]) != 1)
mexErrMsgTxt("Second argument (optional) must be a scalar, N.");

handle_type newHandle = instanceTab.size() ? (instanceTab.rbegin())->first + 1 : 1;

// Store a new CBaslerUsbInstantCameraArray in the instance map
std::pair<instanceMap_type::iterator, bool> insResult =
instanceTab.insert(indPtrPair_type(newHandle, std::make_shared<class_type>(camerasToUse)));

if (!insResult.second) // sanity check
mexPrintf("Oh, bad news. Tried to add an existing handle."); // shouldn't ever happen
else
mexLock(); // add to the lock count

// return the handle
plhs[0] = mxCreateDoubleScalar(insResult.first->first); // == newHandle

// Get all attached devices and exit application if no device or USB Port is found.
CTlFactory& tlFactory = CTlFactory::GetInstance();
// Check if cameras are attached
ITransportLayer *pTL = dynamic_cast<ITransportLayer*>(tlFactory.CreateTl(BaslerUsbDeviceClass));
// todo: some checking here... (pTL == NULL || pTL->EnumerateDevices(devices) == 0)

// Create and attach all Pylon Devices. Load Configuration
CBaslerUsbInstantCameraArray &cameras = *instance;
DeviceInfoList_t devices;
for (size_t i = 0; i < cameras.GetSize(); ++i) {
cameras[i].Attach(tlFactory.CreateDevice(devices[i]));
}

// Open all cameras.
cameras.Open();

// Load Configuration and execute Trigger
for (size_t i = 0; i < cameras.GetSize(); ++i) {
CFeaturePersistence::Load(filenames[i], &cameras[i].GetNodeMap());
}

if (cameras[0].IsOpen() && cameras[1].IsOpen()) {
mexPrintf("\nCameras are fired up and configuration is applied\n");

break;
}
case Action::Delete:
{
instanceMap_type::const_iterator instIt = checkHandle(instanceTab, getHandle(nrhs, prhs));
(instIt->second).close(); // may be unnecessary if d'tor does it
instanceTab.erase(instIt);
mexUnlock();
plhs[0] = mxCreateLogicalScalar(instanceTab.empty()); // just info
break;
}
case Action::Capture:
{
CBaslerUsbInstantCameraArray &cameras = *instance; // alias for the instance

// TODO: create output array and capture a frame(s) into it
plhs[0] = mxCreateNumericArray(...);
pixel_type* data = (pixel_type*) mxGetData(plhs[0]);
cameras[0].GrabOne(...,data,...);
// also for cameras[1]?
}
}
default:
mexErrMsgTxt(("Unhandled action: " + actionStr).c_str());
break;
}
//////////////////////////////// DONE! ////////////////////////////////
}

// See github for getHandle and checkHandle

这个想法是你会调用它一次来初始化:

>> h = pylon_mex_camera_interface('new');

然后您将在 MATLAB 循环中调用它以获取帧:

>> newFrame{i} = pylon_mex_camera_interface('capture', h);

完成后:

>> pylon_mex_camera_interface('delete', h)

您应该用 MATLAB 类包装它。源自 cppclass.m轻松做到这一点。有关派生类示例,请参阅 pqheap.m .

关于c++ - 定期从 mexFile 向 MATLAB 发送数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32527588/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com