728x90
반응형

Machine Learning

데이터 수집부터 머신러닝까지 순서

Pipeline

 

1. Data 수집하기

- Own datasets (csv, pickle등 본인이 수집한 데이터 혹은 기업 데이터/개인이거나 단체가 직접 수집한 데이터)

- Public datasets (공공데이터 API, mnist, kaggle data )

- Crawling & Scraping (거의 대부분이 불법이니 조심해야 한다)

- 기타

2. 도메인 지식 확보하기 (필요할 )

- 데이터에 포함된 Documentation을 읽는다

- 이미 알고 있는 전문 분야일 경우 생략

- 구글링

-

- 기타

3. Data 불러오기

- Pandas DataFrame으로 불러오기

- Numpy로 불러오기

- 기타

4. 대략적인 Data 파악하기

- Info로 데이터 정보 확인하기

- dtype확인 하기

- shape확인 하기

- missing data확인 하기

- 마지막 Tidy data인지 확인 하기

5. Data 조작하기 (Tidy data가 아닐 경우)

- Wide Format인 경우 Long Format으로 바꾸기

- missing data 처리하기

- 부적절한 data값 수정하기

- 기타

6. Data 분석하기(EDA)

- 그래프 그려보기 (histogram, pairplot, bar, pie등)

- 데이터의 숨겨진 의미 파악하기

- 데이터 양이 충분한지 파악하기 => learning_curve를 통해 확인한다 (중심 극한 정리)
- Feature 갯수가 데이터의 양에 비해 많은지 확인하기 (오캄의 면도날)

- 기타

7. Data 전처리

- Hold out (2 way/3 way)

- Feature Selection

- Feature Scaling

- Dimensionality Reduction

- 기타

8. 모델링 하기

- Model selection

- 알고리즘 비교하기

- 하이퍼 파라미터 찾기(GridSearchCV)

- 기타

9. 성능 테스트

- 데이터 양이 적을 경우 Cross validation

- 정확도 파악하기

- 기타

 

Data 형태

머신 러닝의 기본 데이터 형은 정형 데이터이다

정형 데이터는 2차원 형태의 데이터이다

row(행)가 한 개이고 vector형태의 구조여야 한다

column(열)은 feature또는 dimension이라고 부른다

최종적으로 Tidy data 형태로 만들어줘야 한다

EDA(Exploratory Data Analysis)

데이터를 다양한 각도에서 관찰하고 이해하는 과정이다

데이터를 분석하기 전에 그래프나 통계적인 방법으로 자료를 직관적으로 확인하는 과정이라고도 할 수 있다

Data shift

학습데이터셋과 테스트셋의 분포가 다른 경우

Imbalanced data

클래스가 불균등한 데이터

ex) True가 100만개 False가 100개

기초 통계 분석(EDA)시 알아두면 좋은 원칙

1. Law of large numbers( 수의 법칙)

- 모집단에서 무작위로 뽑은 표본의 평균이 전체 모집단의 평균과 가까울 가능성이 높다

- 모집단이 커지면 표본평균은 모평균을 정확히 추정할 있다

2. Occam's Razor (오캄의 면도날)

- 같은 성능을 보일 간단한것을 택한다

3. Curse of dimensionality (차원의 저주)

- 차원이 커지면 커질수록 필요한 데이터의 양이 커져야 한다

4. Central limit theorem (중심 극한 정리)

- 동일한 확률분포를 가진 독립 확률 변수 n개의 평균의 분포는 n이 적당히 크다면 정규분포에 가까워진다는 정리

 

from sklearn.model_selection import learning_curve # 데이터의 많고 적음은 learning_curve를 보고 확인한다 
import numpy as np
import tensorflow as tf 

(X_train, y_train), (X_test, y_test) = tf.keras.datasets.mnist.load_data()

X_test.shape
# (10000, 28, 28)

y_test.shape
# (10000,)

Train-Test Ratio

Holdout 비율 잡는 방법 => 경험

보통은 75%/25% 비율로 한다

import matplotlib.pyplot as plt
plt.hist(y_train); # 균형 잡힌 train 데이터

np.unique(y_train, return_counts=True) # 클래스 종류 10가지 
# (array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], dtype=uint8),
# array([5923, 6742, 5958, 6131, 5842, 5421, 5918, 6265, 5851, 5949]))

from sklearn.datasets import load_iris
from sklearn.neighbors import KNeighborsClassifier
from sklearn_evaluation import plot
# ImportError: cannot import name 'TypeGuard' from 'typing_extensions' (/usr/local/lib/python3.7/dist-packages/typing_extensions.py)
!pip install -U sklearn-evaluation
data = load_iris()
train_size, train_score, test_score = learning_curve(KNeighborsClassifier(), data.data, data.target)
plot.learning_curve(train_score, test_score, train_size);

Holdout

Train data, test data를 분리시키는 방법

1. 2-way => train-test

2. 3-way => train-validation-test

from sklearn.model_selection import train_test_split # 2-way / 3-way는 train_test_split을 두 번 하면 된다

Modeling

모델이란 수많은 데이터를 통해 패턴을 발견하거나 예측을 수행하는 알고리즘의 표현식이다

따라서 모델링은 그러한 알고리즘을 만들어 내는 과정을 말한다

모델을 잘 만들기 위해서 모델링하기 전 데이터에 대한 이해가 필요하다 => EDA를 한다

모델링 하기 전에 알아둬야 할 키워드

1. Ad-hoc : 특별한 목적을 가진 것

- 데이터에 따라서 달라진다

- 일반적이지 않다

2. No free lunch <----> Master algorithm

- 공짜 점심은 없다

from sklearn.model_selection import cross_val_score # 데이터 양이 적을때 사용하는 방법 
re # 데이터 양이 적을때 사용하는 방법 
model = tf.keras.Sequential([
    tf.keras.layers.Flatten(input_shape = (28,28)) # (28,28)인 2차원으로 만들어 준다 
])

X_train[0].shape # 2차원 데이터 
# (28, 28)

X_train.dtype
# dtype('uint8')

data = model(X_train) # 묵시적으로 데이터 타입이 uint8에서 float32로 바뀌었다 / 미분해야 하기 때문에 float타입이어야 한다 
model.fit() # class_weight => 클래스에 가중치를 줌으로써 불균등한 데이터의 문제를 해결할 수 있다

from sklearn.linear_model import LogisticRegression
from sklearn.multiclass import OneVsOneClassifier, OneVsRestClassifier
from sklearn.svm import SVC

Ir = LogisticRegression() # 가정이 성립되면 전통적인 머신러닝 알고리즘 사용 가능하다 
Ir.fit(data.numpy(), y_train)
Ir.predict(X_test[0].reshape(1,-1))
y_test[0]
# 7

svm = SVC()
svm.fit(data.numpy(), y_train)

 

본 수업 용어 규칙

전통적인 머신러닝 모델 = end to end (feature extraction + model)이 아닌 모델

여기서 end to end 모델은 input이 들어가서 output이 나오는 과정을 오로지 데이터에 의존해서 찾아내는 모델을 말한다

end to end 모델이 성능이 좋을때가 많지만 충분한 학습 데이터가 없다면 굉장히 성능이 떨어지는 모델이 될 수 있다

그리고 end to end 모델은 중간 과정을 설명할 수 없기 때문에 중간 과정을 설명해야 하는 중요한 문제가 발생하는 부분에서는 사용하기가 쉽지 않다

 

i.i.d (independent identically distributed)

독립 항등 분포 column을 바꿔도 의미가 유지가 되어야 한다

import seaborn as sns
iris = sns.load_dataset('iris')

이미지는 column이 바뀌면 의미가 유지되지 않는다

그래서 전통적인 방식의 머신러닝으로 이미지 데이터 사용하기 쉽지 않다

단, 가설(가정)을 통해서 가능하게 할 수 있다

 

Assumption

이미지 데이터를 사용하여 전통적인 머신러닝 방식 해결하려면 가정이 필요하다

가정이 잘못 되면 모든 것이 잘 못 될 경우가 있다

이미지 데이터를 사용할 경우 data leakage문제가 발생하지 않는다 라는 가정을 갖고 학습을 하게 되면 전통적인 머신러닝 방식으로도 사용할 수 있다

가정을 많이 할 수록 사용할 수 있는 것이 한정적이게 된다

data leakage 문제: 학습 데이터 밖에서 유입된 데이터가 모델을 만드는데 사용되어 overfitting이 되거나 underfitting이 되는 경우를 말한다

 

데이터를 2차원에서 1차원으로 변형할때 context를 유지해야 한다

!pip install mglearn
import mglearn
mglearn.plot_pca.plot_pca_illustration() # 1차원으로 바꿔도 context가 유지되는 경우

mglearn.plot_scaling.plot_scaling() # 정규화, 표준화 등 scaling을 해도 context가 유지된 경우

Model Selection

1. Algorithm(알고리즘) 선택

2. Hyper parameter(하이퍼 파라미터) 선택

3. Ensemble(앙상블)

4. Train + Test data 합쳐서 재학습 => 최종 모델

 

모델별로 inductive bias가 있다

inductive bias란 학습 시에는 만나보지 않았던 상황에 대하여 정확한 예측을 하기 위해 사용하는 추가적인 가정 (additional assumptions)을 의미한다

이러한 inductive bias를 추가하여 학습한 모델을 일반화 하는 것이 모델 학습의 최종 목표이다

opencv에도 알고리즘이 있다

