画像で「頻度」とはどういう意味ですか?


29

画像/写真で周波数がどのように定義されているかわかりません。私が今理解している限り、高周波数はエッジなどのように画像の鋭いもののようなもので、低周波数は逆のようなものですか?

また、適切に読み取る方法など、離散フーリエ変換の結果を理解したいと思います。

誰かが私に次のことを説明できたらいいですね。

  1. 写真の周波数とはどのようなものですか?

  2. 離散フーリエ変換の結果をどのように読みますか?



おかげで、私はすでにこれを読んだ、それは私を助けましたが、まだ少し手がかりがありません。
ヤコブアブファルター

回答:


44

最初の質問に答えるだけです。画像の周波数とは何ですか?

フーリエ変換は、同じ画像情報が各ピクセルごとにではなく、各周波数ごとに表現される数学的手法です。このように考えてください。海には波があり、その一部は非常にゆっくりと移動し(潮のように)、他は中程度の大きさで、さらにいくつかは突風から形成される波紋のように小さなものです。それらは3つの別々の波と考えることができますが、海面の各ポイントとある瞬間に、1つの高さの水だけが得られます。

同じことが画像にも当てはまります。画像はさまざまな波や周波数で構成されていると考えることができます。画像を作成するには、平均色から始めます(実際にグレースケール画像を考える方が簡単です)。次に、異なる波長と強度の波を追加して、写真の細部をゆっくりと構築します。

ソース画像:

ソース画像

最初の頻度(平均):

平均

垂直次元に沿った2番目の周波数は、画像の下部でゼロから始まり、上昇し、中央の水平線に沿って再びゼロになり、画像の上部で最終的にゼロになる波動です。(位相シフトのないフーリエ級数について説明しましたが、その類似性はまだあります。)

ここで、水平および垂直に沿って2番目の周波数を確認できます。山がどこにあるか(暗い)、空と湖がどこにあるか(明るい)を確認できることに注意してください。

2番目の頻度:

最初のコンポーネント

波または周波数を追加するごとに、より多くのリップルがもたらされるため、より詳細になります。さまざまな画像を取得するために、波の高さ/振幅と、位相とも呼ばれる波の開始点を変更できます。

3番目の頻度:

三番

興味深いことに、この表現では情報量は同じであり、通常の画像(空間領域)とフーリエ変換画像(周波数領域)を行き来できます。周波数領域では、振幅と位相の情報とともにすべての周波数の情報を保持する必要があります。

ここでは、周波数の50%を使用しています。

50%

このすべてのバリエーションがあり、フーリエ級数、フーリエ変換、離散フーリエ変換、離散コサイン変換(DCT)を区別する必要があります。

1つの興味深いアプリケーションは、JPEGなどの圧縮アルゴリズムの使用です。ここでは、DCTを使用して、画像の重要な部分(低周波数)を保存し、高周波数を保存しません。

初心者の読者がフーリエ変換の概念の基本的な理解を得られることを期待して、私はこれを書きました。そのために私はいくつかの単純化を行い、より上級の読者が私を許してくれることを願っています。

アニメーション

Thomas Devoogdtによって生成されたビデオは、Vimeoで見ることができます。

アニメ化


後処理の頻度

主に単一のピクセルを個別に見ることはないため、後処理に周波数に依存する多くの方法があります。多くのアルゴリズムは、このように考える方が自然であるため、周波数で機能します。しかし、フーリエ変換にも同じ情報が含まれているため、周波数領域および空間領域での数学演算(または後処理ステップ)を表現できます。ピクセル単位の記述の方が優れている場合もありますが、頻度の記述の方が優れている場合がよくあります。(このコンテキストでは、より良いということは主に高速であることを意味します。)

私が特定の理由で指摘したくないテクニックの1つは、アーティストが周波数を直接操作していることと、それが*周波数分離*であることを除きます。これについては説明しませんが、PhotoshopとGIMPの両方でYouTubeでどのように機能するかを確認できます。

