Ceci est une question intéressante. Ce qui est intéressant, c'est que votre approche est presque parfaite. La seule raison pour laquelle cela échoue est que struct
ne peut pas être construit en utilisant une entrée scalaire numérique (c'est-à-dire struct(3)
). La raison pour laquelle je mentionne cela est parce que quelque part lors de l'exécution de nlfilter
(en particulier dans mkconstarray.m
), il appelle le code suivant:
repmat(feval(class, value), size);
Où:
class
est 'struct'
.
value
est 0
.
size
est le size()
de l'image d'entrée, par ex. [100,100]
.
... et cela échoue parce feval('struct', 0)
, ce qui équivaut à struct(0)
- et ce que nous savons déjà invalide.
Alors, que faisons-nous? Créez une classe personnalisée que peut être construite de cette façon!
Voici un exemple d'une telle classe:
classdef MyStatsClass % Value class
properties (GetAccess = public, SetAccess = private)
[email protected] scalar = NaN; % Maximum
[email protected] scalar = NaN; % Minimum
[email protected] scalar = NaN; % Mean
[email protected] scalar = NaN; % Mean absolute deviation y = mean(abs(X-mean(x)))
[email protected] scalar = NaN; % Median
[email protected] scalar = NaN; % Root mean square
[email protected] scalar = NaN; % Stardard deviation
[email protected] scalar = NaN; % Variance
[email protected] scalar = NaN; % Range
end % properties
methods (Access = public)
%% Constructor:
function obj = MyStatsClass(vec)
%% Special case:
if (nargin == 0) || (numel(vec) == 1) && (vec == 0)
% This happens during nlfilter allocation
return
end
%% Regular case:
obj.MAX = max(vec(:));
obj.MIN = min(vec(:));
obj.MEA = mean(vec(:));
obj.MAD = mad(vec(:));
obj.MED = median(vec(:));
obj.RMS = rms(vec(:));
obj.STD = std(vec(:));
obj.VAR = var(vec(:));
obj.RAN = obj.MAX - obj.MIN;
end % default constructor
end % public methods
end % classdef
Et voici comment vous pouvez l'utiliser:
function imF = q35693068(outputAsStruct)
if nargin == 0 || ~islogical(outputAsStruct) || ~isscalar(outputAsStruct)
outputAsStruct = false;
end
rng(35693068); % Set the random seed, for repeatability
WINDOW_SZ = 3;
im = randn(100);
imF = nlfilter(im, [WINDOW_SZ WINDOW_SZ], @MyStatsClass);
% If output is strictly needed as a struct:
if outputAsStruct
warning off MATLAB:structOnObject
imF = arrayfun(@struct,imF);
warning on MATLAB:structOnObject
end
Notez que j'ai ajouté une entrée en option (outputAsStruct
) qui peut forcer la sortie pour être un tableau struct
(et non un tableau du type de notre classe personnalisée, qui est fonctionnellement identique à une lecture seule struct
).
Notez également que par défaut nlfilter
PADS tableau avec des zéros, ce qui signifie que la sortie (1,1)
fonctionnera sur un tableau qui ressemble à ceci (en supposant WINDOW_SZ=3
):
[0 0 0
0 1.8096 0.5189
0 -0.3434 0.6586]
et non sur im(1:WINDOW_SZ,1:WINDOW_SZ)
qui est:
[ 1.8096 0.5189 0.2811
-0.3434 0.6586 0.8919
-0.1525 0.7549 0.4497]
le « résultat attendu » pour im(1:WINDOW_SZ,1:WINDOW_SZ)
on trouvera plus loin « intérieur » de la matrice de sortie (dans le cas de WINDOW_SZ=3
à l'indice (2,2)
).
Vous ne pouvez pas le faire directement car, comme vous l'écrivez, 'nlfilter' accepte une poignée de fonction scalaire. Vous pouvez écrire une enveloppe qui appelle 'nlfilter' une fois pour chaque champ de la structure' out'. –
quel est l'emballage? Je ne comprends pas bien. Pouvez-vous éditer un exemple de code pour moi? Maintenant, j'ai une idée, je peux enregistrer le tableau de structure out comme un fichier mat.Mais si je fais cela, il y aura trop de fichiers mat.Si je veux utiliser le résultat de sortie, il faudra beaucoup de temps pour charger ces fichiers mat.Je veux juste enregistrer la sortie à un fichier mat. Avez-vous une bonne idée? Merci! @Itamar Katz –
On ne sait pas quelle est la sortie désirée. 'nlfilter' renvoie une matrice, si votre structure a' n' champs, et vous avez un tableau de telles structures de longueur 'm', alors vous obtenez des matrices' m * n'. Comment voulez-vous les stocker? –