Hyogi's Notebook

픽셀 기반 영상처리와 영역 기반 영상처리가 무엇인가?

by 효기’s

python을 사용하여 openCV 영상처리 실습

 

배경 내에 검정 좌표를 이동시키는 방법 (픽셀 값을 읽고 바꾸기)
import cv2
import numpy as np

img = cv2.imread('images/scene2.jpg', cv2.IMREAD_GRAYSCALE) #이미지를 Grayscale로 읽는다
cv2.imshow('Image Processing', img)

print(img.shape)
px = img[200,200]
print(px)
img[100:210,100:210] = 0 #[배경상단 100 : 세로, 배경좌측 100 : 가로]

cv2.imshow('Results', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

 

픽셀 값과 컬러 영상을 읽는다.
import cv2
import numpy as np

img = cv2.imread('images/scene2.jpg', cv2.IMREAD_COLOR) #이미지파일을 컬러로 읽어들인다.
cv2.imshow('Image Processing', img)

print(img.shape)
px = img[100,100]
print(px)
img[100:110,100:110] = 0    # black
img[110:120,110:120] = [255,255,255]    # white (컬러를 바꾸고 싶으면 이부분을 수정해본다)

cv2.imshow('Results', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

 

컬러 영상을 읽고 red, green, blue 채널을 분리한다.
import cv2
import numpy as np

img = cv2.imread('images/fruits.png', cv2.IMREAD_COLOR) #이미지 파일을 읽어들인다.
cv2.imshow('Image Processing', img)

# b,g,r = cv2.split(img)
# img = cv2.merge((b,g,r))
# split()함수보다 numpy indexing이 빠르다.
b = img[:,:,0] #파란색(blue) 채널분리
g = img[:,:,1] #녹색 (green) 채널분리
r = img[:,:,2] #빨간색 (red) 채널분리

cv2.imshow('Blue', b)
cv2.imshow('Green', g)
cv2.imshow('Red', r)

cv2.waitKey(0)
cv2.destroyAllWindows()

 

산술연산 ( 각 픽셀에 +, -, *, / )
import cv2
import numpy as np

img = cv2.imread('images/scene2.jpg', cv2.IMREAD_GRAYSCALE)
cv2.imshow('Image Processing', img)

img_plus = cv2.add(img, 50,)    # cv2연산은 saturated 연산이어서 255보다 크면 255로 고정됨
img_minus = cv2.subtract(img, 50)    # cv2연산은 saturated 연산이어서 0보다 작으면 0으로 고정됨
img_mul = cv2.multiply(img,2)
img_div = cv2.divide(img,2)

# img_plus = img + 50 #이것도 가능하나, 0~255로 변환이 필요하다.
img_pp = np.clip(img+50., 0, 255).astype(np.uint8)

# opencv에는 이외에도 max(), min(), minMaxLoc(), 
# bitwise_and(), bitwise_or() 등 다양한 함수를 제공한다.

cv2.imshow('ResultsP', img_plus)    #+
cv2.imshow('ResultsM', img_minus)    #-
cv2.imshow('ResultsMu', img_mul)    #*
cv2.imshow('ResultsD', img_div)     #/
cv2.imshow('ResultsPP', img_pp)

cv2.waitKey(0)
cv2.destroyAllWindows()

왼쪽부터 원본, +, -, /, *, pp

 

색이 있는 산술연산 ( 각 픽셀에 +, -, *, / )
import cv2
import numpy as np

img = cv2.imread('images/scene2.jpg', cv2.IMREAD_COLOR)
cv2.imshow('Image Processing', img)

img_plus = cv2.add(img, (50,50,50,0))    # cv2연산은 saturated 연산이어서 255보다 크면 255로 고정됨
img_minus = cv2.subtract(img, (50,50,50,0))    # cv2연산은 saturated 연산이어서 0보다 작으면 0으로 고정됨
img_mul = cv2.multiply(img,(2,2,2,0))
img_div = cv2.divide(img,(2,2,2,0))

# opencv에는 이외에도 max(), min(), minMaxLoc(), 
# bitwise_and(), bitwise_or() 등 다양한 함수를 제공한다.

cv2.imshow('ResultsP', img_plus) #+
cv2.imshow('ResultsM', img_minus) #-
cv2.imshow('ResultsMu', img_mul) #*
cv2.imshow('ResultsD', img_div) #/

cv2.waitKey(0)
cv2.destroyAllWindows()

왼쪽부터 원본, +, -, /, *

 

이진화 (Thresholding)
import cv2
import numpy as np

img = cv2.imread('images/apples.jpg', cv2.IMREAD_GRAYSCALE)
cv2.imshow('Image Processing', img)

#cv2.THRESH_BINARY : 픽셀 값이 임계값을 넘으면 value로 지정하고, 넘지 못하면 0으로 지정
ret, img_binary = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY) # 127임계값, 255 픽셀값

# 최적의 임계값을 찾아주는 otsu의 알고리즘 적용
ret, img_otsu  = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU) 

