用图像替换颤抖箭头 [英] Replace quiver arrowheads with images

查看:61
本文介绍了用图像替换颤抖箭头的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个圆形晶格,在晶格位置上,我绘制了归一化的箭头,这些箭头根据模拟结果保持相同的大小并改变方向,

我的情节看起来像这样

是否可以用jpg/bmp/gif/png图像替换颤动图中的箭头?或通过任何其他命令?

理想情况下,它看起来像这样(尽管不一定是箭头)

解决方案

说明

执行此操作的一种方法是使用具有 FaceColor 设置为,这将导致分配给 CData 的值可以在整个表面上进行映射.

然后要获得透明性,您还可以设置 值设置为texturemap并设置 AlphaData ,这些透明度值也将在整个表面范围内映射.

要对此应用到您的案例中,您想将CData设置为要用来替换箭头的图像.而且,您希望AlphaData与图像数据具有相同的大小,在不透明的情况下值为1,在透明的情况下值为0.这将使它看起来不像您发布的图像,您可以清楚地看到边界框.然后,您将需要绘制其中一个箭头所指向的表面,并对其进行适当的缩放/定位.

实施

更新:现在可以在 Github 以及 MATLAB文件交换.

为了演示我在说什么,我创建了以下函数,该函数实际上就是这样做的.它接受与quiver相同的输入(首先提供图像数据,最后提供可选的AlphaData参数),并在指向请求方向的所有请求坐标上创建一个曲面,并按指定的比例缩放

function h = quiverpic(im, X, Y, dX, dY, scale, alpha)
    % im - RGB or indexed image
    % X - X positions
    % Y - Y positions
    % dX - X direction vector
    % dY - Y direction vector
    % scale - Any scaling (Default = 1)
    % alpha - Transparency (same size as im), if not specified = ~isnan(im)

    h = hggroup();

    if ~exist('scale', 'var')
        % By default there is no scaling
        scale = 1;
    end

    if ~exist('alpha', 'var')
        % By default, any NaN will be transparent
        alpha = ~isnan(im);
    end

    % Determine aspect ratio of the source image
    width_to_height = size(im, 2) / size(im, 1);

    for k = 1:numel(X)
        % Determine angle from displacement vectors
        theta = atan2(dY(k), dX(k));

        % Subtract pi/2 to +y is considered "up"
        theta = theta + pi/2;

        % Setup surface plot boundary
        [xx,yy] = meshgrid([-0.5, 0.5] * width_to_height, [0 1]);

        % Scale depending on magnitude of dX and dY
        this_scale = scale * sqrt(dX(k).^2 + dY(k).^2);

        % Scale X and Y components prior to rotating
        xx = xx .* this_scale;
        yy = yy .* this_scale;

        % Rotate to align with the desired direction
        xdata = xx .* cos(theta) - yy .* sin(theta);
        ydata = xx .* sin(theta) + yy .* cos(theta);

        % Determine what is considered the "anchor" of the graphic.
        % For now this is assumed to be the "bottom-middle"
        xoffset = X(k) - mean(xdata(2,:));
        yoffset = Y(k) - mean(ydata(2,:));

        % Actually plot the surface.
        surf(xdata + xoffset, ...
             ydata  + yoffset, zeros(2), ...
             'Parent', h, ...
             'FaceColor', 'texture', ...
             'EdgeColor', 'none', ...
             'CData', im, ...
             'FaceAlpha', 'texture', ...
             'AlphaData', double(alpha));
    end
end

示例

我写了一个小测试脚本来演示如何使用它并显示结果.

t = linspace(0, 2*pi, 13);
dX = cos(t(1:end-1));
dY = sin(t(1:end-1));
X = (3 * dX) + 5;
Y = (3 * dY) + 5;
scale = 1;

% Load the MATLAB logo as an example image
png = fullfile(matlabroot,'/toolbox/matlab/icons/matlabicon.gif');
[im, map] = imread(png);
im = ind2rgb(im, map);