import cv2
dir(cv2.ml) # 머신러닝 알고리즘
['ANN_MLP_ANNEAL',
 'ANN_MLP_BACKPROP',
 'ANN_MLP_GAUSSIAN',
 'ANN_MLP_IDENTITY',
 'ANN_MLP_LEAKYRELU',
 'ANN_MLP_NO_INPUT_SCALE',
 'ANN_MLP_NO_OUTPUT_SCALE',
 'ANN_MLP_RELU',
 'ANN_MLP_RPROP',
 'ANN_MLP_SIGMOID_SYM',
 'ANN_MLP_UPDATE_WEIGHTS',
 'ANN_MLP_create',
 'ANN_MLP_load',
 'BOOST_DISCRETE',
 
 
 dir(cv2.dnn) # 딥 뉴럴 네트워크
 ['DNN_BACKEND_DEFAULT',
 'DNN_BACKEND_HALIDE',
 'DNN_BACKEND_INFERENCE_ENGINE',
 'DNN_BACKEND_OPENCV',
 'DNN_BACKEND_VKCOM',
 'DNN_TARGET_CPU',
 'DNN_TARGET_FPGA',
 'DNN_TARGET_MYRIAD',
 'DNN_TARGET_OPENCL',
 'DNN_TARGET_OPENCL_FP16',
 'DNN_TARGET_VULKAN',
 'NMSBoxes',
 'NMSBoxesRotated',

 

 

반응형
728x90
반응형

OpenCV

Hisogram

이미지 데이터를 분석하기 위한 방법으로 사용한다

import cv2
import numpy as np

im = cv2.imread('people.jpg')
cv2.calcHist([im],[0], None, [256], [0,256]) # 여러개 동시에 연산하기 때문에 2차로 결과를 낸다 
cv2.calcHist([im,im],[0], None, [256], [0,256])

# 색상 분포
plt.plot(cv2.calcHist([im],[0], None, [256], [0,256])) # B
plt.plot(cv2.calcHist([im],[1], None, [256], [0,256])) # G
plt.plot(cv2.calcHist([im],[2], None, [256], [0,256])) # R 
plt.xlim([0, 256])
# (0.0, 256.0)

squeeze

길이가 1 인 축을 제거한다

a = np.array([[1],[3]])
b = np.array([[[1,2],[3,4]]])

a.shape, b.shape
# ((2, 1), (1, 2, 2))

np.squeeze(a).shape, np.squeeze(b).shape
# ((2,), (2, 2))

cv2.calcHist([im,im],[0], None, [256], [0,256]).shape
# (256, 1)

np.squeeze(cv2.calcHist([im,im],[0], None, [256], [0,256])).shape
# (256,)

plt.plot(cv2.calcHist([im,im],[0], None, [256], [0,256]))
plt.plot(cv2.calcHist([im,im],[1], None, [256], [0,256]))
plt.plot(cv2.calcHist([im,im],[2], None, [256], [0,256]))

속도 비교

opencv는 속도 최적화가 되어 있다

%timeit im*im
# 1000 loops, best of 5: 202 µs per loop

%timeit im**2
# 1000 loops, best of 5: 227 µs per loop

cv2.useOptimized() # opencv연산에 최적화 되어 있다
# True

%timeit cv2.medianBlur(im, 49) # 최적화 되어 있을 때 (최적화 되어 있을 때 일반적으로 20% 빠르다 / colab에서 medianBlur연산은 최적화 해도 그렇게 빠르지 않다)
# 10 loops, best of 5: 37.5 ms per loop

cv2.setUseOptimized(False)
cv2.useOptimized()
# False

%timeit cv2.medianBlur(im, 49) # 최적화 되지 않을 때 
# 10 loops, best of 5: 37.8 ms per loop

cv2.setUseOptimized(True)
cv2.useOptimized()
# True

%timeit im*im*im 
# The slowest run took 20.40 times longer than the fastest. This could mean that an intermediate result is being cached.
# 1000 loops, best of 5: 292 µs per loop

%timeit im**3 # 연산량이 많아지면서 im*im*im연산보다 im**3이 훨씬 느려졌다 
# 100 loops, best of 5: 3.24 ms per loop

EqualizeHist

im = cv2.imread('people.jpg', 0)
im2 = cv2.equalizeHist(im)

plt.hist(im2.ravel(), 256,[0,256]); # 정규 분포 처럼 분포를 균일하게 만들어 준다

plt.imshow(cv2.equalizeHist(im), cmap='gray') # 평탄화 => contrast가 낮아진다 => 분포가 균일해진다 => 밝고 어두운 정도가 구분하기 힘들어진다

from skimage.exposure import cumulative_distribution
len(cumulative_distribution(im))
# 2

y, x = cumulative_distribution(im)
plt.hist(y);
# (array([ 26.,  29.,  48.,  28.,  17.,  13.,  12.,  13.,  16.,  54.]),
#  array([  2.74348422e-05,   1.00024691e-01,   2.00021948e-01,
#           3.00019204e-01,   4.00016461e-01,   5.00013717e-01,
#           6.00010974e-01,   7.00008230e-01,   8.00005487e-01,
#           9.00002743e-01,   1.00000000e+00]),
#  <a list of 10 Patch objects>)

plt.plot(x,y) # 누적 분포

Numpy

Histogram

import matplotlib.pyplot as plt
im = cv2.imread('people.jpg') # color 
np.histogram(im, bins=10) # return이 두 개 (hist array, bin_edges(length(hist)+1) 
# (array([ 78609,  83722,  55425,  62639,  96251, 126726, 146684, 112897, 90637,  21210]),
# array([   0. ,   25.5,   51. ,   76.5,  102. ,  127.5,  153. ,  178.5, 204. ,  229.5,  255. ]))

im.dtype # 2^8 = 256 
# dtype('uint8')
np.histogram(im, bins=256, range=[0,256]) # 256등분 / 0이 92개 1이 51개... / color정보이기 때문에 수치가 많이 나온다 
(array([  92,   51,  119,  224,  406,  664, 1290, 1818, 2323, 2826, 3018,
        3290, 3549, 3736, 3856, 3928, 4209, 4413, 4537, 4848, 4852, 4987,
        5005, 4958, 4881, 4729, 4570, 4256, 4186, 3976, 3849, 3605, 3503,
        3489, 3487, 3281, 3249, 3110, 3217, 3150, 3008, 3073, 3052, 3206,
        3193, 3086, 3089, 2943, 2895, 2695, 2554, 2507, 2258, 2389, 2191,
        2185, 2115, 2019, 2163, 2048, 2012, 1996, 2055, 2095, 2010, 2032,
        2135, 2132, 2138, 2077, 2140, 2097, 2144, 2098, 2128, 2106, 2155,
        2202, 2166, 2168, 2230, 2255, 2285, 2306, 2289, 2345, 2337, 2360,
        2358, 2429, 2430, 2487, 2562, 2697, 2688, 2753, 2745, 2776, 2783,
        2924, 2969, 3095, 3149, 3179, 3199, 3258, 3302, 3349, 3284, 3369,
        3413, 3501, 3640, 3540, 3542, 3759, 3692, 3722, 3801, 3801, 3971,
        3999, 4021, 4278, 4239, 4254, 4480, 4509, 4408, 4414, 4677, 4674,
        4743, 4873, 5055, 5089, 5088, 5225, 5319, 5080, 5087, 5054, 5099,
        5108, 4934, 5152, 5206, 5158, 5211, 5364, 5454, 5661, 5593, 5789,
        5680, 5836, 6015, 6139, 6026, 6087, 6087, 6021, 5803, 5809, 5856,
        5577, 5669, 5457, 5222, 5190, 5102, 5128, 5095, 5237, 5525, 5453,
        5417, 5741, 5723, 5894, 5497, 5167, 5182, 4995, 5002, 4729, 4781,
        4483, 4499, 4386, 4289, 4507, 4544, 4808, 4740, 4456, 4135, 4062,
        4144, 3972, 3651, 3572, 3636, 3766, 3982, 4385, 4202, 3822, 3792,
        3704, 3515, 3518, 3573, 3704, 3808, 4347, 3945, 3734, 3859, 3718,
        3615, 3450, 3275, 2991, 3032, 2811, 2796, 2627, 2314, 2118, 2154,
        1870, 1627, 1593, 1576, 1468, 1315, 1319, 1145, 1057,  959,  866,
         745,  614,  560,  469,  383,  319,  242,  217,  175,  144,  105,
          70,   53,  165]),
 array([   0.,    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.,
          45.,   46.,   47.,   48.,   49.,   50.,   51.,   52.,   53.,
          54.,   55.,   56.,   57.,   58.,   59.,   60.,   61.,   62.,
          63.,   64.,   65.,   66.,   67.,   68.,   69.,   70.,   71.,
          72.,   73.,   74.,   75.,   76.,   77.,   78.,   79.,   80.,
          81.,   82.,   83.,   84.,   85.,   86.,   87.,   88.,   89.,
          90.,   91.,   92.,   93.,   94.,   95.,   96.,   97.,   98.,
          99.,  100.,  101.,  102.,  103.,  104.,  105.,  106.,  107.,
         108.,  109.,  110.,  111.,  112.,  113.,  114.,  115.,  116.,
         117.,  118.,  119.,  120.,  121.,  122.,  123.,  124.,  125.,
         126.,  127.,  128.,  129.,  130.,  131.,  132.,  133.,  134.,
         135.,  136.,  137.,  138.,  139.,  140.,  141.,  142.,  143.,
         144.,  145.,  146.,  147.,  148.,  149.,  150.,  151.,  152.,
         153.,  154.,  155.,  156.,  157.,  158.,  159.,  160.,  161.,
         162.,  163.,  164.,  165.,  166.,  167.,  168.,  169.,  170.,
         171.,  172.,  173.,  174.,  175.,  176.,  177.,  178.,  179.,
         180.,  181.,  182.,  183.,  184.,  185.,  186.,  187.,  188.,
         189.,  190.,  191.,  192.,  193.,  194.,  195.,  196.,  197.,
         198.,  199.,  200.,  201.,  202.,  203.,  204.,  205.,  206.,
         207.,  208.,  209.,  210.,  211.,  212.,  213.,  214.,  215.,
         216.,  217.,  218.,  219.,  220.,  221.,  222.,  223.,  224.,
         225.,  226.,  227.,  228.,  229.,  230.,  231.,  232.,  233.,
         234.,  235.,  236.,  237.,  238.,  239.,  240.,  241.,  242.,
         243.,  244.,  245.,  246.,  247.,  248.,  249.,  250.,  251.,
         252.,  253.,  254.,  255.,  256.]))
np.histogram(im.flatten(), 256, [0,256]) # flatten함수는 일차원으로 바꿔주는 함수 => 연산을 더 빠르게 하기 위해서 바꾼다 
(array([  92,   51,  119,  224,  406,  664, 1290, 1818, 2323, 2826, 3018,
        3290, 3549, 3736, 3856, 3928, 4209, 4413, 4537, 4848, 4852, 4987,
        5005, 4958, 4881, 4729, 4570, 4256, 4186, 3976, 3849, 3605, 3503,
        3489, 3487, 3281, 3249, 3110, 3217, 3150, 3008, 3073, 3052, 3206,
        3193, 3086, 3089, 2943, 2895, 2695, 2554, 2507, 2258, 2389, 2191,
        2185, 2115, 2019, 2163, 2048, 2012, 1996, 2055, 2095, 2010, 2032,
        2135, 2132, 2138, 2077, 2140, 2097, 2144, 2098, 2128, 2106, 2155,
        2202, 2166, 2168, 2230, 2255, 2285, 2306, 2289, 2345, 2337, 2360,
        2358, 2429, 2430, 2487, 2562, 2697, 2688, 2753, 2745, 2776, 2783,
        2924, 2969, 3095, 3149, 3179, 3199, 3258, 3302, 3349, 3284, 3369,
        3413, 3501, 3640, 3540, 3542, 3759, 3692, 3722, 3801, 3801, 3971,
        3999, 4021, 4278, 4239, 4254, 4480, 4509, 4408, 4414, 4677, 4674,
        4743, 4873, 5055, 5089, 5088, 5225, 5319, 5080, 5087, 5054, 5099,
        5108, 4934, 5152, 5206, 5158, 5211, 5364, 5454, 5661, 5593, 5789,
        5680, 5836, 6015, 6139, 6026, 6087, 6087, 6021, 5803, 5809, 5856,
        5577, 5669, 5457, 5222, 5190, 5102, 5128, 5095, 5237, 5525, 5453,
        5417, 5741, 5723, 5894, 5497, 5167, 5182, 4995, 5002, 4729, 4781,
        4483, 4499, 4386, 4289, 4507, 4544, 4808, 4740, 4456, 4135, 4062,
        4144, 3972, 3651, 3572, 3636, 3766, 3982, 4385, 4202, 3822, 3792,
        3704, 3515, 3518, 3573, 3704, 3808, 4347, 3945, 3734, 3859, 3718,
        3615, 3450, 3275, 2991, 3032, 2811, 2796, 2627, 2314, 2118, 2154,
        1870, 1627, 1593, 1576, 1468, 1315, 1319, 1145, 1057,  959,  866,
         745,  614,  560,  469,  383,  319,  242,  217,  175,  144,  105,
          70,   53,  165]),
 array([   0.,    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.,
          45.,   46.,   47.,   48.,   49.,   50.,   51.,   52.,   53.,
          54.,   55.,   56.,   57.,   58.,   59.,   60.,   61.,   62.,
          63.,   64.,   65.,   66.,   67.,   68.,   69.,   70.,   71.,
          72.,   73.,   74.,   75.,   76.,   77.,   78.,   79.,   80.,
          81.,   82.,   83.,   84.,   85.,   86.,   87.,   88.,   89.,
          90.,   91.,   92.,   93.,   94.,   95.,   96.,   97.,   98.,
          99.,  100.,  101.,  102.,  103.,  104.,  105.,  106.,  107.,
         108.,  109.,  110.,  111.,  112.,  113.,  114.,  115.,  116.,
         117.,  118.,  119.,  120.,  121.,  122.,  123.,  124.,  125.,
         126.,  127.,  128.,  129.,  130.,  131.,  132.,  133.,  134.,
         135.,  136.,  137.,  138.,  139.,  140.,  141.,  142.,  143.,
         144.,  145.,  146.,  147.,  148.,  149.,  150.,  151.,  152.,
         153.,  154.,  155.,  156.,  157.,  158.,  159.,  160.,  161.,
         162.,  163.,  164.,  165.,  166.,  167.,  168.,  169.,  170.,
         171.,  172.,  173.,  174.,  175.,  176.,  177.,  178.,  179.,
         180.,  181.,  182.,  183.,  184.,  185.,  186.,  187.,  188.,
         189.,  190.,  191.,  192.,  193.,  194.,  195.,  196.,  197.,
         198.,  199.,  200.,  201.,  202.,  203.,  204.,  205.,  206.,
         207.,  208.,  209.,  210.,  211.,  212.,  213.,  214.,  215.,
         216.,  217.,  218.,  219.,  220.,  221.,  222.,  223.,  224.,
         225.,  226.,  227.,  228.,  229.,  230.,  231.,  232.,  233.,
         234.,  235.,  236.,  237.,  238.,  239.,  240.,  241.,  242.,
         243.,  244.,  245.,  246.,  247.,  248.,  249.,  250.,  251.,
         252.,  253.,  254.,  255.,  256.]))

일차원으로 만드는 함수

1. ravel # view 방식

2. flatten # copy 방식

plt.hist(im.ravel(), 256, [0, 256]); # 내부적으로 bincount를 사용해서 연산한다 
plt.xlim([0,256]) # x축 범위 설정

im2 = cv2.imread('people.jpg', 0) # 흑백 
plt.hist(im2.flatten(), 256, [0, 256]);
plt.xlim([0,256])
# (0.0, 256.0)

# 각각 점의 컬러 분포 
plt.hist(im[...,0].ravel(), 256, [0, 256]); # B
plt.hist(im[...,1].ravel(), 256, [0, 256]); # G
plt.hist(im[...,2].ravel(), 256, [0, 256]); # R
plt.xlim([0,256])

 

im2.shape # 흑백 
# (540, 540)
im2
# array([[191, 193, 194, ..., 165, 166, 168],
#       [190, 192, 193, ..., 173, 175, 176],
#       [189, 191, 192, ..., 182, 183, 184],
#       ..., 
#       [106, 102, 109, ..., 113, 124, 129],
#       [106, 102, 109, ..., 113, 120, 123],
#       [101,  97, 104, ..., 119, 120, 120]], dtype=uint8)

plt.hist(im2[0].flatten(), 256, [0, 256]); 
plt.hist(im2[1].flatten(), 256, [0, 256]); 
plt.hist(im2[539].flatten(), 256, [0, 256]); 
plt.xlim([0,256])

np.bincount(np.arange(5)) # 각각 몇개 있는지 세는 함수   
# array([1, 1, 1, 1, 1])

np.bincount(np.array([0,1,1,3,2,1,7]))
# array([1, 3, 1, 1, 0, 0, 0, 1])

from itertools import count, groupby
t = groupby([1,1,1,2,2]) 
b = count()
next(b)
# 3

next(t) # 그룹으로 묶어서 몇개 있는지 확인 
# (2, <itertools._grouper at 0x7fa251080ad0>)

얼굴부분 crop해서 색 분포 확인하기

face = im[50:300,50:200]
plt.imshow(face[...,::-1])

plt.hist(face[...,0].ravel(), 256, [0, 256], color='blue'); 
plt.hist(face[...,1].ravel(), 256, [0, 256], color='green'); 
plt.hist(face[...,2].ravel(), 256, [0, 256], color='red'); 
plt.xlim([0,256])

mask = np.zeros(im.shape[:2], np.uint8) # mask 
mask[50:300,50:200] = 255 # 흰색으로 
cv2.bitwise_and(im,im,mask=mask) 
plt.imshow(cv2.bitwise_and(im,im,mask=mask))

plt.imshow(cv2.bitwise_and(im,mask)) # 차원이 달라서 연산이 안된다 
# error: OpenCV(4.1.2) /io/opencv/modules/core/src/arithm.cpp:229: error: (-209:Sizes of input arguments do not match) The operation is neither 'array op array' (where arrays have the same size and type), nor 'array op scalar', nor 'scalar op array' in function 'binary_op'
im.shape, mask.shape
# ((540, 540, 3), (540, 540))

im2 = cv2.imread('people.jpg', 0)
plt.imshow(cv2.bitwise_and(im2,mask))

cv2.calcHist([im], [0], mask, [256], [0,256]) # mask외 분포 구할 때 
plt.plot(cv2.calcHist([im], [0], mask, [256], [0,256]))

전통적인 머신러닝에서는 contrast가 높으면 이미지 분류가 잘 안되기 때문에 contrast 분포를 평평하게 만들었었다 (contrast normalization)

from skimage.exposure import histogram, rescale_intensity, equalize_hist
from skimage.util import img_as_float, img_as_ubyte 
im = cv2.imread('people.jpg')
plt.imshow(img_as_float(im)[...,::-1])
# 이미지는 float나 int 둘다 사람이 볼때는 상관 없다 / 하지만 컴퓨터는 float로 바꾸면 연속적이기 때문에 미분이 가능해진다

help(histogram)
np.info(histogram)
np.lookfor('hist', 'skimage')
import scipy
np.lookfor('hist', 'scipy')
equalize_hist(im.flatten())
# array([ 0.73654893,  0.80552241,  0.86368427, ...,  0.47972908, 0.42027549,  0.32775834])
plt.imshow(rescale_intensity(im, (0, 255))) # 범위를 조절 해준다

plt.imshow(rescale_intensity(im[...,::-1], (0, 255)))

plt.imshow(rescale_intensity(im[...,::-1], (0, 50))) # 0에서 50사이로 범위를 조절 했기 때문에 밝게 변한다

plt.imshow(rescale_intensity(im[...,::-1], (, 200)))

advanced

x = [1,2,3,4,5,6]
y = np.array(x)

y.cumsum() # 누적합을 빠르게 구하는 방법 
# array([ 1,  3,  6, 10, 15, 21])

np.add.accumulate(y)
# array([ 1,  3,  6, 10, 15, 21])

np.add.reduce(y)
# 21
import tensorflow as tf 
tf.reduce_sum(y)
# <tf.Tensor: shape=(), dtype=int64, numpy=21>

# import seaborn as sns 
iris = sns.load_dataset('iris')
sns.pairplot(iris, hue='species', diag_kind='hist') # 데이터에 분포에 따라서 옳바른 데이터인지 아닌지 확인할 수 있기 때문에 그래프를 확인한다

sns.pairplot(iris, hue='species', diag_kind='kde')

누적 분포

hist, bins = np.histogram(im.ravel(), 256, [0,256])
cdf = hist.cumsum()

cdf_norm = cdf*float(hist.max()) / cdf.max() # 정규화, 0과 1사이의 값으로 만든다 

plt.hist(im.ravel(), 256, [0,256])
plt.plot(cdf_norm)

반응형
728x90
반응형
im[a,b,0] = 255 # R
im[a,b,1] = 0   # G
im[a,b,2] = 0   # B

plt.figure(figsize=(6,6))
plt.imshow(im)

Image Processing

이미지 처리란 넓은 의미에서 광학, 아날로그, 디지털 사진 혹은 영상 처리를 의미하지만,

computer vision에서는 디지털 이미지 데이터를 조작하여 원하는 데이터 형태로 변환하는 것을 의미한다.

이미지 처리 기법

1. 이미지 자르기(crop), 색상 공간(color space)변경, 이미지 깊이(image depth)변경, 확대·축소·회전·뒤집기와 같은 기하학적 변환

2. 이미지 대비·밝기·색상 밸런스 조정·선명도 변경과 같은 변환

3. 이미지 합성, 필터(filter, kernel, mask) 사용한 블러링(Blurring)

4. 팽창과 침식 연산을 사용한 모폴로지(Morphology) 연산

5. 이미지 분할(Segmentation)

6. 이미지 검출(Detection)

7. 자세 추정(Pose Estimation)

8. 이미지 증강(Augmentation) 다양한 기법들이 있다

 

PIL, opencv, scikit-image등으로 이미지 처리 기법을 구현하여 원하는 이미지 형태로 변형 있다.

단순히 python 라이브러리로 이미지 검출이나, 자세 추정, 이미지 분할등 원하는 형태로 이미지를 가공 있지만

머신러닝, 딥러닝을 활용하면 조금 정교하고 대량의 이미지를 짧은 시간에 처리하는 것이 가능해진다.

이미지 처리를 하는 이유

이미지 데이터를 활용하여 어떠한 목적을 달성해야 할때 (머신러닝, 딥러닝을 활용하여 문제 해결을 해야 할때)

충분하지 못한 이미지 데이터를 갖고 있거나, 데이터 품질이 좋지 못할때, 데이터에 표시를 해야 할때등

여러가지 이유에서 목적을 수월하게 달성할 수 있다.

이미지 처리를 위한 python library

1. Scikit-image => Numpy style

2. OpenCV => C style

3. PIL => Python style

Scikit-Image

scikit-learn과 비슷한 명명 규칙을 따른다

 

skimage의 중분류

1. color # 색 변환

2. draw # 이미지내 그림 표시, 문자 표시, 좌표 그리기

from skimage.draw import line, rectangle, circle
from skimage.io import imread
import matplotlib.pyplot as plt
import numpy as np

len(line(0,0,100,100))
# 2
a, b = line(0,0,100,200) # 좌표평면에서 y축 방향은 앞 두 자리(0,0), x축은 뒤 두 자리(100,200) / 왼쪽 위(0,0)좌표에서 오른쪽 아래(100,200)좌표를 향하는 직선 
a
array([  0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,
         7,   7,   8,   8,   9,   9,  10,  10,  11,  11,  12,  12,  13,
        13,  14,  14,  15,  15,  16,  16,  17,  17,  18,  18,  19,  19,
        20,  20,  21,  21,  22,  22,  23,  23,  24,  24,  25,  25,  26,
        26,  27,  27,  28,  28,  29,  29,  30,  30,  31,  31,  32,  32,
        33,  33,  34,  34,  35,  35,  36,  36,  37,  37,  38,  38,  39,
        39,  40,  40,  41,  41,  42,  42,  43,  43,  44,  44,  45,  45,
        46,  46,  47,  47,  48,  48,  49,  49,  50,  50,  51,  51,  52,
        52,  53,  53,  54,  54,  55,  55,  56,  56,  57,  57,  58,  58,
        59,  59,  60,  60,  61,  61,  62,  62,  63,  63,  64,  64,  65,
        65,  66,  66,  67,  67,  68,  68,  69,  69,  70,  70,  71,  71,
        72,  72,  73,  73,  74,  74,  75,  75,  76,  76,  77,  77,  78,
        78,  79,  79,  80,  80,  81,  81,  82,  82,  83,  83,  84,  84,
        85,  85,  86,  86,  87,  87,  88,  88,  89,  89,  90,  90,  91,
        91,  92,  92,  93,  93,  94,  94,  95,  95,  96,  96,  97,  97,
        98,  98,  99,  99, 100, 100])
        
b
array([  0,   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,  45,  46,  47,  48,  49,  50,  51,
        52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63,  64,
        65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76,  77,
        78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,
        91,  92,  93,  94,  95,  96,  97,  98,  99, 100, 101, 102, 103,
       104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116,
       117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129,
       130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142,
       143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155,
       156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168,
       169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181,
       182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194,
       195, 196, 197, 198, 199, 200])
im = imread('people.jpg') 
type(im) # ndarray => mutable 
# numpy.ndarray

im[a,b] = 0
plt.figure(figsize=(6,6))
plt.imshow(im)

im = imread('people.jpg') 
type(im) # ndarray => mutable 
# numpy.ndarray

im[a,b] = 0
plt.figure(figsize=(6,6))
plt.imshow(im)

x = np.arange(24).reshape(4,6)
x[[0,1,2],[1,2,3]] # 1, 8, 15 방향의 직선 => a, b = line(0,0,100,200) 와 유사한 인덱싱  
# array([ 1,  8, 15])

x
array([[ 0,  1,  2,  3,  4,  5],
       [ 6,  7,  8,  9, 10, 11],
       [12, 13, 14, 15, 16, 17],
       [18, 19, 20, 21, 22, 23]])
h, w = rectangle((20,20),(100,100))
im[h,w] = 0
# 직선과 직사각형이 이미지에 같이 표시되는 이유는 im 객체가 mutable이기 때문에 line함수와 rectangle함수가 적용된 결과가 누적된다 
plt.figure(figsize=(6,6)) 
plt.imshow(im)

h, w = rectangle((300,300),(100,100))
im[h,w] = 0
plt.figure(figsize=(6,6)) 
plt.imshow(im)

im.shape
#(540, 540, 3)

im[h,w,...]

im[h,w,:] == im[h,w]

im[h,w][:]

im[h,w]

 

im[h,w,0] = 0

im[h,w,1] = 0 == im[h,w] = 0

im[h,w,2] = 0

좌표축 그리는 3총사

1. np.meshgrid

2. np.ogrid

3. np.mgrid

meshgrid

a = np.arange(100)
b = np.arange(100)
h,w = np.meshgrid(a,b)

grid = h + w 

h.shape
# (50, 100)

w.shape
# (50, 100)

grid
array([[  0,   1,   2, ...,  97,  98,  99],
       [  1,   2,   3, ...,  98,  99, 100],
       [  2,   3,   4, ...,  99, 100, 101],
       ...,
       [ 47,  48,  49, ..., 144, 145, 146],
       [ 48,  49,  50, ..., 145, 146, 147],
       [ 49,  50,  51, ..., 146, 147, 148]])
grid.shape
# (50, 100)

plt.figure(figsize=(6,6))
plt.imshow(grid)

a = np.arange(100)
b = np.arange(50)
h,w = np.meshgrid(a,b)
grid = h + w 

plt.figure(figsize=(6,6))
plt.scatter(w,h) # x축, y축 
plt.grid()

ogrid

'__getitem__' in dir(np.ogrid) # getitem이 있으면 대괄호([])를 사용할 수 있다
# True

len(np.ogrid[0:100,0:100])
# 2


x, y = np.ogrid[0:100,0:100]
x

y
array([[ 0,  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, 45, 46, 47,
        48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
        64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
        80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
        96, 97, 98, 99]])

x + y
array([[  0,   1,   2, ...,  97,  98,  99],
       [  1,   2,   3, ...,  98,  99, 100],
       [  2,   3,   4, ...,  99, 100, 101],
       ...,
       [ 97,  98,  99, ..., 194, 195, 196],
       [ 98,  99, 100, ..., 195, 196, 197],
       [ 99, 100, 101, ..., 196, 197, 198]])
       
x.shape
(100, 1)

y.shape
(1, 100)

grid = x + y

plt.figure(figsize=(6,6))
plt.imshow(grid)

x, y = np.ogrid[0:50,0:100]
grid = x + y 

plt.figure(figsize=(6,6))
plt.imshow(grid)

h,w = circle(10,10,10) # 원점 (10,10)을 중심으로 반지름이 10인 원 그리기 
grid = x + y 
grid[h,w] = 255

grid.shape
# (100, 100)

plt.figure(figsize=(6,6))
plt.imshow(grid) # ogrid로 만든 좌표축에 circle을 포함시켰다

xx, yy = np.ogrid[0:10:3j,0:10:3j] # 0부터 10까지 숫자를 3등분 해서 좌표축을 만든다  
grid = xx + yy 
h,w = circle(1,1,1)
grid[h,w] = 10

xx
# array([[ 0.],
       [ 5.],
       [10.]])
       
