Posts Eigenface로 해보는 PCA
Post
Cancel

Eigenface로 해보는 PCA

1. Olivetti 데이터


1.1 데이터 소개

  • 미국의 AT&T와 캠프리지 대학 전산 연구실에서 공동으로 제작한 얼굴 사진 데이터
  • 얼굴 인식 등 다양한 분야에서 활용되고 있음
  • 일부 데이터가 sklearn에 dataset으로 내장되어 있음


2. 실습


2.1 Data load

1
2
3
4
from sklearn.datasets import fetch_olivetti_faces

faces_all = fetch_olivetti_faces()
print(faces_all.DESCR)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
.. _olivetti_faces_dataset:

The Olivetti faces dataset
--------------------------

`This dataset contains a set of face images`_ taken between April 1992 and 
April 1994 at AT&T Laboratories Cambridge. The
:func:`sklearn.datasets.fetch_olivetti_faces` function is the data
fetching / caching function that downloads the data
archive from AT&T.

.. _This dataset contains a set of face images: http://www.cl.cam.ac.uk/research/dtg/attarchive/facedatabase.html

As described on the original website:

    There are ten different images of each of 40 distinct subjects. For some
    subjects, the images were taken at different times, varying the lighting,
    facial expressions (open / closed eyes, smiling / not smiling) and facial
    details (glasses / no glasses). All the images were taken against a dark
    homogeneous background with the subjects in an upright, frontal position 
    (with tolerance for some side movement).

**Data Set Characteristics:**

    =================   =====================
    Classes                                40
    Samples total                         400
    Dimensionality                       4096
    Features            real, between 0 and 1
    =================   =====================

The image is quantized to 256 grey levels and stored as unsigned 8-bit 
integers; the loader will convert these to floating point values on the 
interval [0, 1], which are easier to work with for many algorithms.

The "target" for this database is an integer from 0 to 39 indicating the
identity of the person pictured; however, with only 10 examples per class, this
relatively small dataset is more interesting from an unsupervised or
semi-supervised perspective.

The original dataset consisted of 92 x 112, while the version available here
consists of 64x64 images.

When using these images, please give credit to AT&T Laboratories Cambridge.
  • 올리베티 데이터의 일부만 이용하여 PCA 실습 진행


2.2 특정 샘플을 선택 후 출력

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import matplotlib.pyplot as plt

K = 20
faces = faces_all.images[faces_all.target == K]

N = 2
M = 5

fig = plt.figure(figsize=(10, 5))
plt.subplots_adjust(top = 1, bottom = 0, hspace= 0, wspace= 0.05)

for n in range(N * M):
    ax = fig.add_subplot(N , M, n + 1)
    ax.imshow(faces[n], cmap = plt.cm.bone)
    ax.grid(False)
    ax.xaxis.set_ticks([])
    ax.yaxis.set_ticks([])
    
plt.suptitle('Olivetti')
plt.tight_layout()
plt.show()

  • K값을 변환하면 다른 사람의 얼굴이 나온다
  • 양옆을 보는 사진, 웃는 사진 등 1명이 10장으로 구성되어있음


2.3 두개의 성분으로 분석

1
2
3
4
5
6
7
8
9
10
from sklearn.decomposition import PCA

K = 20

pca = PCA(n_components= 2)

X = faces_all.data[faces_all.target == K]
W = pca.fit_transform(X)

X_inv = pca.inverse_transform(W)


2.4 PCA 후 해당 데이터로 원점으로 복귀한 데이터로 그린 이미지

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
N = 2
M = 5

fig = plt.figure(figsize=(10, 5))
plt.subplots_adjust(top=1, bottom=0, hspace=0, wspace=0.05)

for n in range(N * M):
    ax = fig.add_subplot(N, M, n + 1)
    ax.imshow(X_inv[n].reshape(64, 64), cmap=plt.cm.bone)
    ax.grid(False)
    ax.xaxis.set_ticks([])
    ax.yaxis.set_ticks([])

plt.suptitle('PCA result')
plt.tight_layout()
plt.show()

  • PCA를 진행 한 데이터로 원점으로 복귀(X_inv = pca.inverse_transform(W))로 그린 사진으로, 원래의 데이터랑 큰 차이가 없는것으로 보인다


2.5 원점과 두 개의 eigen face

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
face_mean = pca.mean_.reshape(64, 64)
face_p1 = pca.components_[0].reshape(64, 64)
face_p2 = pca.components_[1].reshape(64, 64)

