Skip to main content

Filtering a periodic noise

Note the dithering in the image below

Download original notebook
(*VB[*)(FrontEndRef["42d99f3c-deb2-402c-ac07-1b664f611765"])(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KRCeEJBwK8rPK3HNS3GtSE0uLUlMykkNVgEKmxilWFqmGSfrpqQmGemaGBgl6yYmG5jrGiaZmZmkmRkampuZAgCIexVv"*)(*]VB*)

We can use 2D Fourier transformation and filtern it out in the frequency space. Firstly, lets convert an image to normal array.

donald = ImageData[
  ColorSeparate[(*VB[*)(FrontEndRef["42d99f3c-deb2-402c-ac07-1b664f611765"])(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KRCeEJBwK8rPK3HNS3GtSE0uLUlMykkNVgEKmxilWFqmGSfrpqQmGemaGBgl6yYmG5jrGiaZmZmkmRkampuZAgCIexVv"*)(*]VB*), "L"]
, "Real32"];

Helper functions

It implements a symmetric 2D fourier transformation and its inverse version

fourier2d[data_] := Module[{d, fw, nRow, nCol},
  {nRow, nCol} = Dimensions[data];
  d = data;
  d = d (*SpB[*)Power[(-1)(*|*),(*|*)Table[i + j, {i, nRow}, {j, nCol}]](*]SpB*);
  fw = Fourier[d, FourierParameters -> {1, 1}];
  
  {Log[1 + Abs@fw], Arg[fw]}
]

ifourier2d[amp_, phase_] := Module[{d, nRow, nCol},
  {nRow, nCol} = Dimensions[amp];
  
  d = (Exp[amp] - 1.0) Exp[I phase];
  
  InverseFourier[d, FourierParameters -> {1, 1}] // Abs
]

preview[data_, opts___] := With[{a = data},
  Image[a / Max[a], "Real32", opts]
]

Filtering in frequency domain

Decompose an image to an amplitude and phase using 2D fourier transformation

{amp, phase} = fourier2d[donald];

Row[preview /@ {amp, phase}]
(*GB[*){{(*VB[*)(FrontEndRef["f6d54c4a-13ce-4db4-aae3-4d9f2eef5d9f"])(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KRCeEJBwK8rPK3HNS3GtSE0uLUlMykkNVgEKp5mlmJokmyTqGhonp+qapCSZ6CYmphoDWZZpRqmpaaZAGgCVChbJ"*)(*]VB*)(*|*),(*|*)(*VB[*)(FrontEndRef["1ed5328e-402d-4c34-b037-96bdbcabe01b"])(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KRCeEJBwK8rPK3HNS3GtSE0uLUlMykkNVgEKG6ammBobWaTqmhgYpeiaJBub6CYZGJvrWpolpSQlJyalGhgmAQCBrBXt"*)(*]VB*)}}(*]GB*)

Filter an amplidute spectrum

EventHandler[InputRaster[preview[amp]], (masked = #)&]
(*VB[*)(EventObject[<|"Id" -> "e53306a9-800e-416a-bfa9-9bbbb9e4efa5", "View" -> "11faab3a-8a0d-43e2-9970-3c93ea9620b6"|>])(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KRCeEJBwK8rPK3HNS3GtSE0uLUlMykkNVgEKGxqmJSYmGSfqWiQapOiaGKca6VpamhvoGidbGqcmWpoZGSSZAQCJuRWY"*)(*]VB*)

Here is an example how it can be masked

masked // preview 
(*VB[*)(FrontEndRef["1f6a81c1-3609-4915-a761-aa1796149201"])(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KRCeEJBwK8rPK3HNS3GtSE0uLUlMykkNVgEKG6aZJVoYJhvqGpsZWOqaWBqa6iaamxnqJiYamluaGZpYGhkYAgB00hR8"*)(*]VB*)

Take masked amplitude and recombine it with phase to get back a normal image

ifourier2d @@ {With[{max = Max[amp]},
  ImageData[masked, "Real32"][[All,All,1]] max 
], phase};

Grid[{
  {preview[donald, Magnification->2], preview[%, Magnification->2]},
  {"Original", "Filtered"}
}]
(*GB[*){{(*VB[*)(FrontEndRef["75166c47-f32c-4f1c-99a8-0afe20ebff13"])(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KRCeEJBwK8rPK3HNS3GtSE0uLUlMykkNVgEKm5sampklm5jrphkbJeuapBkm61paJlroGiSmpRoZpCalpRkaAwB+3xXW"*)(*]VB*)(*|*),(*|*)(*VB[*)(FrontEndRef["a6c8468f-ddee-46f8-ae87-b4bfcd776380"])(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KRCeEJBwK8rPK3HNS3GtSE0uLUlMykkNVgEKJ5olW5iYWaTppqSkpuqamKVZ6CamWpjrJpkkpSWnmJubGVsYAACV0hZQ"*)(*]VB*)}(*||*),(*||*){"Original"(*|*),(*|*)"Filtered"}}(*]GB*)