OpenCV - 2

Jaho·2021년 12월 19일
0

Python

목록 보기
14/18

버전을 확인해 보자.

# 버전확인
import cv2 as cv 
print(cv.__version__)

현재 버전 4.5.4

1. 이미지 파일을 읽고 , 저장

#imread(), imwrite(),   imswhow()
from PIL import Image
import numpy as np

#이미지를 읽어온다.
im = cv.imread('c:\\myimg\\gujji.jpg')
print(type(im))
print(im.shape)  # 행, 열, 색상 = 높이, 폭, 채널
print(im.dtype)

# 색상의 순서 BRG
im[:,:,(0,1)] = 0   # 0번째 (B:파랑)와 1번째(G:녹색)을 0(검정)으로 지정한다.

# cv.imshow('my view',im)

#출력
cv.imwrite('c:\\myimg\\cv2\\gujji_b.png',im) # cv.imwrite(파일이름,대상)
cv.imwrite('c:\\myimg\\cv2\\gujji_b02.jpg',im,[cv.IMWRITE_JPEG_QUALITY,50]) # cv.imwrite(파일이름,대상)#params 생략?
cv.imwrite('c:\\myimg\\cv2\\gujji_b03.jpg',im,params=[cv.IMWRITE_JPEG_QUALITY,1]) # cv.imwrite(파일이름,대상) 

cv.imwrite('c:\\myimg\\cv2\\gujji_b04.jpg',im)# 기본값 95

#원본을 로드(png,bmp)   -> 저장 -> jpg 로드시  jpg 화소가 달라진다. 속성 값을 지정한다.
# jpg (1~95) 기본 값은 75    /  윈도우 64bit jpg  0~100 기본값은 95
# png (0~9) 기본 값은 3
# 확장자의 압축률이 높을 수록 로딩하는 속도가 느려진다.

이전에서 배열(np.array)로 읽어올때는 RGB로 읽어왔다.
imread로 읽어올때는 BGR로 순서가 바뀌는걸 명심하자.
type = <class 'numpy.ndarray'>
shape = (1440, 1080, 3)
dtype = uint8
imwrite = True #이미지 저장 성공

2. 그레이 스케일 (흑백처리)

cv.imread (파일,cv.IMREAD_GRAYSCALE)

im = cv.imread('c:\\myimg\\gujji.jpg')
print(type(im))
print(im.shape)  # 행, 열, 색상 = 높이, 폭, 채널
print(im.dtype)


im = cv.imread('c:\\myimg\\gujji.jpg',cv.IMREAD_GRAYSCALE)  # 흑백이라 채널이없다
print(type(im))
print(im.shape)  # 행, 열, 색상 = 높이, 폭, 채널
print(im.dtype)

cv.cvtColor(파일,cv.COLOR_BGR2GRAY)

im = cv.imread('c:\\myimg\\gujji.jpg')
print(type(im))
print(im.shape)  # 행, 열, 색상 = 높이, 폭, 채널
print(im.dtype)


im02 = cv.cvtColor(im,cv.COLOR_BGR2GRAY)
print(type(im02))
print(im02.shape)  # 행, 열, 색상 = 높이, 폭, 채널
print(im02.dtype)

print(im02)
cv.imwrite('c:\\myimg\\cv2\\gujji_G.jpg',im02)

gujji_G.jpg / 흑백처리가 아주 잘되었다!

3. BT.601

#BT.601 = RGB에서 Y 값을 산출하는 공식  =  RGB컬럼 이미지를 흑백으로 변환하는 경우, 신호 Y값을 산출

# BT.601이란? 일반적인 사람의 시각적 특성을 고려한 것으로 가장 밝게 느껴지는 G(녹색)의 계소가 커지는 것을 확인

# Y = 0.299 * R  + 0.587 * G   + 0.114 * B 

im = cv.imread('c:\\myimg\\gujji.jpg')
print(type(im))
print(im.shape)  # 행, 열, 색상 = 높이, 폭, 채널
print(im.dtype)
print('================================================')
im_gray = Y = 0.299*im[:,:,2]  +  0.587 * im[:,:,1]  + 0.114 * im[:,:,0]  # BGR

print(type(im_gray))
print(im_gray.shape)  # 행, 열, 색상 = 높이, 폭, 채널
print(im_gray.dtype)

cv.imwrite('c:\\myimg\\cv2\\gujji_Y.jpg',im_gray)


