この記事はMATLABで行う画像処理のやり方について説明する入門となります。
はじめに
MATLABでは画像が配列として扱われるので、まず配列のことをよく理解しておいたら大分楽です。
配列に関する入門はこの前の記事で纏めていたので、まずはその記事を読むことをおすすめします。
画像処理に関する機能は一部特にパッケージを追加しなくてもすぐ使えますが、一部の関数はImage Processing Toolboxのものなのでインストールしておく必要があります。
画像を読み込む 〔imread〕
MATLABで画像データを扱う時に基本的にimread
関数で画像ファイルを読み込んで、配列に変換します。色画像だったら「高さ×広さ×3」の3次元の配列に、無色画像だったら「高さ×広さ」の2次元の配列になります。値は0から255の8ビットの符号なし整数(uint8)。色の値はRGB(赤、緑、青)。
例としてこの記事の殆どの内容はこの画像を使うことにします。
sarada.jpg
|
画像を読み込んで調べてみます。
ar_img = imread("sarada.jpg");
ar_size = size(ar_img)
ar_max = max(ar_img(:))
ar_size =
405 540 3
ar_max =
uint8
255
このように画像はMATLABの中での配列になって、これを使って色々やることができます。
画像の基本情報を取る 〔imfinfo〕
画像ファイルに関する情報はimfinfo
関数から取得できます。
imginfo = imfinfo("sarada.jpg")
Filename: '/Users/phyblas/Documents/MATLAB/sarada.jpg'
FileModDate: '20-Apr-2024 13:50:23'
FileSize: 37195
Format: 'jpg'
FormatVersion: ''
Width: 540
Height: 405
BitDepth: 24
ColorType: 'truecolor'
FormatSignature: ''
NumberOfSamples: 3
CodingMethod: 'Huffman'
CodingProcess: 'Sequential'
Comment: {}
画像を表示する 〔imshow〕
MATLABの中で画像を表示するには普段imshow
という関数を使います。使い方は色々ありますが、例えば直接画像ファイルの名前を入れたらその画像を読み込んで表示します。
imshow("sarada.jpg")
又はimread
で3次元配列に読み込んでから使うのも同じ結果です。
arimg = imread("sarada.jpg");
imshow(arimg)
無色の画像、つまり2次元配列も表示できます。例えばこの画像の赤の値だけ取って無色画像として表示します。
arimg = imread("sarada.jpg");
imshow(arimg(:,:,1))
画像をグラフとして表示する 〔image〕
imread
関数を使ったらグラフを書くみたいに画像を表示することもできます。この場合アスペクト比を変えたりグリッドを行けたりするもできて使い勝手がいいですね。
figure(Position=[100 100 800 400])
image(imread("sarada.jpg"))
pbaspect([3 1 1])
grid
set(gca,GridLineStyle="--",LineWidth=2,GridColor="#660000")
グラフを書くことについては説明すると長くなるのでここでは割愛します。
画像を書き込む 〔imwrite〕
imwrite
関数で配列を画像ファイルとして書き込むことができます。
例えば乱数で適当に作ってみた配列を画像として出力してみます。
arimg = rand(200,400,3);
imwrite(arimg,"randimg.jpg")
保存する配列はデータ型がdoubleでもuint8でもいいですが、doubleなら[0~1]で、uint8なら[0~255]範囲の値を使います。
2次元の配列の場合は無色の画像として保存されます。
arimg = reshape(mod(1:40000,1250)/1250,200,200);
imwrite(arimg,"rangeimg.jpg")
配列としての機能を駆使する
画像はただの配列だから配列の基本がしっかりわかって使いこなせていれば特に関数を使わなくても色々できます。
例えば一部だけ切り取る。
arimg = imread("sarada.jpg");
imwrite(arimg(140:240,180:270,:),"sarada_migime.jpg")
明るいと暗いを逆にする。
arimg = imread("sarada.jpg");
imwrite(255-arimg,"sarada_gyaku.jpg")
色んな数学計算をして各色の値を調整することもできます。ただしimread
関数で読み込んだ配列はuint8なので、計算する時にまずデータ型をdoubleに変える必要があります。
例えば三角関数を使って波みたいな暗い縞を作ります。
arimg = double(imread("sarada.jpg"));
arimg = arimg.*(0.8+cos(linspace(0,24*pi,540))*0.2);
arimg = arimg.*(0.8+cos(linspace(0,18*pi,405)')*0.2);
imwrite(uint8(arimg),"sarada_cos.jpg")
色を分ける 〔imsplit〕
色画像の配列はRGB3色から成されているから、どちらか使いたい時はarimg(:,:,1)
、arimg(:,:,2)
、arimg(:,:,3)
のように書けばいいですね。
又はimsplit
という関数を使って同時に3色を分けることもできます。
これを使って3色に分解して並んで表示してみます。
arimg = imread("sarada.jpg");
[aka,midori,ao] = imsplit(arimg);
aka = aka.*reshape(uint8([1 0 0]),1,1,3);
midori = midori.*reshape(uint8([0 1 0]),1,1,3);
ao = ao.*reshape(uint8([0 0 1]),1,1,3);
imwrite([arimg aka;midori ao],"sarada_imsplit.jpg")
グレースケール 〔im2gray〕
im2gray
で色画像を自然に無色(グレースケール)にすることができます。
arimg = imread("sarada.jpg");
arimg_gs = im2gray(arimg);
imwrite(arimg_gs,"sarada_gs.jpg")
この関数はただRGBの平均値を取るというわけではなく、「0.299 : 0.587 : 0.114」という違う重みで計算するのです。(詳しくは公式サイト参考)
自分で計算してみてもやはり関数を使うのと同じ結果が出てきます。
[aka,midori,ao] = imsplit(imread("sarada.jpg"));
arimg_gs = uint8(0.299.*aka + 0.587.*midori + 0.114.*ao);
imwrite(arimg_gs,"sarada_gs.jpg")
試しに単なる平均値を取ってみたら……。
arimg = imread("sarada.jpg");
arimg_gs = uint8(mean(arimg,3));
imwrite(arimg_gs,"sarada_gs2.jpg")
本当に結果はちょっと違います。確かにim2gray
を使った方が自然に感じますね。
画像をひっくり返す 〔flip〕
画像を縦方向をひっくり返すにはflip
関数を使うことができます。
arimg = imread("sarada.jpg");
imwrite(flip(arimg),"sarada_flip.jpg")
横の方向で逆にしたい場合は2
を入れて軸を指定します。
arimg = imread("sarada.jpg");
imwrite(flip(arimg,2),"sarada_flip2.jpg")
画像のサイズ(解像度)を変える 〔imresize〕
imresize
関数によって画像を指定した[高さ 広さ]
に大きくしたり小さくしたりできます。
arimg = imread("sarada.jpg");
imwrite(imresize(arimg,[300 200]),"sarada_200x300.jpg")
もしただ高さだけ指定してアスペクト比を保つまま広さも変えたい場合はNaN
と書くのです。
arimg = imread("sarada.jpg");
imwrite(imresize(arimg,[300 NaN]),"sarada_300.jpg")
広さだけ指定したい場合も同じ。
もし指定したのは一つの数値の場合それはピクセルではなく倍数を指定するということになります。
例えば半分サイズにします。
arimg = imread("sarada.jpg");
imwrite(imresize(arimg,0.5),"sarada_x0.5.jpg")
その他にサイズ変更する時の内挿のメソッドも指定できます。既定はbicubic
(双三次内挿)を使ってこれは一番自然にできますが、bilinear
(双一次内挿)やnearest
(最近傍内挿)にすることができます。
例えば左目のところだけ取って拡大してみて、bicubic
とnearest
の違いを見ます。
arimg = imread("sarada.jpg");
arimg = arimg(171:230,301:380,:);
imwrite(imresize(arimg,4),"sarada_resize_bicubic.jpg")
imwrite(imresize(arimg,4,"nearest"),"sarada_resize_nearest.jpg")
こうやってnearest
を利用してモザイク処理もできます。
arimg = imresize(imread("sarada.jpg"),0.1);
imwrite(imresize(arimg,10,"nearest"),"sarada_mozaiku.jpg")
画像を回転させる 〔imrotate〕
imrotate
関数で画像を好きな角度で回転させることができます。
arimg = imread("sarada.jpg");
imwrite(imrotate(arimg,30),"sarada_rotate30.jpg")
既定では回転した後何もないピクセルができてサイズが変わるが、同じ大きさのままにしたい場合は"crop"
と書きます。
arimg = imread("sarada.jpg");
imwrite(imrotate(arimg,45,"crop"),"sarada_rotate45.jpg")
画像を繰り返して並べる 〔repmat〕
repmat
関数を使って同じ画像をコピーして何回も並べることができます。
arimg = imread("sarada.jpg");
arimg = repmat(arimg,[5 4]);
imwrite(imresize(arimg,0.25),"sarada_repmat.jpg")
パディングする 〔padarray〕
padarray
関数で周りの空なピクセルで埋めることができます。
arimg = imread("sarada.jpg");
arimg = padarray(arimg,[15 50]);
imwrite(arimg,"sarada_padarray.jpg")
既定では0
で埋められますが、"replicate"
を書いたら境界のピクセルを取って繰り返すことになります。
arimg = imresize(imread("sarada.jpg"),0.5);
arimg = padarray(arimg,[111 100],"replicate");
imwrite(arimg,"sarada_padarray_replicate.jpg")
"circular"
にしたら画像を循環で繰り返します。"symmetric"
は鏡の反射みたいに逆の方向で繰り返します。
その他にどの方向でパディングするか指定できます。既定では"both"
つまり前も後ろも。前だけにしたいなら"pre"
で、後ろなら"post"
。これを"circular"
、"replicate"
、"symmetric"
と共に書くこともできます。
arimg = imresize(imread("sarada.jpg"),0.25);
arimg = padarray(arimg,[220 270],"symmetric","post");
imwrite(arimg,"sarada_padarray_symmetric.jpg")
色空間を変える 〔rgb2hsv〕
普段色はRGB3色の数値で表示されていますが、他の色空間を使う場合もあります。もう一つよく使われるのはHSV、つまり色相(H)、彩度(S)、明度(V)です。詳しいことは割愛しますが、これが画像分析する時のこの空間を使う場合もあります。
rgb2hsv
関数で普段のRGB空間からHSV空間に変えることができます。返される数値は0から1の小数の配列。
例えばHSVの値を分解してグラフで表示してみましょう。
arimg = imread("sarada.jpg");
arimg_hsv = rgb2hsv(arimg);
figure(Name="HSV")
tiledlayout(2,2,Padding='none',TileSpacing='tight');
nexttile
imshow(arimg_hsv(:,:,1))
title("色相")
nexttile
imshow(arimg_hsv(:,:,2))
title("彩度")
nexttile
imshow(arimg_hsv(:,:,3))
title("明度")
nexttile
imshow(arimg)
title("元の画像")
カラーマップを使う 〔ind2rgb〕
無色の画像を扱う時に単に黒から白で表示するよりもカラーマップを使って色にした方がいいかもしれません。
ind2rgb
関数で無色画像からカラーマップで色に変換することができます。
グレースケールにされた画像に使って綺麗な色に変えてみます。
arimg = imread("sarada.jpg");
arimg_gs = im2gray(arimg);
arimg_parula = ind2rgb(arimg_gs,parula);
imwrite(arimg_parula,"sarada_parula.jpg")
ただし実はimwrite
やimshow
を使う時にわざわざind2rgb
を使う必要がなく、カラーマップを入れたら自動的に変換してくれて便利です。
imwrite(arimg_gs,copper,"sarada_copper.jpg")
その他にも色んなカラーマップがあるので、それぞれ作って比較してみます。
arimg_gs = im2gray(imread("sarada.jpg"));
lis_cmap = ["spring" "summer" "autumn" "winter" ...
"jet" "parula" "copper" "turbo" ...
"hot" "pink" "bone" "sky" "abyss","hsv"];
mkdir("saramap")
for cmap = lis_cmap
imwrite(arimg_gs,eval(cmap),"saramap/"+cmap+".jpg")
end
こうやってこんなフォルダができます。
どんなカラーマップが使えるか公式サイトで調べられます。
フォルダごと画像を読み込む 〔imageDatastore〕
沢山の画像が一緒のフォルダにあって全部使いたい場合はimageDatastore
を使うのも便利です。機械学習などでもよく使われています。
例えば前の例において作成したフォルダで試します。
imds = imageDatastore("saramap")
imds =
ImageDatastore のプロパティ:
Files: {
'/Users/phyblas/Documents/MATLAB/saramap/abyss.jpg';
'/Users/phyblas/Documents/MATLAB/saramap/autumn.jpg';
'/Users/phyblas/Documents/MATLAB/saramap/bone.jpg'
... and 11 more
}
Folders: {
'/Users/phyblas/Documents/MATLAB/saramap'
}
AlternateFileSystemRoots: {}
ReadSize: 1
Labels: {}
SupportedOutputFormats: ["png" "jpg" "jpeg" "tif" "tiff"]
DefaultOutputFormat: "png"
ReadFcn: @readDatastoreImage
読み込んだらImageDatastore
のオブジェクトになって、色んなプロパティとメソッドを持っています。
.read
メソッドを使ったら一つ画像を読み込んで、もう一度使ったら次の画像を読み込みます。forループとかで一枚ずつ読み込んで処理することができます。
imds = imageDatastore("saramap");
for i = 1:length(imds.Files)
img = imds.read;
[~,fn] = fileparts(imds.Files{i});
sx = size(img,2);
sy = size(img,1);
fprintf("%10s [%d×%d]\n",fn,sx,sy)
end
abyss [540×405]
autumn [540×405]
bone [540×405]
copper [540×405]
hot [540×405]
hsv [540×405]
jet [540×405]
parula [540×405]
pink [540×405]
sky [540×405]
spring [540×405]
summer [540×405]
turbo [540×405]
winter [540×405]
又は.readall
メソッドを使って一気にcell配列として全部読み込むこともできます。
(cell配列は何なのかまだよくわからない方はこの記事を呼んでください)
cell配列になるので、もし4次元の配列にしたいならちょっと工夫が必要です。これもcell配列に関して理解しておいた方がいいと思います。
imds = imageDatastore("saramap");
cellimg = imds.readall
allimg = cat(4,cellimg{:});
arrsize = size(allimg)
allimg =
14×1 cell 配列
{405×540×3 uint8}
{405×540×3 uint8}
{405×540×3 uint8}
{405×540×3 uint8}
{405×540×3 uint8}
{405×540×3 uint8}
{405×540×3 uint8}
{405×540×3 uint8}
{405×540×3 uint8}
{405×540×3 uint8}
{405×540×3 uint8}
{405×540×3 uint8}
{405×540×3 uint8}
{405×540×3 uint8}
arrsize =
405 540 3 14
ちなみに横で連結したいならこう書きます。
allimg = [cellimg{:}];
fprintf("%d × %d × %d\n",size(allimg))
405 × 7560 × 3
縦でで連結したいならcell2mat
関数を使います。
allimg = cell2mat(cellimg);
fprintf("%d × %d × %d\n",size(allimg))
5670 × 540 × 3
ReadFcn
というキーワードに関数を入れたら、その関数は画像が読み込まれる時にまず適用されて、その関数の返り値が使われます。
例えばグレースケールにしてサイズ変更したいならこう書きます。
function arimg = fcn(filenamae)
arimg = imread(filenamae);
arimg = im2gray(arimg);
arimg = imresize(arimg,[300 NaN]);
end
imds = imageDatastore("saramap",ReadFcn=@fcn);
join(string(size(cat(4,imds.readall{:})))," × ")
"300 × 400 × 1 × 14"
画像をいっぱい並んで表示する 〔montage〕
沢山の画像を表示する時にmontage
という関数を使うことも多いです。これを使ったら画像が四角形に並んで便利です。
montage
を使う方法は色々ありますが、例えば4次元の配列に使う場合。試しに適当に作って表示してみます。
arimg = zeros(100,100,3,9,"uint8")+100;
arimg(:,:,:,1) = 0;
arimg(:,:,1,2) = 255;
arimg(:,:,2,3) = 255;
arimg(:,:,3,4) = 255;
arimg(:,:,1:2,5) = 255;
arimg(:,:,2:3,6) = 255;
arimg(:,:,[1 3],7) = 255;
arimg(:,:,:,8) = 255;
arimg(31:70,31:70,:,:) = 200;
montage(arimg)
imageDatastore
と使うこともできます。その場合フォルダの中の画像を全部読み込むことになります。
montage(imageDatastore("saramap"))
色々キーワードを入れて表示する方法を設定することができます。例えばSize
は縦と横に並べる数。BorderSize
は各画像の間の隙間。BackgroundColor
は背景の色。
montage(imageDatastore("saramap"),Size=[4 5],BorderSize=4,BackgroundColor="y")
直接画像ファイルの名前を入れて使うこともできます。
montage(["saramap/spring.jpg" ...
"saramap/summer.jpg" ...
"saramap/autumn.jpg" ...
"saramap/winter.jpg" ])
3次元の配列に使う場合、無色の画像と見做されます(その場合カラーマップを指定することもできます)。
例えば1枚だけの色画像を使ったら、3枚の無色だ認識されて、3色に分けられてしまいます。
montage(imread("sarada.jpg"),bone)
画像を並んで連結する〔imtile〕
imtile
はmontage
と似ていますが、表示ではなく一つの大きな画像に合併するのです。
arimg = imtile(imageDatastore("saramap"),GridSize=[5 3],BorderSize=5,BackgroundColor=[0.4 0.2 0.1]);
imwrite(imresize(arimg,0.3),"saramap_imtile.jpg")
参考&もっと読む
- MATLABによる画像処理・コンピュータービジョン入門
- 1.1 MATLABによる画像処理の基本
- 1.2 豊富な可視化機能:MATLAB基本関数
- 2.1.1 各種画像データフォーマットの読込み・書込み
- 2.1.2 画像・3次元ボリュームデータ・医用画像(DICOM/NIfTI)の表示
- 2.1.3 静止画 画像処理・解析のワークフロー
- 2.1.4 グラフィックス (マーカー描画・テキスト描画・図形描画)
- 2.3.1 二値化・適応二値化
- 2.3.4 各種コントラスト調整
- 【Matlab】自分用忘備録 DeepLearning編
- [MATLAB]アフィン変換による変形およびその推定
- 【MATLAB】モザイクアートを手実装する(モノクロ画像編)
- MATLABでPhotoShopの深度ぼかしを再現する。
- MATLAB でスピード感のあるアニメーション作成
終わりに
以上MATLABでよく使われる画像処理の基本的な機能を紹介しました。これはただ基本なので、実際にその他にもまだできることが沢山あります。
外部ライブラリ豊富のPythonと違って、MATLABの画像処理機能はほぼ全部公式のものでやり方は統一しているので、安定で覚えやすくて一旦習得したら戸惑うことなくずっと使えそうですね。