Sfondi

E kam të vështirë t'i mbaj duart të qëndrueshme ndërsa klikoj fotot. Natyrisht, shumë prej tyre vuajnë nga një turbullim. Nëse keni lidhje me këtë problem, jeni në vendin e duhur. Ndërsa unë nuk mund t'ju mësoj fotografinë, mund t'ju tregoj një teknikë për të turbulluar imazhet me disa rreshta kodi python. Duke pasur parasysh maninë rreth mësimit të thellë, një zgjidhje do të ishte trajnimi i një koduesi automatik. Por, ato janë llogaritëse të shtrenjta për t'u trajnuar dhe ndonjëherë, metodat klasike funksionojnë mirë. Pra, ne në vend të kësaj do të përdorim transformimin Fourier.

Transformimi Furier ka aplikime të gjera në përpunimin e sinjalit dhe imazhit. Performanca e tij mund të mos jetë aq mbresëlënëse sa metodat më të fundit të të mësuarit të thellë, por është shumë më e shpejtë. Nëse vëreni ndonjëherë një kërkesë përpunimi pasi të keni klikuar një foto në smartfonin tuaj, shanset janë që transformimi Fourier po funksionon në sfond për të përmirësuar cilësinë e imazhit. Mund të ndihmojë gjithashtu në trajnimin më të mirë të arkitekturave moderne të të mësuarit të thellë. Çdo model është po aq i mirë sa të dhënat me të cilat ushqehet. Duke përdorur transformimin Fourier, mund të aplikoni teknika të shumta të përpunimit të imazhit (zvogëlimi i zhurmës, zbulimi i skajeve, etj) për të përmirësuar cilësinë e të dhënave të trajnimit.

Nuk do të zhytem në detajet matematikore të transformimit të Furierit. Do të gjeni shumë video në youtube nëse jeni të interesuar për këtë. Një që më pëlqen veçanërisht është nga Grant Sanderson, drejtuesi i 3Blue1Brown. Në këtë postim do të përqendrohemi në përdorimin e transformimit Fourier për të zhbllokuar imazhet.

Çfarë është një turbullim matematikisht?

Tani që kemi rënë dakord të hyjmë në fushën e transformimit të Furierit, së pari na duhet një përkufizim matematikor i turbullimit të imazhit. Turbullimi zbut një imazh. Kjo do të thotë, imazhi humbet detajet e skajit. Këtë mund ta arrijmë duke e ndërthurur imazhin me një kernel gausian. Më poshtë është një kernel (3,3) Gaussian.

Vini re se pesha e bërthamës zvogëlohet ndërsa largohemi nga qendra. Prandaj, kur ndërlidhet me një matricë të tillë, një vendndodhje imazhi do të humbasë informacionin nga pikselët përreth, duke çuar në zbutje (turbullim). Përveç gaussian, ka edhe lloje të tjera të "bërthamëve zbutës". Çështja kryesore këtu është se një imazh i paqartë (B) është rezultat i një konvolucioni (H) të aplikuar në imazhin origjinal (I).

Nëse do të mund ta ndryshonim disi këtë operacion, do të ishim në gjendje të gjeneronim imazhin origjinal (I). Ky proces quhet dekonvolucionidhe bëhet më lehtë në domenin e frekuencës (transformimi Fourier).

Transformimi Furier i imazheve

Ideja me transformimin Furier (FT) është se çdo funksion mund të përafrohet si një shumë e ponderuar e sinusoideve të pafundme. Një valë sinus 1-D ka nevojë për 3 parametra për përcaktimin e saj.

  1. Amplituda (A) përcakton diapazonin e valës. Shtrihet nga -A,A
  2. Frekuenca (2π/λ) përcakton distancën ndërmjet dy majave të njëpasnjëshme
  3. Faza (φ) përcakton zhvendosjen horizontale në valë

Prandaj, transformimi Fourier zhvendos një funksion nga fusha hapësinore në domenin e frekuencës.

def plot_sine_1D(amp,wavelength,phase):
    x = np.arange(-500, 501, 1)
    y = np.sin((2 * np.pi * x / wavelength)+phase)
    plt.plot(x, y)
    plt.show()
plot_sine_1D(1,300,0)

Çdo imazh është një funksion diskret dy dimensional. Kjo do të thotë, pikselët janë një funksion i vendndodhjes së tyre hapësinore.

Transformimi diskret i Furierit i zhvendos imazhet në hapësirën e frekuencës ku ato përfaqësohen nga valët sinusoidale 2D.

def plot_sine_2D(amp,wavelength,phase,angle):
    x = np.arange(-500, 501, 1)
    X, Y = np.meshgrid(x, x)
    wavelength = 100
    sine_2D = np.sin(
        2*np.pi*(X*np.cos(angle) + Y*np.sin(angle)) / wavelength
    )
    plt.set_cmap("gray")
    plt.imshow(sine_2D)
plot_sine_2D(1,200,0,np.pi)