yy
# array([[ 0.,  5., 10.]])

grid.shape
# (3, 3)

plt.figure(figsize=(6,6))
plt.imshow(grid)

 

grid[...] = 0

plt.imshow(grid)

x, y = np.ogrid[0:10, 0:10]

grid = x + y 

grid[2*x-y==0]
# array([ 0,  3,  6,  9, 12])

grid # y = 2x 
array([[ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9],
       [ 1,  2,  3,  4,  5,  6,  7,  8,  9, 10],
       [ 2,  3,  4,  5,  6,  7,  8,  9, 10, 11],
       [ 3,  4,  5,  6,  7,  8,  9, 10, 11, 12],
       [ 4,  5,  6,  7,  8,  9, 10, 11, 12, 13],
       [ 5,  6,  7,  8,  9, 10, 11, 12, 13, 14],
       [ 6,  7,  8,  9, 10, 11, 12, 13, 14, 15],
       [ 7,  8,  9, 10, 11, 12, 13, 14, 15, 16],
       [ 8,  9, 10, 11, 12, 13, 14, 15, 16, 17],
       [ 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]])
x, y = np.ogrid[-10:10, -10:10]

grid = x + y 

grid[...] = 0
grid[x+2*y-3 == 0] # x + 2y -3 = 0 값을 0으로 잡아 놨기 때문에 그래프를 그릴 수 없다 
# array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0])

# 값을 0으로 잡지 않고 했을 때는 그래프를 그릴 수 있다 
grid = x + y 
grid[x+2*y-3 == 0]
# array([-3, -2, -1,  0,  1,  2,  3,  4,  5,  6])

x, y = np.ogrid[-5:5, -5:5]
grid = x + y 

grid 
array([[-10,  -9,  -8,  -7,  -6,  -5,  -4,  -3,  -2,  -1],
       [ -9,  -8,  -7,  -6,  -5,  -4,  -3,  -2,  -1,   0],
       [ -8,  -7,  -6,  -5,  -4,  -3,  -2,  -1,   0,   1],
       [ -7,  -6,  -5,  -4,  -3,  -2,  -1,   0,   1,   2],
       [ -6,  -5,  -4,  -3,  -2,  -1,   0,   1,   2,   3],
       [ -5,  -4,  -3,  -2,  -1,   0,   1,   2,   3,   4],
       [ -4,  -3,  -2,  -1,   0,   1,   2,   3,   4,   5],
       [ -3,  -2,  -1,   0,   1,   2,   3,   4,   5,   6],
       [ -2,  -1,   0,   1,   2,   3,   4,   5,   6,   7],
       [ -1,   0,   1,   2,   3,   4,   5,   6,   7,   8]])
       
grid[x==y] # 조건식을 둘수 있다 
# array([-10,  -8,  -6,  -4,  -2,   0,   2,   4,   6,   8])

