0
votes

L'équivalent imgaussfilt de Matlab en Python

J'essaie de reproduire le comportement d'imgaussfilter de Matlab en Python mais je n'ai pas pu reproduire les résultats. La documentation n'aide pas beaucoup car il n'y a pas d'explication de ce qui est exactement fait (par exemple en quoi cette fonction est-elle différente de fspecial ou en quoi elle diffère de l'imsmooth d'Octave (avec Gaussian comme argument).

Code Matlab

[[-0.02936397 -0.03168425 -0.03437067 ...  0.03136461  0.02864492
   0.0258515 ]
 [-0.03212099 -0.03474336 -0.03775951 ...  0.03507491  0.03209814
   0.0290614 ]
 [-0.03512988 -0.03808872 -0.04147083 ...  0.03873842  0.03549169
   0.03219317]
 ...
 [-0.07713819 -0.08337491 -0.08975279 ... -0.04314214 -0.03945259
  -0.03606263]
 [-0.07145471 -0.07714821 -0.0829767  ... -0.03986643 -0.03641586
  -0.03323725]
 [-0.06605119 -0.07122205 -0.07651907 ... -0.03684542 -0.03362923
  -0.03065134]]

avec sortie

skimage.filters.gaussian(image, sigma=s,mode = 'nearest',truncate=2.0)

Le plus proche que j'ai réussi à obtenir avec Python a été:

Python

 [[-0.02936392 -0.03168419 -0.0343706  ...  0.03136455  0.02864487
   0.02585145]
 [-0.03212093 -0.0347433  -0.03775943 ...  0.03507484  0.03209807
   0.02906134]
 [-0.03512981 -0.03808864 -0.04147075 ...  0.03873834  0.03549163
   0.03219311]
 ...
 [-0.07713804 -0.08337475 -0.08975262 ... -0.04314206 -0.03945251
  -0.03606256]
 [-0.07145457 -0.07714807 -0.08297654 ... -0.03986635 -0.03641579
  -0.03323718]
 [-0.06605107 -0.07122191 -0.07651892 ... -0.03684535 -0.03362917
  -0.03065128]]

avec sortie

imgaussfilt(image,sigma)

qui est similaire mais pas exactement le même résultat. Existe-t-il une méthode qui s'en rapproche mieux? Dois-je modifier l'un des paramètres?

EDIT: Si vous cherchez une approximation proche en utilisant OpenCV @avisionx a fourni un bon point de départ dans les solutions.


5 commentaires

vous pouvez consulter la version scipy , voir ici


Je vais regarder OpenCV Gaussian Blur


@MrFuppes Je viens de l'essayer et il semble que la version scipy est la même que la version skimage.


Vous obtenez les mêmes valeurs jusqu'à 6 chiffres décimaux. Êtes-vous sûr que la différence compte compte tenu du bruit et des erreurs de quantification dans l'image d'entrée?


@CrisLuengo Oui. J'essaye de reproduire le plus fidèlement possible


3 Réponses :


2
votes

Il y a plusieurs causes possibles à cela. Puisque Matlab n'est pas un logiciel open source, il est impossible d'en connaître la cause exacte, mais nous pouvons faire des suppositions éclairées.

Concernant ce que fait le filtrage gaussien : il remplace chaque pixel par une somme pondérée de ses voisins. La pondération est déterminée par la fonction de densité de probabilité gaussienne , et le poids exact est déterminé par sigma mais aussi par le paramètre truncate que vous pouvez voir dans la documentation scipy.ndimage.gaussian_filter . Ce paramètre est nécessaire car, techniquement, la fonction gaussienne ne se désintègre jamais à zéro, elle s'approche juste de zéro lorsque la distance va vers l'infini, donc un flou gaussien "parfait" aurait besoin de faire la somme d'un nombre infini de pixels voisins, ce qui est impossible. Par conséquent, la fonction doit décider à quelle distance vous êtes suffisamment proche de zéro pour arrêter la somme des choses.

Un autre facteur de complication est que le flou gaussien est séparable , ce qui signifie que vous pouvez faire un flou 2D (ou nD) en floutant séparément le long de chaque axe en séquence, ce qui peut réduire les coûts de calcul. La séparabilité affecte l'ordre de calcul et le calcul en virgule flottante n'est pas exact , donc si Matlab et Python effectuent les opérations dans un ordre différent, vous vous attendez à des résultats légèrement différents.

Même si vous filtrez les axes exactement dans le même ordre (vous pouvez y parvenir, par exemple, en transposant l'image en Python, en la filtrant, puis en la transposant), les bibliothèques de calcul de tableau de bas niveau sous-jacentes peuvent sommer les tableaux dans un ordre différent, ce qui changerait encore une fois les résultats exacts.

En bref, quelques causes possibles des différences que vous voyez:

  • troncature différente
  • différentes implémentations (séparer le filtre ou non)
  • ordre différent de traitement des axes
  • ordre différent des sommes de bas niveau

Il n'y a peut-être aucun moyen de les démêler, et à la fin mon conseil reflète le commentaire de Cris Luengo: vos résultats ne devraient probablement pas reposer sur des valeurs plus précises que six chiffres significatifs. Une correspondance exacte entre Matlab et Python n'aura ici aucun sens, car aucun des deux ne peut garantir une précision parfaite par rapport à la valeur théorique d'un filtre gaussien. Les deux sont des approximations et une correspondance exacte signifie uniquement que vous faites les mêmes erreurs d'approximation dans les deux.


3 commentaires

Bon résumé. Encore une chose à ajouter: MATLAB utilise soit une implémentation séparable, soit une implémentation de domaine de Fourier selon sigma . Il existe également des filtres récursifs, mais je ne sais pas si l'une ou l'autre des méthodes d'OP les utilise.


Oh ouais, j'ai totalement oublié la convolution de Fourier! 🤦‍♂️


Merci beaucoup pour votre réponse Juan. Je comprends qu'essayer de produire le même résultat à partir de deux langues n'est pas quelque chose qui se fait habituellement ou qui est souhaitable. S'en tenir aux approximations, c'est bien. Cependant, numpy et d'autres bibliothèques de traitement d'image essaient dans de nombreux cas d'émuler les résultats Matlab, donc j'espérais trouver un moyen de reproduire le résultat exact. Cela pourrait être une chose, après tout. Je vais toujours essayer de garder la question ouverte un peu pour voir si quelqu'un a un moyen de la résoudre, sinon je choisirai la vôtre comme réponse car c'est une très bonne réponse à la question.



1
votes

J'ai pu obtenir une correspondance relativement bonne (meilleure que 10e-10 %) entre imgaussfilt appelé avec l'option de remplissage circular et scipy.ndimage.gaussian_filter appelé avec mode='wrap' paramètre mode='wrap' , à condition que imgaussfilt utilise la taille de filtre par défaut de 2*ceil(2*sigma)+1 et gaussian_filter spécifie truncate=np.ceil(2*sigma)/sigma . Ces paramètres donnent le même rayon et la même taille globale pour le noyau gaussien sous-jacent, pour le cas de remplissage circular . Je n'ai pas testé d'autres types de rembourrage.


0 commentaires

1
votes

Récemment, je travaillais sur la conversion d'un code Matlab en python et je cherchais à peu près la même chose sur Internet et la documentation pour les fonctions a trouvé exactement les mêmes résultats avec l'implémentation d'OpenCV.

import cv2
# in python
cv2.GaussianBlur(image, ksize=(0, 0), sigmaX=100, borderType=cv2.BORDER_REPLICATE)

est équivalent à

% In Matlab
imgaussfilt(image, 100)

entrez la description de l'image ici


4 commentaires

Exact comme dans les valeurs à virgule flottante identiques? C'est hautement improbable. Même des versions différentes de MATLAB peuvent ne pas produire une sortie numériquement identique. De plus, OpenCV dans ce code produit probablement une sortie entière, pas une sortie à virgule flottante comme le cas d'OP.


Je pense que cette tentative est digne d'éloges car elle est une approximation d'une solution potentiellement exacte. J'ai voté pour - et je l'ai souligné dans ma question initiale - parce que je pense que les personnes qui cherchent à résoudre ce problème à l'avenir pourraient prendre en considération cette approche. Cependant, comme le dit @Cris Luengo, la bonne réponse est toujours valable: il n'y a pas de réplication parfaite du résultat Matlab en Python.


@CrisLuengo Par exact ici, je pourrais obtenir le résultat similaire / le plus proche dans Matlab et python, évidemment, comment l'arrondi et les algorithmes sont écrits dans chaque bibliothèque affecteront la sortie, mais mon point principal est borderType = cv2.BORDER_REPLICATE est quelque chose qu'il faut changer par défaut la sortie ne sera pas la même


@avisionx: OP avait déjà des résultats identiques jusqu'à 6 chiffres décimaux, et une réponse a montré une égalité jusqu'à 10 chiffres décimaux. Ils ont évidemment compris comment faire correspondre la condition aux limites. Cette réponse montre juste des résultats visuellement similaires, je ne vois pas comment cela ajoute de la valeur.