「画像処理基礎」

九州大学 大学院システム情報科学研究院
情報知能工学部門
データサイエンス実践特別講座
備瀬竜馬, Diego Thomas, 正井克俊

画像解析概要

画像データ解析の流れ

2

画像データ（画像空間）

いろいろな画像

4画像データは意味を持つか？
●画像はあくまでピクセルごとの輝度値情報のみ
意味情報
着物を着た日本人女性が、三味線を弾いている江戸時代の絵？

The flow of analysis●データから情報を取り出し、情報から知識へデータからの情報の抽出●ピクセルの数値情報でしかない画像から、人は様々な情報を抽出できる●どんな色が多い?
●エッジはどこにある?
●人はどこにいる？
●建物はどこにある？

Look into histograms

2値画像，濃淡画像，カラー画像

8

カラー画像

+

=R成分

+

G成分

B成分

9

デジタル画像
規則的に並んだ有限個の点（画素）の集合

各画素の色は、赤、緑、青の3つの成分で表現されている

＋＋

R成分
G成分
0～255 0～255

B成分
0～255

10

画像の走査（スキャン)●ラスタ走査 (raster scan)

ゴール

スタート
すべての画素を１回ずつ通過

11ラスタ走査 (つづき)●画像のベクトル表現

画素値をラスタ走査順に列挙( f1,1,, f1,Y , f 2,1,, f x, y ,, f X ,Y )XY次元ベクトル●任意の画像＝XY次元空間内の１点

12

画像のベクトル表現(vector representation of image)●2値画像の場合の例

x = (0, 0 ,1,1,1,1, 0, 0,1,...,1, 0 )

T

7×7画像

49次元ベクトル●多値画像の場合の例

x = (0, 0, 255, 213,182, 0, 0,...,0 )

T

7×7画像

49次元ベクトル
13

“画像空間” (image space)

N×N画像

ゴール

(17, 128, 72, ....., 153)

N2次元ベクトル
第2画素72

スタート
第N2画素

128

17

第1画素の明るさ

14画像空間:任意の１点＝1画像

x

第1次元

A point in the image space corresponds to an image
15

画像空間

第10000画素

100x100画像

第1画素
任意の100ｘ100画像は10000次元空間で表せる！

16

画像データ●カラー画像データは、ピクセルごとにRGBの3つmのチャンネルの数字の組み合わせ

pixel = [red, green, blue]●n 行 m 列の画像： 𝑛𝑛 × 𝑚𝑚 ピクセルの数値

n●カラー画像：1つのピクセルは3つのチャンネルの数値を持つ● red, green, blue.

●例：100×100のカラー画像⇒3×100×100=30000の次元のベクトル

練習●Numpyをインポートする●ラスタ走査を使って “2”の画像をベクトルにする

白ピクセル＝０。青ピクセル＝255●numpy.array を使ってデータ変換する●Reshape を使ってベクトルから７x７の行列を求める●７x７の行列をプリントする

Google Driveとの連携

19

準備：Google Driveへフォルダごとアップ

フォルダごとドラッグすれば、フォルダの中身も全てアップロード可能

Google Driveとの接続

Drive をマウントをクリック

セルが現れるので、実行

Google Driveとの接続

コピー

リンクをクリックペースト

Google Driveのアカウントを選択

許可

driveが追加された

Drive上のファイルを読めるかを確認

Google Drive上のファイルのパスを記載

画像解析に便利なライブラリ

OpenCV / scikit-image

24

OpenCV

If interested, try at home ●http://opencv.org

http://docs.opencv.org/3.0beta/doc/py_tutorials/py_tutorials.html●CV = “Computer Vision”●様々な画像解析ライブラリ（関数群）が提供されている●Python用にライブラリが整備されている●注）アナコンダにはデフォルトでは入っていないため、インストールが別途必要。

scikit-image●Python用画像処理ライブラリ●Numpy arraysを利用●グレースケール画像は2次元配列(array)で表現●http://scikit-image.org

参考: http://www.scipy-lectures.org/packages/scikit-image/データの取得●skimage.dataに予め用意されている画像を読み込み●ファイルから画像を読み込み：skimage.io.imread()画像の可視化●画像の表示：skimage.io.imshow()●画像サイズ（（））●輝度値の最大、最小、平均（（（）））

練習1●skimage から io をインポートする●“coffee.tiff” を読み込んで、可視化する●画像のサイズとピクセルの寸法を求める

画像と配列，画素レベルの処理

画像データ構造，動画，閾値処理30

画素値へのアクセス
100●画素値へのアクセス
200

（（（））
）