cv2.imshow('ResultsB', img_binary)
cv2.imshow('ResultsO', img_otsu)

cv2.waitKey(0)
cv2.destroyAllWindows()

 

적응적 이진화 (adaptiveThreshold)
import cv2
import numpy as np

img = cv2.imread('images/sudoku.jpg', cv2.IMREAD_GRAYSCALE)
cv2.imshow('Image Processing', img)

blk_size = 9    # 블럭 사이즈
C = 5           # 차감 상수
ret, img_otsu  = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU) 
img_a1 = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY, blk_size, C)
img_a2 = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, blk_size, C)

cv2.imshow('Results Otsu', img_otsu) #OTSU 알고리즘을 적용
cv2.imshow('Results Adaptive1', img_a1) #적응적 이진화 : 이웃 픽셀의 평균으로 결정
cv2.imshow('Results Adaptive2', img_a2) #적응적 이진화 : 가우시안 분포에 따른 가중치의 합으로 결정

cv2.waitKey(0)
cv2.destroyAllWindows()

 

히스토그램
import cv2
import numpy as np
import matplotlib.pylab as plt

# 이미지 그레이 스케일로 읽기 및 출력
img = cv2.imread('images/Lenna.png', cv2.IMREAD_GRAYSCALE)
cv2.imshow('Image Processing', img)

# 히스토그램 계산 및 그리기
# 이미지 리스트에 감싸서 전달, 분석 처리 할 채널 리스트에 감싸서 전달,
# 마스크에 지정한 픽셀만 히스토그램 계산 None이면 전체영역, 계급(Bin)의 개수 채널 개수에 맞게 리스트로 표현, 픽셀이 가질 수 있는 값의 범위 RGB인경우 [0, 256]
hist = cv2.calcHist([img], [0], None, [256], [0,256])
plt.plot(hist) #히스토그램 출력

print("hist.shape:", hist.shape)  # 히스토그램의 shape (256,1)
print("hist.sum():", hist.sum(), "img.shape:",img.shape) # 히스토그램 총 합계와 이미지의 크기
plt.show()

 

컬러 영상의 히스토그램 
import cv2
import numpy as np
import matplotlib.pylab as plt

# 컬러영상
img = cv2.imread('images/Lenna.png', cv2.IMREAD_COLOR)
cv2.imshow('Image Processing', img)

# 히스토그램 계산 및 그리기
channels = cv2.split(img)
colors = ('b', 'g', 'r')
for (ch, color) in zip (channels, colors):
    hist = cv2.calcHist([ch], [0], None, [256], [0, 256])
    plt.plot(hist, color = color)

plt.show()

 

히스토그램 평활화
import cv2
import numpy as np
import matplotlib.pylab as plt

# 그레이 스케일로 읽기
img = cv2.imread('images/low_contrast.jpg', cv2.IMREAD_GRAYSCALE)
rows, cols = img.shape[:2]

