C++ 是否可以通过调用c/c++;matlab中的代码?

C++ 是否可以通过调用c/c++;matlab中的代码?,c++,matlab,plot,matlab-figure,C++,Matlab,Plot,Matlab Figure,在Matlab中调用mex文件(用c/c++编写)以加速某些计算通常非常容易。然而,根据我的经验,Matlab中真正的瓶颈是数据绘图。创建句柄非常昂贵,即使只更新句柄数据(例如,扩展数据、YData、ZData),也可能需要很长时间。更糟糕的是,由于Matlab是一个单线程程序,因此不可能同时更新多个绘图 > >强> >我的问题< /强>:是否可以编写一个Matlab图形用户界面并调用C++(或其他可并行化代码)来处理绘图/可视化?我正在寻找一个跨平台的解决方案,将工作在Windows,Mac

在Matlab中调用
mex
文件(用c/c++编写)以加速某些计算通常非常容易。然而,根据我的经验,Matlab中真正的瓶颈是数据绘图。创建句柄非常昂贵,即使只更新句柄数据(例如,扩展数据、YData、ZData),也可能需要很长时间。更糟糕的是,由于Matlab是一个单线程程序,因此不可能同时更新多个绘图

<> > >强> >我的问题< /强>:是否可以编写一个Matlab图形用户界面并调用C++(或其他可并行化代码)来处理绘图/可视化?我正在寻找一个跨平台的解决方案,将工作在Windows,Mac和Linux上,但任何解决方案,让我开始在任何一个操作系统是非常感谢

我发现了一个似乎使用Matlab的
plot()
语法的工具,但我不确定这是否会加快速度,因为我担心如果我在Matlab的
figure()
窗口中绘图,事情可能会再次变慢

我非常感谢以前处理过这种情况的人的任何意见和反馈

编辑:显然,我已经分析了我的代码,瓶颈是绘图(十几个包含大量数据的面板)

EDIT2:为了让你获得赏金,我需要一个现实生活中的、最简单的工作示例来说明如何做到这一点——暗示性的回答对我没有帮助

EDIT3:关于要绘制的数据:在最简单的情况下,考虑20个线条图,它们需要每秒更新1000000个数据点

EDIT4:我知道这是一个需要绘制的大量点,但我从未说过这个问题很容易。我不能只忽略某些数据点,因为在实际绘制它们之前,无法评估哪些点是重要的(数据以亚毫秒的时间分辨率采样)。事实上,我的数据是使用商业数据采集系统采集的,该系统带有数据查看器(用c++编写)。该程序可以可视化多达60个线图,甚至超过1000000个数据点


EDIT5:我不喜欢当前讨论的方向。我知道对我的数据进行次采样可能会加快速度,但这不是问题所在。这里的问题是如何获得一个C/C++/Python/java接口来与MATLAB一起工作,以便希望通过直接与硬件对话(或使用其他技巧/方式)加速绘图,我认为这是可能的,但可能需要从头开始编写绘图代码(至少使用的部分)。因为任何你可以重用的东西都会让你慢下来

为了测试可行性,我首先测试任何Win32 GUI是否可以从MEX工作(调用
MessageBox
),然后继续创建自己的窗口,测试窗口消息是否到达WndProc。完成所有这些之后,您可以将OpenGL上下文绑定到它(或者只使用GDI),然后开始绘图


然而,节省可能来自更简单的绘图代码和使用更新的OpenGL功能(如VBOs),而不是线程。GPU上的一切都已经并行,更多的线程无法帮助更快地将命令/数据传输到GPU。

是否可以使用替代架构?例如,使用MATLAB生成数据,并使用fast库或应用程序(GNUplot?)处理绘图

当绘图仪消耗数据时,甚至可以让MATLAB将数据写入流。然后,当MATLAB生成数据时,绘图将被更新


这种方法可以避免MATLAB绘制速度慢得可笑,并将工作分为两个单独的过程。OS/CPU可能会理所当然地将进程分配给不同的内核。

您是否尝试过将渲染方法更改为OpenGL的简单解决方案

opengl hardware;
set(gcf,'Renderer','OpenGL');
警告! 在这种模式下会有一些东西消失,看起来会有点不同,但通常绘图会运行得更快,特别是如果您有硬件加速器的话

顺便问一下,您确定您将实际获得性能提升吗? 例如,根据我的经验,
C#
中的
WPF
图形要比Matlabs慢得多,尤其是散点图和圆

编辑:我想到了一个事实,即实际绘制到屏幕上的点数不会那么多。基本上,这意味着您需要在屏幕上有像素的位置进行插值。查看此对象:

