MATLAB图像处理:68:测量图像中的距离


Home


此示例说明如何使用线 ROI 来测量图像中的距离。您还可以将测量值校准为真实世界的值并指定单位。该示例说明了如何在无需进入任何特定绘图模式的情况下无缝添加、编辑和删除 ROI。
将图像读入工作区并显示图像
将图像读入工作区。

im = imread('concordorthophoto.png');

获取有关图像的数据,例如其大小,并将数据存储在可以传递给回调函数的结构中。
sz = size(im);
myData.Units = 'pixels';
myData.MaxValue = hypot(sz(1),sz(2));
myData.Colormap = hot;
myData.ScaleFactor = 1;

显示图像。
hIm = imshow(im);


为图像上的ButtonDownFcn指定回调函数。将myData结构传递给回调函数。此回调函数创建线对象并开始绘制 ROI。
hIm.ButtonDownFcn = @(~,~) startDrawing(hIm.Parent,myData);


创建回调函数以开始绘制 ROI
创建与ButtonDownFcn回调一起使用的函数以创建线 ROI。该函数:
实例化一个线 ROI 对象。
设置侦听器以对 ROI 的点击和移动做出反应。
向包含“全部删除”选项的 ROI 添加自定义上下文菜单。
开始绘制 ROI,以图像中单击的点为起点。
function startDrawing(hAx,myData)
​
% Create a line ROI object. Specify the initial color of the line and
% store the |myData| structure in the |UserData| property of the ROI.
h = images.roi.Line('Color',[0, 0, 0.5625],'UserData',myData);
​
% Set up a listener for movement of the line ROI. When the line ROI moves,
% the |updateLabel| callback updates the text in the line ROI label and
% changes the color of the line, based on its length.
addlistener(h,'MovingROI',@updateLabel);
​
% Set up a listener for clicks on the line ROI. When you click on the line
% ROI, the |updateUnits| callback opens a GUI that lets you specify the
% known distance in real-world units, such as, meters or feet.
addlistener(h,'ROIClicked',@updateUnits);
​
% Get the current mouse location from the |CurrentPoint| property of the
% axes and extract the _x_ and _y_ coordinates.
cp = hAx.CurrentPoint;
cp = [cp(1,1) cp(1,2)];
​
% Begin drawing the ROI from the current mouse location. Using the
% |beginDrawingFromPoint| method, you can draw multiple ROIs.
h.beginDrawingFromPoint(cp);
​
% Add a custom option to the line ROI context menu to delete all existing
% line ROIs.
c = h.UIContextMenu;
uimenu(c,'Label','Delete All','Callback',@deleteAll);
​
end


创建回调函数以更新 ROI 标签和颜色
创建在 ROI 线移动时(即'MovingROI'事件发生时)调用的函数。此函数使用线的长度更新 ROI 标签,并根据线的长度更改线的颜色。
当 ROI 移动时,会重复调用此函数。如果您只想在移动完成后更新 ROI,请改为监听'ROIMoved'事件。
function updateLabel(src,evt)
​
% Get the current line position.
pos = evt.Source.Position;
​
% Determine the length of the line.
diffPos = diff(pos);
mag = hypot(diffPos(1),diffPos(2));
​
% Choose a color from the color map based on the length of the line. The
% line changes color as it gets longer or shorter.
color = src.UserData.Colormap(ceil(64*(mag/src.UserData.MaxValue)),:);
​
% Apply the scale factor to line length to calibrate the measurements.
mag = mag*src.UserData.ScaleFactor;
​
% Update the label.
set(src,'Label',[num2str(mag,'%30.1f') ' ' src.UserData.Units],'Color',color);
​
end

创建回调函数以更新测量单位
创建双击 ROI 标签时调用的函数。此功能打开一个弹出对话框,您可以在其中输入有关实际距离和单位的信息。
该函数监听'ROIClicked'事件,使用事件数据来检查点击的类型和被点击的 ROI 部分。
弹出对话框提示您输入此测量的已知距离和单位。使用此信息,您可以将所有 ROI 测量值校准为真实世界单位。
function updateUnits(src,evt)
​
% When you double-click the ROI label, the example opens a popup dialog box
% to get information about the actual distance. Use this information to
% scale all line ROI measurements.
if strcmp(evt.SelectionType,'double') && strcmp(evt.SelectedPart,'label')
​
    % Display the popup dialog box.
    answer = inputdlg({'Known distance','Distance units'},...
        'Specify known distance',[1 20],{'10','meters'});
​
    % Determine the scale factor based on the inputs.
    num = str2double(answer{1});
​
    % Get the length of the current line ROI.
    pos = src.Position;
    diffPos = diff(pos);
    mag = hypot(diffPos(1),diffPos(2));
​
    % Calculate the scale factor by dividing the known length value by the
    % current length, measured in pixels.
    scale = num/mag;
​
    % Store the scale factor and the units information in the |myData|
    % structure.
    myData.Units = answer{2};
    myData.MaxValue = src.UserData.MaxValue;
    myData.Colormap = src.UserData.Colormap;
    myData.ScaleFactor = scale;
​
    % Reset the data stored in the |UserData| property of all existing line
    % ROI objects. Use |findobj| to find all line ROI objects in the axes.
    hAx = src.Parent;
    hROIs = findobj(hAx,'Type','images.roi.Line');
    set(hROIs,'UserData',myData);
​
    % Update the label in each line ROI object, based on the information
    % collected in the input dialog.
    for i = 1:numel(hROIs)
​
        pos = hROIs(i).Position;
        diffPos = diff(pos);
        mag = hypot(diffPos(1),diffPos(2));
​
        set(hROIs(i),'Label',[num2str(mag*scale,'%30.1f') ' ' answer{2}]);
​
    end
​
    % Reset the |ButtonDownFcn| callback function with the current |myData|
    % value.
    hIm = findobj(hAx,'Type','image');
    hIm.ButtonDownFcn = @(~,~) startDrawing(hAx,myData);
​
end
​
end


创建回调函数以删除所有 ROI
创建删除所有 ROI 的函数。在startDrawing回调函数中,向每条线 ROI 添加了一个自定义上下文菜单项。这是与该自定义上下文菜单关联的回调。此回调使用findobj函数搜索 ROI 类型并删除任何找到的 ROI。
function deleteAll(src,~)
​
hFig = ancestor(src,'figure');
hROIs = findobj(hFig,'Type','images.roi.Line');
delete(hROIs)
​
end


======================================================================
我的测试结果及程序
下面是我测试的代码:

 


注:本文根据MATLAB官网内容修改而成。