SVD를 이용한 이미지 처리

2022. 10. 17. 11:16R study/Multivariate Analysis

이 글은 책 'R 응용 다변량 분석(나종화)'를 바탕으로 작성되었습니다.

 

특잇값분해(singuar value decomposition, SVD)는 고윳값분해와 마찬가지로 행렬을 대각화하는 방법이다. 고윳값분해가 정사각($n\times n$)행렬에 대해서만 적용되는 반면, 특잇값분해는 직사각($m\times n$)행렬에 대해서도 적용되므로 그 활용도가 매우 높다. 다변량 분석(주성분 분석, 다차원척도법 등), 데이터마이닝과 기계학습 등의 주요 알고리즘에 대해 특잇값분해가 사용된다.

$$ A=U\Sigma V^{T} $$

$A$ : 임의의 $m\times n$ 행렬

$U$ : $m\times n$ 직교행렬(Orthgonal matrix)

$V$ : $n\times n$ 직교행렬

$\Sigma $ : $m\times n$ 직사각 대각행렬

 

특잇값분해의 개념은 건너 뛰고 SVD의 기하학적 의미 설명

 

행렬 $A$를  통한 선형변환($Ax$)는 벡터(x)에 대해 회전(rotation), 스케일 변환, 반사(reflection)의 작용을 한다. 이 과정은 직교행렬($V^{T}$)에 의해 회전되고, 대각행렬($\Sigma$)에 의해 스케일 변환된 후, 다시 직교행렬($U$)에 의해 회전되는 과정의 결과와 동일하다. 직교행렬은 회전변환 또는 반사 회전변환(180도)을 수행하고, 대각행렬은 각 좌표성분으로의 스케일 변환을 수행한다. 

 

SVD가 활용되는 예로는 데이터 축소, 선형 최소제곱해 문제, 영상처리 및 압축, 잡음제거, 데이터 군집화에서 군집개수 결정, 다변량 이상치 탐지, 관측값 변수의 추세 탐지, 행렬의 계수 결정 등이 있다. 

 

library(OpenImageR)

img <- readImage("C:/Users/82109/OneDrive/사진/vegtable.png")
dim(img)
imageShow(img)

사진 출처 : RGB 이미지나 컬러맵을 회색조로 변환하기 - MATLAB rgb2gray - MathWorks 한국

가로 pixel이 467, 세로 pixel이 678, color channel이 3개

r <- rgb_2gray(img)
imageShow(r)
dim(r)

grey로 변경

 

r[1:10, 1:10]
r[100:130,100:130]
summary(r)

pixel의 summary

 

r.svd = svd(r)
u = r.svd$u
d = r.svd$d
v = r.svd$v
dim(u)
dim(v)
dim(v)
length(d)
d
round(d, 3)

SVD  적용

 

plot(1:length(r.svd$d), r.svd$d)

y축은 특잇값의 크기이다. singular value가 점점 떨어지는 것을 볼 수 있다.

u1 <- as.matrix(u[,1]) # 467x1
v1 <- as.matrix(v[,1]) # 678x1
d1 <- as.matrix(d[1,1]) # scalar
l1 <- u1%*%d1%*%t(v1) # 467x678
plot(0, type='n', axes=F, xlab="", ylab="")
imageShow(l1)

depth <- 5 
us <- as.matrix(u[,1:depth])
vs <- as.matrix(v[,1:depth])
ds <- as.matrix(d[1:depth, 1:depth])
ls <- us%*%ds%*%t(vs)
plot(0, type='n', axes=F, xlab="", ylab="")
imageShow(ls)

depth <- 20
us <- as.matrix(u[,1:depth])
vs <- as.matrix(v[,1:depth])
ds <- as.matrix(d[1:depth, 1:depth])
ls <- us%*%ds%*%t(vs)
plot(0, type='n', axes=F, xlab="", ylab="")
imageShow(ls)

SVD를 근사했을 때 1개의 특잇값을 이용했을 때부터 20개의 특잇값을 근사했을 때 이다.

특잇값이 커질 수록 사진이 점점 선명해지는 것을 볼 수 있고 정보의 손실이 적어진다. 

 

원본 이미지의 경우 $400\times 678=271200$ 메모리가 필요한 반면, $k=20$인 SVD 사용 시 25580($467\times 20(U)+20(\Sigma )+20\times 678=25580$) 메모리가 필요하다. 원본의 약 10% 메모리로 이미지 압축했다. 

$k=150$일 경우 실제 이미지와 화질이 비슷하였다.

 

이 그림을 컬러 이미지로도 근사하였다.

 

depth <- 30
x <- readImage("C:/Users/82109/OneDrive/사진/vegtable.png")
for(i in 1:3){
  x.svd <- svd(x[,,i])
  d <- diag(x.svd$d)
  u <- x.svd$u
  v <- x.svd$v
  us <- as.matrix(u[, 1:depth])
  vs <- as.matrix(v[, 1:depth])
  ds <- as.matrix(d[1:depth, 1:depth])
  assign(paste("ls", i, sep = ""), us%*%ds%*%t(vs))
}
ls <- array(c(ls1, ls2, ls3), c(nrow(ls1), ncol(ls1),3))
plot(0, type="n", axes=F, xlab="", ylab="")
imageShow(ls)

 

'R study > Multivariate Analysis' 카테고리의 다른 글

결측값 대치  (1) 2022.10.03