# 히스토그램 평활화 계산
hist = cv2.calcHist([img], [0], None, [256], [0, 256])  # 히스토그램 계산
cdf = hist.cumsum()                                     # 누적 히스토그램 
cdf_m = np.ma.masked_equal(cdf, 0)                      # 0(zero)인 값을 NaN으로 제거
cdf_m = (cdf_m - cdf_m.min()) /(rows * cols) * 255      # 이퀄라이즈 히스토그램 계산
cdf = np.ma.filled(cdf_m,0).astype('uint8')             # NaN을 다시 0으로 환원
print(cdf.shape)
img2 = cdf[img]                                         # 히스토그램을 픽셀로 맵핑

# OpenCV API로 이퀄라이즈 히스토그램 적용
img3 = cv2.equalizeHist(img)

# 이퀄라이즈 결과 히스토그램 계산
hist2 = cv2.calcHist([img2], [0], None, [256], [0, 256])
hist3 = cv2.calcHist([img3], [0], None, [256], [0, 256])

# 결과 출력
cv2.imshow('Before', img)
cv2.imshow('Manual', img2)
cv2.imshow('cv2.equalizeHist()', img3)
hists = {'Before':hist, 'Manual':hist2, 'cv2.equalizeHist()':hist3}
for i, (k, v) in enumerate(hists.items()):
    plt.subplot(1,3,i+1)
    plt.title(k)
    plt.plot(v)
plt.show()

 

컬러영상 히스토그램 평활화
import cv2
import numpy as np
import matplotlib.pylab as plt

# 컬러영상 읽기
img = cv2.imread('images/cute.jpg', cv2.IMREAD_COLOR)

# 컬러공간을 HSV로 변경
img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

# V(밝기값) 공간에 히스토그램 평활화 적용
img_hsv[:,:,2] = cv2.equalizeHist(img_hsv[:,:,2])

# 컬러공간을 RGB로 원위치
img2 = cv2.cvtColor(img_hsv, cv2.COLOR_HSV2BGR)
b, g, r = cv2.split(img)
b = cv2.equalizeHist(b)
g = cv2.equalizeHist(g)
r = cv2.equalizeHist(r)
img3 = cv2.merge((b,g,r))

# 결과 출력
cv2.imshow('Before', img)
cv2.imshow('After', img2)
cv2.imshow('RGB', img3)
cv2.waitKey()
cv2.destroyAllWindows()

 

영역기반 영상처리

입력 픽셀과 그 주변 픽셀을 이용하여 출력 픽셀 값을 결정

합성곱 기법을 널리 이용

ex) 흐리게하기, 선명하게하기, 경계산 검출, 노이즈 제거

 

합성곱 (Convolution) 필터 적용으로 영상 흐림

합성곱 : 하나의 함수와 다른 함수를 반전 이동한 값을 곱하고 구간에 대해 적분하여 새로운 함수를 구하는 수학 연산자(회선)

콘볼루션 : 함수 f가 주어졌을 떄 우리가 원하는 목적에 따라 함수 g를 선정하여 분해, 변환, 필터링 할 수 있다.

 

합성곱 영상처리 : 입력 픽셀과 주위 픽셀 값에 합성곱 마스크의 값을 곱하여 더한 값을 출력 픽셀 값으로 정한다.

합성곱하는 함수 : 마스크(mask), 필터(filter), 템플릿(template), 커널(kernel)

마스크가 데칭이므로 실제 연산은 correlation(상관) 과 같다.

import cv2
import sys
import numpy as np

img = cv2.imread('images/Lenna.png', cv2.IMREAD_COLOR)

if img is None:
    print('영상 읽기 실패')
    sys.exit()

size = 7   #사이즈를 조절하면 흐림 정도 조절가능 높을수록 흐림
kernel = np.ones((size, size), dtype=np.float64) / (size*size)
result = cv2.filter2D(img, -1, kernel)

