web-dev-qa-db-fra.com

Effacer une image

J'essaie de débloquer une image en Python mais j'ai rencontré quelques problèmes. Voici ce que j'ai essayé, mais gardez à l'esprit que je ne suis pas un expert sur ce sujet. Selon mon comprendre, si vous connaissez la fonction d'étalement des points, vous devriez pouvoir débloquer l'image tout simplement en effectuant une déconvolution. Cependant, cela ne semble pas fonctionner et je ne sais pas si je fais quelque chose de stupide ou si je ne comprennent tout simplement pas les choses correctement. Dans le livre de Mark Newman sur la physique computationnelle (en utilisant Python), il aborde ce sujet dans le problème 7.9. l'objectif du problème est de débloquer l'image à l'aide d'un gaussien, ce qui est accompli en divisant la FFT 2D de l'image floue par la FFT 2D du psf puis en prenant la transformée inverse. Cela fonctionne assez bien.

Pour étendre ce problème, je voulais effacer une image réelle prise avec un appareil photo qui était délibérément flou. J'ai donc installé un appareil photo et pris deux séries de photos. La première série d'images était au point. Le premier était d'une très petite lumière LED dans une pièce complètement sombre et le second était d'un morceau de papier avec du texte dessus (à l'aide du flash). Puis, sans changer aucune des distances ou quoi que ce soit, j'ai changé le réglage de mise au point sur l'appareil photo afin que le texte soit très flou. J'ai ensuite pris une photo du texte à l'aide du flash et pris une deuxième photo de la LED (sans flash). Voici les images floues.

Blurred Text

Blurred Point Light Source

Maintenant, selon ma compréhension, l'image de la source de lumière ponctuelle floue devrait être la fonction d'étalement du point, et en tant que telle, je devrais pouvoir l'utiliser pour débloquer mon image. Le problème est que lorsque je le fais, j'obtiens une image qui ressemble à du bruit. Après avoir fait quelques recherches, il semble que le bruit puisse être un gros problème lors de l'utilisation des techniques de déconvolution. Cependant, étant donné que j'ai mesuré ce que je pense être la fonction d'étalement de points exacte, je suis surpris que le bruit soit un problème ici.

Une chose que j'ai essayée était de remplacer les petites valeurs (inférieures à epsilon) dans la transformation psf par 1 ou par epsilon, et j'ai essayé cela avec une large gamme de valeurs pour epsilon. Cela a produit une image qui n'était pas seulement du bruit, mais n'est pas non plus une version floue de l'image; cela ressemble à une version étrange et floue de l'image d'origine (non floue). Voici une image de mon programme (vous pouvez ignorer la valeur de sigma, qui n'a pas été utilisée dans ce programme).

enter image description here