低周波数と高周波数の2つのレイヤーを作成します。ポートレートの場合、低周波数の肌のトーンに影響を与えることなく、高周波数で肌のスムージングを行うことができます。

コード

これは、上記の例を生成するためのコードです。単純なPythonプログラムとして実行できます。

from PIL import Image
from numpy.fft import rfft2, irfft2
import numpy as np

def save_dims(ft, low, high, name):
    ft2 = np.zeros_like(ft)
    # copy the frequencies from low to high but all others stay zero.
    ft2[low:high, low:high] = ft[low:high, low:high]
    save(ft2, name)

def save(ft, name):
    rft = irfft2(ft)
    img = Image.fromarray(rft)
    img = img.convert('L')
    img.save(name)

def main():
    # Convert input into grayscale and save.
    img = Image.open("input.jpg")
    img = img.convert('L')
    img.save('input_gray.png')
    # Do Fourier Transform on image.
    ft = rfft2(img)
    # Take only zeroth frequency and do Inverse FT and save.
    save_dims(ft, 0, 1, 'output_0.png')
    # Take first two frequencies in both directions.
    save_dims(ft, 0, 2, 'output_1.png')
    save_dims(ft, 0, 3, 'output_2.png')
    # Take first 50% of frequencies.
    x = min(ft.shape)
    save_dims(ft, 0, x/2, 'output_50p.png')

def generateGif():
    ''' Generates images to be later converted to a gif.
    This requires ImageMagick:
    convert -delay 100 -loop 0 output_*.png animation.gif
    '''
    # Requires images2gif from code.google.com/p/visvis/source/browse/vvmovie/images2gif.py 
    # from images2gif import writeGif

    img = Image.open('input.jpg')
    img = img.convert('L')
    # Resize image before any calculation.
    size = (640,480)
    img.thumbnail(size, Image.ANTIALIAS)
    ft = rfft2(img)

    images = []
    for x in range(0, max(ft.shape)):
        ft2 = np.zeros_like(ft)
        ft2[0:x, 0:x] = ft[0:x,0:x]
        rft = irfft2(ft2)
        img_out = Image.fromarray(rft).convert('L')
        fname = 'animation/output_%05d.jpg' %(x, )
        img_out.save(fname, quality=60, optimize=True)

    #writeGif('animation.gif', images, duration=0.2)


if __name__=='__main__':
    main()
    #generateGif()

理論的には、手元にある画像の無限の知識があると仮定して、それを成分周波数に分解し、損失なく再構成できることを明確にする必要があります...現実の世界では不可能です。光パイプラインに沿ったすべての「インターフェース」で発生する実世界の画像の畳み込みは、事実上不可逆的なプロセスです。すべての畳み込み係数を知ることはできないため、FFTを画像に再構築することは難しく、極端な変更は通常、アーティファクトとデータ損失をもたらします。
jrista

@jrista Unapiedraが可逆性について指摘した点は、デジタル画像(コンピューター上のピクセルの配列)を操作したら、周波数空間に戻って元の画像を取得できるということだったと思います。あなたは、現実世界の制限が侵入する物理的なイメージングシステム(レンズなど)のより大きな画像を見ています。
コーンスレイヤー

3
jristaのコメントは、FTが情報損失のせいであるという点で誤解を招きます。もちろん、写真は損失の多いプロセスであり、後処理も同様です。離散画像をフーリエ空間に変換し、そこで損失のある処理を行ってから、元に戻すと、もちろん情報が失われます。ただし、変換ステップではなく、処理ステップで発生します。確かに、機械の精度のために、すべての数学的操作は情報を失いますが、チャネルイメージごとに8ビットについて話している場合、機械の精度エラーに気付くことはありません。
-Unapiedra

