빅데이터 서비스 교육/딥러닝

딥러닝 OpenCV실습

Manly 2022. 7. 28. 14:11
반응형

충돌 방지를 위해 jupyter 3.7버전으로 anaconda에서 만들어서 실행

# 파이썬 버전 확인
import sys
print(sys.version)
3.7.13 (default, Mar 28 2022, 08:03:21) [MSC v.1916 64 bit (AMD64)]

OpenCV 개요

  • Computer Vision : 사람의 시작적인 부분을 기계로 구현하는것을 목적으로 하는 딥러닝 분야
  • 이미지, 동영상 등의 처리를 지원하는 라이브러리
  • C++로 제작되어 있고 Java, Android, Python 등 다양한 언어에서 구현 가능
  • 특히 Python에서 OpenCV를 사용할 경우 Numpy, Matplotlib 등의 라이브러리들과 바로 연동 가능

 

유용한 OpenCV 사이트

import numpy as np
import matplotlib.pyplot as plt
# OpenCV 임포트
import cv2

# 이미지 불러오기
cat = cv2.imread('image/image_cat.jpg')

# OpenCV와 matplotlib간 연동됨
plt.imshow(cat);

OpenCV의 색상 체계

  • 일반적인 이미지는 RGB 색상을 사용
  • OpenCV에서는 BGR색상 체계를 사용함(그래서 RGB를 그대로 사용하면 Red계열 색상이 Blue계열로 변경되어 출력됨)
  • 초기에는 알파벳 순서대로 BGR로 쓰다가 이후에 색상 주파수가 낮은 순으로 RGB로 바뀌어 현재는 RGB가 대중적으로 사용됨
  • OpenCV에서는 RGB를 BGR로 변환하여 불러와야 함
cat = cv2.imread('image/image_cat.jpg')
# cvtColor : 색상 변환 함수
cat2 = cv2.cvtColor(cat, cv2.COLOR_RGB2BGR)

# x축, y축 좌표 눈금을 없애고 싶을때
plt.xticks([])
plt.yticks([])

plt.imshow(cat2)

이미지 색상 변환

  • 컬러 이미지(RGB)
  • 흑백 이미지(Gray) -> 0~255 사이의 흑백 픽셀값으로 구성된 이미지
    • 컬러 이미지는 용량이 크고 연산량이 많기 때문에 실시간 처리가 힘들고, 이를 간소화시켜 계산과 연산을 용이하게 하기 위해 흑백이미지나 이진이미지를 사용
    • 컬러 이미지는 채도와 명도에 영향을 받기 때문에 이를 최소화 하기 위함
      • 명도(밝은 정도) - 밤에 색상을 볼 때 정확한 색상을 보여주지 못하는 경우 존재
      • 채도(탁한 정도) - 색상에 빛을 강하게 비추는 경우 정확한 색상을 보지 못하는 경우가 존재
  • 이진 이미지(binary) -> 0(검정)과 255(흰) 두가지 색상으로만 구성된 이미지
    • 배경과 객체를 구분
    • 관심 영역과 비관심 영역을 분리
    • 필터를 만들거나 단순한 이미지 처리를 할 경우 사용

흑백(Gray) 이미지 만드는 방법

1. 기존 컬러 이미지를 Gray로 불러서 출력하기

# 이미지를 불러올때 gray로 받아주고 출력시에도 gray 색상으로 변환하여 출력
cat_gray = cv2.imread("image/image_cat.jpg", cv2.IMREAD_GRAYSCALE)

plt.imshow(cat_gray, cmap='gray')

2. 컬러 이미지를 그대로 불러온 다음 cvColor를 통해 gray로 변환 후 출력하기

cat2 = cv2.imread("image/image_cat.jpg")

cat2_gray = cv2.cvtColor(cat2, cv2.COLOR_BGR2GRAY)

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

 

 

이진(binary) 이미지 만들기

  • 기존 이미지가 컬러 이미지라면 gray로 변환 후에 이진 이미지로 만들어줘야함
