2021-12-30 vision 인식 & Data분석

ansunny1170·2021년 12월 30일
0

비전인식

영상처리

이미지나 영상을 분석하고 유의미한 정보를 생성하는 기술
물체 - Object
전경 - Foreground
배경 - Background

OpenCV

실시간 영상처리에 중점을 둔 영상처리 라이브러리

OpenCV 설치
1. opencv사이트에서 최신 버전 opencv 설치
pip install opencv-python입력

주피터에 import cv2입력하니 error가 없다. 제대로 설치가 되었다는 뜻

2. ㅇㅇㅇ

디지털 이미지 프로세싱

이미지 데이터에서 유의미한 데이터를 얻기 위해 가공 필요
전처리, 노이즈&디노이즈, 특징&유사성 검출

용어

이미지 - 너비(width), 높이(height)
IDE

  • 통합 개발 환경
  • 코딩, 디버그, 컴파일, 배포 등 프로그램 개발 관련 작업을 처리할 수 있도록 개발된 소프트웨어

색상 표현 정밀도(비트) = 비트 깊이 = 색상 깊이 = 색상 심도

  • 화소 하나의 색을 지시하기 위해 활용 되는 비트 수
  • 정밀도가 높으면 처리 결과 정밀도도 높다

이진화 이미지 - 1bit 이미지
그레이 스케일 이미지 - 8bit 이미지

채널(색상 채널)

  • 일반적으로 Red, Green, Blue, Alpha로 구성(4채널)
  • Hue, Saturation, Value 채널 존재
  • 흑백 이미지 -> 1채널

OpenCV(python) 채널 표현
(row, column, 채널 수)
color = np.zeros((height, width, 3), np.uint8)
gray = np.zeros((rows, cols, 1), np.uint8)

ROI(Region Of Interest)
OpenCV 에서는 N차원 배열을 사용
1920x1280 배율의 3채널 색상 이미지를 사용할 경우 처리해야 할 데이터 공간은
1920x1280x3임 너무크다!

그래서 ROI영역으로 Matching 필요한 부분만 잘라서 사용한다.

COI(Channel Of Interest)
관심 채널을 설정하여 데이터의 양 1/3으로 감축
Blue, Green, Red 셋중에 하나
그레이 스케일과 COI는 다르다.
그레이 스케일은 각 컬러 채널별 가중치를 다르게 주어서 계산
Gray = 0.299 x R + 0.578 x G + 0.114 x B

히스토그램
막대그래프로 나타내는 것
x축 : 픽셀 값(0~255)
y축 : 픽셀 개수

빈도수 : x축 간격...

기본 데이터

list 자료형

리스트(List)의 특징 [값1, 값2,...값n]
파이썬은 배열이 없다.

  • Container - 데이터 종류와 무관하게 값을 저장할 수 있음
  • Mutable - 리스트 값의 생성, 추가, 삭제 변경 가능
  • Sequence - 순서가 중요, index를 통해 값에 접근
  • 생성
    a = []
    b = [1,2,3]
    c = ['Life', 'is', 'too', 'short']
    d = [1,2, 'Life', 'is']
    e = [1,2,['Life', 'is']]

  • 리스트 끼리 더하면 리스트가 이어진다.

  • 리스트를 곱하면 곱한 수 만큼 나열한다.

  • 인덱싱
    인덱스 값으로 음수가 가능하다.

  • 슬라이싱

  • 값 수정

  • 요소 삭제

  • 요소 추출

  • 위치 반환

  • 요소 삽입

  • 요소 추가

사전 자료형

  • 생성
    dic = {'name' : 'hello', 'phone':'01000001111','birth':'1229'}
    print(dic['name'])
