Posts Mahotas로 해보는 비슷한 이미지 찾기
Post
Cancel

Mahotas로 해보는 비슷한 이미지 찾기

1. Mahotas


1.1 Mahotas

https://mahotas.readthedocs.io/en/latest/

  • pip install mahotas
  • Mahotas는 Python 용 컴퓨터 비전 및 이미지 처리 라이브러리
  • 여기에는 속도를 위해 C ++로 구현 된 많은 알고리즘이 포함되어 있으며 매우 깨끗한 Python 인터페이스를 사용하여 numpy 배열에서 작동함

2. 실습


2.1 데이터 설명

https://github.com/luispedro/BuildingMachineLearningSystemsWithPython/tree/master/SimpleImageDataset

  • 건물, 자연경관, 문서 각 30장짜리 데이터
  • Building Machine Learning Systems with Python의 예제 자료

2.2 Data Load

1
2
3
4
5
6
7
from glob import glob
import mahotas as mh
import numpy as np
import matplotlib.pyplot as plt

images = glob('./data/SimpleImageDataset/*.jpg')
images[:5]
1
2
3
4
5
['./data/SimpleImageDataset/text20.jpg',
 './data/SimpleImageDataset/building13.jpg',
 './data/SimpleImageDataset/text08.jpg',
 './data/SimpleImageDataset/building07.jpg',
 './data/SimpleImageDataset/scene07.jpg']
  • 필요한 패키지를 불러오고, glob을 활용하여 각 이미지경로를 list에 담음


2.3 라벨 처리

1
images[0][26:-len('00.jpg')]
1
'text'
  • 파일의 라벨을 보면 text20.jpg 처럼 text의 20번째 jpg 파일이란 뜻
  • 라벨 뒤의 번호는 버리고 text만 가져옴
  • 이미지 파일이 있는 경로가 다르기 떄문에 오프셋인덱스의 26은 각자 상황에 맞게 바꿔야함


2.4 Gray로 변경

1
2
3
im = mh.imread(images[0])
im = mh.colors.rgb2gray(im, dtype=np.uint8)
im
1
2
3
4
5
6
7
array([[156, 176, 175, ..., 189, 187, 186],
       [154, 171, 169, ..., 188, 186, 185],
       [161, 175, 170, ..., 187, 186, 186],
       ...,
       [152, 153, 153, ..., 181, 181, 182],
       [152, 152, 152, ..., 181, 180, 182],
       [151, 152, 152, ..., 182, 181, 183]], dtype=uint8)
  • 이미지들을 Gray 컬러로 변경함


2.5 Haralick 적용

1
mh.features.haralick(im)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
array([[ 3.66204021e-03,  7.44385321e+01,  9.69875419e-01,
         1.23551148e+03,  4.76090180e-01,  3.21647886e+02,
         4.86760740e+03,  7.07458389e+00,  9.51129063e+00,
         1.00520606e-03,  2.93680057e+00, -4.35358414e-01,
         9.97483493e-01],
       [ 2.84549272e-03,  1.19362555e+02,  9.51673431e-01,
         1.23495790e+03,  4.04957709e-01,  3.21652894e+02,
         4.82046903e+03,  7.07435139e+00,  9.86550048e+00,
         8.21391898e-04,  3.27570061e+00, -3.76958948e-01,
         9.94872815e-01],
       [ 3.66198391e-03,  5.61980068e+01,  9.77246908e-01,
         1.23495320e+03,  4.78601123e-01,  3.21649202e+02,
         4.88361480e+03,  7.07197481e+00,  9.44835451e+00,
         1.03328177e-03,  2.83518971e+00, -4.45619712e-01,
         9.97778262e-01],
       [ 2.82616958e-03,  1.26394950e+02,  9.48826212e-01,
         1.23495792e+03,  4.03305323e-01,  3.21652893e+02,
         4.81343672e+03,  7.07529020e+00,  9.88137065e+00,
         8.17570442e-04,  3.28551507e+00, -3.74348101e-01,
         9.94707031e-01]])
  • Haralick는 이미지의 날카로움을 잘 나타낸다고 알려져 있음
  • Haralick는 이미지의 질감에 대해 2차원 특징을 추출하는 알고리즘


2.6 이미지를 특성 데이터로 전환

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import time

features = []
labels = []

start = time.time()

for im in images:
    labels.append(im[26:-len('00.jpg')])
    im = mh.imread(im)
    im = mh.colors.rgb2gray(im, dtype = np.uint8)
    features.append(mh.features.haralick(im).ravel())

print(f'fit time : {time.time() - start}')
1
fit time : 26.879966974258423
  • 이미지간 유사도 검출을 위해 이미지를 특성 데이터로 전환함


2.7 Array 전환

1
2
3
features = np.array(features)
labels = np.array(labels)
features
1
2
3
4
5
6
7
8
9
10
11
12
13
array([[ 3.66204021e-03,  7.44385321e+01,  9.69875419e-01, ...,
         3.28551507e+00, -3.74348101e-01,  9.94707031e-01],
       [ 1.28249663e-02,  4.87581223e+01,  9.94975935e-01, ...,
         3.91602238e+00, -3.87974632e-01,  9.97929776e-01],
       [ 7.63507483e-04,  4.50258748e+01,  9.89989318e-01, ...,
         3.76396230e+00, -3.97447535e-01,  9.98546677e-01],
       ...,
       [ 2.75960062e-03,  1.08364337e+02,  9.54449800e-01, ...,
         3.44586857e+00, -3.70228466e-01,  9.95528380e-01],
       [ 4.44557401e-03,  5.74946979e+01,  9.54265194e-01, ...,
         3.42370629e+00, -3.36906001e-01,  9.90473989e-01],
       [ 3.85204285e-04,  8.62514064e+01,  9.89901742e-01, ...,
         4.11483879e+00, -3.67041452e-01,  9.98309470e-01]])
  • 생성한 결과를 array로 변경함