gujji_Y.jpg / 흑백처리 하는데도 방식이 여러개라니..

cv에서 사용되는 BT.601 공식이 적용된 속성

im_gray_read = cv.imread('c:\\myimg\\apple.jpg',cv.IMREAD_GRAYSCALE) # os 코덱에 따라 화소가 다르다.
print(type(im_gray_read ))
print(im_gray_read .shape)  # 행, 열, 색상 = 높이, 폭, 채널
print(im_gray_read .dtype)


im = cv.imread('c:\\myimg\\apple.jpg') # os 코덱에 따라 화소가 다르다.
im_gray = cv.cvtColor(im,cv.COLOR_BGR2GRAY)  # BT.601 적용
print(type(im_gray))
print(im_gray.shape)  # 행, 열, 색상 = 높이, 폭, 채널
print(im_gray.dtype)

#판별
im_diff = im_gray.astype(int) - im_gray_read .astype(int)
print(im_diff.max()) #최대
print(im_diff.min()) #최소

--판별--
IMREAD_GRAYSCALE로 흑백처리한 값 - cvtColor()로 흑백처리한 값


둘다 흑백처리 되었으므로 채널이 없다.

4. 이미지 결합 = 세로연결 / 가로 연결 / 바둑판 연결

cv.vconcat()

  • 폭이 동일한 이미지를 세로로 연결
  • 같은 이미지를 반복 세로로 연결
  • 폭이 서로 다른 이미지도 세로로 연결

cv.hconcat()

  • 높이가 동일한 이미지를 가로로 연결
  • 같은 이미지를 반복 가로로 연결
  • 높이가 서로 다른 이미지도 가로로 연결

np.tile() : 같은 이미지를 반복 정렬

4-1. 같은 이미지를 세로로 연결 해보자.

im1 = cv.imread('c:\\myimg\\apple.jpg')
im2 = cv.imread('c:\\myimg\\gujji.jpg')

im_v = cv.vconcat([im1,im1])
cv.imwrite('c:\\myimg\\cv2\\v_img_test.jpg',im_v)

im_v02 = np.tile(im1,(2,1,1)) 
cv.imwrite('c:\\myimg\\cv2\\v_img02.jpg',im_v02)

v_img_test.jpg

np.tile(2,1,1)을 출력하면 위 사진과 동일하게 저장된다.

np.tile(2,1,1)로 저장한 사진을 확인해 보자.

np.tile(2,1,1) :2행 1열
np.tile(2,2,1) : 2행 2열

4-2. 폭이 다른 이미지를 세로로 연결해보자. (단 폭이 적은 데이터를 기준으로 조정하자)


#함수선언 resize(src, dsize[.dst[,fx[,fy[, interpolation]]]])
#함수선언 resize(이미지, 결과 영상크기(w,h)[ 결과영상[,fx[,fy[,interpolation]]]])   # fx= factor
# interpolation = cv2.INTER_LINEAR (2*2) (단일 이미지) /  CV2.INTER_CUBIC (4*4)  (영상대상 축소)
import cv2 as cv
import numpy as np
im1 = cv.imread('c:\\myimg\\apple.jpg')
im2 = cv.imread('c:\\myimg\\gujji.jpg')

#폭이 다른 이미지를 세로로 연결하겠다.

#im.shape [0]는 높이 , [1]폭
def my_resize(im_list,interpolation = cv.INTER_CUBIC):
    #1. 폭이 가장 작은 값을 리턴 받자.
    w_min = min(im.shape[1] for im in im_list)
    
    #2. 폭의 사이즈를 재조정
    im_list_resize = [cv.resize(im,(w_min,int(im.shape[0]* w_min / im.shape[1])),
                            interpolation = interpolation) for im in im_list]
    
    return cv.vconcat(im_list_resize) #결합해서 리턴

im_v = my_resize ([im1,im2,im1])
cv.imwrite('c:\\myimg\\cv2\\v_img_resize.jpg',im_v)


v_img_resize.jpg

4-3 높이가 다른 이미지를 가로로 연결해보자.

# cv.hconcat()
import cv2 as cv
import numpy as np
im1 = cv.imread('c:\\myimg\\apple.jpg')
im2 = cv.imread('c:\\myimg\\gujji.jpg')
#함수선언 resize(src, dsize[.dst[,fx[,fy[, interpolation]]]])