Je crois que je fais face à un problème de bruit, mais je ne sais pas pourquoi et je ne sais pas quoi faire à ce sujet. Tout conseil serait très apprécié (en gardant à l'esprit que je ne suis pas un expert dans ce domaine).

Notez que je n'ai délibérément pas publié le code parce que je pense que c'est quelque peu hors de propos à ce stade. Mais je serais heureux de le faire si quelqu'un pense que ce serait utile. Je ne pense pas que ce soit un problème de programmation car j'ai utilisé la même technique et cela fonctionne bien lorsque j'ai la fonction d'étalement de points connue (comme lorsque je divise la FFT de l'image originale au point par la FFT de la sortie de -focus image puis transformation inverse). Je ne comprends tout simplement pas pourquoi je n'arrive pas à utiliser ma fonction d'étalement ponctuel mesurée expérimentalement.

8
DJElectric

Le problème que vous avez cherché à résoudre est, malheureusement, plus difficile que vous ne le pensez. Permettez-moi de l'expliquer en quatre parties. La première section suppose que vous êtes à l'aise avec la transformée de Fourier.

  1. Pourquoi vous ne pouvez pas résoudre ce problème avec une simple déconvolution.
  2. Un aperçu de la façon dont l'effacement des images peut être effectué.
  3. Déconvolution par FFT et pourquoi c'est une mauvaise idée
  4. Une méthode alternative pour effectuer la déconvolution

Mais d'abord, quelques notations:

J'utilise [~ # ~] i [~ # ~] pour représenter une image et [~ # ~] k [~ # ~] pour représenter un noyau de convolution. I * K est la convolution de l'image [~ # ~] i [~ # ~] avec le noyau [~ # ~] k [~ # ~] . F (I) est la transformée de Fourier (n-dimensionnelle) de la image [~ # ~] i [~ # ~] et F (K) est la transformée de Fourier du noyau de convolution [~ # ~] k [~ # ~] (c'est aussi appelé la fonction d'étalement des points, ou PSF). De même, Fi est la transformée de Fourier inverse.

Pourquoi vous ne pouvez pas résoudre ce problème avec une déconvolution simple:

Vous avez raison lorsque vous dites que nous pouvons récupérer une image floue Ib = I * K en divisant la transformée de Fourier de Ib par la transformée de Fourier de [~ # ~] k [~ # ~] . Cependant, le flou de l'objectif n'est pas une opération de flou par convolution. Il s'agit d'une opération de flou par convolution modifiée où le noyau de flou [~ # ~] k [~ # ~] dépend de la distance à l'objet que vous avez photographié. Ainsi, le noyau change de pixel en pixel.

Vous pourriez penser que ce n'est pas un problème avec votre image, car vous avez mesuré le noyau correct à la position de l'image. Cependant, cela pourrait ne pas être le cas, car la partie de l'image qui est éloignée peut influencer la partie de l'image qui est proche. Une façon de résoudre ce problème consiste à rogner l'image de sorte que seul le papier soit visible.

Pourquoi la déconvolution par FFT est une mauvaise idée:

Le théorème de convolution indique que I * K = Fi ( F (I) F (K)) . Ce théorème conduit à l'hypothèse raisonnable que si nous avons une image, Ib = I * K floue par un noyau de convolution [~ # ~] k [~ # ~] , alors nous pouvons récupérer l'image floue en calculant I = ( F (Ib)/ F (K)) .

Avant de voir pourquoi c'est une mauvaise idée, je veux obtenir une certaine intuition pour ce que signifie le théorème de convolution. Lorsque nous convolons une image avec un noyau, cela revient à prendre les composantes fréquentielles de l'image et à la multiplier élément par élément avec les composantes fréquentielles du noyau.

Maintenant, laissez-moi vous expliquer pourquoi il est difficile de déconvoluer une image avec la FFT. Le flou, par défaut, supprime les informations haute fréquence. Ainsi, les hautes fréquences de [~ # ~] k [~ # ~] doivent aller vers zéro. La raison en est que les informations haute fréquence de [~ # ~] i [~ # ~] sont perdues quand elles sont floues - donc , les composantes haute fréquence de Ib doivent aller vers zéro. Pour que cela se produise, les composantes haute fréquence de [~ # ~] k [~ # ~] doivent également aller vers zéro.

Du fait que les composantes haute fréquence de [~ # ~] k [~ # ~] sont presque nulles, nous voyons que la haute fréquence les composantes de Ib sont amplifiées de manière significative (car nous divisons presque par zéro) lorsque nous déconvoluons avec la FFT. Ce n'est pas un problème dans le cas sans bruit.

Dans le cas bruyant, cependant, c'est un problème. La raison en est que le bruit est, par définition, une information haute fréquence. Ainsi, lorsque nous essayons de déconvoluer Ib , le bruit est amplifié dans une mesure presque infinie. C'est la raison pour laquelle la déconvolution par la FFT est une mauvaise idée.

De plus, vous devez considérer comment l'algorithme de convolution basé sur la FFT traite les conditions aux limites. Normalement, lorsque nous convolutons des images, la résolution diminue quelque peu. Il s'agit d'un comportement indésirable, nous introduisons donc des conditions aux limites qui spécifient les valeurs des pixels des pixels en dehors de l'image. Des exemples de telles conditions aux limites sont

  1. Les pixels à l'extérieur de l'image ont la même valeur que le pixel le plus proche à l'intérieur de l'image
  2. Les pixels en dehors de l'image ont une valeur constante (par exemple 0)
  3. L'image fait partie d'un signal périodique, donc la rangée de pixels au-dessus de la rangée supérieure est égale à la rangée inférieure de pixels.

La condition limite finale a souvent un sens pour les signaux 1D. Pour les images, cependant, cela n'a pas beaucoup de sens. Malheureusement, le théorème de convolution spécifie que des conditions aux limites périodiques sont utilisées.

En plus de cela, il semble que la méthode d'inversion basée sur la FFT soit significativement plus sensible aux noyaux erronés que les méthodes itératives (par exemple la descente en gradient et la FISTA).

Une méthode alternative pour effectuer la déconvolution

Il peut sembler que tout espoir est perdu maintenant, car toutes les images sont bruyantes et la déconvolution augmentera le bruit. Cependant, ce n'est pas le cas, car nous avons des méthodes itératives pour effectuer la déconvolution. Permettez-moi de commencer par vous montrer la méthode itérative la plus simple.

Soit || I || ² soit la somme au carré de tous [~ # ~] i [~ # ~] ' s pixels. Résoudre l'équation

Ib = I * K

par rapport à [~ # ~] i [~ # ~] équivaut alors à résoudre le problème d'optimisation suivant:

min L(I) = min || I * K - Ib || ²

en ce qui concerne [~ # ~] i [~ # ~] . Cela peut être fait en utilisant la descente du gradient, car le gradient de [~ # ~] l [~ # ~] est donné par

DL = Q * (I * K - Ib)

[~ # ~] q [~ # ~] est le noyau que vous obtenez en transposant [~ # ~ ] k [~ # ~] (il s'agit également du filtre adapté dans la littérature sur le traitement du signal).

Ainsi, vous pouvez obtenir l'algorithme itératif suivant qui effacera une image.

from scipy.ndimage import convolve

blurred_image = # Load image
kernel = # Load kernel/psf
learning_rate = # You need to find this yourself, do a logarithmic line search. Small rate will always converge, but slowly. Start with 0.4 and divide by 2 every time it fails.
maxit = 100

def loss(image):
    return np.sum(convolve(image, kernel) - blurred_image)

def gradient(image):
    return convolve(convolve(image, kernel) - blurred_image)

deblurred = blurred_image.copy()
for _ in range(maxit):
    deblurred -= learning_rate*gradient(image)

La méthode ci-dessus est peut-être la plus simple des algorithmes de déconvolution itérative. La façon dont ceux-ci sont utilisés dans la pratique se fait par le biais d'algorithmes de déconvolution régularisés. Ces algorithmes fonctionnent en spécifiant d'abord une fonction qui mesure la quantité de bruit dans une image, par ex. TV (I) (la variation totale de [~ # ~] i [~ # ~] ). Ensuite, la procédure d'optimisation est effectuée sur L (I) + wTV (I) . Si vous êtes intéressé par de tels algorithmes, je vous recommande de lire l'article de FISTA par Amir Beck et Marc Teboulle. Le papier est assez lourd en mathématiques, mais vous n'avez pas besoin de comprendre la plupart de celui-ci - seulement comment implémenter l'algorithme de effacement TV.

En plus d'utiliser un régularisateur, nous utilisons des méthodes accélérées pour minimiser la perte L (I) . Un tel exemple est la descente à gradient accéléré de Nesterov. Voir Redémarrage adaptatif pour les schémas de dégradé accéléré par Brendan O'Donoghue, Emmanuel Candes pour plus d'informations sur ces méthodes.

Un aperçu de la façon dont l'effacement des images peut être effectué.

  1. Recadrez votre image pour que tout soit à la même distance de la caméra
  2. Trouvez le noyau de convolution de la même manière que vous l'avez fait maintenant (Testez d'abord votre algorithme de déconvolution sur des images synthétiquement floues)
  3. Implémenter une méthode itérative pour calculer la déconvolutoin
  4. Déconvoluez l'image.
9
Yngve Moe