Constraining imline to points of an existing imellipse?

1 次查看(过去 30 天)
I'd like to draw a line and then be able to adjust the endpoints of that line while restricting them to the vertices of an ellipse. I don't understand how to use the setPositionConstraintFcn though.
function drawStuff
% Draw ellipse.
figure;
e = imellipse;
global ePos
ePos = wait(e)';
hold on;
plot(ePos(:,1),ePos(:,2),'color','r'); % Replace imroi with a plotted line object.
hold off;
delete(e);
% Draw a line constrained by points of ellipse.
iFirst2Pts = randi(size(ePos,1),2,1);
while iFirst2Pts(1) == iFirst2Pts(2) % Two unique initial points for line.
iFirst2Pts(2) = randi(size(ePos,1));
end
l = imline(gca,ePos(iFirst2Pts,1),ePos(iFirst2Pts,2));
l.setColor('g');
l.setPositionConstraintFcn(@constrainNewPos);
lPos = l.wait;
plot(lPos(:,1),lPos(:,2),'color','g');
delete(l);
% Create constraint function
function constrainNewPos
for idx = 1:100
% Check if both points are within polygon of ellipse.
linePos = l.getPosition;
for jdx = 1:2
in = inpolygon(linePos(jdx,1),linePos(jdx,2),ePos(1,:),ePos(2,:));
% If point is not in polygon, shift to nearest point on ellipse.
if ~in
% Compute Euclidean distances.
distances = sqrt(sum(bsxfun(@minus,ePos',linePos(jdx,:)).^2,2));
% Find smallest distance, use to index into ellipse points.
linePos(jdx,:) = ePos(:,distances == min(distances))';
l.setPosition = linePos;
end
end
pause(.0001);
end
end
end
-------------------------
Error using drawStuff/constrainNewPos Too many input arguments.
Error in imline>imlineAPI/endPointMotion (line 590) new_position=position_constraint_function(candidate_position);
Error in imline>@(varargin)endPointMotion(h_hit) (line 525) @(varargin) endPointMotion(h_hit) );
Error in iptaddcallback/callbackProcessor (line 149) fun(varargin{:});
Error while evaluating Figure WindowButtonMotionFcn. fun(varargin{:});
-------------------------

回答(1 个)

Tim Jackman
Tim Jackman 2018-9-27
This is the approach that I would take. First, beginning in 18b the Image Processing Toolbox has a new suite of ROI tools. I would suggest using those. The basic work flow to do this would be as follows:
1. Draw an ellipse and turn off all interactions so it is static after being drawn
2. Create a line ROI object
3. Add a listener to listen for any line ROI motion
4. In the listener callback, check if the line is outside the ellipse and set the previous position if true.
Here is an example to accomplish this task:
function lineInsideEllipse
% Draw an ellipse and then turn off all interactions
hEllipse = drawellipse('InteractionsAllowed','none');
% Create an empty line ROI
hLine = images.roi.Line('Color','red');
% Listen to any line movement
addlistener(hLine,'MovingROI',@(src,evt) movingCallback(src,evt,hEllipse));
% Begin interactive placement of the line starting from the ellipse center
beginDrawingFromPoint(hLine,hEllipse.Center);
end
function movingCallback(hLine,evt,hEllipse)
xCandidates = evt.CurrentPosition(:,1);
yCandidates = evt.CurrentPosition(:,2);
% Check if the line current position is now outside the ellipse
TF = inROI(hEllipse, xCandidates, yCandidates);
if ~all(TF)
% Line is at least partially outside the ellipse, reset the line
% position to be the previous position
hLine.Position = evt.PreviousPosition;
end
end

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by