“moon” は 4 つの値を持つ! ：red, green, blue, alpha （透過度）

画素値へのアクセス●(0,0) ：画像の左上

00※）pythonでは、０から始まる
Image type

coordinates

2D grayscale(row, col)2D multichannel(RGB)(row, col, ch)

3D grayscale(pln, row, col)3D multichannel(pln, row, col, ch)row ： 行
col ： 列

カラー画像●1画素につき、(Red,Green,Blue）の3チャンネルの数値●データ名.shape を使って確認しよう●それぞれのチャンネルに、0 から 255 までの値が入っている●例：赤（255, 0, 0）●Pythonで, それぞれのチャンネルにアクセスするには[row, col, 0 or 1 or 2]
RedGreenBlueカラー画像⇔グレースケール画像変換●（red, green, blue）⇒ gray value●画像変換：rgb2gray

Input color image

Output gray image

コントラスト強調●画素値： (一般的には)0 ～ 255 を取りうる●実際には、その中の狭い範囲にしか値がない画像も多い●下記の画像では [50, 100]の値しかない●コントラストが低い●skimage.exposure ：画像のコントラストを強調（利用する画素値の幅を広める）する関数が提供されている

コントラスト強調手法●ガンマ補正●暗い画素を持ち上げる（明るくする）●輝度ヒストグラムを用いたコントラスト補正●輝度の分布を用いて、輝度値を補正し、コントラストを強調●線形濃度変換●輝度値の分布範囲を[0, 255]に広げる

Histogram equalization● “Histogram_Equalization.py” を利用

Output images
元画像

線形変換

ヒストグラム
均一化

ヒストグラム
適応均一化
輝度値のヒストグラム
輝度範囲： [0: 1]
red curve ：輝度の積算

Source: http://scikit-image.org/docs/stable/auto_examples/color_exposure/plot_equalize.html#sphx-glrauto-examples-color-exposure-plot-equalize-py

練習2●skimage から data をインポートする●“chelsea"を読み込んで、 red channel > 160 となっている画

素を green [0, 255, 0]に上書きして、表示

cat = data.chelsea() # load the cat image
reddish = cat[:, :, 0] > 160

Data type Range●Note on data typeuint8

0 to 255

uint160 to 65535

uint320 to 232

float-1 to 1 or 0 to 1

int8-128 to 127

int16-32768 to 32767

int32-231 to 231 - 1

画素レベルの処理

Segmentation39セグメンテーション●ピクセルごとに背景か前景かをラベル付け
元画像ピクセル前景：１
背景：０

セグメンテーション画像

1101111001110011100111000001100000000000011

1 1
1 1
11

Load the coin image●skimage.data閾値によるセグメンテーション●閾値法：画素が閾値より高ければ前景、低ければ背景●Example:閾値：100閾値：1502値化の手がかり：ヒストグラム
画素数

黒(0)

白(２５６)
どうもこの辺が「背景」？

2値化の手がかり：ヒストグラム
画素数
どこに「しきい値」(threshold)を設定？
黒(0)

白(２５６)

モード法●ヒストグラムの谷＝しきい値

画素数

黒(0)

白(255)

45

大津の二値化●最適しきい値を決定

分散A

評価基準
分散C

分散B
分散A黒左部分の平均分散C

白右部分の平均＋分散B

これを最大化するようにしきい値を決定

閾値の限界●輝度値の分布が、前景と背景で必ずしもきれいに分かれているとは限らない●背景でも、前景より輝度値が高い画素（もしくはその逆）が存在●高すぎる閾値は、前景を取り逃し、低すぎる閾値は多めに前景を抽出してしまうFilling the holes●境界の内側をぬりつぶすことで、コインの領域を抽出●ndi.binary_fill_holes()を利用

連結成分解析●連結成分＝黒画素（もしくは白画素）の「塊」●４連結と8連結

４連結だと何個の連結成分？8連結では？

Removing small objects●ラベリングされた小さすぎる、大きすぎるオブジェクトは間違って抽出された可能性が高いので、大きさをチェックして、削除●ndi.label function を利用

フィルタリング
何かしらの計算結果

画像の全画素について計算

52

最も基本的なフィルタ：平滑化●単純化した例

1/3
1/31/3
1/3
1/3
1/3 1/3
1/3 1/3
1/3 1/3
1/3 1/3
1/31/3
1/3
1/3
1/3 1/3
1/31/3
1/3
1/3 1/3
1/3
1/3
1/3 1/3
1/3 1/3

フィルタ
マスク
33

13

3

3

0

1

03

00

原信号

2.3

2.3

2.3

2

3

0.3

1.3

1.3

1.3

153

1/9

1/9

1/9

1/9

1/9

1/9

1/9

1/9マスク

最も基本的なフィルタ：平滑化

1/9

1/9

1/9

1/9

1/9

1/9

1/9

1/9

1/9

1/9

内積

平滑化後

原画像

平滑化用
フィルタマスク(3x3)

10101010201010101010101010111010101054

最も基本的なフィルタ：平滑化

55

平滑化用のフィルタマスク

http://codezine.jp/article/detail/129

56

7.1 フィルタリングとは●画像上の各画素を中心とした局所領域で何らかの計算●画質改善や特徴抽出を目的

57

基本的なフィルタ：エッジ検出●単純化した例
-1/2

1-1/2

33フィルタマスク
33

3300000000000

原信号

3/2-3/2000058

基本的なフィルタ：エッジ検出

59

Painting images with labels●一まとまりの領域ごとにID(label)をつける●ndi.label

Visualize results (1)●label2rgb() でラベルごとに独立した色を与えて可視化.

Visualize results (2)●オブジェクトの境界を可視化●skimage.morphology.erosion

gray2rgbgray2rgb

演習65

演習 1 (thresholding)●”camera”画像の呼び出し●輝度値のヒストグラム可視化●複数の閾値を用いて、セグメンテーションの結果を比べよう！

●ヒント:●skimage.data.camera()●numpy.histogram()●画像配列をベクトルに直す方法

image.reshape(-1)

演習 2●“astronaut” 画像を読み込み、RGB成分それぞれの画像を表示してみよう●ヒント:●image = data.astronaut()●image.shape: (512L, 512L, 3L)

演習 3 (image stiching)●４つの画像(im1.tiff, im2.tiff, im3.tiff, im4.tiff)を読み込んで、つなげることで一つの画像を作って、保存しよう！

●ヒント:●画像の読み込み： io.imread●画像の大きさ：shape attribute●画像の初期化： numpy.zero (specify np.uint8 for the typeto show nice results)●画像の保存 io.imsave

演習 4 (downsampling)●“atronaut” 画像を読み込み, 画像を2分の１のサイズにダウンサン

プリングせよ●関数を利用する●ヒント●from skimage.transform import downscale_local_mean●downscale_local_mean(image, (2,2,1))→ 2×2×1のウィンドウで平均値を求めてその値を利用

演習 5●“coins”画像を読み込み、色んなコントラスト強調を試してみよう●ヒント:●from skimage import data, io●coins = data.coins()●36ページ

Advance
早く終わった人はやってみよう演習 6●“camera"画像を読み込み、下図のように円状（中心：画像の中心、半径R：画像の縦横のサイズの半分）の外の画素値を全て０とするプログラム
円の方程式
2𝑖𝑖, 𝑗𝑗 𝑖𝑖 − 𝑐𝑐𝑖𝑖 2 + 𝑗𝑗 − 𝑐𝑐𝑗𝑗 < 𝑅𝑅2 )},※）(𝑖𝑖, 𝑗𝑗) ：ピクセルの座標(𝑐𝑐𝑖𝑖 , 𝑐𝑐𝑗𝑗 ) ：円の中心座標
𝑅𝑅 ：円の半径