% Determine alpha channel based on upper left hand corner pixel
flatim = reshape(im, [], 3);
alpha = ~ismember(flatim, squeeze(im(1,1,:)).', 'rows');
alpha = reshape(alpha, size(im(:,:,1)));

% Plot some things prior to creating the quiverpic object
fig = figure();
hax = axes('Parent', fig);
axis(hax, 'equal');

% Plot a full circle
t = linspace(0, 2*pi, 100);
plot((cos(t) * 3) + 5, (sin(t) * 3) + 5, '-')

hold(hax, 'on')

% Plot markers at all the quiver centers
plot(X, Y, 'o', 'MarkerFaceColor', 'w')

% Plot a random image behind everything to demonstrate transparency
him = imagesc(rand(9));
uistack(him, 'bottom')

axis(hax, 'equal')
colormap(fig, 'gray')
set(hax, 'clim', [-4 4]);

% Now plot the quiverpic
h = quiverpic(im, X, Y, dX, dY, 1, alpha);

axis(hax, 'tight')

结果

荒谬

矢量和缩放比例不同的同一张图片

任何宽高比的图像都可以正常工作

I have a circular lattice and on the lattice sites I plot normalized arrows that remain in the same magnitude and change direction according to a simulation, the details of which don't matter.

My plots look like this

Is it possible to replace the arrow in the quiver plot by an jpg/bmp/gif/png image? or by any other command?

Ideally, it would look something like this (although not necessarily arrows)

解决方案

Explanation

One way that you can do this, would be to use a surface object with a texture-map as the FaceColor.

In MATLAB, you can create a simple rectangular surface. You can set the FaceColor to be texturemap which will cause the value assigned to CData to be mapped across the surface.

Then to get transparency, you can also set the FaceAlpha value to be texturemap and set the AlphaData and those transparency values will be mapped across the extent of the surface as well.

For this to be applied to your case, you want to set the CData to the image that you want to use to replace your arrows. And you will want the AlphaData to be the same size as your image data with values of 1 where you want it to be opaque and 0 where you want it to be transparent. This will allow it to not look like the image that you have posted where you can clearly see the bounding box. Then you will need to draw one of these surfaces where each of the arrows would go and scale/position it appropriately.

Implementation

Update: A more polished version of this code (ImageQuiver) is now available on Github as well as the MATLAB File Exchange.

As a demonstration of what I'm talking about, I have created the following function which essentially does just this. It accepts the same inputs as quiver (with the image data being supplied first and an optional AlphaData parameter at the end) and creates a surface at all of the requested coordinates pointing in the requested direction, and scaled by the specified amount.

function h = quiverpic(im, X, Y, dX, dY, scale, alpha)
    % im - RGB or indexed image
    % X - X positions
    % Y - Y positions
    % dX - X direction vector
    % dY - Y direction vector
    % scale - Any scaling (Default = 1)
    % alpha - Transparency (same size as im), if not specified = ~isnan(im)

    h = hggroup();

    if ~exist('scale', 'var')
        % By default there is no scaling
        scale = 1;
    end

    if ~exist('alpha', 'var')
        % By default, any NaN will be transparent
        alpha = ~isnan(im);
    end

    % Determine aspect ratio of the source image
    width_to_height = size(im, 2) / size(im, 1);

    for k = 1:numel(X)
        % Determine angle from displacement vectors
        theta = atan2(dY(k), dX(k));

        % Subtract pi/2 to +y is considered "up"
        theta = theta + pi/2;

        % Setup surface plot boundary
        [xx,yy] = meshgrid([-0.5, 0.5] * width_to_height, [0 1]);

        % Scale depending on magnitude of dX and dY
        this_scale = scale * sqrt(dX(k).^2 + dY(k).^2);

        % Scale X and Y components prior to rotating
        xx = xx .* this_scale;
        yy = yy .* this_scale;

        % Rotate to align with the desired direction
        xdata = xx .* cos(theta) - yy .* sin(theta);
        ydata = xx .* sin(theta) + yy .* cos(theta);

        % Determine what is considered the "anchor" of the graphic.
        % For now this is assumed to be the "bottom-middle"
        xoffset = X(k) - mean(xdata(2,:));
        yoffset = Y(k) - mean(ydata(2,:));

        % Actually plot the surface.
        surf(xdata + xoffset, ...
             ydata  + yoffset, zeros(2), ...
             'Parent', h, ...
             'FaceColor', 'texture', ...
             'EdgeColor', 'none', ...
             'CData', im, ...
             'FaceAlpha', 'texture', ...
             'AlphaData', double(alpha));
    end
end

Example

I wrote a little test script to show how this can be used and to show the results.

t = linspace(0, 2*pi, 13);
dX = cos(t(1:end-1));
dY = sin(t(1:end-1));
X = (3 * dX) + 5;
Y = (3 * dY) + 5;
scale = 1;

% Load the MATLAB logo as an example image
png = fullfile(matlabroot,'/toolbox/matlab/icons/matlabicon.gif');
[im, map] = imread(png);
im = ind2rgb(im, map);

% Determine alpha channel based on upper left hand corner pixel
flatim = reshape(im, [], 3);
alpha = ~ismember(flatim, squeeze(im(1,1,:)).', 'rows');
alpha = reshape(alpha, size(im(:,:,1)));

% Plot some things prior to creating the quiverpic object
fig = figure();
hax = axes('Parent', fig);
axis(hax, 'equal');

% Plot a full circle
t = linspace(0, 2*pi, 100);
plot((cos(t) * 3) + 5, (sin(t) * 3) + 5, '-')

hold(hax, 'on')

% Plot markers at all the quiver centers
plot(X, Y, 'o', 'MarkerFaceColor', 'w')

% Plot a random image behind everything to demonstrate transparency
him = imagesc(rand(9));
uistack(him, 'bottom')

axis(hax, 'equal')
colormap(fig, 'gray')
set(hax, 'clim', [-4 4]);

% Now plot the quiverpic
h = quiverpic(im, X, Y, dX, dY, 1, alpha);

axis(hax, 'tight')

Results

Absurdity

Same image with varying vectors and scaling

Any image of any aspect ratio will work just fine

这篇关于用图像替换颤抖箭头的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