# threshold : 특정 기준을 통해서 데이터를 변환시켜주는 함수(문턱(경계)이라는 뜻)
# (이미지, 경계 기준값, 경계값보다 클 경우 적용되는 값, 경계값 적용 방식)
# 경계 기준값 : 0 ~ 255 값 중에서 선택
# 적용값 : 기준값보다 큰 경우에 할당되는 값(150보다 크면 255, 작으면 0)
_, bi_cat = cv2.threshold(cat2_gray, 128, 255, cv2.THRESH_BINARY)

# _ : 첫번째 리턴값은 받지 않음(경계값 / 위에선 128)
# bi_cat : 두번째 리턴값은 threshold가 적용된 이미지 데이터

plt.imshow(bi_cat, cmap='gray')

temp, bi_cat = cv2.threshold(cat2_gray, 128, 255, cv2.THRESH_BINARY)

 

temp

128.0

bi_cat

array([[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]], dtype=uint8)

경계값 적용 방식 종류

  • cv2.THRESH_BINARY : 픽셀값이 경계값보다 크면 value(적용값), 아니면 0을 할당(흭색, 검은색으로만 표시)
  • cv2.THRESH_BINARY_INV : THRESH_BINARY의 반대(픽셀값이 경계값보다 크면 0, 아니면 value를 할당)
  • cv2.THRESH_TRUNC : 픽셀값이 경계값보다 크면 경계값, 아니면 픽셀값을 그대로 할당
  • cv2.THRESH_TOZERO : 픽셀값이 경계값보다 크면 픽셀값, 아니면 0을 할당 (0은 검은색으로 검은색을 좀 더 부각)
  • cv2.THRESH_TOZERO_INV : THRESH_TOZERO의 반대(픽셀값이 경계값보다 크면 0, 아니면 픽셀값 할당)

동영상 혹은 카메라(웹 캠) 불러오기

  • 카메라로부터 프레임 캡쳐 후 연결하여 영상으로 보여주기
  • 동영상 파일로부터 프레임 캡쳐 후 연결하여 영상으로 보여주기
# 영상 파일을 다룰 때는 예외처리(제대로 동작하지 않았을 경우에 대한 처리)를 해주는
# 것이 오류 방지에 좋다

# 1. 영상 파일에서 프레임단위로 사진을 캡쳐해 받아오기
try:
    # VideoCapture : 동영상을 프레임 단위로 캡쳐
    cap = cv2.VideoCapture("image/video.mp4")
    print("비디오 캡쳐 시작")
except:
    print("비디오 캡쳐 실패")
    
# 2. 캡쳐해 온 프레임 출력
ret, frame = cap.read()
print(ret)
print(frame)