plt.figure(figsize=(12, 7))
plt.subplot(131)
plt.imshow(face_mean, cmap=plt.cm.bone)
plt.grid(False); plt.xticks([]); plt.yticks([]); plt.title('mean')
plt.subplot(132)
plt.imshow(face_p1, cmap=plt.cm.bone)
plt.grid(False); plt.xticks([]); plt.yticks([]); plt.title('face_p1')
plt.subplot(133)
plt.imshow(face_p2, cmap=plt.cm.bone)
plt.grid(False); plt.xticks([]); plt.yticks([]); plt.title('face_p2')
plt.show()

  • face_mean은 원점, face_p1은 한방향, face_p2은 다른 한방향으로 생각하면 된다.
  • 이 3개의 이미지가 앞에서 보았던 10개의 이미지를 대표한다고 생각하면 된다


2.5 가중치 선정

1
2
3
4
5
6
import numpy as np

N = 2
M = 5
w = np.linspace(-5, 10, N * M)
w
1
2
array([-5.        , -3.33333333, -1.66666667,  0.        ,  1.66666667,
        3.33333333,  5.        ,  6.66666667,  8.33333333, 10.        ])
  • -5 ~ 10까지 가중치(w)를 설정하여 face에 적용시켜보려고 한다


2.6 첫번째 성분의 변화

1
2
3
4
5
6
7
8
9
10
11
12
fig = plt.figure(figsize=(10, 5))
plt.subplots_adjust(top = 1, bottom= 0, hspace=0, wspace= 0.05)

for n in range(N * M):
    ax = fig.add_subplot(N, M, n + 1)
    ax.imshow(face_mean + w[n] * face_p1, cmap=plt.cm.bone)
    plt.grid(False); plt.xticks([]); plt.yticks([])
    plt.title('Weight : ' + str(round(w[n])))


plt.tight_layout()
plt.show()

  • 평균얼굴(원점)에 가중치를 곱한 face_p1을 더하면 해당 얼굴이 보인다. 오른쪽과 왼쪽을 보는 얼굴로 파악된다


2.7 두번째 성분에 대한 변화

1
2
3
4
5
6
7
8
9
10
11
12
fig = plt.figure(figsize=(10, 5))
plt.subplots_adjust(top = 1, bottom= 0, hspace=0, wspace= 0.05)

for n in range(N * M):
    ax = fig.add_subplot(N, M, n + 1)
    ax.imshow(face_mean + w[n] * face_p2, cmap=plt.cm.bone)
    plt.grid(False); plt.xticks([]); plt.yticks([])
    plt.title('Weight : ' + str(round(w[n])))


plt.tight_layout()
plt.show()

  • 두번째 얼굴은 정면을 바라보고 있고, 가중치가 더해짐에 따라 점점 무표정이 되거나 웃는 얼굴로 변화되는것으로 파악된다


2.8 두개의 성분을 모두 표현하기

1
2
3
4
nx, ny = (5, 5)
x = np.linspace(-5, 8, nx)
y = np.linspace(-5, 8, ny)
w1, w2 = np.meshgrid(x, y)


2.9 Shpae 조정

1
w1.shape
1
(5, 5)
  • shape가 5 ,5로 되어있으므로, 이를 조정하여 25로 바꾼다


1
2
3
w1 = w1.reshape(-1, )
w2 = w2.reshape(-1, )
w1.shape
1
(25,)


2.10 성분 2개에 가중치를 준것을 출력

1
2
3
4
5
6
7
8
9
10
11
12
fig = plt.figure(figsize=(12, 10))
plt.subplots_adjust(top=1, bottom=0, hspace=0, wspace=0.05)

N = 5
M = 5

for n in range(N * M):
    ax = fig.add_subplot(N, M, n+1)
    ax.imshow(face_mean + w1[n] * face_p1 + w2[n] * face_p2, cmap = plt.cm.bone)
    plt.grid(False); plt.xticks([]); plt.yticks([])
    plt.title('Weight : ' + str(round(w1[n],1)) + ', ' + str(round(w2[n],1)))
plt.show()

  • 위의 사진들은 원점(평균얼굴)에서 성분1과 성분2의 사이들에 퍼저있는 사진이라고 생각하면됨
  • 앞에서 K값을 변경하면 다른 사람들의 얼굴이 나오고, 해당 얼굴로도 PCA를 해보면 정면, 좌우가 아닌 다른 성분으로 분리된 사진들이 나오게 된다.
This post is licensed under CC BY 4.0 by the author.