How to define a slicing like x(i).property in a custom class?

1 回表示 (過去 30 日間)
Daigo
Daigo 2024 年 7 月 14 日
コメント済み: Daigo 2024 年 7 月 15 日
One minor but useful thing about image feature classes in MATLAB is that they have varieties of ways to slice the feature points and get a subset. For example, let's say we extract SIFT features from an image:
I = imread('cameraman.tif');
points = detectSIFTFeatures(I);
fprintf('Number of detected points: %d\n', points.Count);
We have the following ways to slice them, which give us the same sets of results:
% Subset of indices
subs = 1:10;
% Method 1
a = points(subs);
aa = a.Location;
% Method 2
b = points.Location;
bb = b(subs,:);
% Method 3
c = points.Location(subs,:);
% Method 4
d = points(subs).Location;
I'm wondering how to define a custom class to achieve all these slicing methods. I tried to use subsref function to define a custom class like this:
% File name: MyCustomPoints.m
classdef MyCustomPoints
properties
Scale % (n x 1)
Location % (n x 2)
end
methods (Access='public')
% Constructor
function this = MyCustomPoints(scale, location)
this.Scale = scale;
this.Location = location;
end
% Slicing
function varargout = subsref(this, s)
switch s(1).type
case '()'
subs = s(1).subs{1};
varargout{1} = MyCustomPoints(this.Scale(subs,:), ...
this.Location(subs,:));
case '.'
% Handle property access
if isscalar(s)
varargout{1} = this.(s(1).subs);
else
[varargout{1:nargout}] = builtin('subsref', this, s);
end
end
end
end
end
Below is an example usage of this class:
% Example input
Scale = rand(100,1);
Location = rand(100,2);
myPoints = MyCustomPoints(Scale, Location);
subs = 1:3; % subset indices
% Method 1
a = myPoints(subs);
aa = a.Location; % --> Successful.
% Method 2
b = myPoints.Location;
bb = b(subs,:); % --> Successful.
% Method 3
c = myPoints.Location(subs,:); % --> Successful.
% Method 4
d = myPoints(subs).Location; % --> Failed.
Only the last slicing method gives me an error message:
Output argument "varargout{2}" (and possibly others) not assigned a value
in the execution with "MyCustomPoints/subsref" function.
Could you please advise how to modify my class to enable all the slicing methods above?

採用された回答

Matt J
Matt J 2024 年 7 月 14 日
編集済み: Matt J 2024 年 7 月 14 日
function varargout = subsref(this, s)
switch s(1).type
case '()'
subs = s(1).subs{1};
this = MyCustomPoints(this.Scale(subs,:), ...
this.Location(subs,:));
case '.'
% Handle property access
this=this.(s(1).subs);
end
s(1)=[];
if ~isempty(s)
[varargout{1:nargout}] = builtin('subsref', this, s);
else
varargout={this};
end
end
  4 件のコメント
Matt J
Matt J 2024 年 7 月 15 日
Perhaps the real problem you are experiencing is when you try to index without assigning the result to something. This can be addressed by overloading numArgumentsFromSubscript, as in the attached version
% Example input
Scale = rand(100,1);
Location = rand(100,2);
myPoints = MyCustomPoints(Scale, Location);
subs = 1:3; % subset indices
% Method 4
d=myPoints(subs).Location % -->
d = 3x2
0.3032 0.3080 0.1679 0.6912 0.8951 0.1266
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
% Additional Checks: No output arguments
myPoints(subs) % -->
ans =
MyCustomPoints with properties: Scale: [3x1 double] Location: [3x2 double]
myPoints(subs).Location % -->
ans = 3x2
0.3032 0.3080 0.1679 0.6912 0.8951 0.1266
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
myPoints(subs).Location(1)
ans = 0.3032
Daigo
Daigo 2024 年 7 月 15 日
@Matt J I haven't heard of numArgumentsFromSubscript before. Your code works like a charm. Thank you so much for your help!

サインインしてコメントする。

その他の回答 (0 件)

製品


リリース

R2024a

Community Treasure Hunt

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

Start Hunting!

Translated by