1
@Turkeyphant、なぜその文脈で対角線に言及するのか覚えていません。2番目の周波数の主方向がその特定の対角線であるように見えることがわかります。たぶんそれが理由です。質問に答えるには、2D画像を表すのに2つの軸のみが必要です。2つの軸が直交していることが重要です。水平軸と垂直軸はその基準を満たしています。(また、実用的です。)離散画像(つまり、ピクセルで構成される)では、エイリアシングは他のすべての角度を悪化させます。
-Unapiedra

1
@Turkeyphant修正、Unapiedra は最初の周波数ではなく、2番目の周波数を0、-1、0、+ 1、0として説明しました。2番目の周波数を説明する段落は1番目の周波数画像(均一なグレー画像)の直後にあり、前の画像の説明としてその段落を読みたいと思うかもしれません(記事はしばしば画像を表示し、画像に続くテキストで説明します)。しかしこの場合はそうではありません。=)
scottbb

8

できるだけ簡単な数学用語で説明しようと思います。数学をスキップしたい場合は、パートIIにジャンプしてください。短い答えを取得したい場合は、パートIIIにスキップしてください。

パートI

信号の頻度とは、単位時間あたりの繰り返しイベントの発生数を意味します。時間の単位が秒の場合、周波数はHerzで測定されます:1Hz = 1 / s。そのため、100Hzの信号には、1秒間に100回繰り返すパターンがあります。

最も基本的な信号(信号処理の観点から)は、洞信号です。

y(t)= sin(2πft)

ここで、fはこの洞信号の周波数、tは時間です。この信号が音で、fが約50Hzの場合、1つの非常に低い低音が聞こえます。15kHzのような高い周波数では、より高いトーンになります。

概念を一般化するために、信号は一時的な信号ではなく空間的な信号である可能性があります。まるで紙の上に洞波を描き、xと呼ばれる軸を右に、y軸を垂直にx軸に。

y(x)= sin(2πfx)

ここで、fは信号の周波数、xは空間変数です。ここでのfは1 / sではなく、1 /(スペースの単位)で測定されます。

フランスの数学者のフーリエは、さまざまな振幅と周波数の多数のサイン信号とコサイン信号を追加することで、任意の信号を生成できることを示しました。それはフーリエ解析と呼ばれます。

フーリエ解析を使用すると、関数y(x)を異なる周波数のサイン信号とコサイン信号の合計として書くことができるため、関数y(x)は周波数Y(f)に関連するいくつかの関数に関して書き直すことができます。y(x)= Some_Function(Y(f))と言うことができます。またはY(f)= Reverse_of_Some_Function(y(x))

フーリエ変換は、信号をxドメインから周波数ドメインに変換する関数Fです。

Y(f) = F( y(x) )

y(x) = F_inv(Y(f))

Fはアナログ関数、離散フーリエ変換DFTはFの数値近似です。高速フーリエ変換FFTは、速度を最適化したDFTを実行する方法です。

OK...

パートII

現在、コンピューター画像はピクセルで構成されており、すべてのピクセルは赤、緑、青、別名RGB値の強度値を持っています。グレースケール画像では、任意のピクセルのR、G、Bの強度は等しく、R = G = B = Iなので、グレースケール画像のIについて説明できます。

以下の800px X 100pxのグレースケール画像は、I(x)= sin(2πfx)を使用して生成されました。f= 1繰り返し/ 800px = 0.00125繰り返し/ px

ここに画像の説明を入力してください

Python3で自分で生成できます

from PIL import Image, ImageDraw
from math import sin, pi

img = Image.new('RGB', (800,100), color='black')
draw = ImageDraw.draw(img)

#cacluate the frequency
n = 10 #repetitions
f = n/img.width #

#iterate of the width pixels
for x in range(img.width):
 #calculate the intensity i in that pixel x
 y = sin(2*pi*f*x - pi/2) #this will generate values between -1 and +1, -pi/2 is to make sure that i starts with value 0 in the next line.
 i = (255+255*y)/2 #shifting and scaling y so that the values are between 0 and 255
 draw.line((i,0,i,img.height), fill=(int(i),int(i),int(i)))