#im.shape [0]는 높이 , [1]폭
def my_hresize(im_list,interpolation = cv.INTER_CUBIC):
    #1. 폭이 가장 작은 값을 리턴 받자.
    h_min = min(im.shape[0] for im in im_list)
    
    #2. 폭의 사이즈를 재조정
    im_list_resize = [cv.resize(im,(int(im.shape[1]* h_min / im.shape[0]),h_min),
                            interpolation = interpolation) for im in im_list]
    
    return cv.hconcat(im_list_resize) #결합해서 리턴

im_h = my_hresize ([im1,im2,im1])
cv.imwrite('c:\\myimg\\cv2\\h_img_resize.jpg',im_h)


h_img_resize.jpg

4-4. 바둑판식 타일형을 만들어보자.

image = cv.imread('c:\\myimg\\gujji.jpg')

def my_tile(im_list_2d):
    return cv.vconcat([cv.hconcat(im_list_h) for im_list_h in im_list_2d])

    #dsize = (h,w) 절대크기
    
im01 = cv.resize(image,dsize=(0,0), fx=0.5,fy=0.5) #fx = 수평측 비율   fy=수직측 비율

im_tile = my_tile([[im01,im01,im01,im01],
                  [im01,im01,im01,im01],
                 [im01,im01,im01,im01]])

cv.imwrite('c:\\myimg\\cv2\\tile_img03.jpg',im_tile)

dsize = (0,0) = dsize = None 으로도 표현할수 있다.
fx= 0.5 : 1이 원본 크기이면 0.5는 절반의 크기


tile_img03.jpg

5. 이미지 회전과 상하 좌우 반전 회전 : cv.rotate(ndarray, rotate_code), np.rot90()

상하 좌우 반전 : cv.flip(ndarray, flip_code) , np.flip()

flip_code = 0 상하 반전, flip_code > 0 좌우 반전 , flip_code < 0

5-1 이미지 회전을 해보자.

import matplotlib.pyplot as plt
image = cv.imread('c:\\myimg\\gujji.jpg')
print(image.shape)

img_r_90 = cv.rotate(image,cv.ROTATE_90_CLOCKWISE)
img_r_90
plt.imshow(img_r_90)

# 5-2  이미지 반전을 해보자.

img01 = cv.flip(image,0) # 뒤집음
plt.imshow(img01)

img02 = cv.flip(image,1) # 좌우반전
plt.imshow(img02)

img03 = cv.flip(image,-1)# 뒤집고 좌우반전
plt.imshow(img03)


shape 과 img_r_90 출력이미지


plt.imshow(img01)

plt.imshow(img02)

plt.imshow(img03)

6. 임계 값 처리 : 이미지 처리 중 가장 많이 사용하는 처리방식

0~ 255 중에서 127의 값을 기점으로 127보다 작은 모두  0,127보다 크면 255로 처리하게 된다.

cv.threshold(대상 이미지, 임계 값, 임계 값 보다 큰 값, 적용 타입)
cv.threshold(src , thresh,  maxval , type)
  • type의 속성 값들

    • cv.THRESH_BINARY : 픽셀 값 IMG(X,Y) thresh 값 보다 크면 value 작으면 0

    • cv.THRESH_BINARY_INV : 픽셀 값 IMG(X,Y) thresh 값 보다 크면 0 작으면 value

    • cv.THRESH_TRUNC : 픽셀 값 IMG(X,Y) thresh 값 보다 크면 thresh 작으면 IMG(X,Y)

    • cv.THRESH_TOZERO : 픽셀 값 IMG(X,Y) thresh 값 보다 크면 IMG(X,Y) 작으면 0

    • cv.THRESH_TOZERO_INV : 픽셀 값 IMG(X,Y) thresh 값 보다 크면 0 작으면 IMG(X,Y)

6. 임계 값을 지정해 이미지를 확인 해보자.

image = cv.imread('c:\\myimg\\gujji.jpg')
print(image.shape)

th, im_th=cv.threshold(image, 127,255, cv.THRESH_BINARY)
print(th)

cv.imwrite('c:\\myimg\\temp\\Th01.png',im_th)

#임계 값 보다 큰 값은 원래의 상태로 작은 값은 0으로 지정해서 이미지를 확인 해보자.

th, im_th=cv.threshold(image, 127,255, cv.THRESH_TOZERO)
print(th)

cv.imwrite('c:\\myimg\\temp\\Th02.png',im_th)

shape =(1440, 1080, 3)
print(th) = 127.0
print(th) = 127.0