x == y 
# array([[ True, False, False, False, False, False, False, False, False, False],
       [False,  True, False, False, False, False, False, False, False, False],
       [False, False,  True, False, False, False, False, False, False, False],
       [False, False, False,  True, False, False, False, False, False, False],
       [False, False, False, False,  True, False, False, False, False, False],
       [False, False, False, False, False,  True, False, False, False, False],
       [False, False, False, False, False, False,  True, False, False, False],
       [False, False, False, False, False, False, False,  True, False, False],
       [False, False, False, False, False, False, False, False,  True, False],
       [False, False, False, False, False, False, False, False, False, True]])
       
grid[x==y] = 0 
grid 
array([[ 0, -9, -8, -7, -6, -5, -4, -3, -2, -1],
       [-9,  0, -7, -6, -5, -4, -3, -2, -1,  0],
       [-8, -7,  0, -5, -4, -3, -2, -1,  0,  1],
       [-7, -6, -5,  0, -3, -2, -1,  0,  1,  2],
       [-6, -5, -4, -3,  0, -1,  0,  1,  2,  3],
       [-5, -4, -3, -2, -1,  0,  1,  2,  3,  4],
       [-4, -3, -2, -1,  0,  1,  0,  3,  4,  5],
       [-3, -2, -1,  0,  1,  2,  3,  0,  5,  6],
       [-2, -1,  0,  1,  2,  3,  4,  5,  0,  7],
       [-1,  0,  1,  2,  3,  4,  5,  6,  7,  0]])
       
grid[x==y] = 255
grid # y = x / 통념상 y = x일 때 왼쪽 아래에서 오른쪽 위로 뻗는 직선이 맞지만 grid함수로 만들어진 좌표축은 y축 방향이 ↓(아래쪽 화살표) 아래로 향하기 때문에 왼쪽 위에서 오른쪽 아래로 뻗는 직선이 나온다   
array([[255,  -9,  -8,  -7,  -6,  -5,  -4,  -3,  -2,  -1],
       [ -9, 255,  -7,  -6,  -5,  -4,  -3,  -2,  -1,   0],
       [ -8,  -7, 255,  -5,  -4,  -3,  -2,  -1,   0,   1],
       [ -7,  -6,  -5, 255,  -3,  -2,  -1,   0,   1,   2],
       [ -6,  -5,  -4,  -3, 255,  -1,   0,   1,   2,   3],
       [ -5,  -4,  -3,  -2,  -1, 255,   1,   2,   3,   4],
       [ -4,  -3,  -2,  -1,   0,   1, 255,   3,   4,   5],
       [ -3,  -2,  -1,   0,   1,   2,   3, 255,   5,   6],
       [ -2,  -1,   0,   1,   2,   3,   4,   5, 255,   7],
       [ -1,   0,   1,   2,   3,   4,   5,   6,   7, 255]])

mgrid

 

len(np.mgrid[0:100,0:100])
# 2

a, b = np.mgrid[0:100,0:100]
aa, bb = np.mgrid[0:10:5j,0:10:5j] # 0부터 10까지 숫자를 5등분 해서 좌표축을 만든다 
a
array([ 0,  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, 45, 46, 47, 48, 49, 50,
       51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
       68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
       85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99])
       

aa
array([[ 0. ,  0. ,  0. ,  0. ,  0. ],
       [ 2.5,  2.5,  2.5,  2.5,  2.5],
       [ 5. ,  5. ,  5. ,  5. ,  5. ],
       [ 7.5,  7.5,  7.5,  7.5,  7.5],
       [10. , 10. , 10. , 10. , 10. ]])
       
b
array([[ 0,  1,  2, ..., 97, 98, 99],
       [ 0,  1,  2, ..., 97, 98, 99],
       [ 0,  1,  2, ..., 97, 98, 99],
       ...,
       [ 0,  1,  2, ..., 97, 98, 99],
       [ 0,  1,  2, ..., 97, 98, 99],
       [ 0,  1,  2, ..., 97, 98, 99]])
       
a.shape
(100, 100)

b.shape
(100, 100)

grid = a + b

plt.figure(figsize=(6,6))
plt.imshow(grid)

c, d = np.mgrid[0:10,0:10]
c + d # 안에 있는 값은 의미 없다 / 좌표축을 만들어 준다는 것이 중요하다 
array([[ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9],
       [ 1,  2,  3,  4,  5,  6,  7,  8,  9, 10],
       [ 2,  3,  4,  5,  6,  7,  8,  9, 10, 11],
       [ 3,  4,  5,  6,  7,  8,  9, 10, 11, 12],
       [ 4,  5,  6,  7,  8,  9, 10, 11, 12, 13],
       [ 5,  6,  7,  8,  9, 10, 11, 12, 13, 14],
       [ 6,  7,  8,  9, 10, 11, 12, 13, 14, 15],
       [ 7,  8,  9, 10, 11, 12, 13, 14, 15, 16],
       [ 8,  9, 10, 11, 12, 13, 14, 15, 16, 17],
       [ 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]])
       

(c + d)[(0,1),(0,1)] = 0 # 흑백 이미지 / 2차원 좌표축 만드는 것

meshgrid vs ogrid vs mgrid

mesgrid ogrid mgrid
indexer 표현 X indexer 표현 O indexer 표현 O
행과 열이 바뀌어 표현한다 중복된것 줄여서작게 표현한다 다 표현해 준다
j(n등분)를 사용 X j(n등분)를 사용 O j(n등분)를 사용 O
비어 있는 2차원 좌표축을 그릴때 사용한다
me1, me2 = np.meshgrid(np.arange(100),np.arange(100))
og1, og2 = np.ogrid[0:100,0:100]
mg1, mg2 = np.mgrid[0:100,0:100]

np.array_equal(mg1+mg2, og1+og2) # mg1+mg2(mgrid)는 모든 수 다 표현해 준다 / or1+or2(ogrid)는 broadcasting 연산을 하도록 표현한다 
# True

mg1+mg2
array([[  0,   1,   2, ...,  97,  98,  99],
       [  1,   2,   3, ...,  98,  99, 100],
       [  2,   3,   4, ...,  99, 100, 101],
       ...,
       [ 97,  98,  99, ..., 194, 195, 196],
       [ 98,  99, 100, ..., 195, 196, 197],
       [ 99, 100, 101, ..., 196, 197, 198]])
       
og1+og2
array([[  0,   1,   2, ...,  97,  98,  99],
       [  1,   2,   3, ...,  98,  99, 100],
       [  2,   3,   4, ...,  99, 100, 101],
       ...,
       [ 97,  98,  99, ..., 194, 195, 196],
       [ 98,  99, 100, ..., 195, 196, 197],
       [ 99, 100, 101, ..., 196, 197, 198]])

mg1 == og1
array([[ True,  True,  True, ...,  True,  True,  True],
       [ True,  True,  True, ...,  True,  True,  True],
       [ True,  True,  True, ...,  True,  True,  True],
       ...,
       [ True,  True,  True, ...,  True,  True,  True],
       [ True,  True,  True, ...,  True,  True,  True],
       [ True,  True,  True, ...,  True,  True,  True]])

mg2 == og2
array([[ True,  True,  True, ...,  True,  True,  True],
       [ True,  True,  True, ...,  True,  True,  True],
       [ True,  True,  True, ...,  True,  True,  True],
       ...,
       [ True,  True,  True, ...,  True,  True,  True],
       [ True,  True,  True, ...,  True,  True,  True],
       [ True,  True,  True, ...,  True,  True,  True]])

np.array_equal(mg1+mg2, me1+me2) 
# True

mg1 == me1 # 중앙 대각선만 일치한다 
array([[ True, False, False, ..., False, False, False],
       [False,  True, False, ..., False, False, False],
       [False, False,  True, ..., False, False, False],
       ...,
       [False, False, False, ...,  True, False, False],
       [False, False, False, ..., False,  True, False],
       [False, False, False, ..., False, False,  True]])

mg1 == me1.T # 둘 중 하나를 전치행렬(Transposed matrix)을 구하면 둘이 같아 진다 
array([[ True,  True,  True, ...,  True,  True,  True],
       [ True,  True,  True, ...,  True,  True,  True],
       [ True,  True,  True, ...,  True,  True,  True],
       ...,
       [ True,  True,  True, ...,  True,  True,  True],
       [ True,  True,  True, ...,  True,  True,  True],
       [ True,  True,  True, ...,  True,  True,  True]])

mg2 == me2.T
array([[ True,  True,  True, ...,  True,  True,  True],
       [ True,  True,  True, ...,  True,  True,  True],
       [ True,  True,  True, ...,  True,  True,  True],
       ...,
       [ True,  True,  True, ...,  True,  True,  True],
       [ True,  True,  True, ...,  True,  True,  True],
       [ True,  True,  True, ...,  True,  True,  True]])

np.array_equal(og1+og2, me1+me2) 
# True

og1+og2 
array([[  0,   1,   2, ...,  97,  98,  99],
       [  1,   2,   3, ...,  98,  99, 100],
       [  2,   3,   4, ...,  99, 100, 101],
       ...,
       [ 97,  98,  99, ..., 194, 195, 196],
       [ 98,  99, 100, ..., 195, 196, 197],
       [ 99, 100, 101, ..., 196, 197, 198]])

me1 + me2
array([[  0,   1,   2, ...,  97,  98,  99],
       [  1,   2,   3, ...,  98,  99, 100],
       [  2,   3,   4, ...,  99, 100, 101],
       ...,
       [ 97,  98,  99, ..., 194, 195, 196],
       [ 98,  99, 100, ..., 195, 196, 197],
       [ 99, 100, 101, ..., 196, 197, 198]])

og1 == me1.T
array([[ True,  True,  True, ...,  True,  True,  True],
       [ True,  True,  True, ...,  True,  True,  True],
       [ True,  True,  True, ...,  True,  True,  True],
       ...,
       [ True,  True,  True, ...,  True,  True,  True],
       [ True,  True,  True, ...,  True,  True,  True],
       [ True,  True,  True, ...,  True,  True,  True]])

og2 == me2.T
array([[ True,  True,  True, ...,  True,  True,  True],
       [ True,  True,  True, ...,  True,  True,  True],
       [ True,  True,  True, ...,  True,  True,  True],
       ...,
       [ True,  True,  True, ...,  True,  True,  True],
       [ True,  True,  True, ...,  True,  True,  True],
       [ True,  True,  True, ...,  True,  True,  True]])

grid[c==d] # boolena indexing 방식 
# array([-10,  -8,  -6,  -4,  -2,   0,   2,   4,   6,   8])

c==d
array([[ True, False, False, False, False, False, False, False, False, False],
       [False,  True, False, False, False, False, False, False, False, False],
       [False, False,  True, False, False, False, False, False, False, False],
       [False, False, False,  True, False, False, False, False, False, False],
       [False, False, False, False,  True, False, False, False, False, False],
       [False, False, False, False, False,  True, False, False, False, False],
       [False, False, False, False, False, False,  True, False, False, False],
       [False, False, False, False, False, False, False,  True, False, False],
       [False, False, False, False, False, False, False, False,  True, False],
       [False, False, False, False, False, False, False, False, False, True]])

grid[2*c==d] = 255
grid 
array([[-10,  -9,  -8,  -7,  -6,  -5,  -4,  -3,  -2,  -1],
       [ -9,  -8,  -7,  -6,  -5,  -4,  -3,  -2,  -1,   0],
       [ -8,  -7,  -6,  -5,  -4,  -3,  -2,  -1,   0,   1],
       [ -7, 255,  -5,  -4,  -3,  -2,  -1,   0,   1,   2],
       [ -6,  -5,  -4, 255,  -2,  -1,   0,   1,   2,   3],
       [ -5,  -4,  -3,  -2,  -1, 255,   1,   2,   3,   4],
       [ -4,  -3,  -2,  -1,   0,   1,   2, 255,   4,   5],
       [ -3,  -2,  -1,   0,   1,   2,   3,   4,   5, 255],
       [ -2,  -1,   0,   1,   2,   3,   4,   5,   6,   7],
       [ -1,   0,   1,   2,   3,   4,   5,   6,   7,   8]])

circle

x, y = circle(3,3,3) # 원점이 3,3이고 반지름이 3인 원 
x
# array([[-5],
       [-4],
       [-3],
       [-2],
       [-1],
       [ 0],
       [ 1],
       [ 2],
       [ 3],
       [ 4]])
       
y
# array([[-5, -4, -3, -2, -1,  0,  1,  2,  3,  4]])

Scikit learn에서는 font를 지원하지 않는다

Scikit Masking

im1 = np.zeros((200,200))
im2 = np.zeros((200,200))

h1,w1 = rectangle((40,40),(160,160))
h2,w2 = circle(100,100,50)

im1[h1,w1] = 255
im2[h2,w2] = 255
plt.imshow(im1, cmap='gray');

plt.imshow(im2, cmap='gray');

OpenCV

import numpy as np
import cv2 # opencv 

im = cv2.imread('people.jpg')

type(im) # opencv로 불러올 때도 im객체가 ndarray이기 때문에 mutable이다 
# numpy.ndarray

# im객체가 rectangel이라는 함수를 사용하면 결과가 누적된다 (mutable)
im_r = cv2.rectangle(im, (100,100), (250,250), (255,0,0), 10) # 두번째 인자는 직사각형에서 왼쪽 위 좌표, 오른쪽 아래 좌표 / 세번째 인자는 RGB / 네번째 인자는 테두리 크기
plt.figure(figsize=(6,6))
plt.imshow(im_r);

텍스트 그리기

opencv에서는 font변경이 한정적이기 때문에 기본적으로 한글 사용 불가하다

opencv를 font를 바꾸고 나서 compile하면 한글 사용할 수 있다

beatmap형태를 지원한다

im = cv2.imread('people.jpg')
cv2.putText(im, 'moon', (200,100), 1, 6, (255,0,0), 2)  # 이미지 / 텍스트 / 위치 / 폰트 / 폰트크기 / RGB / 두께  

for i in dir(cv2):
  if 'FONT' in i:
    print(i, getattr(cv2, i))