plt.imshow(frame)
비디오 캡쳐 시작
True
[[[177 152  90]
  [175 151  89]
.................

 [[ 48  46  19]
  ...
  [ 42  31  17]]

 [[ 31  29   2]
  ...
  [ 27  16   2]]]
# 영상 파일을 다룰 때는 예외처리(제대로 동작하지 않았을 경우에 대한 처리)를 해주는
# 것이 오류 방지에 좋다

# 1. 영상 파일에서 프레임단위로 사진을 캡쳐해 받아오기
try:
    # VideoCapture : 동영상을 프레임 단위로 캡쳐
    # 1) 웹캠으로 부터 캡쳐
    # 카메라번호 - USB포트 번호, 일반적으로 웹캠 하나 : 0번
    # cap = cv2.VideoCapture(0)
    
    # 2) 동영상으로 부터 캡쳐
    cap = cv2.VideoCapture("image/video.mp4")
    print("비디오 캡쳐 시작")
except:
    print("비디오 캡쳐 실패")
    
# 2. 캡쳐해 온 프레임 계속해서 한 장씩 읽어와 연결하여 출력(영상으로 보여준다)
while True:
    # read : 캡쳐한 이미지 프레임을 한 장씩 읽어오는 함수
    # ret : 읽기 성공여부(True, False)
    # frame : 읽어온 이미지 데이터(numpy 배열 타입)
    ret, frame = cap.read()
    
    # 프레임을 읽지 못했거나 영상의 모든 프레임을 다 읽었을 경우 종료
    if ret==False :
        print("프레임 읽기 실패 or 프레임 모두 읽음")
        # 비디오 캡쳐 종료
        cap.release()
        # 생성한 창을 모두 닫아주기
        cv2.destroyAllWindows()
        break
    
    #윈도우 창 크기 변경
    frame = cv2.resize(frame,(1000,700))
    # 흑백 영상 출력
    frame = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
        
#imshow(OpenCV):새 윈도우 창을 띄워서 이미지를 계속 출력(윈도우창 이름, 전달받을 프레임) 
    cv2.imshow("Video", frame)
    
    # waitKey : 키보드에 특정 키 값을 입력할 때까지 기다리는 명령
    # (숫자) : 한 장의 프레임을 읽어들이고 40ms(0.004초) 기다렸다가 다음 사진을 읽어들일
    #          수 있도록 딜레이를 주는 역할
    key = cv2.waitKey(40)
    # ex) 영상이 초당 60 프레임이라면 1000/60 -> 16.66   16ms로 설정해야 한다
    # 영상 초당 프레임수와 waitKey값의 차이가 나면 플레이 자체는 문제 없지만
    # 마지막 프레임이 잘리는 현상이 발생할 수 있음
    
    # 재생중에 영상을 끄고 싶을 경우
    # 윈도우 창의 X를 누르지 말고 키보드로 멈춰야한다(X누르면 에러or커널 재시작해야함)
    # 27 : 아스키코드로 ESC , 49는 아스키코드로 1
    if key == 27 :
        print("동영상 읽기 종료")
        cap.release()
        cv2.destroyAllWindows()
        break

 

영상 녹화하기

try:
    cap = cv2.VideoCapture("image/video.mp4")
    print("비디오 캡쳐 시작")
except:
    print("비디오 캡쳐 실패")
    
# 녹화될 파일 설정
fps = 30.0          # 초당 프레임 수
w = int(cap.get(3)) # 캡쳐한 비디오의 가로(3)크기
h = int(cap.get(4)) # 캡쳐한 비디오의 세로(4)크기

# 영상의 코덱 설정(CODEC : COder and DECoder)
# COder : 음성 또는 영상의 신호를 디지털 신호로 변환
# DECoder : corder의 반대
# DIVX : 일반적으로 avi 파일에 많이 사용되는 코덱
codec = cv2.VideoWriter_fourcc(*'DIVX')

out = cv2.VideoWriter("image/record_file.avi", codec, fps, (w,h))


# 녹화 상태 여부
record = False

while True:
    ret, frame = cap.read()
    
    if ret == False:
        print("비디오 읽기 실패 또는 비디오 모두 읽음")
        cap.release()
        out.release()
        cv2.destroyAllWindows()
        break
        
    cv2.imshow("record", frame)
    # 영상 녹화 시작 여부
    if record:  # record가 True가 되면 녹회 시작
        out.write(frame)
        
    k = cv2.waitKey(40)
    
    if k == 27 :
        print("영상 및 녹화를 종료합니다")
        cap.release()
        out.release()
        cv2.destroyAllWindows()
        break
        
    # 키보드 숫자2 : 50
    if k == 50 :
        record=True
        print("녹화를 시작합니다")

이미지의 픽셀값 변경하기

img11 = cv2.imread("image/11.png")
img11 = cv2.cvtColor(img11, cv2.COLOR_BGR2RGB)

print("불러온 이미지 타입 : ",type(img11))

print(img11[150,330])   # 픽셀값에 접근([세로, 가로])

# 픽셀값 변경하기
for i in range(21):
    for j in range(20):
        img11[150+i,330+j] = [255,0,0]

plt.imshow(img11)
불러온 이미지 타입 :  <class 'numpy.ndarray'>
[254 242   0]
<matplotlib.image.AxesImage at 0x21f3b695788>

 

ROI(Region of Interest)관심영역 추출하기

img11 = cv2.imread("image/11.png")
img11 = cv2.cvtColor(img11, cv2.COLOR_BGR2RGB)

roi_img11 = img11[160:220,280:390]

plt.imshow(roi_img11)

ROI 영역을 표시하고 글씨도 출력해보자

  • rectangle : 사각형 그리는 함수
  • circle : 원 그리는 함수
  • purText : 글씨 출력 함수
img11 = cv2.imread("image/11.png")
img11 = cv2.cvtColor(img11, cv2.COLOR_BGR2RGB)

# 픽셀값은 배열구조라 ([세로,가로])   이미지 접근은 (가로, 세로)

# 사각형 박스 출력(이미지명, 좌상단좌표, 우하단좌표, 색상, 선두께)
img11 = cv2.rectangle(img11, (280,160), (400,250), (255,0,0), 3)
# 텍스트 출력(이미지, 출력글씨, 출력좌표(좌측하단), 폰트, 폰트크기, 색상, 선두께)
img11 = cv2.putText(img11, "mouth", (300,150), cv2.FONT_HERSHEY_SCRIPT_SIMPLEX,
                   1, (255,0,0), 2)

# 원형 출력(이미지, 원 중심좌표, 반지름(라디안), 색상, 선두께)
img11 = cv2.circle(img11, (75,165),(70),(255,0,0), 3 )

plt.imshow(img11)

OCR(Optical Character Recognition) - 광학문자판독

# 파이썬용 tesseract 설치
!pip install pytesseract

import pytesseract
# 설치한 폴더의 위치를 설정
# \ : 밑에 이어서 한줄로 코드를 작성하는 것과 같은 효과
pytesseract.pytesseract.tesseract_cmd = \
"C:/Program Files/Tesseract-OCR/tesseract"

story = cv2.imread("image/story.png")
# lang : 언어 설정
result = pytesseract.image_to_string(story, lang="kor")
print(result)
소년

여기저기서 단풍잎 같은 슬픈 가을이 뚝뚝 떨어진다. 단풍잎
떨어져 나온 자리마다 봄을 마련해 놓고 나못가지 위에 하늘이
펼쳐 있다. 가만히 하늘을 들여다보려면 눈썸에 파란 물감이
든다. 두 손으로 따뜻한 볼을 쓸어 보면 손바닥에도 파란 물감
이 묻어난다. 다시 손바닥을 들여다본다. 손금에는 맑은 강물
이 흐르고, 맑은 강물이 흐르고, 강물 속에는 사랑처럼 슬픈 얼
굴ㅡ- 아름다운 순이의 얼굴이 어린다. 소년은 황홀히 눈을
감아 본다. 그래도 맑은 강물은 흘러 사랑처럼 슬픈 얼굴--
아름다운 순이의 얼굴은 어린다.


car = cv2.imread("image/car.png")
car = cv2.cvtColor(car,cv2.COLOR_RGB2BGR)
plt.imshow(car);

car = cv2.imread("image/car.png")
car = cv2.cvtColor(car,cv2.COLOR_RGB2BGR)
result = pytesseract.image_to_string(car, lang="kor")
print(result)

  -> 결과가 없다

 

  • 문자인식 전 이진이미지로 변경하면 판독 정확성이 올라감

car = cv2.imread("./image/car.png", cv2.IMREAD_GRAYSCALE)
_, bi_car = cv2.threshold(car, 128, 255, cv2.THRESH_BINARY)
plt.imshow(bi_car, cmap='gray');

car = cv2.imread("./image/car.png", cv2.IMREAD_GRAYSCALE)
_, bi_car = cv2.threshold(car, 128, 255, cv2.THRESH_BINARY)
result = pytesseract.image_to_string(bi_car, lang="kor")
print(result)

527 3108!


 

반응형