Valët sinus 2D gjithashtu mund të rrotullohen në lidhje me boshtet x, y. Më poshtë është e njëjta valë 2D e rrotulluar me π/6 radianë.

plot_sine_2D(1,200,0,np.pi/6)

Le të përfytyrojmë disa transformime të Furierit. Ne përdorim np.fft.fft2 për ta bërë këtë. Rreshti i dytë i funksionit zhvendos pikselin 0,0 në qendër të grafikut dhe e bën më të lehtë vizualizimin. Grupi ynë është i madhësisë 1001,1001, kështu që qendra është zhvendosur në 500,500. Gjithashtu, marrim absolutin sepse FT kthen një numër kompleks.

def compute_fft(f):
    ft = np.fft.fft2(f)
    ft = np.fft.fftshift(ft)
    return ft

sin = plot_sine_2D(1,200,0,np.pi,False)
ft = compute_fft(sin)
plt.xlim([480,520])
plt.ylim([520,480]) 
plt.imshow(abs(ft))

sin = plot_sine_2D(1,200,0,np.pi/6,False)
ft = compute_fft(sin)
plt.xlim([480,520])
plt.ylim([520,480]) 
plt.imshow(abs(ft))

Në FT-në e parë, marrim dy pika në një distancë prej 10 njësive nga qendra. Distanca nga qendra përfaqëson frekuencën. Në komplotin e dytë FT, marrim të njëjtat dy pika, por të rrotulluara. Këndi i rrotullimit paraqet rrotullimin e valës (30 gradë). Vlerat e pikselit në dy pikat përshkruajnë amplituda. Informacioni i fazës është i koduar në pjesën komplekse, të cilën ne nuk e përshkruajmë.

f,ax = plt.subplots(1,2,figsize=(15,20))
ax = ax.flatten()
im = cv2.imread('/kaggle/input/randomimages/pic2.jpeg',-1)
im = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
ax[0].imshow(im,cmap='gray')
ax[1].imshow(20*np.log(abs(compute_fft(im))),cmap='gray')

FT e imazheve reale janë më të vështira për t'u vizualizuar. Ne bëjmë një operacion regjistri në FT për t'i zvogëluar vlerat për t'i paraqitur ato si një imazh.

Dekonvolucioni duke përdorur transformimin Furier

Ne kemi bërë bujë mjaft për FT-të, por si e ndihmojnë ato çështjen tonë? Epo, në fushën e frekuencës, konvolucioni shndërrohet në shumëzim. Prandaj, ekuacioni ynë bëhet

Or,

Marrja e transformimit të anasjelltë të Furierit të RHS duhet të japë imazhin origjinal. Por prisni, si të gjeni bërthamën e duhur zbutëse (H)? Mund të provoni kernel të ndryshëm, në varësi të turbullimit. Le t'i përmbahemi Gaussian-it tani për tani dhe ta zbatojmë atë në kod.

Ne do të lexojmë në një imazh dhe do ta turbullojmë atë duke përdorur një kernel gaussian 7,7 me sigma = 5 (devijimi standard i kernelit)

# Plotting image and its blurred version
f,ax = plt.subplots(1,2,figsize=(15,20))
ax = ax.flatten()
im = cv2.imread('../input/randomimages/pic1.jpeg',-1)
im = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
im_blur = cv2.GaussianBlur(im,(7,7), 5, 5)
ax[0].imshow(im,cmap='gray')
ax[1].imshow(im_blur,cmap='gray')

Më pas, ne do të përcaktojmë dy funksione. Njëra për të gjeneruar një kernel gaussian të madhësisë së caktuar dhe një tjetër që merr një imazh të paqartë dhe e mpreh atë.

def gaussian_filter(kernel_size,img,sigma=1, muu=0):
    x, y = np.meshgrid(np.linspace(-1, 1, kernel_size),
                       np.linspace(-1, 1, kernel_size))
    dst = np.sqrt(x**2+y**2)
    normal = 1/(((2*np.pi)**0.5)*sigma)
    gauss = np.exp(-((dst-muu)**2 / (2.0 * sigma**2))) * normal
    gauss = np.pad(gauss, [(0, img.shape[0] - gauss.shape[0]), (0, img.shape[1] - gauss.shape[1])], 'constant')
    return gauss

def fft_deblur(img,kernel_size,kernel_sigma=5,factor='wiener',const=0.002):
    gauss = gaussian_filter(kernel_size,img,kernel_sigma)
    img_fft = np.fft.fft2(img)
    gauss_fft = np.fft.fft2(gauss)
    weiner_factor = 1 / (1+(const/np.abs(gauss_fft)**2))
    if factor!='wiener':
        weiner_factor = factor
    recon = img_fft/gauss_fft
    recon*=weiner_factor
    recon = np.abs(np.fft.ifft2(recon))
    return recon