img.show()

以下の800px X 100pxグレースケール画像は、I(x)= sin(2πfx)を使用して生成されました。f= 10repetitions / 800px = 0.0125 repeats / px

ここに画像の説明を入力してください

これで、この画像の水平周波数が10であることが簡単にわかります。周波数を10倍に増やして、n = 100にします。f= 100/800 = 1/8 = 0.125繰り返し/ px:

ここに画像の説明を入力してください

前述のように、任意の信号(1Dグレースケールイメージ)を、異なる周波数の正弦信号(1Dグレースケールサイン画像)の和シリーズとして表すことができます。

パートIII

したがって、1Dグレースケール画像Aは、「細かい」詳細がある場合、別のグレースケール画像Bよりも高い周波数を持ちます。

この原理を色付きの2Dおよび3D画像に一般化できます。画像の「詳細」が細かいほど、その画像の周波数成分は高くなります。

したがって、青い空は、花の画像と比較して低頻度です。

これについては、フーリエ解析とデジタル画像処理について読んでください。


4

簡単に言うと、頻度とは変化率を指します。より正確には、周波数は変化の周期の逆数です。つまり、ある明るさ(または何であれ)から別の明るさに戻って再び戻るまでにかかる時間です。変化が速ければ速いほど(例えば、明から暗へ)、画像のその部分を表現するために必要な視覚的な「周波数」が高くなります。

つまり、画像内の頻度を変化率と考えることができます。ある色から別の色に急速に変化する画像の部分(鋭いエッジなど)には高周波数が含まれ、徐々に変化する部分(たとえば無地の大きな表面)には低周波数のみが含まれます。

DCT、FFT、およびその他の同様の変換について説明するとき、通常は画像の一部でそれらを実行します(たとえば、JPEG圧縮、エッジ検出など)。それから、与えられたサイズの変換ブロックのコンテキストで、変換について話すのが最も理にかなっています。

画像データの32ピクセルx 32ピクセルのブロックを想像してください。(この数値は任意です。)画像が、左側が白、中央が黒、右側が白の単純なグラデーションであると仮定します。この信号は、32ピクセルごとに白から黒、白へと完全なサイクルを繰り返すため、幅32ピクセルあたりおよそ1波長の周期を持っていると言えます。

この周波数を任意に「1」と呼ぶことがあります。つまり、32ピクセルあたり1サイクルです。これは変換教科書では一般的にθと呼ばれていること、またはθ/ 2であることを漠然と思い出しますが、間違っていることを覚えているかもしれません。いずれにせよ、今のところ1と呼びます。これは、絶対的な意味で本当にarbitrary意的だからです。重要なのは、相対的な意味での周波数間の関係です。:-)

一方の端が白の2番目の画像があり、もう一方の端が白から黒、白、黒、そして再び白になるように2倍速くフェードするとします。その周波数は、その32ピクセルブロックの幅で2倍頻繁に変化するため、「2」と呼びます。

これらの単純な画像を再現したい場合、文字通り、すべての行は1または2の周波数の信号で構成され、画像がどのように見えるかを知ることができます。画像が黒から50%グレーになった場合、同じことを行うことができますが、50%の強度で1または2の頻度であったと言わなければなりません。

もちろん、現実世界の画像は単なるグラデーションではありません。左から右にスキャンすると、画像は頻繁に変更され、定期的には変更されません。ただし、十分に小さいブロック(8ピクセル、16ピクセルなど)内では、そのピクセルの行を一連の信号の合計として概算できます。行のピクセル値の平均で始まり、その後に「周波数0.5 "信号(片側に黒、白にフェード)でブレンド(またはマイナスの量、減算する信号の量)、その後に周波数1の量、周波数2、周波数4など。

