深層学習を使用した JPEG イメージのデブロック
この例では、ノイズ除去畳み込みニューラル ネットワーク (DnCNN) を使用してイメージの JPEG 圧縮アーティファクトを低減する方法を説明します。
イメージの圧縮は、イメージのメモリ フットプリントを縮小するために使用します。JPEG イメージ形式は一般的で強力な圧縮方式を使用しており、この方式では画質係数を使用して圧縮量を指定します。画質の値を下げると、圧縮率が高くなりメモリ フットプリントは小さくなりますが、イメージの画質が犠牲になります。
JPEG 圧縮は "非可逆" であり、これは圧縮処理によりイメージから情報が失われることを意味します。JPEG イメージでは、この情報損失はイメージのブロック アーティファクトとして現れます。図に示すとおり、圧縮率が高くなると、失われる情報が増え、アーティファクトが目立つようになります。高周波数成分のあるテクスチャ領域、芝生や雲などは不鮮明に見えます。家の屋根や灯台の上部にある手すりなど、鋭いエッジではリンギングが現れます。
JPEG デブロックは、JPEG イメージで圧縮アーティファクトの影響を除去する処理です。JPEG デブロックにはいくつかの手法があり、深層学習を使用する手法はその中で特に効果的です。この例で実行するのは、深層学習をベースにしたメソッドで、JPEG 圧縮アーティファクトの影響を最小化します。
DnCNN ネットワーク
この例で使用するのは、組み込みの深層フィードフォワード畳み込みニューラル ネットワーク (DnCNN
) です。このネットワークは主としてイメージからノイズを除去するために設計されました。しかし、JPEG 圧縮アーティファクトを取り除いたり、イメージの解像度を高めるために、DnCNN アーキテクチャに学習させることもできます。
参考文献 [1] で採用しているのは残差学習法です。これは DnCNN ネットワークに残差イメージを推定するように学習させるものです。残差イメージは初期状態のイメージとそのイメージの歪んだコピーの差分です。残差イメージにはイメージの歪みに関する情報が含まれます。この例では、歪みは JPEG のブロック アーティファクトとして現れています。
DnCNN ネットワークは、カラー イメージの輝度から残差イメージを検出するように学習しています。イメージの輝度チャネル Y は、各ピクセルの明度を赤、緑および青ピクセル値の線形結合で表したものです。一方、イメージの 2 つの色差チャネル Cb および Cr は、赤、緑および青ピクセル値の異なる線形結合で、色差情報を表します。人間の知覚は色の変化よりも明度の変化に敏感であるため、DnCNN は輝度チャネルだけを使用して学習します。
が初期状態のイメージの輝度で、 が JPEG 圧縮アーティファクトを含むイメージの輝度である場合、DnCNN ネットワークへの入力は で、ネットワークは学習データから を予測するために学習します。
DnCNN ネットワークが残差イメージの推定方法を学習すると、残差イメージを圧縮された輝度チャネルに追加し、そのイメージを RGB 色空間に変換し直すことで、圧縮された JPEG イメージの歪みのないバージョンを再構成できるようになります。
学習データのダウンロード
20,000 個の静止した自然イメージから成る、IAPR TC-12 ベンチマークをダウンロードします [2]。このデータ セットには、人物、動物、都市などの写真が含まれます。データ ファイルのサイズは~1.8 GB です。学習データをダウンロードしない、またはネットワークに学習させない場合、コマンド ラインで load("trainedJPEGDnCNN.mat")
と入力して、事前学習済みの DnCNN ネットワークを読み込むことができます。その後、この例の DnCNN ネットワークを使用した JPEG デブロックの実行の節に直接進みます。
データをダウンロードするために補助関数 downloadIAPRTC12Data
を使用します。この関数は、この例にサポート ファイルとして添付されています。dataDir
をデータの目的の場所として指定します。
dataDir =
tempdir;
downloadIAPRTC12Data(dataDir);
この例ではネットワークを IAPR TC-12 ベンチマーク データの小さなサブセットで学習させます。imageCLEF 学習データを読み込みます。すべてのイメージは 32 ビット JPEG カラー イメージです。
trainImagesDir = fullfile(dataDir,"iaprtc12","images","00"); exts = [".jpg",".bmp",".png"]; imdsPristine = imageDatastore(trainImagesDir,FileExtensions=exts);
学習イメージの数を表示します。
numel(imdsPristine.Files)
ans = 251
学習データの準備
学習データ セットを作成するには、初期状態のイメージを読み取り、多様な圧縮レベルで JPEG ファイル形式のイメージを書き出します。
イメージ圧縮アーティファクトをレンダリングするために使用する JPEG の画質の値を指定します。画質の値は [0, 100] の範囲でなければなりません。画質の値が小さいと、圧縮率が高くなり、圧縮アーティファクトが目立つようになります。画質の値が小さく密度の濃いサンプリングを使用すると、学習データの広範囲に圧縮アーティファクトが現れます。
JPEGQuality = [5:5:40 50 60 70 80];
圧縮イメージは、ディレクトリ compressedImagesDir
の MAT ファイルとしてディスクに格納されます。計算された残差イメージは、ディレクトリ residualImagesDir
の MAT ファイルとしてディスクに格納されます。ネットワークの学習時に精度を向上させるため、MAT ファイルはデータ型 double
として格納されます。
compressedImagesDir = fullfile(dataDir,"iaprtc12","JPEGDeblockingData","compressedImages"); residualImagesDir = fullfile(dataDir,"iaprtc12","JPEGDeblockingData","residualImages");
補助関数 createJPEGDeblockingTrainingSet
を使用して学習データを前処理します。この関数は、この例にサポート ファイルとして添付されています。
この補助関数は、初期状態の各学習イメージについて、参照イメージとして使用するために品質係数 100 でイメージのコピーを書き込み、ネットワーク入力として使用するためにそれぞれの品質係数でイメージのコピーを書き込みます。この関数は、残差イメージの計算時に精度を向上させるため、データ型 double
で参照イメージと圧縮イメージの輝度 (Y) チャネルを計算します。圧縮イメージは、ディレクトリ compressedDirName
の MAT ファイルとしてディスクに格納されます。計算された残差イメージは、ディレクトリ residualDirName
の MAT ファイルとしてディスクに格納されます。
[compressedDirName,residualDirName] = createJPEGDeblockingTrainingSet(imdsPristine,JPEGQuality);
学習用ランダム パッチ抽出データストアの作成
ランダム パッチ抽出データストアを使用して、ネットワークに学習データを供給します。このデータストアは、ネットワーク入力と目的のネットワーク応答が含まれる 2 つのイメージ データストアから、対応するランダムなパッチを抽出します。
この例では、ネットワーク入力は圧縮イメージです。目的のネットワーク応答は、残差イメージです。圧縮イメージ ファイルのコレクションから imdsCompressed
というイメージ データストアを作成します。計算された残差イメージ ファイルのコレクションから imdsResidual
というイメージ データストアを作成します。いずれのデータストアでも、イメージ ファイルからイメージ データを読み取るには補助関数 matRead
が必要です。この関数は、この例にサポート ファイルとして添付されています。
imdsCompressed = imageDatastore(compressedDirName,FileExtensions=".mat",ReadFcn=@matRead); imdsResidual = imageDatastore(residualDirName,FileExtensions=".mat",ReadFcn=@matRead);
データ拡張のパラメーターを指定する imageDataAugmenter
(Deep Learning Toolbox) を作成します。学習中にデータ拡張を使用して学習データを変化させることによって、使用可能な学習データの量が効果的に増加します。ここで、拡張により、90 度のランダムな回転、および x 方向のランダムな鏡映を指定します。
augmenter = imageDataAugmenter( ... RandRotation=@()randi([0,1],1)*90, ... RandXReflection=true);
2 つのイメージ データストアから randomPatchExtractionDatastore
を作成します。パッチ サイズとして 50 x 50 ピクセルを指定します。それぞれのイメージは、サイズが 50 行 50 列ピクセルの 128 個のランダム パッチを生成します。ミニバッチ サイズとして 128 を指定します。
patchSize = 50; patchesPerImage = 128; dsTrain = randomPatchExtractionDatastore(imdsCompressed,imdsResidual,patchSize, ... PatchesPerImage=patchesPerImage, ... DataAugmentation=augmenter); dsTrain.MiniBatchSize = patchesPerImage;
ランダム パッチ抽出データストア dsTrain
では、データのミニバッチが、エポックの反復でネットワークに渡されます。データストアからの読み取りの結果をプレビューします。
inputBatch = preview(dsTrain); disp(inputBatch)
InputImage ResponseImage ______________ ______________ {50×50 double} {50×50 double} {50×50 double} {50×50 double} {50×50 double} {50×50 double} {50×50 double} {50×50 double} {50×50 double} {50×50 double} {50×50 double} {50×50 double} {50×50 double} {50×50 double} {50×50 double} {50×50 double}
DnCNN 層のセットアップ
関数 dnCNNLayers
を使用して、組み込み DnCNN ネットワークの各層を作成します。既定では、ネットワークの深さ (畳み込み層の数) は 20 です。
layers = dnCNNLayers
layers = 1×59 Layer array with layers: 1 'InputLayer' Image Input 50×50×1 images 2 'Conv1' Convolution 64 3×3×1 convolutions with stride [1 1] and padding [1 1 1 1] 3 'ReLU1' ReLU ReLU 4 'Conv2' Convolution 64 3×3×64 convolutions with stride [1 1] and padding [1 1 1 1] 5 'BNorm2' Batch Normalization Batch normalization with 64 channels 6 'ReLU2' ReLU ReLU 7 'Conv3' Convolution 64 3×3×64 convolutions with stride [1 1] and padding [1 1 1 1] 8 'BNorm3' Batch Normalization Batch normalization with 64 channels 9 'ReLU3' ReLU ReLU 10 'Conv4' Convolution 64 3×3×64 convolutions with stride [1 1] and padding [1 1 1 1] 11 'BNorm4' Batch Normalization Batch normalization with 64 channels 12 'ReLU4' ReLU ReLU 13 'Conv5' Convolution 64 3×3×64 convolutions with stride [1 1] and padding [1 1 1 1] 14 'BNorm5' Batch Normalization Batch normalization with 64 channels 15 'ReLU5' ReLU ReLU 16 'Conv6' Convolution 64 3×3×64 convolutions with stride [1 1] and padding [1 1 1 1] 17 'BNorm6' Batch Normalization Batch normalization with 64 channels 18 'ReLU6' ReLU ReLU 19 'Conv7' Convolution 64 3×3×64 convolutions with stride [1 1] and padding [1 1 1 1] 20 'BNorm7' Batch Normalization Batch normalization with 64 channels 21 'ReLU7' ReLU ReLU 22 'Conv8' Convolution 64 3×3×64 convolutions with stride [1 1] and padding [1 1 1 1] 23 'BNorm8' Batch Normalization Batch normalization with 64 channels 24 'ReLU8' ReLU ReLU 25 'Conv9' Convolution 64 3×3×64 convolutions with stride [1 1] and padding [1 1 1 1] 26 'BNorm9' Batch Normalization Batch normalization with 64 channels 27 'ReLU9' ReLU ReLU 28 'Conv10' Convolution 64 3×3×64 convolutions with stride [1 1] and padding [1 1 1 1] 29 'BNorm10' Batch Normalization Batch normalization with 64 channels 30 'ReLU10' ReLU ReLU 31 'Conv11' Convolution 64 3×3×64 convolutions with stride [1 1] and padding [1 1 1 1] 32 'BNorm11' Batch Normalization Batch normalization with 64 channels 33 'ReLU11' ReLU ReLU 34 'Conv12' Convolution 64 3×3×64 convolutions with stride [1 1] and padding [1 1 1 1] 35 'BNorm12' Batch Normalization Batch normalization with 64 channels 36 'ReLU12' ReLU ReLU 37 'Conv13' Convolution 64 3×3×64 convolutions with stride [1 1] and padding [1 1 1 1] 38 'BNorm13' Batch Normalization Batch normalization with 64 channels 39 'ReLU13' ReLU ReLU 40 'Conv14' Convolution 64 3×3×64 convolutions with stride [1 1] and padding [1 1 1 1] 41 'BNorm14' Batch Normalization Batch normalization with 64 channels 42 'ReLU14' ReLU ReLU 43 'Conv15' Convolution 64 3×3×64 convolutions with stride [1 1] and padding [1 1 1 1] 44 'BNorm15' Batch Normalization Batch normalization with 64 channels 45 'ReLU15' ReLU ReLU 46 'Conv16' Convolution 64 3×3×64 convolutions with stride [1 1] and padding [1 1 1 1] 47 'BNorm16' Batch Normalization Batch normalization with 64 channels 48 'ReLU16' ReLU ReLU 49 'Conv17' Convolution 64 3×3×64 convolutions with stride [1 1] and padding [1 1 1 1] 50 'BNorm17' Batch Normalization Batch normalization with 64 channels 51 'ReLU17' ReLU ReLU 52 'Conv18' Convolution 64 3×3×64 convolutions with stride [1 1] and padding [1 1 1 1] 53 'BNorm18' Batch Normalization Batch normalization with 64 channels 54 'ReLU18' ReLU ReLU 55 'Conv19' Convolution 64 3×3×64 convolutions with stride [1 1] and padding [1 1 1 1] 56 'BNorm19' Batch Normalization Batch normalization with 64 channels 57 'ReLU19' ReLU ReLU 58 'Conv20' Convolution 1 3×3×64 convolutions with stride [1 1] and padding [1 1 1 1] 59 'FinalRegressionLayer' Regression Output mean-squared-error
学習オプションの選択
モーメンタム項付き確率的勾配降下 (SGDM) 最適化を使用してネットワークに学習させます。関数 trainingOptions
(Deep Learning Toolbox) を使用して SGDM 用ハイパーパラメーター設定を指定します。
深いネットワークの学習には時間がかかります。高い学習率を指定して学習を加速します。ただし、これによりネットワークの勾配が発散つまり制御できないほど増大し、ネットワークを正常に学習させることができない場合があります。勾配を意味のある範囲に維持するには、"GradientThreshold"
を 0.005
に設定することで勾配のクリップを有効にし、"GradientThresholdMethod"
を指定して勾配の絶対値を使用します。
maxEpochs = 30; initLearningRate = 0.1; l2reg = 0.0001; batchSize = 64; options = trainingOptions("sgdm", ... Momentum=0.9, ... InitialLearnRate=initLearningRate, ... LearnRateSchedule="piecewise", ... GradientThresholdMethod="absolute-value", ... GradientThreshold=0.005, ... L2Regularization=l2reg, ... MiniBatchSize=batchSize, ... MaxEpochs=maxEpochs, ... Plots="training-progress", ... Verbose=false);
ネットワークの学習
この例では既定で、事前学習済みの DnCNN ネットワークを読み込みます。この事前学習済みのネットワークを使用することで、学習の完了を待たずに JPEG デブロックを実行できます。
ネットワークに学習させるには、次のコードで変数 doTraining
を true
に設定します。関数trainNetwork
(Deep Learning Toolbox)を使用して DnCNN ネットワークを学習させます。
GPU が利用できる場合、GPU で学習を行います。GPU を使用するには、Parallel Computing Toolbox™、および CUDA® 対応の NVIDIA® GPU が必要です。詳細については、GPU 計算の要件 (Parallel Computing Toolbox)を参照してください。学習には NVIDIA™ Titan X で約 40 時間を要します。
doTraining =false; if doTraining [net,info] = trainNetwork(dsTrain,layers,options); modelDateTime = string(datetime("now",Format="yyyy-MM-dd-HH-mm-ss")); save("trainedJPEGDnCNN-"+modelDateTime+".mat","net"); else load("trainedJPEGDnCNN.mat"); end
これで、DnCNN ネットワークを使用して、イメージから JPEG 圧縮アーティファクトを取り除くことができるようになりました。
DnCNN ネットワークを使用した JPEG デブロックの実行
DnCNN を使用して JPEG デブロックを実行するには、この例の残りの手順に従って以下を行います。
3 種類の画質レベルで、JPEG 圧縮アーティファクトを含むサンプル テスト イメージを作成します。
DnCNN ネットワークを使用して、圧縮アーティファクトを取り除きます。
デブロックの前後のイメージを視覚的に比較します。
歪みのない参照イメージとの類似度を測定することで、圧縮イメージとデブロックされたイメージの画質を評価します。
ブロック アーティファクトがあるサンプル イメージの作成
テスト データ セット testImages
には、Image Processing Toolbox™ に付属する 20 個の歪みのないイメージが含まれています。イメージを imageDatastore
に読み込みます。
fileNames = ["sherlock.jpg","peacock.jpg","fabric.png","greens.jpg", ... "hands1.jpg","kobi.png","lighthouse.png","office_4.jpg", ... "onion.png","pears.png","yellowlily.jpg","indiancorn.jpg", ... "flamingos.jpg","sevilla.jpg","llama.jpg","parkavenue.jpg", ... "strawberries.jpg","trailer.jpg","wagon.jpg","football.jpg"]; filePath = fullfile(matlabroot,"toolbox","images","imdata")+filesep; filePathNames = strcat(filePath,fileNames); testImages = imageDatastore(filePathNames);
テスト イメージをモンタージュとして表示します。
montage(testImages)
いずれかのテスト イメージを選択して、JPEG デブロック ネットワークのテストに使用します。
testImage ="lighthouse.png"; Ireference = imread(testImage); imshow(Ireference) title("Uncompressed Reference Image")
JPEG Quality
値が 10、20 および 50 である 3 種類のテスト用圧縮イメージを作成します。
imwrite(Ireference,fullfile(tempdir,"testQuality10.jpg"),"Quality",10); imwrite(Ireference,fullfile(tempdir,"testQuality20.jpg"),"Quality",20); imwrite(Ireference,fullfile(tempdir,"testQuality50.jpg"),"Quality",50);
圧縮イメージの前処理
イメージの圧縮バージョンをワークスペースに読み取ります。
I10 = imread(fullfile(tempdir,"testQuality10.jpg")); I20 = imread(fullfile(tempdir,"testQuality20.jpg")); I50 = imread(fullfile(tempdir,"testQuality50.jpg"));
圧縮イメージをモンタージュとして表示します。
montage({I50,I20,I10},Size=[1 3])
title("JPEG-Compressed Images with Quality Factor: 50, 20 and 10 (left to right)")
人間の知覚は色の変化よりも明度の変化に敏感であるため、DnCNN はイメージの輝度チャネルだけを使用して学習させるということを思い出してください。関数 rgb2ycbcr
を使用して、JPEG 圧縮イメージを RGB 色空間から YCbCr 色空間に変換します。
I10ycbcr = rgb2ycbcr(I10); I20ycbcr = rgb2ycbcr(I20); I50ycbcr = rgb2ycbcr(I50);
DnCNN ネットワークの適用
ネットワークのフォワード パスを実行するには、関数 denoiseImage
を使用します。この関数で使用するのは、イメージのノイズ除去のための学習およびテスト手順とまったく同じものです。JPEG 圧縮アーティファクトはイメージ ノイズの一種と考えることができます。
I10y_predicted = denoiseImage(I10ycbcr(:,:,1),net); I20y_predicted = denoiseImage(I20ycbcr(:,:,1),net); I50y_predicted = denoiseImage(I50ycbcr(:,:,1),net);
色差チャネルは処理する必要ありません。デブロックされた輝度チャネルと元の色差チャネルを連結して、デブロックされたイメージを YCbCr 色空間で取得します。
I10ycbcr_predicted = cat(3,I10y_predicted,I10ycbcr(:,:,2:3)); I20ycbcr_predicted = cat(3,I20y_predicted,I20ycbcr(:,:,2:3)); I50ycbcr_predicted = cat(3,I50y_predicted,I50ycbcr(:,:,2:3));
関数 ycbcr2rgb
を使用して、デブロックされた YCbCr イメージを RGB 色空間に変換します。
I10_predicted = ycbcr2rgb(I10ycbcr_predicted); I20_predicted = ycbcr2rgb(I20ycbcr_predicted); I50_predicted = ycbcr2rgb(I50ycbcr_predicted);
デブロックされたイメージをモンタージュとして表示します。
montage({I50_predicted,I20_predicted,I10_predicted},Size=[1 3])
title("Deblocked Images with Quality Factor 50, 20 and 10 (Left to Right)")
改善を視覚的に分かりやすくするために、各イメージの小領域を調べます。関心領域 (ROI) をベクトル roi
を使って [x y width height] の形式で指定します。各要素は、ROI の左上隅の x と y 座標、幅と高さで定義されます。
roi = [30 440 100 80];
圧縮イメージをこの ROI にトリミングして、結果をモンタージュとして表示します。
i10 = imcrop(I10,roi);
i20 = imcrop(I20,roi);
i50 = imcrop(I50,roi);
montage({i50 i20 i10},Size=[1 3])
title("Patches from JPEG-Compressed Images with Quality Factor 50, 20 and 10 (Left to Right)")
デブロックされたイメージをこの ROI にトリミングして、結果をモンタージュとして表示します。
i10predicted = imcrop(I10_predicted,roi);
i20predicted = imcrop(I20_predicted,roi);
i50predicted = imcrop(I50_predicted,roi);
montage({i50predicted,i20predicted,i10predicted},Size=[1 3])
title("Patches from Deblocked Images with Quality Factor 50, 20 and 10 (Left to Right)")
定量的比較
デブロックされたイメージの画質を、4 つのメトリクスを通じて定量化します。補助関数 jpegDeblockingMetrics
を使用して、品質係数が 10、20、50 の圧縮イメージとデブロック イメージに対してこれらのメトリクスを計算します。この関数は、この例にサポート ファイルとして添付されています。
構造的類似性 (SSIM) 指数。SSIM は参照イメージに対してイメージの 3 つの特性である輝度、コントラスト、構造の視覚的影響を評価します。SSIM 値が 1 に近いほど、テスト イメージは参照イメージに近づきます。ここでは、参照イメージは JPEG 圧縮前の歪みのない元のイメージ
Ireference
です。このメトリクスの詳細については、ssim
を参照してください。ピーク S/N 比 (PSNR)。PSNR 値が大きいほど、歪みと比べて信号が強くなります。このメトリクスの詳細については、
psnr
を参照してください。Naturalness Image Quality Evaluator (NIQE)。NIQE は自然シーンで学習させたモデルを使用して知覚的画質を測定します。NIQE スコアが小さいほど知覚的画質が良好なことを示します。このメトリクスの詳細については、
niqe
を参照してください。Blind/Referenceless Image Spatial Quality Evaluator (BRISQUE)。BRISQUE は自然シーンの歪みのあるイメージで学習させたモデルを使用して知覚的画質を測定します。BRISQUE スコアが小さいほど知覚的画質が良好なことを示します。このメトリクスの詳細については、
brisque
を参照してください。
jpegDeblockingMetrics(Ireference,I10,I20,I50,I10_predicted,I20_predicted,I50_predicted)
------------------------------------------ SSIM Comparison =============== I10: 0.90624 I10_predicted: 0.91286 I20: 0.94904 I20_predicted: 0.95444 I50: 0.97238 I50_predicted: 0.97482 ------------------------------------------ PSNR Comparison =============== I10: 26.6046 I10_predicted: 27.0793 I20: 28.8015 I20_predicted: 29.3378 I50: 31.4512 I50_predicted: 31.8584 ------------------------------------------ NIQE Comparison =============== I10: 7.2194 I10_predicted: 3.9469 I20: 4.5158 I20_predicted: 3.0681 I50: 2.8874 I50_predicted: 2.4107 NOTE: Smaller NIQE score signifies better perceptual quality ------------------------------------------ BRISQUE Comparison ================== I10: 52.372 I10_predicted: 38.9272 I20: 45.3772 I20_predicted: 30.8993 I50: 27.7093 I50_predicted: 24.3847 NOTE: Smaller BRISQUE score signifies better perceptual quality
参考文献
[1] Zhang, K., W. Zuo, Y. Chen, D. Meng, and L. Zhang, "Beyond a Gaussian Denoiser: Residual Learning of Deep CNN for Image Denoising." IEEE® Transactions on Image Processing. Feb 2017.
[2] Grubinger, M., P. Clough, H. Müller, and T. Deselaers. "The IAPR TC-12 Benchmark: A New Evaluation Resource for Visual Information Systems." Proceedings of the OntoImage 2006 Language Resources For Content-Based Image Retrieval. Genoa, Italy. Vol. 5, May 2006, p. 10.
参考
rgb2ycbcr
| ycbcr2rgb
| dnCNNLayers
| denoiseImage
| trainingOptions
(Deep Learning Toolbox) | trainNetwork
(Deep Learning Toolbox) | randomPatchExtractionDatastore
関連するトピック
- イメージの深層学習向け前処理 (Deep Learning Toolbox)
- 深層学習用のデータストア (Deep Learning Toolbox)
- 深層学習層の一覧 (Deep Learning Toolbox)