기이치 분해 이미지의 낮은 등급 근사

11142 단어 Python

개시하다


기이치가 분해되었나요?>안부를 묻다
요즘 주변 사람들이 특이치 분해를 하는 것 같아서 저도 해봤어요.한 마디로 하면 이미지를 직접 행렬로 삼아 특이값(Singular-Value-Decomposion, SVD)을 분해하고 낮은 등급의 비슷한 이미지를 만든다.특이치 분해에 관해서는 Wikipedia 등을 참조하세요.
나는 누가 이미지 특이치 분해를 말하기 시작했는지 모르겠지만, 나는 이 논문T. Kumamoto, M. Suzuki, and H. Matsueda arXiv:1608.08333을 통해 알게 되었다.
소스 코드
https://github.com/kaityo256/image_svd
구문을 사용합니다.

그림 불러오기


이미지 읽기는 Python Pillow를 사용합니다.안 들어갔으면.
$ pip install Pillow
잠깐만. 넣어둬.
그림을 입력하는 것이지만 문자가 있는 쪽의 근사 정밀도가 알기 쉽기 때문에 먼저 이런 것을 준비해 보았습니다.

우선 이것을 그레이스케일로 변환합니다.
from PIL import Image
img = Image.open('stop.jpg')
gray_img = img.convert('L')
gray_img.save('stop_mono.jpg')
이렇게 된 느낌.

기이치 분해


특이치 분해를 위해 numby와 scipy를 사용합니다.우선 그것을 한쪽에 놓아라.
import numpy as np
from scipy import linalg
numby의 asary로 그림 데이터를 직접 읽을 수 있습니다.다음은 scipy의 linalg.svd로 SVD를 진행할 수 있습니다.너무 편해.
a = np.asarray(gray_img)
u, s, v = linalg.svd(a)
여기서 발생하는 u,s,v는 특이치 분해의 결과이다.그중 s는 특이치의 목록이다.

저등급 근사


특이치가 분해된 후 상위의 등급만 선택하여 구성하면 낮은 등급과 비슷해진다.

그렇지만Σ(코드 중s은 사실 하나의 행렬이지만 linelg이다.svd의 반환 값은 벡터이기 때문에 행렬로 바꿔야 합니다.그리고 필요한 부분을 절단하여 계산하면 저등급 근사 행렬을 완성할 수 있다.
코드로 하면 이런 느낌이에요.
rank = 10
ur = u[:, :rank]
sr = np.matrix(linalg.diagsvd(s[:rank], rank,rank))
vr = v[:rank, :]
b = np.asarray(ur*sr*vr)
img2 = Image.fromarray(np.uint8(b))
img2.save('stop_r10_mono.jpg')
얻은 결과는 이런 느낌이다.

컬러판


간단하게 그레이스케일을 만들기 위해 RGB의 각 요소를 SVD로 하면 컬러판도 가능하다.여기서 유일하게 사람을 매혹시키는 부분은 흑백 버전의 Image다.fromaray로 그렇게 깊이 들어갔지만, 색깔은 (r, g, b)의 원조의 배열이 필요합니다.numby 행렬을 곱할 수 있는 대상은 Matrix 대상이기 때문에 나중에 그룹으로 접근하기 위해 np입니다.Asaray로 다시 배열해야 합니다.거기만 조심하면 금방 할 수 있어.
이렇게 하면 행렬의 낮은 등급의 근사 함수다.
def perform_svd(a,rank):
    u, s, v = linalg.svd(a)
    ur = u[:, :rank]
    sr = np.matrix(linalg.diagsvd(s[:rank], rank,rank))
    vr = v[:rank, :]
    return np.asarray(ur*sr*vr)
아사라이를 보답하는 것이 소박한 포인트다.이걸 사용하면 컬러판도 쉽게 만들 수 있어요.
    w = img.width
    h = img.height
    A = np.asarray(img)
    r = perform_svd(A[:,:,0],rank).reshape(w*h)
    g = perform_svd(A[:,:,1],rank).reshape(w*h)
    b = perform_svd(A[:,:,2],rank).reshape(w*h)
    B = np.asarray([r,g,b]).transpose(1,0).reshape(h,w,3)
    img2 = Image.fromarray(np.uint8(B))
    img2 = Image.fromarray(np.uint8(data))
    img2.save(`stop_r10.jpg`)
이미지 데이터에서 numpy 배열을 만들면 (높이, 너비, 색)의 3차원 배열이 되므로 각 색을 SVD로 하고 이를 붙이면 (색, 높이, * 너비)의 배열이 되므로transspose로 교환한 후 원래의 3차원 배열 형식으로 복원하여 삽입Image.fromarray할 수 있다.
완성된 이미지는 이런 느낌입니다.

끝말


만약 이 그림이라면 20개의 등급을 얻으면 기본적으로 원래의 그림을 회복할 수 있다.얼마나 취해야 하는지, 어떤 이미지에 어떤 스펙트럼이 있는지 조사하는 게 재미있잖아요.
그러나 그림을 읽고 그레이스케일을 만들어 행렬을 만들고 SVD를 만들어 낮은 등급으로 비슷하게 이미지 저장에 복원했다. 많이 만들었고 파이톤으로 적당한 프로그램 라이브러리를 만들었고 15줄로 완성했다.곰곰이 생각해 보면'도서관의 충실도는 언어의 강함이다'.

좋은 웹페이지 즐겨찾기