cv2.imshow('Original', img)
cv2.imshow('Result', result)
cv2.waitKey()
cv2.destroyAllWindows()

 

합성곱 (Convolution) 마스터
# blur()함수로 영상 흐림

import cv2
import sys
import numpy as np

img = cv2.imread('images/Lenna.png', cv2.IMREAD_GRAYSCALE)

if img is None:
    print('영상 읽기 실패')
    sys.exit()
    
result3 = cv2.blur(img, (3,3))
result5 = cv2.blur(img, (5,5))

cv2.imshow('Original', img)
cv2.imshow('Result3', result3)
cv2.imshow('Result5', result5)
cv2.waitKey()
cv2.destroyAllWindows()

 

합성 곱 마스터 특징 : 픽셀 주변을 대칭적으로 계산하므로 홀수 값을 사용(3 * 3, 5 * 5)

마스크 계수의 합은 1또는 0이 되도록 함

0  -1  0

-1  5  -1

 0  -1  0

경계 계산 : 0으로 계산, 이웃 픽셀 값 복사, wrap-around 등, 경계선 안쪽에서만 합성곱 계산, 계산 안된 부분은 그대로

영상 흐리게 하기 (Blurring) : 영상의 노이즈를 없애거나, 부드럽게 한다(smoothing), 평균값, 가우시안, 중간값 등의 필터 사용

평균값 필터로 흐리게 하기 : 영상의 노이즈는 없애지만 명암비는 낮아짐 (일반적인 잡티를 없앨 수 있음)

 

가우시안 필터로 흐리게하기

중앙 픽셀의 가중치가 높음 (영상의 중요 부분 보전 하면서 흐려짐)

# GaussianBlur()함수로 영상 흐림

import cv2
import sys
import numpy as np

img = cv2.imread('images/Lenna.png', cv2.IMREAD_GRAYSCALE)

if img is None:
    print('영상 읽기 실패')
    sys.exit()

# sigma 지정    
result1 = cv2.GaussianBlur(img, (0,0), 1)
result3 = cv2.GaussianBlur(img, (0,0), 3)

# ksize 지정, mean smoothing과 비교
resultB = cv2.blur(img, (5,5)) #평균값필터
resultG = cv2.GaussianBlur(img, (5,5), 0)

cv2.imshow('Original', img)
cv2.imshow('Result_S_1', result1)
cv2.imshow('Result_S_3', result3)
cv2.imshow('Result_mean', resultB) #평균값필터
cv2.imshow('Result_Gaussian', resultG)
cv2.waitKey()
cv2.destroyAllWindows()

 

중간값 필터 (Median) 필터

비전형 필터, 이웃 픽셀들 값을 오름차순으로 정렬한 수 중앙에 있는 값을 출력 값으로 선택

노이즈 제거에 효과적

# Median Filtering 중간값 필터

import cv2
import sys
import numpy as np

# img = cv2.imread('images/Lenna.png', cv2.IMREAD_GRAYSCALE)
# img = cv2.imread('images/pns.jpg', cv2.IMREAD_GRAYSCALE)
img = cv2.imread('images/gnoise.jpg', cv2.IMREAD_GRAYSCALE)

if img is None:
    print('영상 읽기 실패')
    sys.exit()

# sigma 지정    
result3 = cv2.medianBlur(img, 3)
result5 = cv2.medianBlur(img, 5)

# ksize 지정, mean smoothing과 비교
resultB = cv2.blur(img, (5,5))
resultG = cv2.GaussianBlur(img, (5,5), 0)

cv2.imshow('Original', img)
cv2.imshow('Result_3', result3) #중간값 필터3
cv2.imshow('Result_5', result5) #중간값 필터5
cv2.imshow('Result_mean', resultB) #평균값필터
cv2.imshow('Result_Gaussian', resultG) #가우시안필터
cv2.waitKey()
cv2.destroyAllWindows()

블로그의 정보

감성 개발자 효기

효기’s

활동하기