これで、画像は両方向に周波数を持つという点でユニークです。水平と垂直の両方に移動すると、明るくなったり暗くなったりします。このため、1Dではなく2D DCTまたはFFT変換を使用します。しかし、原則は基本的に同じです。同じサイズのバケットの8x8グリッドで8x8画像を正確に表現できます。

画像も色のためにより複雑ですが、ここではそれを無視し、写真の赤いチャンネルを単独で見ることで得られるかもしれない単一のグレースケール画像のみを見ていると仮定します。

変換の結果を読み取る方法については、1D変換を見るか2D変換を見るかによって異なります。1D変換の場合、一連のビンがあります。最初は、すべての入力値の平均です。2番目は追加する周波数1信号の量、3番目は追加する周波数2信号の量などです。

2D変換の場合、n x nの値のグリッドがあります。通常、左上はその平均であり、水平方向に進むと、各バケットには、1、2、4などの水平周波数で混合する信号の量が含まれ、垂直方向に進むと、は、1、2、4などの垂直周波数で混合する信号の量です。

それは、もちろん、DCTについて話している場合の完全なストーリーです。対照的に、FFTの各ビンには実数部と虚数部が含まれます。FFTは、周波数がビンにマッピングされる方法が異なり、数学がより複雑であることを除いて、同じ基本的な考え方(一種)に基づいています。:-)

もちろん、これらの種類の変換を生成する最も一般的な理由は、さらに一歩進んでデータの一部を破棄することです。たとえば、DCTはJPEG圧縮で使用されます。左上(平均)から始まって右下に向かってジグザグパターンの値を読み取ると、最も重要なデータ(平均および低周波情報)が最初に記録され、その後、次第に高周波のデータが記録されます。ある時点で、あなたは基本的に「これで十分」と言い、最高頻度のデータを捨てます。これは基本的に、細かいディテールを捨てることで画像を滑らかにしますが、それでもほぼ正しい画像を提供します。

また、IIRC、FFTはエッジ検出にも使用される場合があります。エッジ検出では、鋭いエッジでコントラストの高い領域を検出する手段として、高周波成分以外はすべて捨てます。

ナショナルインスツルメンツには、これを写真で説明した素晴らしい記事があります。:-)


0

フォトセルで画像を1行ずつスキャンし、結果をプロッター(紙に黒い波を作るこれらのフラットマシン)、オシロスコープ(画面に緑色の波をちらつく)、またはスペクトラムアナライザー(大きなボックス緑またはマルチカラーのピケットフェンスを作成します)。またはラウドスピーカーですら。画像内の構造が細かいほど、表示される/聞こえる信号の周波数(スピーカーのピッチ)が高くなります。微細構造のコントラストが高いほど、信号の高周波部分の振幅が大きくなります。


-2

二次元FFTの結果を読むのは...まあ、トリッキーです。基本的には、出力が複素数ドメインにあるためです。

私はそのほとんどを自分で忘れているので、非常に詳細な説明をすることはできませんが、基本的には、一連の虚数の指数の合計として表される分解があります。

コサイン変換(たとえば、実際の係数のみを持つJPEGエンコードで使用)やさまざまな種類のウェーブレットなど、DFTよりも画像処理に便利な周波数変換があります。


この答えは基本的に「説明できない、または説明したくない名詞」で構成されています。
scottbb

@scottbbの答えは、フーリエ変換(opが求めている変換)を視覚的に解釈することの難しさを説明しています。場合あなたは複素数、指数関数または合計があるかわからない...まあ、私はいくつかの背景の読書をお勧めします。
fortran

私は同意しません。視覚的な方法でFTを解釈することの難しさを説明するのではなく、単に複雑な数字のために難しいと断言し、それをそのままにしておきます。余談ですが、複素数と何かを知っています。FTの定義を忘れていません。
scottbb
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.