classdef InterpolatedPlot < handle
    properties(Access=private)
        hPlot;
    end

    methods(Access=public)
        function this = InterpolatedPlot(x,y,varargin)
            this.hPlot = plot(0,0,varargin{:});
            this.setXY(x,y);
        end        
    end    

    methods
        function setXY(this,x,y)
            parent = get(this.hPlot,'Parent');
            set(parent,'Units','Pixels')
            sz = get(parent,'Position');
            width = sz(3); %Actual width in pixels
            subSampleX = linspace(min(x(:)),max(x(:)),width);

            subSampleY = interp1(x,y,subSampleX);
            set(this.hPlot,'XData',subSampleX,'YData',subSampleY);
        end

    end
end

另一个可能的改进: 此外,如果对x数据进行了排序,则可以使用
interp1q
而不是
interp
,这将更快

classdef InterpolatedPlot < handle
    properties(Access=private)
        hPlot;
    end

%     properties(Access=public)
%         XData;
%         YData;      
%     end

    methods(Access=public)
        function this = InterpolatedPlot(x,y,varargin)
            this.hPlot = plot(0,0,varargin{:});
            this.setXY(x,y);
%             this.XData = x;
%             this.YData = y;
        end        
    end    

    methods
        function setXY(this,x,y)
            parent = get(this.hPlot,'Parent');
            set(parent,'Units','Pixels')
            sz = get(parent,'Position');
            width = sz(3); %Actual width in pixels
            subSampleX = linspace(min(x(:)),max(x(:)),width);

            subSampleY = interp1q(x,y,transpose(subSampleX));
            set(this.hPlot,'XData',subSampleX,'YData',subSampleY);
        end

    end
end

您无法在一个小绘图上拟合1000000个数据点。你每10000个点选一个,画出来怎么样

你可以考虑在大向量上调用<代码> imResiths<代码>以缩小它,但是手动省略99%的点来构建向量可能会更快。


@memyself采样操作已经开始了。Matlab正在选择要包含在图形中的数据。你为什么相信matlab?在我看来,你显示的图表明显歪曲了数据。密集区域应表明信号处于恒定值,但在您的图形中,它可能意味着信号处于该值的一半时间-或者在对应于该像素的间隔内至少处于该值一次?

正如许多人在回答中提到的,不需要绘制那么多点。我认为重要的是要接受安德烈的评论:

这是一个巨大的分数!屏幕上没有足够的像素来绘制该数量

重写p
classdef InterpolatedPlot < handle
    properties(Access=private)
        hPlot;
    end

%     properties(Access=public)
%         XData;
%         YData;      
%     end

    methods(Access=public)
        function this = InterpolatedPlot(x,y,varargin)
            this.hPlot = plot(0,0,varargin{:});
            this.setXY(x,y);
%             this.XData = x;
%             this.YData = y;
        end        
    end    

    methods
        function setXY(this,x,y)
            parent = get(this.hPlot,'Parent');
            set(parent,'Units','Pixels')
            sz = get(parent,'Position');
            width = sz(3); %Actual width in pixels
            subSampleX = linspace(min(x(:)),max(x(:)),width);

            subSampleY = interp1q(x,y,transpose(subSampleX));
            set(this.hPlot,'XData',subSampleX,'YData',subSampleY);
        end

    end
end
function TestALotOfPoints()
    x = rand(10000,1);
    y = rand(10000,1);
    x = sort(x);
    ip = InterpolatedPlot(x,y,'color','r','LineWidth',2);