plt.figure(figsize=(6,6))
plt.imshow(im)
im = cv2.imread('people.jpg')
cv2.putText(im, '한글', (200,100), 1, 6, (255,0,0), 2)
plt.figure(figsize=(6,6))
plt.imshow(im)

이미지 합성

주의 해야할 연산 가지

1. saturated : 255넘을 나머지 무시 => cv2.add

2. modular : % 255넘을 255나눈 나머지 => np.add

im1 = cv2.imread('people.jpg') 
im2 = cv2.imread('apple.jpg')

cv2.addWeighted(im1, 0.7, im2, 0.3, 0) # im1의 불투명도를 70% im2의 불투명도를 30% / 두 개 이미지 shape이 같아야 한다 
# error: OpenCV(4.1.2) /io/opencv/modules/core/src/arithm.cpp:663: error: (-209:Sizes of input arguments do not match) The operation is neither 'array op array' (where arrays have the same size and the same number of channels), nor 'array op scalar', nor 'scalar op array' in function 'arithm_op'
im1.shape, im2.shape
((540, 540, 3), (1000, 816, 3))

im2[:540,:540].shape
im2 = im2[250:790,150:690]
blend = cv2.addWeighted(im1, 0.7, im2, 0.3, 0) # 합성 이미지 / blending => 크기와 채널이 같아야 한다 / 두 이미지를 합 할때 가중치를 두고 연산한다 (가중합) 

plt.imshow(blend)

Bitwise 연산

a = 20
bin(a)
# '0b10100'

a.bit_length()
# 5

a = 20
b = 21

# 10100 
# 10101
#   ↓ 
# 10100 
a&b # bitwise and 연산 / 둘 다 1일 때 1, 둘 중 하나라도 0이면 0 
# 20

# 10100 
# 10101
#   ↓ 
# 10101 
a|b # bitwise or 연산 / 둘 중 하나라도 1이면 1, 둘 다 0이면 0
# 21

bin(a),bin(b)
# ('0b10100', '0b10101')

a >> 2  # 두 칸 뒤로 / 10100 => 00101
# 5

a << 2 # 두 칸 앞으로 / 10100 => 1010000
# 80

이미지에서 bitwise 연산

im1 = cv2.imread('people.jpg', 0)
im2 = cv2.imread('apple.jpg', 0)

im2 = im2[250:790,150:690]
t=cv2.bitwise_and(im1, im2)

plt.imshow(t, cmap='gray') # masking

Opencv masking

im1 = np.zeros((200,200))
im2 = np.zeros((200,200))

h1,w1 = rectangle((40,40),(160,160))
h2,w2 = circle(100,100,50)

im1[h1,w1] = 255
im2[h2,w2] = 255
plt.imshow(cv2.bitwise_and(im1,im2), cmap='gray');

plt.imshow(cv2.bitwise_or(im1,im2), cmap='gray');

plt.imshow(cv2.bitwise_xor(im1,im2), cmap='gray');

PIL

from PIL import Image, ImageDraw, ImageDraw2, ImageOps
import PIL

im_pil = Image.open('people.jpg')

type(im_pil)
# PIL.JpegImagePlugin.JpegImageFile

dir(PIL.JpegImagePlugin.JpegImageFile)
PIL.JpegImagePlugin.JpegImageFile.__class__
# type

im_pil

 

type(ImageDraw.ImageDraw) # Class 
# type

type(ImageDraw.Draw) # function
# function

draw = ImageDraw.ImageDraw(im_pil) # composition 방식 
draw2 = ImageDraw.Draw(im_pil) # function 방식 / function 방식이지만 return이 instacne이기 때문에 헷갈려서 대문자로 만들었다   

draw.rectangle(((0,0),(100,100))) # mutable 방식 
draw2.rectangle(((100,100),(200,200)))

im_pil

type(ImageOps)
# module

ImageOps.expand(im_pil, 20) # composition 함수 / im_pil이라는 인스턴스를 인자로 넣고 사용하기 때문에 composition 방식이다 / 결과가

텍스트 그리기

im_pil = Image.open('people.jpg')
from PIL import ImageFont
draw = ImageDraw.ImageDraw(im_pil)
draw2 = ImageDraw.Draw(im_pil)
draw.text((120,100),'Chim') # mutable 방식 
im_pil

draw.text((100,120),'한글') # 기본적인 방식에서는 한글 지원 안한다 

UnicodeEncodeError: 'latin-1' codec can't encode characters in position 0-1: ordinal not in range(256)
!sudo apt-get install -y fonts-nanum # colab에서 사용시 폰트를 다운 받아야 한다 
!sudo fc-cache -fv
!rm ~/.cache/matplotlib -rf
font = ImageFont.truetype('NanumBarunGothic', 35) # PIL은 truetype으로 깔끔하게 나온다 
draw.text((240,170),'주호민', font=font, fill='pink') 
im_pil

 

 

반응형
728x90
반응형

Image 처리

import tensorflow as tf 
im = tf.io.read_file('people.jpg')
im = tf.image.decode_jpeg(im)
im
# <tf.Tensor: shape=(540, 540, 3), dtype=uint8, numpy=
# array([[[200, 188, 176],
#         [202, 190, 178],
#         [204, 192, 180],
#         ...,

상황에 따라 알맞은 라이브러리를 사용하면 된다

from scipy import ndimage # 기본적인 이미지 처리 할 수 있다 
from scipy import io
import imageio # image를 읽고 저장하는 기능만 제공한다 
import numpy as np
import scipy # low level이기 때문에 전문가들이 주로 사용한다 / image processing에 초첨이 맞추어져 있다 
# scipy-toolkit => scipy에서 파생되어 사용자 친화적인 high level인 라이브러리가 생겼다 
# scipy-toolkit image => scikit-image 
# scipy-toolkit machine learning => scikit-learn 
# opencv => Practical 
import cv2 # computer vision에 초점이 맞추어 져있다 / image array 구조가 Numpy와 다르다 
import matplotlib.pyplot as plt
from PIL import Image  # pythonic한 image 처리 라이브러리 
from skimage import io
import PIL

# !pip install -U opencv-python # opecnv 설치 / colab에서 하시면 설치하지 않으셔도 됩니다 / 파이썬 기반의 opencv는 한글처리 기능이 지원되지 않는다 
!pip list
Package                       Version
----------------------------- --------------
absl-py                       0.12.0
alabaster                     0.7.12
albumentations                0.1.12
altair                        4.1.0
appdirs                       1.4.4
argcomplete                   1.12.3
argon2-cffi                   21.1.0
arviz                         0.11.2
astor                         0.8.1
astropy                       4.3.1
astunparse                    1.6.3
atari-py                      0.2.9
atomicwrites                  1.4.0
attrs                         21.2.0
audioread                     2.1.9
autograd                      1.3
Babel                         2.9.1
backcall                      0.2.0
beautifulsoup4                4.6.3
bleach                        4.0.0
blis                          0.4.1
bokeh                         2.3.3
Bottleneck                    1.3.2
branca                        0.4.2
bs4                           0.0.1
...
dir(ndimage)
dir(io)
dir(imageio)
['RETURN_BYTES',
 '__builtins__',
 '__cached__',
 '__doc__',
 '__file__',
 '__loader__',
 '__name__',
 '__package__',
 '__path__',
 '__spec__',
 '__version__',
 'core',
 'formats',
 'get_reader',
 'get_writer',
 'help',
 'imread',
 'imsave',
 'imwrite',
 'mimread',
 'mimsave',
 'mimwrite',
 'mvolread',
 'mvolsave',
 'mvolwrite',
 'plugins',
 'read',
 'save',
 'show_formats',
 'volread',
 'volsave',
 'volwrite']
imageio.formats # 95가지 image format을 지원한다 
# <imageio.FormatManager with 96 registered formats>
imageio.imread('people.jpg')
# Array([[[201, 189, 177],
#         [203, 191, 179],
#         [204, 192, 180],
#         ...,
type(imageio.imread('people.jpg'))
# imageio.core.util.Array

issubclass(type(imageio.imread('people.jpg')), np.ndarray)
# True

imageio.core.util.Array.__base__ # 부모 클래스 
# numpy.ndarray

imageio.core.util.Array.mro() 
# [imageio.core.util.Array, numpy.ndarray, object]

OpenCV

opencv c버전은 c/c++ 관례를 따른다

