2013-06-24 6 views
0

Supposons que j'ai une matrice d'image RVB et que je souhaite y appliquer des filtres spatiaux. En général, je souhaite appliquer des opérations par élément (notez qu'il s'agit d'une affectation collégiale et que je ne suis pas autorisé à utiliser les fonctions intégrées disponibles dans la boîte à outils Traitement d'image). J'ai décidé d'écrire les filtres en tant que fonctions, puis d'appliquer bsxfun à ces fonctions sur l'image.Comment appliquer des opérations par éléments sans utiliser de boucles et sans influencer la vitesse

Un exemple simple serait ceci:
Je veux ajouter 50 à tous les niveaux de gris d'une image, puis remplacer tous les niveaux de gris avec au-dessus de 200 à 200. Voici mon code:

a='C:\Users\sepideh\Desktop\IP_abadpour\S45C-113050518040.jpg'; 
b=imread(a); 
b(:,:,1)=b(:,:,1)+50; 
b(:,:,2)=b(:,:,2)+50; 
b(:,:,3)=b(:,:,3)+50; 
c=reshape(b,[],1); 
d=bsxfun(@test,c,200); 

test est une fonction sous cette forme:

function Out = test(in,a) 
    if in>a 
     in=200; 
    end 
    Out = in; 
end 

ce code ne fonctionnera pas parce que, dans la deuxième ligne « dans> un » est une matrice ayant 0 et de 1 (je veux dire tous les éléments ne sont pas 1 et ne devrait pas être) afin que le débogueur ne se branche pas dans le e if déclaration.

Pourriez-vous me guider comment écrire cette fonction et comment appliquer des analyses spatiales et de Fourier sur l'image, sans affecter les performances et la vitesse d'exécution?

Répondre

1

est ici quelques suggestions:

  1. Tout d'abord, vous n'avez pas besoin d'ajouter 50 à chaque couche de la matrice RVB individuellement. Vous pouvez juste faire:

    b = b + 50; 
    
  2. Pourquoi vous remodeler b avant de passer à bsxfun? La taille de la sortie de bsxfun est la même que celle de votre image, il n'y a vraiment aucun besoin de remodeler quelque chose ici.

  3. En ce qui concerne votre fonction test, notez ce que les official documentation of bsxfun états:

    Une fonction binaire élément par élément de la forme C = fun(A,B) accepte des tableaux A et B de taille arbitraire mais égale et retourne la sortie de la même taille. Chaque élément du tableau de sortie C est le résultat d'une opération sur les éléments correspondants de A et B uniquement. fun doit également prendre en charge l'expansion scalaire, de sorte que si A ou B est un scalaire, C est le résultat de l'application du scalaire à chaque élément de l'autre tableau d'entrée.

    Ainsi bsxfun effectue l'expansion singleton et « gonfle » ses deux tableaux d'entrée à la même taille, puis applique la fonction spécifiée aux réseaux gonflés. La fonction par élément fun fonctionne, en fait, sur les tableaux, pas sur les scalaires. Je ne vois aucun gain réel en employant bsxfun ici.

    Cela dit, vous pouvez simplifier votre code comme indiqué dans Dan la suggestion de, ou la mettre en œuvre en fonction:

    function out = test(in, a); 
        out = in; 
        out(in > a) = a; 
    

    Je suppose que si vous utilisiez la valeur 210 au lieu de 200, vous souhaitez plafonner tous les niveaux de gris avec 210 ainsi, de sorte que vous devriez vraiment utiliser a au lieu d'une valeur codée en dur 200. vous pouvez aussi écrire votre fonction comme ceci:

    function out = test(in, a) 
        out = min(in, a); 
    

    puis invoquer avec:

    d = test(b, 200); 
    

    au lieu de d = bsxfun(@test, b, 200) plus compliqué.

    Une autre alternative consiste à utiliser arrayfun:

    d = arrayfun(@(x)test(x, 200), a); 
    

    ou

    d = arrayfun(@test, a, 200 * ones(size(a))); 
    

    dans lequel arrayfun appliquera test élément par élément, et la fonction test devrait fonctionner uniquement sur scalaires. Cependant, arrayfun s'exécute généralement plus lentement que les boucles, sans parler des opérations vectorisées.

  4. Pour l'analyse spatiale, consultez conv2 comme Dan suggéré (ou mettre en œuvre votre propre convolution 2-D, pour le bien de la pratique). Pour l'analyse de Fourier, envisagez d'utiliser les fonctions fft2 et ifft2 dans le domaine fréquentiel.

Espérons que cela aide!

+0

Eh bien, la fonction que vous avez suggérée fonctionne bien, sauf que la fonction max doit être remplacée par min.Mais une autre question s'est levée. Pourquoi ma fonction ne fonctionne pas. Je veux dire que si vous arrêtez le débogueur dans la fonction, vous verrez que "in" n'est pas un scalaire et est une matrice quand le test est invoqué et vous avez dit: il n'y a rien de mal à votre fonction car elle est actuellement écrite ?? !! – sepideh

+0

@sepideh Oh, vous avez raison, ma mauvaise! S'il vous plaît voir mon edit. –

1

Donc, pour l'exemple que vous avez affichée, vous pouvez simplement profiter du fait que la plupart des opérateurs dans le travail de Matlab en mode natif sur les matrices:

b=imread(a); 
c = a + 50; 
c(c > 200) = 200; 

Il est aussi simple que cela.

Pour le filtrage, si vous êtes autorisé, je voudrais jeter un oeil à la fonction conv2. Vous pouvez faire un filtrage spatial de cette façon sans vous transformer en domaine fréquentiel (rappelez-vous, la multiplication d'un filtre dans le domaine fréquentiel est la même que la convolution dans le domaine spatial). Ainsi, par exemple un filtre passe-bas de base:

lpf = ones(5)./25; 
c(:,:,1) = conv2(b(:,:,1), lpf); 
c(:,:,2) = conv2(b(:,:,2), lpf); 
c(:,:,3) = conv2(b(:,:,3), lpf); 
Questions connexes