2.8 Logistic Regression 적용

1
2
3
4
5
6
7
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression

clf = Pipeline([('preproc', StandardScaler()),
                ('classifier', LogisticRegression())])
clf
1
2
Pipeline(steps=[('preproc', StandardScaler()),
                ('classifier', LogisticRegression())])
  • Standardscaler와, LogisticRegression을 pipeline으로 생성


2.9 Cross Validation

1
2
3
4
from sklearn.model_selection import cross_val_score

scores = cross_val_score(clf, features, labels)
scores
1
array([0.77777778, 0.88888889, 0.83333333, 0.88888889, 0.77777778])
  • CV를 5번 진행하였을떄 라벨(text 등)을 맞춘 확률


1
print('Accuracy: {:2%}'.format(scores.mean()))
1
Accuracy: 83.333333%
  • CV의 Accuracy는 83%정도 나온다


2.10 Scaler

1
2
3
4
5
6
from scipy.spatial import distance

sc = StandardScaler()
features = sc.fit_transform(features)

dists = distance.squareform(distance.pdist(features))
  • feature에 scaler를 손으로 적용


2.11 Dists는?

1
dists[0]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
array([ 0.        ,  9.52430388,  6.80370623,  9.32497065, 11.25987833,
       10.61131364,  9.4115134 , 10.59962453,  1.77757172,  9.41331504,
       13.44918325,  3.00852352,  6.28968132,  8.65644664, 10.61250131,
       14.90126811, 16.93407315,  8.82744014, 13.01219666, 12.19972587,
        7.91865399,  3.32765773, 10.00279286,  9.30144472,  6.9250823 ,
        5.90013122,  9.86700903, 14.41636827, 11.73352847,  7.69310467,
       14.42948581, 11.93597518,  8.64056175,  4.14724299, 10.57420591,
        9.42784866,  2.71311061,  9.60793104,  9.13885778,  3.21521643,
        7.92824414,  8.97416642, 11.45093424, 10.59822376,  1.63251016,
        9.21061649,  7.58279627, 10.7034599 ,  7.53869737,  3.80226852,
        3.70638927,  8.66907659, 12.77482358, 10.85494835,  3.99808513,
       10.18964684,  3.56897747, 16.7687143 , 10.46788865,  5.13169458,
        6.0190094 , 10.50286623, 14.49668247, 16.94976398, 11.12082812,
        8.78755595, 14.83611024,  5.64524318, 11.34606274,  3.85074009,
        9.24280937,  8.01420865,  6.93247105,  4.90357171, 10.93565002,
       12.63837001, 19.37773956,  9.68593925, 10.77371778,  3.27491197,
        2.13785205, 10.99261702,  8.97774871,  4.225051  ,  4.6199186 ,
       11.70321631, 15.44084137,  2.30388604,  3.66714748, 10.50795977])
  • dists 행렬은 각 이미지가 어떤 이미지와 가장 비슷한지 거리를 보여주는것임
  • dists[0]은 0번째 이미지가 다른 나머지 이미지들과의 거리를 나타냄


2.12 유사한 이미지를 찾는 함수

1
2
3
4
def selectimage(n, m, dists, images):
    image_position = dists[n].argsort()[m]
    image = mh.imread(images[image_position])
    return image
  • n : 유사한 이미지를 찾을 이미지
  • m : 찾을 갯수


2.13 유사한 이미지 4개를 그리는 함수

1
2
3
4
5
6
7
8
9
def plotImages(n):
    fig, ax = plt.subplots(1,4, figsize = (15,5))
    
    for i in range(4):
        ax[i].imshow(selectimage(n,i, dists, images))
        ax[i].set_xticks([])
        ax[i].set_yticks([])
        
    plt.show()
  • 유사한 이미지를 찾을 번호를 입력하면 비슷한 이미지 4개를 출력해준다


2.14 유사한 이미지 찾기

1
plotImages(10)

  • 10번 이미지와 비슷한 사진을 찾아봤음


1
plotImages(11)

  • 11번 이미지와 비슷한 사진을 찾았고, 문서 이미지는 잘 찾는듯 함


1
plotImages(32)

  • 32번 이미지와 비슷한 사진을 찾았고, 건물도 잘찾음


3. 요약


3.1 요약

  • 이미지를 처리하는 알고리즘을 사용하여 유사 이미지 검색을 해보았는데 생각보다 잘 나와서 신기했다.
  • 또한 이미지에 대한 라벨을 넣고 그 라벨을 맞추는 것도 83%라고 하니 낮은 수준은 아닌듯 하다
  • 하지만 이미지는 딥러닝 부분이 더 강력한것으로 알고 있으니, 나중에 딥러닝도 해보는것이 좋을듯 하다
  • 유사 이미지라는게 사실 추천 시스템과도 맥락을 같이 한다.
This post is licensed under CC BY 4.0 by the author.