Le të zhytemi thellë në funksionin fft_deblur.

  1. Ne gjenerojmë një filtër gaussian të madhësisë së caktuar dhe devijimit standard. E mbulojmë gjithashtu me zero, në mënyrë që të përputhet me formën e figurës. Kjo është e nevojshme për të llogaritur ndarjen në domenin e frekuencës
  2. Llogaritni FT-në e imazhit të paqartë
  3. Llogaritni FT-në e kernelit
  4. Përcaktoni faktorin Wiener. Do të vijmë tek kjo më vonë. Tani për tani, supozoni se është 1
  5. Përcaktoni rindërtimin si ndarje të (3) dhe (4)
  6. Shumëzoni (6) me (5)
  7. Transformimi i anasjelltë i Furierit (7) dhe llogaritja e vlerës së tij absolute

Le të analizojmë rezultatin.

recon = fft_deblur(im_blur,7,5,factor=1)
plt.subplots(figsize=(10,8))
plt.imshow(recon,cmap='gray')

Oops! Kjo nuk funksionoi. Kjo është kështu sepse ne nuk kemi marrë parasysh një komponent thelbësor - zhurmën. Zhurma mund të hyjë në një imazh nga burime të ndryshme. Prandaj, ekuacioni i imazhit të paqartë modifikohet në

Tani ndërsa llogaritim FT-në e imazhit të turbullt (B), ne në mënyrë implicite llogarisim edhe FT-në e komponentit të zhurmës. FT e zhurmës ka shumë vlera me frekuencë të lartë.

noise = np.random.rand(100,100)
noise_fft = np.fft.fft2(noise)
noise_fft = np.fft.fftshift(noise_fft)
f,ax = plt.subplots(1,2,figsize=(15,20))
ax = ax.flatten()
ax[0].imshow(noise,cmap='gray')
ax[0].set_title('Original Image')
ax[1].imshow(20*np.log(abs(compute_fft(noise_fft))),cmap='gray')
ax[1].set_title('Fourier Transform')

Nga ana tjetër, kerneli zbutës ka shumë vlera me frekuencë të ulët. Siç e shihni në grafikun më poshtë, nëse largohemi nga qendra, hyjmë në një rajon kryesisht të zi (0 piksel). Imazhi i tij origjinal është gjithashtu kryesisht i zi sepse e kemi mbushur me zero. Ka një zonë të vogël të bardhë afër majtas lart.

gauss = gaussian_filter(7,im,5)
gauss_fft = np.fft.fft2(gauss)
gauss_fft = np.fft.fftshift(gauss_fft)
f,ax = plt.subplots(1,2,figsize=(15,20))
ax = ax.flatten()
ax[0].imshow(gauss,cmap='gray')
ax[0].set_title('Original Image')
ax[1].imshow(np.abs(gauss_fft),cmap='gray')
ax[1].set_title('Fourier Transform')

Në thelb vlerat e frekuencës së lartë në FT(B) korrespondojnë me zhurmën. Kur e ndajmë me FT(H), të përbërë kryesisht nga zero, ne e përforcojmë zhurmën. Prandaj, ne kemi nevojë për një rregullues. Në të vjen faktori Wiener. Mund të gjeni më shumë detaje rreth filtrit Wiener këtu. Ne mund të zëvendësojmë 0.002 me çdo vlerë tjetër konstante.

f,ax = plt.subplots(1,2,figsize=(15,20))
recon = fft_deblur(im_blur,7,5,factor='wiener')
ax[0].imshow(im_blur,cmap='gray')
ax[1].imshow(recon)
ax[0].set_title('Blurry Image')
ax[1].set_title('Image reconstruction')
plt.show()

Me faktorin Wiener, ne marrim rezultate më të mira. Tani mund të luajmë me konstanten për të marrë rindërtime më të qarta.

f,ax = plt.subplots(1,2,figsize=(15,20))
recon = fft_deblur(im_blur,7,5,factor='wiener',const=0.5)
ax[0].imshow(im_blur,cmap='gray')
ax[1].imshow(recon)
ax[0].set_title('Blurry Image')
ax[1].set_title('Image reconstruction')
plt.show()

Ne nuk mund të operojmë drejtpërdrejt FT në imazhet RGB. Për të zhbllokuar imazhet RGB, ne mund të ekzekutojmë funksionin e fshirjes në çdo dimension ngjyrash veçmas dhe më pas t'i bashkojmë ato.

konkluzioni

Ky ishte një udhëzues i shkurtër se si të përdorni transformimin Fourier për të zhbllokuar imazhet. Ndërsa një aplikim në vetvete, zhbllokimi mund të përdoret gjithashtu si një hap i rëndësishëm para-përpunimi në një tubacion trajnimi të të mësuarit të thellë. Një kuptim i plotë i transformimit të Furierit do të ndihmojë këdo që punon në shkencat e vizionit/sinjalit. Është një algoritëm madhështor që, sipas Veritasium, transformoi botën.

Referencat

https://thepythoncodingbook.com/2021/08/30/2d-fourier-transform-in-python-and-fourier-synthesis-of-images/