Answer

演習 ４：Advance (downsampling)●“atronaut” 画像を読み込み, 画像を2分の１のサイズにダウンサンプリン

グしよ●周辺の画素の平均値を求めて、新画像の1画素の値にする●ヒント●float型に変換してデータを取得•image = data.astronaut().astype(float)●行と列の数の取得•nrows, ncols, _ = image.shape (color image は 3次元)
●unsigned int8 型に戻す
•io.imshow(result.astype(np.uint8))

演習 7●“atronaut” 画像を読み込み、円状（中心：画像の中心、半径R：画像の縦横のサイズの半分）の外の画素値を全て０とするプログ
ラム

●ヒント:

●26ページのカラーバージョン

演習 8●“LENNA.bmp” を読み込み、sobel filter でエッジ抽出してみよう●ヒント:●60ページ

演習９●“Text.bmp”を読み込み、テキスト領域を閾値を用いてセグメンテー

ションせよ●領域ごとにラベリングを行って、領域ごとに色をつけよ●ヒント:●平滑化してから、輝度値で閾値処理●他の領域を含んでいてもO.K.

演習 10●“Text.bmp”を読み込み、テキスト領域をwatershedを用いてセグメン

テーション

●ヒント:
●Sobel filter を用いてelevation_mapを作成●マーカー領域は、閾値でラフ（明らかに輝度が高い領域を抽出）に抽出●from skimage.morphology import watershed●他の領域を含んでいてもO.K.