keyvalue
namehello
phone01000001111
birth1229

  • 추가
    a={1:'a'}
    print(a)
    a[2]='b'
    print(a)

  • key중복
    a={1:'a',1:'b'}
    print(a)

  • key리스트
    a = {'name' : 'hello', 'phone':'01000001111','birth':'1229'}
    a_keys=a.keys()
    print(a_keys)

    list형태가 아니라 dict_keys라는 객체로 반환됨.
    리스트 형태로 쓰고 싶다면 (list(a.keys())로 쓸것
    print(a_keys[0] -> 에러

    for name in a.keys():
    print(name)

a = {'name' : 'hello', 'phone':'01000001111','birth':'1229'}
a_keys=list(a.keys())
print(a_keys)

list(a.keys())에 커서를 올려놓고 shift+TAP을 누루면 설명이 나온다.

아래와 같이 출력

for name in a.keys():
print(name)

  • value 리스트

  • key, value 쌍 얻기

a_items = a.items()
print(a_items)

  • key로 value 얻기
print(a.get('name')) 
# a['name']과 같은 동작
  • 없는 key 접근
print(a.get('nope')) # -> None 반환
print(a.['nope'] # -> Error 발생
  • default 값
print(a.get('name','default_value'))
# 키가 없는 경우(name)이 없는경우, default값 반환

  • key 조사
print('name' in a)
print('nope' in a)

집합 자료형

Container
Mutable
Set - 중복 불가, 순서에 영향 받지 않음

*생성

s0 = set() # 비어있는 집합
s1 = set([1,2,3])
print(s1)
s1=set([1,2,3,1,2])
print(s1)

  • 집합 자료형 인덱스 접근을 위해서는 리스트나 튜플로 변환 후 사용
s1 = set([1,2,3])
l1 = list(s1)
print(l1[0])

s1 = set([1,2,3])
t1 = tuple(s1)
print(t1[0])

  • 교집합
    &
s1 = set([1,2,3,4,5,6])
s2 = set([4,5,6,7,8,9])
print(s1 & s2)
print(s1.intersection(s2))

  • 합집합
    |
print(s1 | s2)
print(s1.union(s2))

  • 차집합
    -
print(s1-s2)
print(s1.difference(s2))

  • 한개 추가
s1 = set([1,2,3])
s1.add(4)
print(s1)

  • 여러개 추가
s1 = set([1,2,3])
s1.update([4,5,6])
print(s1)

  • 제거
s1 = set([1,2,3])
s1.remove(2)
print(s1)

Numpy (라이브러리)

영상처리에서는 이미지 데이터를 행렬로 표한함
파이썬에서는 행렬을 표현하는 기본 자료형이 없음
->Numpy 라이브러리 사용

import numpy as np

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

print(array.ndim) # 차원 개수
print(array.shape) # 차원의 크기(모양)
print(array.dtype) # 자료형

import numpy as np

array1 = np.array([[1,2,3],[4,5,6]])
array2 = np.array([1,2,3],dtype = complex, ndmin=3)
# complex 복소수 형 ndim>????
array3 = np.array(array1, copy=False)
# array3은 array1의 메모리 주소값을 참조하고 있다.    
# copy=true는 defalut이며, 최초 값을 가지고 있는다.
array1[0] = [4,5,6]
                   
print(array1)
print(array2)
print(array3)

  • np.arange()
import numpy as np
a= np.arange(6)
print(a)


import numpy as np
a= np.arange(2,6)
print(a)

import numpy as np
a= np.arange(2,6,2) #2에서 시작 6에서 끝 스텝은 2씩 증가
print(a)

import numpy as np
a= np.arange(2,6.5,0.5)
print(a)

  • np.zeros(), np.ones(), np.full()
a = np.zeros([3,3])
print(a)

a = np.ones([3,3])
print(a)

a = np.full([3,3],2.5)
print(a)

  • 다차원 배열 (행렬)
array1 = np.array([1,2,3])
array2 = np.array([[1,2],[3,4]])
array3 = np.array([[[1,2,],[3,4],[5,6],[7,8]]])

print(array1[-1]
print(array2[0][1])
print(array3[0][1][1])


import numpy as np

array = np.array([[[1,2],[3,4],[5,6],[7,8]]])

for i in array [0]:
for j in i:
if j % 2 == 0:
print(j)

  • 배열 블록 단위 요소 접근
import numpy as np
array = np.array([[1,2,3,4,5,],[6,7,8,9,10],[11,12,13,14,15],[16,17,18,19,20]])

print(array[1:3])
print(array[::2])
print(array[2:, 1::2])

Python array[::] 용법

내용 출처 사이트
Wonkyung's blog Python array[::] 용법

간단한 파이썬 팁입니다.
arr[::], arr[1:2:3], arr[::-1] 등으로 배열의 index에 접근하는 방법을 Extended Slices 라고 부릅니다.

설명
arr[A:B:C]의 의미는, index A 부터 index B 까지 C의 간격으로 배열을 만들어라는 말입니다.
만약 A가 None 이라면, 처음부터 라는 뜻이고
B가 None 이라면, 할 수 있는 데까지 (C가 양수라면 마지막 index까지, C가 음수라면 첫 index까지가 되겠습니다.)라는 뜻입니다.
마지막으로 C가 None 이라면 한 칸 간격으로 라는 뜻입니다.

>> arr = range(10)
>> arr 
[0,1,2,3,4,5,6,7,8,9]
>> arr[::2] # 처음부터 끝까지 두 칸 간격으로 
[0,2,4,6,8]
>> arr[1::2] # index 1 부터 끝까지 두 칸 간격으로 
[1,3,5,7,9]
>> arr[::-1] # 처음부터 끝까지 -1칸 간격으로 ( == 역순으로) 
[9,8,7,6,5,4,3,2,1,0] >> arr[::-2] # 처음부터 끝까지 -2칸 간격으로 ( == 역순, 두 칸 간격으로) 
[9,7,5,3,1] >> arr[3::-1] # index 3 부터 끝까지 -1칸 간격으로 ( == 역순으로) 
[3,2,1,0]
>> arr[1:6:2] # index 1 부터 index 6 까지 두 칸 간격으로 
[1,3,5]

rou-major(행우선), column-major(열우선)

참고 사이트
잡다한 지식/CS 베이스의 blog
A=[a11a12a13 a21a22a23 a31a32a33] 일 경우,
행 우선

[a11 a12 a13 a21 a22 a23 a31 a32 a33]
열 우선

[a11 a21 a31 a12 a22 a32 a13 a23 a33]

import numpy as np
array = np.arange(12)

reshape1 = array.reshape(2,3,2)
#(a,b,c) a-3차원 개수
# b-2차원 개수
# c-1차원 개수
reshape2 = np.reshape(array, (2,-1), order='F')
# -1을 하면 요소 개수에 맞게 알아서 넣준다.
# reshape함수가 알아서 해라! 라는 뜻

print(reshape1)
print(reshape2)

order='F'는
google에 검색 포트란 구조

열우선??

행우선??

  • 배열 차원 확장(newaxis)
    1차원을 2차원으로
    2차원을 3차원으로 확장
    np.newaxis : -> 기존 차원 앞에 차원 추가
    : np.newaxis -> 기존 차원 뒤에 차원 추가
import numpy as np

array = np.arange(4)
# [0,1,2,3]

axis1 = array[np.newaxis]
# == array[np.newaxis: ]
axis2 = array[:, np.newaxis]

print(axis1)
# (1,4) [[0,1,2,3]]
print(axis2)
# (4,1) [[0],[1],[2],[3]]
axis1.shape
# (1,4)

  • 배열 차원 축소(flatten, ravel)
import numpy as np

array = np.arange(12).reshape(3,-1)
print(array)
flat1 = array.flatten(order='F')
flat2 = array.ravel()

print(flat1)
print(flat2)

axis축 개념

축개념

  • 배열의 병합 stack
    stack 참조 내용
    합치려는 배열의 shape이 같아야함

    reshape은 지정한 axis의 shape을 1로 설정하게된다. 그리고 이것을 axis=0방향으로 합친다.
    그러면 shpae(2,2,2)로 변한다.
import numpy as np

array1 = np.arange(6).reshape(2,3)
array2 = np.arange(6,12).reshape(2,3)

merge1 = np.stack([array1, array2], axis=0)
merge2 = np.stack([array1, array2], axis-1)

print(merge1)
print(merge2)

  • hstack
import numpy as np
a = np.arange(10).reshape(2,5)
b = np.arange(6).reshape(2,3)

print(a)
print(b)

c = np.hstack((a,b))
print(c)

# or c = np.hstack([a,b])
print(c)

  • vstack
import numpy as np
a = np.arange(10).reshape(2,5)
b = np.arange(15).reshape(3,5)

print(a)
print(b)

c = np.vstack((a,b))
print(c)

# or c = np.vstack([a,b])
print(c)

용어

히스토그램 P50

import cv2
import numpy as np

image = cv2.imread("mountain.jpg")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
result = np.zeros((image.shape[0], 256), dtype = np.uint8)

hist = cv2.calcHist([image], [0], None, [256], [0, 256])
# 원본image의 0으로 감쌌다?
# [0]은 분석 채널(x축의 대상) 이미지가 graysacale이면 [0], color면[0],[0,1](형태1:blue, 2:green, 3:red)
# None은 mask(분석 영역)
# 256은 hist size이다. 0~255
# [0,256] 중 0은
cv.2normalize(hist, hist, 0, 255, cv2.NORM_MINMAX)
# 원본 변수
# output 변수
# 0,255 압축 사이즈?
for x, y in enumerate(hist):
    cv2.line(result, (int(x), image.shape[0]), (int(x), image.shape[0] - int(y)), 255)
#
dst = np.hstack([image[:,:,0], result])
cv2.imshow("dst",dst)
cv2.waitKey(0)
cv2.destroyAllWindows()


참고내용[python] opencv(cv2) 패키지 유용한 함수 10개 정리

  • 배열 분리(split) P104
import numpy as np

array = np.arange(10).reshape(2,5)

detach1 = np.split(array, 2, axis=0)
detach2 = np.split(array, [2,3], axis=1)

print(detach1)
print(detach2)

  • 배열 연산 P105
import numpy as np

array1 = np.array([1,2,3,4]).reshape(2,2)
array2 = np.array([1.5,2.5])

add = array1 + array2

print(add)

  • ndarray 클래스 - ROI 예제 (관심영역) P111
import numpy as np

array = np.zeros((1280, 1920, 3), np.uint8)

x, y, w, h = 100, 100, 300, 300
roi = array[a:x+w, y:y+h]

print(array.shape)
print(roi.shape)

  • ndarray 클래스 - COI 예제 (관심채널) P112

영상처리 기본 예제

기초예제

이미지 입력

import cv2
src = cv2.imread("OpenCV_Logo.png", cv2.IMREAD_GRAYSCALE)
print(src.ndim, src.shape, src.dtype)

이미지 출력

import cv2
src = cv2.imread("OpenCV_Logo.png", cv2.IMREAD_GRAYSCALE)

cv2.namedWindow("src", flags=cv2.WINDOW_FREERATIO)
cv2.resizeWindow("src", 400, 200)
cv2.imshow("src", src)
cv2.waitKey(0)
sv2.destroyWindow("src")


아래와 같이 출력하고 이미지 종료시 누른 버튼은 ASC코드로 출력된다. 여기서는 'q'를 입력했다.

동영상 출력 1

import cv2

capture = cv2.VideoCapture("Star.mp4")

while True:
    ret, frame = capture.read()
    
    if(capture.get(cv2.CAP_PROP_POS_FRAMES) == capture.get(cv2.CAP_PROP_FRAME_COUNT)):
        capture.open("Star.mp4")
    # CAP_PROP_POS_FRAMES - > 다음 프레임 값
    # CAP_PROP_FRAME_COUNT -> 입력 영상의 프레임 수
    cv2.imshow("VideoFrame", frame)
    if cv2.waitKey(33) == ord('q'): break
    # 33 ms를 기다린다. ord는 뒤의 'q'에 해당하는 ASC값을 가져온다.
capture.release()
cv2.destroyAllWindows()
  • 아래 사진은 동영상이다. q를 입력하면 종료
    33은 fps값이다.

동영상 출력 2

import cv2

capture = cv2.VideoCapture("Star.mp4")

while True:
    ret, frame = capture.read()
    
    if ret == False:
        break
        
    cv2.imshow("VideoFrame", frame)
    if cv2.waitKey(33) == ord('q'): break
    
capture.release()
cv2.destroyAllWindows()

이렇게 하면 동영상이 전체 이미지를 show하고나서 종료된다. 즉, 1회 출력

FPS

카메라 출력

import cv2

capture = cv2.VideoCapture(0)
capture.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
capture.set(cv2.CAP_PROP_FRAME_HEIGHT, 640)

while True:
    ret, frame = capture.read()
    if ret == True:
        cv2.imshow("VideosFrame", frame)
        if cv2.waitKey(33) == ord('q'): break
    else :
        break
                
capture.release()
cv2.destroyAllWindows()

작업중인 노트북 카메라가 출력한다!

이미지 연결

import cv2
import numpy as np

one = cv2.imread("one.jpg")
two = cv2.imread("two.jpg")
three = cv2.imread("three.jpg")
four = cv2.imread("four.jpg")

horizontal1 = np.full((50, one.shape[1],3), [0,0,0], dtype = np.uint8)
# 높이 50, one이미지의 x길이 만큼의 이미지를  0으로 채우겠다. [0,0,0]은 RGB값임
horizontal2 = np.full((50, two.shape[1],3), (0,0,0), dtype = np.uint8)

left = cv2.vconcat((one, horizontal1, three))
right = np.vstack((two, horizontal2, four))

vertical = np.full((left.shape[0], 50, 3), 0, dtype = np.uint8)

dst = cv2.hconcat((left, vertical, right))

cv2.imshow("dst", dst)
cv2.waitKey()
cv2.destroyAllWindow()

도형 그리기 p157

import numpy as np
import cv2

img = np.zeros((768, 1366, 3), dtype = np.uint8)

cv2.line(img, (100, 100), (1200, 100), (0, 0, 255), 3, cv2.LINE_AA)
cv2.circle(img, (300, 300), 50, (0, 255, 0), cv2.FILLED, cv2.LINE_4)
cv2.rectangle(img, (500, 200), (1000, 400), (255, 0, 0), 5, cv2.LINE_8)
cv2.ellipse(img, (1200, 300), (100, 50), 0, 90, 180, (255, 255, 0), 2)

pts1 = np.array([[[100, 500], [300, 500], [200, 600]], [[400, 500], [500, 500], [600, 700]]])
pts2 = np.array([[700, 500], [800, 500], [700, 600]])
cv2.polylines(img, pts1, True, (0, 255, 255), 10)
cv2.fillPoly(img, [pts2], (255, 0, 255), cv2.LINE_AA)

cv2.putText(img, "OpenCV", (900, 600), cv2.FONT_HERSHEY_COMPLEX | cv2.FONT_ITALIC, 2, (255, 255, 255), 3)

cv2.imshow("img", img)
cv2.waitKey(0)
cv2.destroyAllWindows()

트랙바

import cv2
import numpy as np

def onChangeBlue(pos):
    global b # b 전역 변수
    b = pos # pos 지역 변수
    cv2.imshow("Palette", createImage(b, g, r))
    

def createImage(b, g, r):
    return np.full((500, 500, 3), (b, g, r), dtype=np.uint8)
# 500 x 500 x 3사이즈 이미지에 b,g,r 순서로 full하겠다.

b, g, r = 0, 0, 0
cv2.namedWindow("Palette")
cv2.createTrackbar("Blue", "Palette", 100, 255, onChangeBlue)
# 콜백함수 onChangeBlue 트랙바 값이 변할때마다 on...ue함수에 입력
cv2.createTrackbar("Green", "Palette", 0, 255, lambda x:x)
# lambda 식.. 아무것도 안하겠다라는 뜻의 익명 함수
cv2.createTrackbar("Red", "Palette", 0, 255, lambda x:x)

while True:
    g = cv2.getTrackbarPos("Green", "Palette")
    # Palette의 Green에서 값을 받아오겠다. 받아서 g에 넣는다.(트랙바의 위치값)
    r = cv2.getTrackbarPos("Red", "Palette")
    
    cv2.imshow("Palette", createImage(b, g, r))
    # 팔레트에 그린다.
    if cv2.waitKey(33) & 0xFF == ord('q'):
        break

cv2.destroyAllWindows()

트랙바를 생성하고 부착하기 위해서는 먼저 윈도우가 정의되어야 한다.
cv2.NamedWindow()함수를 사용해 Window 이름을 갖는 윈도우를 생성한다.
blue만 onchangeBlue 함수를 사용하고 있는데 bluewhile문에 넣어도 사용 가능하다.

결과 저장

이미지 저장

import numpy as np
import cv2

img = np.zeros((480, 640, 3), dtype = np.uint8)

save = cv2.imwrite("CV.jpeg", img, (cv2.IMWRITE_JPEG_QUALITY, 100, cv2.IMWRITE_JPEG_PROGRESSIVE, 1))
print(save)

동영상 저장

p174

이미지 변형 p181

import cv2

src = cv2.imread("crow.jpg")
dst = cv2.cvtColor(src, cv2.COLOR_BGR2HSV)

cv2.imshow("dst", dst)
cv2.imshow("src", src)
cv2.waitKey(0)
cv2.destroyAllWindows()

HSV 색상 공간

Hue, Saturation, Value

  • 채널 분리
mv = cv2.split(src)
# mv배열에 src 분리하여 채널별 정보저장
c0, c1, c2 = cv2.split(src)
# c0, c1, c2 각 변수에 단일 채널 정보 저장
import cv2

src = cv2.imread('tomato.jpg')
mv = cv2.split(src)

cv2.imshow('ch0', mv[0])
cv2.imshow('ch1', mv[1])
cv2.imshow('ch2', mv[2])

cv2.waitKey(0)
cv2.destroyAllWindows()
  • Blue
  • Green
  • Red
import cv2

src = cv2.imread("tomato.jpg")
hsv = cv2.cvtColor(src, cv2.COLOR_BGR2HSV)

h, s, v = cv2.split(hsv)
h_red = cv2.inRange(h, 0, 5)

dst = cv2.bitwise_and(hsv, hsv, mask = h_red)
# mask에 값이 있는 것들만 연산한다.
dst = cv2.cvtColor(dst, cv2.COLOR_HSV2BGR)
# HSV -> BGR 변환

cv2.imshow("dst", dst)
cv2.waitKey(0)
cv2.destroyAllWindows()

조금더 잘 구분해 보자

import cv2

src = cv2.imread("tomato.jpg")
hsv = cv2.cvtColor(src, cv2.COLOR_BGR2HSV)

# h, s, v = cv2.split(hsv)
# h_red = cv2.inRange(h, 0, 5)

lower_red = cv2.inRange(hsv, (0,100,100),(5,255,255))
upper_red = cv2.inRange(hsv, (170,100,100),(179,255,255))
complete_red = cv2.addWeighted(lower_red, 1.0, upper_red, 1.0, 0.0)

dst = cv2.bitwise_and(hsv, hsv, mask = complete_red)
dst = cv2.cvtColor(dst, cv2.COLOR_HSV2BGR)

cv2.imshow("dst", dst)
cv2.waitKey(0)
cv2.destroyAllWindows()

다른 색상을 추출하고 싶다면?
P201 표5.3 HSV 색상 파라미터 참조

이진화 P202

import cv2

src = cv2.imread("swan.jpg")
src = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
# 바로위 코드에 유무에 따라 gray적용이 다르다.

_, binary = cv2.threshold(src, 127, 255, cv2.THRESH_BINARY)
# 필요없는 변수들은 _를 사용해서 버릴 수 있다.
# 127은 기준값
# 기법은 cv2.THRESH_BINARY

cv2.imshow("origin", src)
cv2.imshow("binary", binary)
cv2.waitKey(0)
cv2.destroyAllWindows()
  • 원본 코드

  • GRAYSCALE적용시
    src = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)

  • BINARY -> OTSU

import cv2

src = cv2.imread("swan.jpg")
gray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
binary = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 33, -5)
# 33은 BLOCK SIZE 3X3 이고 주위에 몇개를 볼것이냐 요런 것

cv2.imshow("binary", binary)
cv2.waitKey(0)
cv2.destroyAllWindows()
  • ADAPTIVE_THRESH_MEAN(적응형)

  • otsu

숙제

hue 값을 트랙바 사용하여 전체 컬러 추출하도록

profile
공정 설비 개발/연구원에서 웹 서비스 개발자로 경력 이전하였습니다. Node.js 백엔드 기반 풀스택 개발자를 목표로 하고 있습니다.

0개의 댓글