Th01.png


Th02.png

6-1 APPLICATION 을 연동해서 확인 하자 (흑백으로 호출해서 확인한다.)

image = cv.imread('c:\\myimg\\gujji.jpg',0) # 0 (흑백) 으로변환
print(image.shape)

th, im_th=cv.threshold(image, 100,255, cv.THRESH_BINARY)

print(im_th)
cv.imshow('im_th',im_th)
cv.waitKey()  # 뭘까?
cv.destroyAllWindows() # 모두 close ?

shape = (1440, 1080)
print(th) = 100.0


cv.imshow('im_th',im_th)

6-2. 임계 값 자동 처리 cv.THRESH_OTSU

# cv.imread(src,flags)   -1[변화없이]   0[그레이]  1[색상]   2[임의 깊이]   3[임의 색상]
import cv2 as cv
image = cv.imread('c:\\myimg\\gujji.jpg',0)
print(image.shape)

th, im_th=cv.threshold(image, 0,255, cv.THRESH_OTSU)

print('th:{}'.format(th))

cv.imshow('otsu',image)
cv.waitKey()
cv.destroyAllWindows() 

shape = (1440, 1080)
print(th) = th:111.0

7. 이미지처리

  • 흑백, 지정 범위 색상 추출 [HSV], 가장자리, 크기조정, 이미지 히스토그램 시각화
  • 감마처리, 평행이동, 회전,회선
  • 특정 픽셀 - ORB 특징 추출 , 매칭, 거리계산

7-1 지정 범위 색상 추출 [HSV]

HSV = H + SV
= H (색상 : Hue) 0 ~ 360 + S (채도 : Saturation) 원의 중심에서 0 ~ 100 + V (명도 : Value) 높이로 0 ~ 100

  openCV     H[0~179] ,  SV[0~255]
  
# 1) 대상 이미지를 hsv 형태로 변환
import numpy as np

image = cv.imread('c:\\myimg\\gujji.jpg')
#hsv로 형변환 한다.
hsv = cv.cvtColor(image,cv.COLOR_BGR2HSV)

# 2) 추출 색상 범위를 지정한 이미지 
start_color = np.array([20,50,50])
end_color = np.array([255,255,255])

#mask : cv.inRange(대상,시작 범위,마지막 범위)
img_mask = cv.inRange(hsv,start_color,end_color)

# 3) 원본 이미지와 mask 이미지를 2진 으로 비교 : cv.bitwise_and(대상,연산할 대상,mask)
# img_color = cv.bitwise_and(image,image,mask = img_mask)
# cv.imwrite('c:\\myimg\\temp\\HSV_mask.png',img_color)


cv.imshow('HSV',img_mask)
cv.waitKey()
cv.destroyAllWindows()


cv.imshow('HSV',img_mask)


3번 HSV_mask.png

7-2 가장자리 Canny()

#cv.Canny(	image, threshold1[최소], threshold2[최대][, edges 저장변수[, apertureSize[, L2gradient]]]	) ->	edges
#cv.Canny(	dx, dy, threshold1, threshold2[, edges[, L2gradient]]	) ->	edges
# L2gradient  = False       di/dx + di/dv
# L2gradient = True         sqrt( {(di/dx)}^2  +  (di/dy)^2) 

#흑백으로 이미지불러오기
image = cv.imread('c:\\myimg\gujji.jpg',0)

c_img = cv.Canny(image,50,110) #최소 50 최대 110
cv.imwrite('c:\\myimg\\temp\\Canny.png',c_img)

#7-3 사이즈 조정
w,h = 60,60  # 변수에 값
img_res = cv.resize(image,(w,h))
cv.imwrite('c:\\myimg\\temp\\resize_Canny.png',img_res)


Canny.png


resize_Canny.png

7-3. 히스토그램 시각화

import matplotlib.pyplot as plt

# cv.calcHist(images, channels, mask, histSize, ranges) -> hist
image = cv.imread('c:\\myImg\\apple.jpg')

color = ('b', 'g', 'r')

#enumerate 형식으로 for문을 돌린다.
for i, col in enumerate(color):
    print(i, col)
    histr = cv.calcHist([image],[i],None,[256],[0,256])
    plt.plot(histr, color = col)
    plt.xlim([0,256])
    
plt.show()

print(i,col) :
0 b
1 g
2 r

profile
개발 옹알이 부터

0개의 댓글