end
// On Mac OS X, compile using: g++ -O3 -framework GLUT -framework OpenGL glview.cpp
// The file "input" is assumed to contain a line for each point:
// 0.1 1.0
// 5.2 3.0
#include <vector>
#include <sstream>
#include <fstream>
#include <iostream>
#include <GLUT/glut.h>
using namespace std;
struct float2 { float2() {} float2(float x, float y) : x(x), y(y) {} float x, y; };
static vector<float2> points;
static float2 minPoint, maxPoint;
typedef vector<float2>::iterator point_iter;
static void render() {
    glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(minPoint.x, maxPoint.x, minPoint.y, maxPoint.y, -1.0f, 1.0f);
    glColor3f(0.0f, 0.0f, 0.0f);
    glEnableClientState(GL_VERTEX_ARRAY);
    glVertexPointer(2, GL_FLOAT, sizeof(points[0]), &points[0].x);
    glDrawArrays(GL_LINE_STRIP, 0, points.size());
    glDisableClientState(GL_VERTEX_ARRAY);
    glutSwapBuffers();
}
int main(int argc, char* argv[]) {
    ifstream file("input");
    string line;
    while (getline(file, line)) {
        istringstream ss(line);
        float2 p;
        ss >> p.x;
        ss >> p.y;
        if (ss)
            points.push_back(p);
    }
    if (!points.size())
        return 1;
    minPoint = maxPoint = points[0];
    for (point_iter i = points.begin(); i != points.end(); ++i) {
        float2 p = *i;
        minPoint = float2(minPoint.x < p.x ? minPoint.x : p.x, minPoint.y < p.y ? minPoint.y : p.y);
        maxPoint = float2(maxPoint.x > p.x ? maxPoint.x : p.x, maxPoint.y > p.y ? maxPoint.y : p.y);
    }
    float dx = maxPoint.x - minPoint.x;
    float dy = maxPoint.y - minPoint.y;
    maxPoint.x += dx*0.1f; minPoint.x -= dx*0.1f;
    maxPoint.y += dy*0.1f; minPoint.y -= dy*0.1f;
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
    glutInitWindowSize(512, 512);
    glutCreateWindow("glview");
    glutDisplayFunc(render);
    glutMainLoop();
    return 0;
}
// On Mac OS X, compile using: g++ -O3 -framework GLUT -framework OpenGL glview.cpp
#include <vector>
#include <sstream>
#include <fstream>
#include <iostream>
#include <cmath>
#include <iostream>
#include <GLUT/glut.h>
using namespace std;
struct float2 { float2() {} float2(float x, float y) : x(x), y(y) {} float x, y; };
struct Vbo {
    GLuint i;
    Vbo(int size) { glGenBuffersARB(1, &i); glBindBufferARB(GL_ARRAY_BUFFER, i); glBufferDataARB(GL_ARRAY_BUFFER, size, 0, GL_DYNAMIC_DRAW); } // could try GL_STATIC_DRAW
    void set(const void* data, size_t size, size_t offset) { glBindBufferARB(GL_ARRAY_BUFFER, i); glBufferSubData(GL_ARRAY_BUFFER, offset, size, data); }
    ~Vbo() { glDeleteBuffers(1, &i); }
};
static const int vboCount = 20;
static const int vboSize = 100000;
static const int pointCount = vboCount*vboSize;
static float endTime = 0.0f;
static const float deltaTime = 1e-3f;
static std::vector<Vbo*> vbos;
static int vboStart = 0;
static void addPoints(float2* points, int pointCount) {
    while (pointCount) {
        if (vboStart == vboSize || vbos.empty()) {
            if (vbos.size() >= vboCount+2) { // remove and reuse vbo
                Vbo* first = *vbos.begin();
                vbos.erase(vbos.begin());
                vbos.push_back(first);
            }
            else { // create new vbo
                vbos.push_back(new Vbo(sizeof(float2)*vboSize));
            }
            vboStart = 0;
        }

        int pointsAdded = pointCount;

        if (pointsAdded + vboStart > vboSize)
            pointsAdded = vboSize - vboStart;

        Vbo* vbo = *vbos.rbegin();
        vbo->set(points, pointsAdded*sizeof(float2), vboStart*sizeof(float2));

        pointCount -= pointsAdded;
        points += pointsAdded;
        vboStart += pointsAdded;
    }
}
static void render() {
    // generate and add 10000 points
    const int count = 10000;
    float2 points[count];
    for (int i = 0; i < count; ++i) {
        float2 p(endTime, std::sin(endTime*1e-2f));
        endTime += deltaTime;
        points[i] = p;
    }
    addPoints(points, count);
    // render
    glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(endTime-deltaTime*pointCount, endTime, -1.0f, 1.0f, -1.0f, 1.0f);
    glColor3f(0.0f, 0.0f, 0.0f);
    glEnableClientState(GL_VERTEX_ARRAY);
    for (size_t i = 0; i < vbos.size(); ++i) {
        glBindBufferARB(GL_ARRAY_BUFFER, vbos[i]->i);
        glVertexPointer(2, GL_FLOAT, sizeof(float2), 0);

        if (i == vbos.size()-1)
            glDrawArrays(GL_LINE_STRIP, 0, vboStart);
        else
            glDrawArrays(GL_LINE_STRIP, 0, vboSize);
    }
    glDisableClientState(GL_VERTEX_ARRAY);
    glutSwapBuffers();
    glutPostRedisplay();
}
int main(int argc, char* argv[]) {
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
    glutInitWindowSize(512, 512);
    glutCreateWindow("glview");
    glutDisplayFunc(render);
    glutMainLoop();
    return 0;
}