dir(cv2)
['',
 'ACCESS_FAST',
 'ACCESS_MASK',
 'ACCESS_READ',
 'ACCESS_RW',
 'ACCESS_WRITE',
 'ADAPTIVE_THRESH_GAUSSIAN_C',
 'ADAPTIVE_THRESH_MEAN_C',
im2 = cv2.imread('people.jpg')
plt.imshow(im2)

RGB로 처리하는 것이 선명하게 잘 보여주지만 비용이 많이 들기 때문에

저가 모니터는 BGR 처리를 한다

opencv는 BGR 배열로 표현해준다

plt.imshow(im2[...,::-1])

im3 = cv2.imread('people.jgp') # 확장자를 잘 못 적어도 에러가 나지 않는다 
plt.imshow(im)

im1 = cv2.imread('people.jpg')    # 3차원으로 불러온다 / 컬러 이미지 

im2 = cv2.imread('people.jpg', 0) # 2차원으로 불러온다 / 흑백 이미지 

im1.shape, im2.shape
# ((540, 540, 3), (540, 540))

im3 = cv2.imread('people.jpg', 100)
im3.shape
# (135, 135, 3)
dir(cv2) # 대문자는 옵션이다 
for i in dir(cv2):
  if 'imread' in i:
    print(i)
# imread
# imreadmulti
for i in dir(cv2):
  if 'IMREAD' in i:
    print(i, getattr(cv2, i))   # 옵션 
    
IMREAD_ANYCOLOR 4
IMREAD_ANYDEPTH 2
IMREAD_COLOR 1
IMREAD_GRAYSCALE 0
IMREAD_IGNORE_ORIENTATION 128
IMREAD_LOAD_GDAL 8
IMREAD_REDUCED_COLOR_2 17
IMREAD_REDUCED_COLOR_4 33
IMREAD_REDUCED_COLOR_8 65
IMREAD_REDUCED_GRAYSCALE_2 16
IMREAD_REDUCED_GRAYSCALE_4 32
IMREAD_REDUCED_GRAYSCALE_8 64
IMREAD_UNCHANGED -1

Saturated / Modular 연산

im = cv2.imread('people.jpg')
im 
# array([[[177, 189, 201],
#         [179, 191, 203],
#         [180, 192, 204],
#         ...,
cv2.add(im, im) # 가장 큰 값이 255이기 때문에 합이 255를 넘어가면 saturated 연산이 적용된다
array([[[255, 255, 255],
        [255, 255, 255],
        [255, 255, 255],
        ...,
        [252, 255, 255],
        [254, 255, 255],
        [255, 255, 255]],
(177+177) - 256 # im의 첫번쨰 값: 177 / 177 + 177이 255을 초과 했기 때문에 modular연산에서는 256(dtype이 8이었기 때문에 2^8)을 빼는 연산을 한다 
# 98
im.dtype
# dtype('uint8')

np.add(im, im) # modular 연산 
# array([[[ 98, 122, 146],
#         [102, 126, 150],
#         [104, 128, 152],
#         ...,

Basic Operation

im[100,40]
# array([183, 198, 207], dtype=uint8)

im[100,40,2]
# 207

im.item(100,40,2)
# 207

im[100,40,2] = 100

im.item(100,40,2)
# 100

im.itemset((100,40,2), 207) # 값 조정 
im.item(100,40,2)
# 207

im[200:30,330:2]

array([], shape=(0, 0, 3), dtype=uint8)
plt.imshow(im[...,::-1])

Channel

im_cv = cv2.imread('people.jpg')
im[...,2]
array([[201, 203, 204, ..., 193, 194, 196],
       [200, 202, 203, ..., 201, 203, 204],
       [199, 201, 202, ..., 209, 210, 211],
       ...,
       [114, 112, 120, ...,  98, 109, 114],
       [116, 112, 120, ...,  96, 103, 106],
       [111, 107, 115, ..., 102, 103, 103]], dtype=uint8)
len(cv2.split(im))
# 3
plt.imshow(im_cv)

B, G, R = cv2.split(im_cv) # function 방식 
im_cv = cv2.merge((R,G,B))
plt.imshow(im_cv)

for i in dir(cv2):
  if 'COLOR_BGR2' in i:
    print(i, getattr(cv2, i))
    
COLOR_BGR2BGR555 22
COLOR_BGR2BGR565 12
COLOR_BGR2BGRA 0
COLOR_BGR2GRAY 6
COLOR_BGR2HLS 52
COLOR_BGR2HLS_FULL 68
COLOR_BGR2HSV 40
COLOR_BGR2HSV_FULL 66
COLOR_BGR2LAB 44
COLOR_BGR2LUV 50
COLOR_BGR2Lab 44
COLOR_BGR2Luv 50
COLOR_BGR2RGB 4
COLOR_BGR2RGBA 2
COLOR_BGR2XYZ 32
COLOR_BGR2YCR_CB 36
COLOR_BGR2YCrCb 36
COLOR_BGR2YUV 82
COLOR_BGR2YUV_I420 128
COLOR_BGR2YUV_IYUV 128
COLOR_BGR2YUV_YV12 132
cv2.cvtColor(im_cv, cv2.COLOR_BGR2GRAY) # 색공간 바꾸기 
array([[187, 189, 190, ..., 152, 153, 155],
       [186, 188, 189, ..., 160, 162, 163],
       [185, 187, 188, ..., 170, 171, 172],
       ...,
       [100,  96, 103, ..., 119, 130, 135],
       [100,  96, 103, ..., 119, 126, 129],
       [ 95,  91,  98, ..., 125, 126, 126]], dtype=uint8)
cv2.cvtColor(im_cv, cv2.COLOR_BGR2RGB)
array([[[177, 189, 201],
        [179, 191, 203],
        [180, 192, 204],
        ...,
for i in dir(cv2):
  if 'BORDER_' in i :
    print(i, getattr(cv2, i))
BORDER_CONSTANT 0
BORDER_DEFAULT 4
BORDER_ISOLATED 16
BORDER_REFLECT 2
BORDER_REFLECT101 4
BORDER_REFLECT_101 4
BORDER_REPLICATE 1
BORDER_TRANSPARENT 5
BORDER_WRAP 3
plt.imshow(cv2.copyMakeBorder(im_cv, 10,10,10,10,0))

plt.imshow(np.pad(im_cv,[(10,10),(10,10),(0,0)], mode='constant'))

PIL

PIL은 이미지 파일 자체에 대한 내용도 알 수 있다

meta data에 대한 정보가 필요할떄 유용하다

im4 = Image.open('people.jpg') # mutable 방식 지원 
plt.imshow(im4)

b = np.array(im4)
Image.fromarray(b)

 

type(b)
# numpy.ndarray

type(im4) # 데이터 구조 자체가 numpy와 다르다 하지만 Numpy와 호환이 된다 
# PIL.JpegImagePlugin.JpegImageFile

im4.format_description
# 'JPEG (ISO 10918)'

im4.getexif().keys()
# KeysView(<PIL.Image.Exif object at 0x7f424eb895d0>)
im_pil = Image.open('people.jpg')
R, G, B = im_pil.split() # method 방식 
Image.merge('RGB', (R,G,B))

Image.merge('RGB', (B,G,R))

'ImageMode' in dir(PIL) # composition 방식으로 만들어짐 
# True
from PIL import ImageMode
ImageMode._modes # Image.merge(mode, bands) 모드 자리에 들어 갈 수 있는 키값들 
{'1': <PIL.ImageMode.ModeDescriptor at 0x7f4249d1b350>,
 'CMYK': <PIL.ImageMode.ModeDescriptor at 0x7f4249d45bd0>,
 'F': <PIL.ImageMode.ModeDescriptor at 0x7f4249d45d50>,
 'HSV': <PIL.ImageMode.ModeDescriptor at 0x7f4249d45590>,
 'I': <PIL.ImageMode.ModeDescriptor at 0x7f4249d45d90>,
 'I;16': <PIL.ImageMode.ModeDescriptor at 0x7f4249d45a50>,
 'I;16B': <PIL.ImageMode.ModeDescriptor at 0x7f4249d45f50>,
 'I;16BS': <PIL.ImageMode.ModeDescriptor at 0x7f4249d45e90>,
 'I;16L': <PIL.ImageMode.ModeDescriptor at 0x7f4249d45410>,
 'I;16LS': <PIL.ImageMode.ModeDescriptor at 0x7f4249d450d0>,
 'I;16N': <PIL.ImageMode.ModeDescriptor at 0x7f4249d45390>,
 'I;16NS': <PIL.ImageMode.ModeDescriptor at 0x7f4249d31610>,
 'I;16S': <PIL.ImageMode.ModeDescriptor at 0x7f4249d45ad0>,
 'L': <PIL.ImageMode.ModeDescriptor at 0x7f4249d1bd10>,
 'LA': <PIL.ImageMode.ModeDescriptor at 0x7f4249d45190>,
 'LAB': <PIL.ImageMode.ModeDescriptor at 0x7f4249d45110>,
 'La': <PIL.ImageMode.ModeDescriptor at 0x7f4249d457d0>,
 'P': <PIL.ImageMode.ModeDescriptor at 0x7f4249d45e50>,
 'PA': <PIL.ImageMode.ModeDescriptor at 0x7f4249d452d0>,
 'RGB': <PIL.ImageMode.ModeDescriptor at 0x7f4249d45850>,
 'RGBA': <PIL.ImageMode.ModeDescriptor at 0x7f4249d45210>,
 'RGBX': <PIL.ImageMode.ModeDescriptor at 0x7f4249d45e10>,
 'RGBa': <PIL.ImageMode.ModeDescriptor at 0x7f4249d45510>,
 'YCbCr': <PIL.ImageMode.ModeDescriptor at 0x7f4249d45a90>}
 
 im_pil.convert('L')

PIL은 pad를 지원하지 않는다

im_pil.width
# 540

im_pil.height
# 540

im_pil.info # meat data 
# {'jfif': 257, 'jfif_density': (1, 1), 'jfif_unit': 0, 'jfif_version': (1, 1)}

im_new = Image.new('RGB',(im_pil.width + 20, im_pil.height + 20))
im_new.paste(im_pil, (20,20)) # output이 없다 / mutable 방식 
im_new

from PIL import ImageOps
ImageOps.expand(im_pil, 10) # composition 방법

PIL을 사용하는 이유

tensorflow와 pytorch에서 이미지를 불러올 때 내부적으로 처리하기 때문에 알고 있어야 한다

tf.keras.preprocessing.image.load_img('people.jpg')

Scikit image

from skimage.color import rgb2gray # skimage는 BGR를 지원하지 안는다 
plt.imshow(rgb2gray(im[...,::-1]))

plt.imshow(rgb2gray(im[...,::-1]),  cmap='gray')

plt.imshow(np.mean(im,2))

R,G,B = im[...,0], im[...,1], im[...,2]
gray = R*0.13 + G*0.15 + B*0.14
np.mean(im,2) # (im[...,0]) + im[...,1] + im[...,2]) / 3
plt.imshow(np.mean(im,2), cmap='gray')

각각 이미지 처리 라이브러리에 대한 장점들

속도 차이 : opencv > numpy > PIL

im = tf.io.read_file('people.jpg')
im = tf.image.decode_jpeg(im)  

im = imageio.imread('people.jpg') # Array (array 상속) / 다양한 포맷 지원 / 여러 이미지 불러올 수 있다 

im = cv2.imread('people.jpg') # c/c++ style / array가 BGR로 구성되어 있다 / opencv는 gpu도 지원하기 때문에 속도가 가장 빠르다 

im = Image.open('people.jpg') # numpy와 호환이 되지만 numpy format은 아니다 / PIL이 가장 느리다 

plt.imread('people.jpg') # png파일 불러오지 못함 
array([[[201, 189, 177],
        [203, 191, 179],
        [204, 192, 180],
        ...,
        [194, 158, 126],
from skimage import io
im = io.imread('people.jpg')
plt.imshow(im)

im = Image.open('people.jpg')
im2 = im.getdata()

type(im2)
# ImagingCore

list(im2)
'__iter__' in dir(im2)
# False

im2.__class__.mro() # ImagingCore에 __iter__가 있기때문에 반복, 순회 가능
# [ImagingCore, object]

im = Image.open('people.jpg').convert('1') # meta data를 갖고 있기때문에 가능한 방법
im.getcolors()
# [(142786, 0), (148814, 255)]

 

복습

Stride

a = np.arange(24).reshape(6,4) # 내부적으로는 일렬로 저장된다 
a.flags # Information about the memory layout of the array.
#  C_CONTIGUOUS : True
#  F_CONTIGUOUS : False
#  OWNDATA : False
#  WRITEABLE : True
#  ALIGNED : True
#  WRITEBACKIFCOPY : False
#  UPDATEIFCOPY : False

a.dtype
# dtype('int64')

a.strides # 1차원의 array를 조립하는 가이드 라인 
# (32, 8)

a.itemsize # memory 크기가 8인 정육각형 
# 8

a 
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11],
       [12, 13, 14, 15],
       [16, 17, 18, 19],
       [20, 21, 22, 23]])
       
a.shape
# (6, 4)

a.sum(0) # axis = 0 기준으로 더한다 
# array([60, 66, 72, 78])

a.sum(1) # axis = 1 기준으로 더한다 
# array([ 6, 22, 38, 54, 70, 86])

b = np.arange(24).reshape(2,3,4)
b.shape
# (2, 3, 4)

b.sum(axis=1) # shape에서 index 1을 지우면 결과는 (2,4) 
array([[12, 15, 18, 21],
       [48, 51, 54, 57]])
       
b.sum(axis=2) # shape에서 index 2를 지우면 결과는 (2,3) 
array([[ 6, 22, 38],
       [54, 70, 86]])

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

반응형
728x90
반응형
import matplotlib
len(dir(matplotlib)) 
# 165

import matplotlib.pyplot as plt 
len(dir(matplotlib))  # colab에서는 matplotlib이나 matplotlib.pyplot이나 똑같이 나오네요 
# 165

!pip list # matplotlib version = 3.2.2
!python --version

Image

Image는 2차원의 함수로 정의 한다

Image는 공간에 어떤한 값을 넣었을 값에 대한 강도를 나타낸다

 

Color image는 3 이상 값의 조합으로 좌표에 대한 강도를 나타낸다

 

어떻게 강도를 표현하느냐에 따라 함수가 달라질 있다

특히 함수가 한정적일 경우 디지털 이미지라고 부른다

 

직사각형 형태의 어떤 값으로 강도를 나타낸다

정의 자체는 함수이지만 함수를 좌표계로 구성되어 있는 array로 표현할 있다

Image의 두 종류

1. 벡터 이미지

- 각각 좌표에 대한 함수가 아니라 이미지 자체를 함수로 표현

- 점과 점을 연결해 수학적 원리로 그림을 그려 표현하는 방식이다

- 이미지의 크기를 늘리고 줄여도 손상되지 않는다

- 사진과 같은 복잡한 그림을 표현하려면 컴퓨터에 엄청난 부담을 주기 때문에 웹에서는 사용되지 않는다

- 최근에는 컴퓨터 하드웨어의 발달로 웹사이트의 로고 아이콘 표시에 벡터 그래픽이 사용되고 있다

- ex) ai, eps, svg

 

2. 비트맵 이미지

- 서로 다른 (픽셀)들의 조합으로 그려지는 이미지 표현 방식이다

- 비트맵 이미지는 크기를 늘리거나 줄이면 원본 이미지에 손상되어 번져 보인다

- 컴퓨터에 부담을 주는 구조를 갖고 있기 때문에, 웹에서 이미지를 표시할 때는 주로 비트맵 이미지를 사용한다

- ex) jpg, jpeg, png, gif

색을 표현하는 두 가지 방식

1. HSV

- 밝기로 구분한다

- 색상(Hue), 채도(Saturation), 명도(Value) 좌표를 써서 특정한 색을 지정한다

2. RGB

- 세가지 색이 섞여서 색을 표현한다

- 3장의 array가 합쳐진 것이다

비트맵 이미지를 표현하는 단위

1. Pixel @@@ 추가 설명

- 픽셀은 상대적 크기로 표현한다

- 픽셀은 정사각형으로 표현한다

- ppi가 클수록 1인치당 픽셀의 밀도가 더 높고 더 선명하게 보인다

2. Voxel

- 3차원 이미지에서는 voxel이라고 한다

이미지 처리를 위한 사전단계

1. Image파일을 바이너리 형태로 불러온다

2. image를 array로 바꿔준다

 

with open('Elon.jpg', 'rb') as f: # 기본 옵션 r은 unicode형식으로 불러온다  / rb는 바이너리로 불러온다 
  print(f.read())                 # 파이썬에서는 이미지는 불러올수는 있지만 각각의 값이 어떤 색을 표현하는지 해석할 수 없다 

#  b'\xff\xd8\xff\xe1\x00\x18Exif\x00\x00II*\x00\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xec\x00\x11Ducky\x00\x01\x00\x04...
import tensorflow as tf
im = tf.io.read_file('Elon.jpg') # vectorization으로 불러온다 / array연산을 최적화 하도록 불러온다 
im
# <tf.Tensor: shape=(), dtype=string, numpy=b'\xff\xd8\xff\xe1\x00\x18Exif\x00\x00II*\x00\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0
# .numpy() 하면 기타정보 빼고 내용만 보여줌
im.numpy()

# b'\xff\xd8\xff\xe1\x00\x18Exif\x00\x00II*\x00\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xec\x00\x11Ducky\x00\x01\x00\x04
t = tf.image.decode_gif(im) # 바이너리 값을 해석해준다 
t
# <tf.Tensor: shape=(1, 600, 960, 3), dtype=uint8, numpy=
# array([[[[ 4,  3,  9],
#          [ 3,  2, 10],
#          [ 4,  3, 11],
         ...,
t = tf.image.decode_image(im)
t
# <tf.Tensor: shape=(600, 960, 3), dtype=uint8, numpy=
# array([[[ 4,  3,  9],
#         [ 3,  2, 10],
#         [ 4,  3, 11],
import cv2
cv2.imread('Elon.jpg', ) # OpenCV는 BGR로 불러온다  / python으로 불러오는 것과 opencv로 불러오는 것은 편의성 옵션의 차이일 뿐이다 
# array([[[12,  4,  5],
#         [10,  2,  3],
#         [11,  2,  5],
s = cv2.imread('Elon.jpg', )
s.dtype # int이기 때문에 color에서 부호가 없다 / 2^8 = 256 => 0~255까지로 강도를 표현한다 
# dtype('uint8')

이미지를 불러올 때 tensor가 좋은 점은 gpu연산이 가능하기 때문에 대용량 이미지를 더 빠르게 불러올 수 있다

 

import matplotlib.pyplot as plt
plt.figure(figsize=(10,10))
plt.imshow(t) # array를 image로 해석하는 방법을 제공한다 / version 때문에 tensor를 직접 표현 못할 수 있다. 혹시 안된다면 colabd으로 사용해 보는 것을 추천한다
plt.colorbar(); # 컬러바 표시하기
plt.axis('off'); # 좌표 축 없애기

State machine

State Machine은 외부 입력에 따라 시스템의 상태가 결정되고,

이 상태와 입력에 의해서 시스템의 동작이 결정되는 시스템이다.

[특징]

1. 변수가 없다

2. figure안에 axes가 포함되어 있다. 그리고 plt.axes만 실행하면 plt.figure의 default값으로 자동실행 된다

3. 변수를 지정하지 않아도 상태를 보고 자동적으로 만들어 준다

 

# 같은 셀안에서 실행하면 
plt.figure();
plt.axes([0.5,0.5,1,1]); # figure 안에서 좌표형태로 보여준다 
plt.plot([4,5,4]);
plt.axes([0,0,0.5,0.5]);
plt.plot([4,5,4]);

plt.axes([0,0,0.5,0.5])

# plt.figure()
# plt.axes()
plt.plot([1,2,3]) # plot만 하면 figure, axes default값으로 자동 지정된다

 

s = t / 255
t.dtype
# tf.uint8

s.dtype
# tf.float32

plt.imshow(s) # 이미지를 구성하는 값들은 상대적인 개념이기 때문에 특정 값을 기준으로 나누어도 사람이 볼때는 똑같은 이미지로 볼 수 있다

im = tf.io.read_file('Elon.jpg')
t = tf.image.decode_image(im)
ss = tf.cast(t, 'float32')

ss.dtype
# tf.float32

sss = (ss/127.5) -1 # -1에서 1 사이로 변환해주는 방법 / 가장 큰 값이 255이기 때문에 절반으로 나누고 1을 빼면 -1과 1 사이의 값으로 구성된다 
import numpy as np
np.min(sss)
# -1.0

plt.imshow(sss) # imshow는 -1값은 표현하지 못하기 때문에 달라 보인다

plt.imshow(sss - 1)

sss.shape
# TensorShape([600, 960, 3])

sss[...,0][..., tf.newaxis]
# <tf.Tensor: shape=(600, 960, 1), dtype=float32, numpy=
# array([[[-0.96862745],
#         [-0.9764706 ],
#         [-0.96862745],
#         ...,
t[...,2] # color 이미지에서 채널 하나 빼면 흑백이 된다 / color는 각 픽셀당 3가지 값으로 표현해야 한다 
# <tf.Tensor: shape=(600, 960), dtype=uint8, numpy=
# array([[ 9, 10, 11, ...,  0,  0,  0],
#        [ 8, 10, 11, ...,  0,  0,  0],
#        [ 9, 10, 11, ...,  0,  0,  0],
#        ...,
#        [ 9, 11, 13, ..., 11, 11, 12],
#        [ 9, 11, 10, ..., 12, 12, 12],
#        [10, 11, 10, ..., 14, 14, 14]], dtype=uint8)>
plt.imshow(t[...,1]) # (0,1), (0,255) / 흑백 이미지는 기본 colormap으로 표현 / 색깔정보가 없으면 기본 색으로 입혀준다 /imshow는 default를 color로 간주한다

plt.imshow(t[...,1], cmap='gray') # 숫자 값이 크면 클 수록 밝게 표현한다

plt.imshow(t[...,1], cmap='gray_r') # 숫자 값이 크면 클 수록 어둡게 표현한다

plt.imshow(t[...,1], cmap=plt.cm.Reds)

plt.imshow(t[...,1], cmap=plt.cm.Reds_r)

import matplotlib
len(dir(matplotlib)) 
# 165

import matplotlib.pyplot as plt 
len(dir(matplotlib))  # colab에서는 matplotlib이나 matplotlib.pyplot이나 똑같이 나오네요 
# 165

!pip list # matplotlib version = 3.2.2
!python --version
# Python 3.7.11

Monkey patch

한국에서는 잠수함 패치라고 부르고 영어권에서는 게릴라 패치, 고릴라 패치, 몽키 패치라고 부른다 런타임상에서 함수, 메소드, 속성을 바꾸는 패치

 

from PIL import Image # 파이썬 스럽게 이미지를 처리해주는 라이브러리(일반인대상으로 가장 많이 사용한다)
Image.open('Elon.jpg')

im = Image.open('Elon.jpg')
dir(im) # numpy 방식이 아닌 numpy 호환 형태로 데이터를 갖고 있다 
['_Image__transformer',
 '__array_interface__',
 '__class__',
 '__copy__',
 '__delattr__',
 '__dict__',
 '__dir__',
 '__doc__',
 '__enter__',
 '__eq__',
 '__exit__',
 '__format__',
 '__ge__',
 '__getattribute__',
 '__getstate__',
 '__gt__',
 '__hash__',
 '__init__',
 '__init_subclass__',
 '__le__',
 '__lt__',
 '__module__',
 '__ne__',
 '__new__',
 '__reduce__',
 '__reduce_ex__',
 '__repr__',
 '__setattr__',
 '__setstate__',
 '__sizeof__',
 '__str__',
 '__subclasshook__',
 '__weakref__',
 '_close_exclusive_fp_after_loading',
 '_copy',
 '_crop',
 '_dump',
 '_ensure_mutable',
 '_exclusive_fp',
 '_exif',
 '_expand',
 '_get_safe_box',
 '_getexif',
 '_getmp',
 '_min_frame',
 '_new',
 '_open',
 '_repr_png_',
 '_seek_check',
 '_size',
 'alpha_composite',
 'app',
 'applist',
 'bits',
 'category',
 'close',
 'convert',
 'copy',
 'crop',
 'custom_mimetype',
 'decoderconfig',
 'decodermaxblock',
 'draft',
 'effect_spread',
 'entropy',
 'filename',
 'filter',
 'format',
 'format_description',
 'fp',
 'frombytes',
 'fromstring',
 'get_format_mimetype',
 'getbands',
 'getbbox',
 'getchannel',
 'getcolors',
 'getdata',
 'getexif',
 'getextrema',
 'getim',
 'getpalette',
 'getpixel',
 'getprojection',
 'height',
 'histogram',
 'huffman_ac',
 'huffman_dc',
 'icclist',
 'im',
 'info',
 'layer',
 'layers',
 'load',
 'load_djpeg',
 'load_end',
 'load_prepare',
 'load_read',
 'mode',
 'offset',
 'palette',
 'paste',
 'point',
 'putalpha',
 'putdata',
 'putpalette',
 'putpixel',
 'pyaccess',
 'quantization',
 'quantize',
 'readonly',
 'reduce',
 'remap_palette',
 'resize',
 'rotate',
 'save',
 'seek',
 'show',
 'size',
 'split',
 'tell',
 'thumbnail',
 'tile',
 'tobitmap',
 'tobytes',
 'toqimage',
 'toqpixmap',
 'tostring',
 'transform',
 'transpose',
 'verify',
 'width']
dir(im.getdata())
['__class__',
 '__delattr__',
 '__dir__',
 '__doc__',
 '__eq__',
 '__format__',
 '__ge__',
 '__getattribute__',
 '__getitem__',
 '__gt__',
 '__hash__',
 '__init__',
 '__init_subclass__',
 '__le__',
 '__len__',
 '__lt__',
 '__ne__',
 '__new__',
 '__reduce__',
 '__reduce_ex__',
 '__repr__',
 '__setattr__',
 '__sizeof__',
 '__str__',
 '__subclasshook__',
 'bands',
 'box_blur',
 'chop_add',
 'chop_add_modulo',
 'chop_and',
 'chop_darker',
 'chop_difference',
 'chop_hard_light',
 'chop_invert',
 'chop_lighter',
 'chop_multiply',
 'chop_or',
 'chop_overlay',
 'chop_screen',
 'chop_soft_light',
 'chop_subtract',
 'chop_subtract_modulo',
 'chop_xor',
 'color_lut_3d',
 'convert',
 'convert2',
 'convert_matrix',
 'convert_transparent',
 'copy',
 'crop',
 'effect_spread',
 'entropy',
 'expand',
 'fillband',
 'filter',
 'gaussian_blur',
 'getband',
 'getbbox',
 'getcolors',
 'getextrema',
 'getpalette',
 'getpalettemode',
 'getpixel',
 'getprojection',
 'histogram',
 'id',
 'isblock',
 'mode',
 'modefilter',
 'new_block',
 'offset',
 'paste',
 'pixel_access',
 'point',
 'point_transform',
 'ptr',
 'putband',
 'putdata',
 'putpalette',
 'putpalettealpha',
 'putpalettealphas',
 'putpixel',
 'quantize',
 'rankfilter',
 'reduce',
 'resize',
 'save_ppm',
 'setmode',
 'size',
 'split',
 'transform2',
 'transpose',
 'unsafe_ptrs',
 'unsharp_mask']
im_ = np.array(im)
plt.imshow(im_)

 

tf.keras.preprocessing.image.load_img('Elon.jpg')

i  = tf.keras.preprocessing.image.load_img('Elon.jpg') # tensorflow, pytorch는 내부적으로 PIL 사용한다 
type(i)
# PIL.JpegImagePlugin.JpegImageFile

 

(X_train, y_train), (X_test, y_test) = tf.keras.datasets.mnist.load_data()
# Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/mnist.npz
# 11493376/11490434 [==============================] - 0s 0us/step
# 11501568/11490434 [==============================] - 0s 0us/step

plt.imshow(X_train[100])

np.set_printoptions(formatter={'int': '{:>01d}'.format}, linewidth=80) # int 데이터일 경우에 한 자리로 표현해 준다 
print(X_train[100])
[[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 0 0 2 18 46 136 136 244 255 241 103 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 15 94 163 253 253 253 253 238 218 204 35 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 131 253 253 253 253 237 200 57 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 155 246 253 247 108 65 45 0 0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 207 253 253 230 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 157 253 253 125 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 89 253 250 57 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 89 253 247 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 89 253 247 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 89 253 247 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 21 231 249 34 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 225 253 231 213 213 123 16 0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 172 253 253 253 253 253 190 63 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 2 116 72 124 209 253 253 141 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 25 219 253 206 3 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 104 246 253 5 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 213 253 5 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 26 226 253 5 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 132 253 209 3 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 78 253 86 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]]
plt.imshow(i)
plt.annotate('0', xy=(0,0))
# Text(0, 0, '0')

 

def visualize_bw(img):
  w, h = img.shape
  plt.figure(figsize=(10,10))
  plt.imshow(img, cmap='binary') # binary는 작은 숫자가 밝게 / gray는 큰 숫자가 밝게 
  for i in range(w):
    for j in range(h):
      x = img[j,i]
      plt.annotate(x, xy=(i,j), horizontalalignment='center', verticalalignment='center', color = 'black' if x <= 128 else 'white') # 점 하나당 대체 시킨다
      
visualize_bw(X_train[0])

Image processing

input image가 어떠한 함수에 의해 새로운 image가 output으로 나오는 것

array연산을 통해서 새로운 형태의 image를 만들어 내는 것

 

visualize_bw(X_train[5][::-1])
# 뒤집기

visualize_bw(X_train[5][4:24,4:24])
# 잘라내기

visualize_bw(np.flipud(X_train[5])) # flipud => 이미지 뒤집기

# 크기가 (20,20)인 흑백 이미지 생성
visualize_bw(np.ones((20,20)))

 

 

 

반응형
728x90
반응형

python 기반 주요 이미지 라이브러리

PIL ( python image library

주로 이미지 처리만을 위해 사용, 처리성능이 상대적으로 느림

skimage

파이썬 기반의 전반적인 컴퓨터 비전 기능 제공

사이파이 기반

오픈소스 기반의 최고 인기 컴퓨터 비전 라이브러리

컴퓨터 비전 기능 일반화에 크게 기여 ( 어려운 기능도 api 몇줄로 간단하게 구현

c++기반이지만  python도 지원 ( java, c# 도 지원

인델이 개발주도, window, linux, mac, 안드로이드, i-os 다양한 플랫폼에서 사용

방대한 컴퓨터 비전 관련 라이브러리와 손쉬운 인터페이스 제공

 

# 주의사항

imread('파일명')으로 이미지 로드하여 numpy.array로 변환

주의할 점은  이미지를 rgb가 아닌 bgr로 로딩하기 때문에 색감이 원본과 다름

그래서 cv2.cvtColor(img, cv2. COLOR_BGR2RGB)로 바꿈

 

# Windows Frame interface

os의 window frame과 바로 인터페이스 하여 사용할 수 있는 여러기능을 제공함

하지만 기능사용하려면, 생성가능한 gui 환경에서만 가능 (window gui, linux x-windows 등)

주피터 노트북 기반에서는 사용시 오류 발생

 

구 분 PIL SKimage OpenCV
library from PIL import image from skimage import io import cv2
데이터로드 image file 객체 생성 np.array np.array
로드 코드 image.open() io.imread() cv2.imread()
cv2.imwrite()
이미지 출력 plt.imshow plt.imshow plt.imshow
RGB RGB RGB BGR(imread) > RGB(imwrite)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

반응형
728x90
반응형

80개 Object category

300k의 image와 1.5million개의 object들

tensorflow object detection api 및 많은 오픈소스계열의 주요 패키지들은 coco dataset으로 pretrained모델을 제공함

 

cocodataset은 이미지 한개에 여러개 object를 가지고 있어서 타 dataset에 비해 난이도가 높다

 

반응형
728x90
반응형

# 데이터 다운로드

# pascal voc 2012 데이터를 다운로드 후 /content/data 디렉토리에 압축 해제
# DOWNLOAD시 약 3분정도 시간 소요. 아래 디렉토리가 잘 동작하지 않을 경우 https://web.archive.org/web/20140815141459/http://pascallin.ecs.soton.ac.uk/challenges/VOC/voc2012/VOCtrainval_11-May-2012.tar
!mkdir ./data

!wget http://host.robots.ox.ac.uk/pascal/VOC/voc2012/VOCtrainval_11-May-2012.tar
!tar -xvf VOCtrainval_11-May-2012.tar -C /content/data

- annotation과 jpegimage가 1대1로 mapping됨

# 로드 상태 확인

!ls /content/data/VOCdevkit/VOC2012
!ls /content/data/VOCdevkit/VOC2012/JPEGImages | head -n 5

# Annotations  ImageSets	JPEGImages  SegmentationClass  SegmentationObject
# 2007_000027.jpg
# 2007_000032.jpg
# 2007_000033.jpg
# 2007_000039.jpg
# 2007_000042.jpg

JPEGImages 디렉토리에 있는 임의의 이미지 보기

import cv2
import matplotlib.pyplot as plt
import os
%matplotlib inline

# 코랩 버전은 상대 경로를 사용하지 않습니다. /content 디렉토리를 기준으로 절대 경로를 이용합니다. 
# default_dir 은 /content/data 로 지정하고 os.path.join()으로 상세 파일/디렉토리를 지정합니다. 
default_dir = '/content/data'
img = cv2.imread(os.path.join(default_dir, 'VOCdevkit/VOC2012/JPEGImages/2007_000032.jpg'))
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
print('img shape:', img.shape)

plt.figure(figsize=(8, 8))
plt.imshow(img_rgb)
plt.show()

img shape : (281, 500, 3)

# annotation 확인하면 object 설정 상태 확인 =>aeroplane, aeroplane, person, person

SegmentationObject 디렉토리에 있는 있는 임의의 maksing 이미지 보기

img = cv2.imread(os.path.join(default_dir, 'VOCdevkit/VOC2012/SegmentationObject/2007_000032.png'))
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
print('img shape:', img.shape)

plt.figure(figsize=(8, 8))
plt.imshow(img_rgb)
plt.show()

Annotation xml 파일에 있는 요소들을 파싱하여 접근하기

  • ElementTree를 이용하여 XML 파싱(lxml 패키지는 이미 코랩에 설치됨. pip install lxml)
import os
import random

# 코랩 버전 절대경로 수정. 
VOC_ROOT_DIR ="/content/data/VOCdevkit/VOC2012/"
ANNO_DIR = os.path.join(VOC_ROOT_DIR, "Annotations")
IMAGE_DIR = os.path.join(VOC_ROOT_DIR, "JPEGImages")

xml_files = os.listdir(ANNO_DIR)      # list 형태로 annotataion가져옴                  
print(xml_files[:5]); print(len(xml_files)) # 확인, 개수
# ['2012_001655.xml', '2011_001699.xml', '2010_002954.xml', '2012_000123.xml', '2008_001031.xml']
# 17125
# !pip install lxml
import os
import xml.etree.ElementTree as ET
# 사이즈 로드 1) anno > size, 2) opencv array
# ground truth 형태를 가져오려면, xml은 부모자식의 수직적 형태임.
# xml을 잘 parsing하는 것은 et임

# annotation 하나 잡고, parsing 확인
xml_file = os.path.join(ANNO_DIR, '2007_000032.xml') 

# XML 파일을 Parsing 하여 Element 생성
tree = ET.parse(xml_file)
root = tree.getroot() # root node를 찾음

# image 관련 정보는 root의 자식으로 존재
image_name = root.find('filename').text # filename node를 찾음
full_image_name = os.path.join(IMAGE_DIR, image_name) # 해당filename으로 가져옴

image_size = root.find('size')
image_width = int(image_size.find('width').text)
image_height = int(image_size.find('height').text) # 숫자형으로 바꾸기까지

# 파일내에 있는 모든 object Element를 찾음.
objects_list = []
for obj in root.findall('object'):
    # object element의 자식 element에서 bndbox를 찾음. 
    xmlbox = obj.find('bndbox')

	# bndbox element의 자식 element에서 xmin,ymin,xmax,ymax를 찾고 이의 값(text)를 추출 
    x1 = int(xmlbox.find('xmin').text)
    y1 = int(xmlbox.find('ymin').text)
    x2 = int(xmlbox.find('xmax').text)
    y2 = int(xmlbox.find('ymax').text)
    
    bndbox_pos = (x1, y1, x2, y2) # 튜플형태로 저장
    class_name=obj.find('name').text
    object_dict={'class_name': class_name, 'bndbox_pos':bndbox_pos}
    objects_list.append(object_dict)

print('full_image_name:', full_image_name,'\n', 'image_size:', (image_width, image_height))

for object in objects_list:
    print(object)
    
# full_image_name: /content/data/VOCdevkit/VOC2012/JPEGImages/2007_000032.jpg 
# image_size: (500, 281)
# {'class_name': 'aeroplane', 'bndbox_pos': (104, 78, 375, 183)}
# {'class_name': 'aeroplane', 'bndbox_pos': (133, 88, 197, 123)}
# {'class_name': 'person', 'bndbox_pos': (195, 180, 213, 229)}
# {'class_name': 'person', 'bndbox_pos': (26, 189, 44, 238)}

Annotation내의 Object들의 bounding box 정보를 이용하여 Bounding box 시각화

import cv2
import os
import xml.etree.ElementTree as ET

xml_file = os.path.join(ANNO_DIR, '2007_000032.xml')

tree = ET.parse(xml_file)
root = tree.getroot()

image_name = root.find('filename').text
full_image_name = os.path.join(IMAGE_DIR, image_name)

img = cv2.imread(full_image_name)
# opencv의 rectangle()는 인자로 들어온 이미지 배열에 그대로 사각형을 그려주므로 별도의 이미지 배열에 그림 작업 수행. 
# rectangle때문에 메모리가 꼬일수가 있어서
draw_img = img.copy()
# OpenCV는 RGB가 아니라 BGR이므로 빨간색은 (0, 0, 255)
green_color=(0, 255, 0)
red_color=(0, 0, 255)

# 파일내에 있는 모든 object Element를 찾음.
objects_list = []
for obj in root.findall('object'):
    xmlbox = obj.find('bndbox')
    
    left = int(xmlbox.find('xmin').text)
    top = int(xmlbox.find('ymin').text)
    right = int(xmlbox.find('xmax').text)
    bottom = int(xmlbox.find('ymax').text)
    
    class_name=obj.find('name').text
    
    # draw_img 배열의 좌상단 우하단 좌표에 녹색으로 box 표시 
    cv2.rectangle(draw_img, (left, top), (right, bottom), color=green_color, thickness=1)
    # draw_img 배열의 좌상단 좌표에 빨간색으로 클래스명 표시
    cv2.putText(draw_img, class_name, (left, top - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.4, red_color, thickness=1)

img_rgb = cv2.cvtColor(draw_img, cv2.COLOR_BGR2RGB)
plt.figure(figsize=(10, 10))
plt.imshow(img_rgb)

 

반응형

'Computer_Science > Computer Vision Guide' 카테고리의 다른 글

2-4~5. OpenCV 개요  (0) 2021.09.21
2-3. MS-COCO DATASETS  (0) 2021.09.21
2-1. 주요 pretrained dataset  (0) 2021.09.21
1-9~10. 성능평가지표 mAP - 정밀도, 재현율  (0) 2021.09.17
1-8. Non Max Suppression  (0) 2021.09.17
728x90
반응형

PASCAL VOC

XML format

20개의 오브젝트 카테고리

MS COCO

json Format

80개의 오브젝트 카테고리

 

Google Open Images

csv Format

600개의 오브젝트 카테고리

 

* 많은 detection과 segmentation 딥러닝 패키지가 위의 dataset을 기반으로 pretrained 되어 배포됨

 

 

Annotation이란?

=> 이미지의 detection정보를 별도의 설명 파일로 제공되는 것을 일반적으로 annotation이라고 함. ( 주석, 설명

annotation은 object의 bounding box 위치나 object이름 등 특정 포맷을 제공함

<annotation>

	<folder>VOC2012</folder>
    <filename>2007_000032.jpg</filename>  # file에 대한 정보를 가짐
    <source>
    	<dataset>the VOC2007 Database</dataset>
    	<annotation>PASCAL VOC2007</annotation>
    	<image>flickr</image>
	</source>

	<size>
    	<width>500</width>
    	<height>281</height>
    	<depth>3</depth>        
	</size>    
    <segmented>1</segmented>    

	<object>                          # 개별 object 정보
    	<name>aeroplane</name>
    	<pose>Frontal</pose>
    	<truncated>0</truncated>        
    	<difficult>0</difficult>
        <bndbox>
	        <xmin>104</xmin>
	        <ymin>78</ymin>
	        <xmax>375</xmax> 
	        <ymax>183</ymax>            
        </bndbox>        
	</object>
    
    <object>
    	<name>aeroplane</name>
    	<pose>Left</pose>
    	<truncated>0</truncated>        
    	<difficult>0</difficult>
        <bndbox>
	        <xmin>104</xmin>
	        <ymin>78</ymin>
	        <xmax>375</xmax> 
	        <ymax>183</ymax>            
        </bndbox>        
	</object>    

</annotation>

VOCdevkit

- VOC2012

-- annotations : xml format이며, 개별 xml file은 1개 image에 대한 annotation 정보를 가짐. 확장자 xml을 제회한 파일명은 image file명과 동일함 mapping

-- imageset : 어떤 image를 train, test, trainval, val에 사용할 것인지에 대한 mapping 정보를 개별 object별로 파일로 가지고 있음

-- JPEGimages : detection과 segmentation에 사용될 원본 image

-- segmentationClass : semantic segmentation에 사용될 masking 이미지

-- segmentationObject : instance segmentation에 사용될 masking 이미지

 

 

 

반응형
728x90
반응형

numpy

기계학습은 한번에 동시에 연산해야 하는데

array 연산

homogeneous / sequence : matrix

1차 : vector

2차 : matrix

3차이상 : tensor

 

섞이면

array는 자동으로 가장 큰 데이터 타입으로 바꿔주는데

tensor는 sequence를 mixed로 할수없다

torch도 sequence를 mixed로 할수없다

homogeneous는 데이터의 종류가 같다. 동질성

sequence는 indexing, slicing, sequence operator(vectorization)

 => 연산할 때 값이 아닌 인덱싱 이어준다

vectorization : loop없이 한번에 여러개의 연산을 elementwise 방식으로 동시에 하게 해준다. 

elementwise : 같은 위치의 값끼리, 자기에 맞는 위치의 값끼리 연산

 

numpy는 cpu vectorization 연산 지원(4코어면 4개 동시 연산), tensorflow는 gpu vectorization 연산지원(5000개면 5000개 동시엔 연산)한다. => 코딩량, 연산횟수가 줄어듬

tensorflow는 numpy 기반이라 배울 필요가 있다.

 

homo : '1' in 'abc'

hetero : '1' in ['1', b, c]

homo가 데이터 타입 체크를 할 필요가 없기 때문에 더 빠른 연산을 한다.

* a = 1, b = 1. 이건 coercion : 같은 형의 두인자를 수반하는 연산이면 한형의 인스턴스를 다른형으로 묵시적으로 변환해버림

그 외엔 같은 데이터 타입이어야 한다

 

 

linear algebra 선형대수연산

image는 array형태이고, 머신러닝도 빅데이터 병렬연산을 위한 array을 사용함

numpy는 gpu지원안하니깐 tensorflow와 pytorch가 50배나 더빠른 gpu를 사용 

안그래도 c언어보다 python이 20~100배 느린데, 수치연산에 불리하다

하지만 자동화랑 mutable이 너무 좋은걸?

 

그래서 하드웨어 성능을 끌어오는 방법,

compiler를 쓰면 빠름

또 homogenuous 형태를 통해서 속도를 향상시킴

np.ScalarType으로 확인할 수 있음

data type에 따라서 연산 최적화가 달라짐 => backpropagation, 미분 등

미분은 연속만 가능한데 uint8은 불연속이라 float형태로 바꿔줘야 함

=> 중요한 문제라 data type을 항상 알려줌, 타입에 따라서 연산의 방식이 달라지니깐

 

t.gradient()으로 확인

빅데이터는 가장큰 데이터 타입쓰면 됨 => float64

근데 mldl은 gpu연산 라이브러리 들이 32bit 연산에 최적화됨

 

ndarray는 numpy의 class 이름임, 그래서 np.ndarray((2,3))이렇게 만들수있는데 사용자가 불편함

그래서 factory method 방식으로 np.array를 쉽게 쓸수있게 만듬. __repr__로 가능

사실 그냥 똑같은거다 array의 통칭 정도

비어있으면 안되고, 직각 형태로 만들어야 한다.

 

1) , indexing

index로 개별로 가져오기, slicing 뭉탱이로 가져오기

# a[1][1] = a[1,1]

a[1] => 2차원의 1 idx의 list를 가져옴

혹은

a[1,:]으로 하면 동일함

3차원은 a[,,]

 

2) boolean indexing => filter

a[ ( a > 3 ) | ~(a<5) ]

 

3) fancy indexing

재조합해서 만들수있음

a[[1,0]]    a[['aaa', 'bbb']]

 

4) extended fancy indexing

a[[0,1], [1,2]] => 자리값맞춰주면 각각 가져옴

 

5) ellipsis ...

1 이상의 :을 대체, 2차원에서는 별로 의미없음

a[,:] = a[,...]

a[:,:] = a[...]

 

# mutable 개념은 언제 중요할까?  선언 vs 얕은 복사 vs 깊은복사

- a = b # 이렇게 array 선언하면 memory를 공유함

그래서 a 수정하면 b도 수정됨

- a = b[:], b[...]#이렇게 하면 내용을 가져옴 => 얕은 복사, 메모리는 다르니 다른 객체이지만 영향을 받음 id() 다른 메모리 할당

- a = b.copy() # copy도 내용을 가져옴 => 원본과 분리되어 메모리 별도로 받음 : deepcopy()

numpy에만 있고 tensorflow에는 없는 개념임

이제 무조건 copy되도록

 

img의 데이터 운용은 좀더 복잡하다

a[:,:,:] 이 (60000, 28, 28)이면

a[10000:50000,:,:]으로 일부 때오거나

a[:,:14,:14]으로 일부 자르거나 할수있다.

 

shape

a = np.array([1,2,3])

a[:,none] 하면 차원을 증가시킴

[[1],[2],[3]] : none은 여기서 np.newaxis, tf.newaxis와 같다

반대는 np.squeeze(bb)

 

 

 

 

 

 

img 자체는 array로 구현함

import matplotlib.pyplot as plt

plt.imshow(x_train[0], cmap='gray')

 

2차 흑백 이미지

0이니깐 검은색으로 표

 

현 명암만 가능

좌표값의 색상정보

(6,6,1)

1이 0 ~ 255임

 

3차 색깔 이미지 

RGB방식으로 값을 주면 가능 0,0 => [R, G, B]

x_train[0]=> (6,6,3) => 값이 3개가 나옴

6x6이 3장 겹쳐진 상태임, 3이 [R,G,B]형태임

 

4차 영상이미지

개별의 dataset이냐 연속된 이미지인가

x_train => 3000, 6, 6, 3

 

 

 

 

 

 

 

 

 

 

 

 

 

반응형

+ Recent posts