본문 바로가기

AI 개론

AI 개론 _ OpenCV를 이용한 컴퓨터 비전 + opencv를 이용한 영상 정규화 실습

728x90

opencv를 이용한 컴퓨터 비전

 

  • computer vision Top project 2024기준
    • Football player dete

  • fish detection in sea

  • vehicle detection tracking and countin

  • personal protective equipment detection and monitoring

  • virtual gym using pose estimation

 

디지털 영상 처리 분류

  • 화소 점 처리 (point processing)
    • 화소 점의 원래 값이나 화소 점의 위치를 기반으로 화소 값 변경
  • 영역 처리 (area processing)
    • 화소의 원래 값과 이웃하는 화소의 값을 기반으로 화소값 변경
  • 기하학 처리 (geometric processing)
    • 화소들의 위치나 배열을 변화시킴
  • 프레임 처리 (frame processing)
    • 두 개 이상의 서로 다른 디지털 영상들이 연산 등의 조합을 통해서 새로운 화소값 생성

 

디지털 영상 : 표본화 양자화

 

https://medium.com/@muhammad.a0625

 

표본화에 따른 영상차이

 

From Wimarshika Thamali, Medium

 

양자화에 따른 영상 차이

 

표본화 + 양자화

 

영상 신호의 디지털화 과정

출처: Opencv로 실습하며 배우는 영상처리

 

디지털 영상의 표현 방법

opencv 로 실습하며 배우는 영상처리

 

색공간 모델

 

RGB 색상 예제

 

산술 연산을 이용한 물체 인식

 

Grayscale stretching

 

Histogram

  • 이미지에서 주어진 값의 픽셀 수를 나타내는 간단한 데이터
  • ex) 8비트 그레이 스케일 이미지

 

 영상과 히스토그램 분포

 

RGB 히스토그램

히스토그램 수정
• 히스토그램을 기반으로 이미지 대비 및 밝기 개선 히스토그램 모양과 범위에 초점을 맞춥니다

 

fields

 

Scaling

 

opencv를 이용한 영상 정규화 실습

 

영상읽기

# !pip install opencv-python
!pip install matplot
# pip install opencv-python
import cv2
import numpy as np
import sys
import matplotlib.pyplot as plt
from pathlib import Path
print(cv2.__version__)
4.11.0
# cv2.imread(filename. flags = None) -> retval
# flags:
# cv2.IMREAD_COLOR: BGR color로 읽기
# cv2.IMREAD_GRAYSCALE: 그레이 color로 읽기
# cv2.IMREAD_UNCHANGED: 파일 속성대로 읽기
# cv2.IMREAD_REDUCED_GRAYSCALE_2 
# cv2.IMREAD_REDUCED_COLOR_2 

# retval: numpy.ndarray로 반환
folder = "fig"

img = cv2.imread(Path(folder, "dog.bmp"), cv2.IMREAD_COLOR)
# img  = cv2.imread(Path(folder, "mri_brain.jpeg"), cv2.IMREAD_GRAYSCALE)

if img is None:
    print("Image read failed")
    sys.exit()

print(type(img)) # class numpyㅁ
print(img.shape) # bgr (rgb x)
print(img.dtype)

# # cv2_imshow(img)
cv2.imshow("dog", img)

cv2.waitKey(0) # ms
cv2.destroyAllWindows()
Image read failed

 

새창띄우기 : cv2.namedWindow()

# cv2.namedWindow(winname, flags = None) -> None

# winname: 창 이름
# flags:
# cv2.WINDOW_NORMAL: 영상크기를 창 크기에 맞게 지정
# cv2.WINDOW_AUTOSIZE: 창크기를 영상 크기에 맞게 변경

# cv2.imwrite(filename, mat) -> None
# filename: 저장할 이름
# mat: numpy.ndarray (default = uint8)

# uint16, int32의 경우 255로 나누어서 출력
# float32, float64의 경우 0 ~ 1로 만든 후 행렬값에 255를 곱해서 출력
## cv2.namedWindow()
img = cv2.imread(Path(folder, "dog.bmp"), cv2.IMREAD_COLOR)

print("width = {}, height = {}".format(
    img.shape[1], img.shape[0]))

# img_resize = cv2.resize(img, (img.shape[1]//2, img.shape[0]//2))

if img is None:
    print("Image read failed")
    sys.exit()

## cv2.WINDOW_AUTOSIZE: 창의 크기를 영상에 맞춤
cv2.namedWindow("Dog", cv2.WINDOW_AUTOSIZE)
# cv2.namedWindow("Dog", cv2.WINDOW_NORMAL)

cv2.imshow("Dog", img)
# cv2.imshow("Dog_resize", img_resize)

cv2.waitKey(0)
cv2.destroyAllWindows()

# mac os
# cv2.waitKey(1)
width = 640, height = 480

 

키보드 입력대기

# waitKey([, delay]) -> retval
# delay: Delay in milliseconds. 0 is the special value that means "forever"
# cv2.waitKey() -> ASCII code
# retval
img  = cv2.imread(Path(folder, "dog.bmp"), cv2.IMREAD_COLOR)

if img is None:
    print("Image read failed")
    sys.exit()

cv2.namedWindow("dog", cv2.WINDOW_NORMAL)
cv2.imshow("dog", img)

while True:
    if cv2.waitKey() == ord("q"):
        break
    
# cv2.waitKey()
cv2.destroyAllWindows()

matplotlib

import matplotlib.pyplot as plt

img  = cv2.imread(Path(folder, "dog.bmp"), cv2.IMREAD_COLOR) # BGR
imgrgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) #RGB
imggray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # GRAY

if img is None:
    print("Image read failed")
    sys.exit()

# plt.imshow(imgrgb)
# plt.axis("off")
# plt.show()

plt.figure(figsize=(10,3))
plt.subplot(131), plt.imshow(img), plt.axis("off")
plt.subplot(132), plt.imshow(imgrgb), plt.axis("off")
plt.subplot(133), plt.imshow(imggray, cmap = "gray"), plt.axis("off")
plt.show()

# fig, axs = plt.subplots(1, 3, figsize = (10, 4))
# axs[0].imshow(img)
# axs[0].set_title("BGR")
# axs[0].axis('off')
# plt.show()

 

온라인 영상 읽기

from urllib import request

url = "https://image.artbox.co.kr/upload/C00001/goods/800_800/179/241101006087179.jpg?s=/goods/org/179/241101006087179.jpg"
# url = "https://i.ytimg.com/vi/VCUT4Hqy5lA/maxresdefault.jpg"
source = request.urlopen(url).read() # bytes
print(type(source))
print(source)
# bytearray(source)
image = np.array(bytearray(source), dtype = np.uint8)
print("image shape = ", image.shape) # (101968,)

image = cv2.imdecode(image, cv2.IMREAD_COLOR)
cv2.imwrite("Charistmas.png", image)

# cv2.namedWindow("img", cv2.WINDOW_NORMAL)
cv2.imshow("img", image)

cv2.waitKey()
cv2.destroyAllWindows()
image shape =  (161202,)

디렉토리 내 영상읽기

import os

img_list = os.listdir(Path(folder, "images"))
# print(img_list)

img_files = [] # list
for i in img_list:
    img_dir = Path(folder, "images", i) # python string
    img_files.append(img_dir)


# print(img_files)

cv2.namedWindow("folder images", cv2.WINDOW_NORMAL)
cv2.setWindowProperty("folder images", cv2.WND_PROP_FULLSCREEN,
                      cv2.WINDOW_FULLSCREEN)

idx = 0
while True:
# for i in img_files:

    img = cv2.imread(img_files[idx], cv2.IMREAD_COLOR)
    cv2.imshow('folder images', img)

    if cv2.waitKey(3000) == 27:
        break

    idx += 1

    if idx >= len(img_files):
        idx = 0

cv2.destroyAllWindows()

영상의 픽셀값 참조


img  = cv2.imread(Path(folder, "dog.bmp"), cv2.IMREAD_COLOR)

if img is None:
    print("image read failed")
    sys.exit()

print("img width = {}, height = {}".format(
    img.shape[1], img.shape[0]))

## 영상 픽셀값
x = 320; y = 240
print("x = {}, y = {} 의 픽셀값".format(x, y))
print(img[240, 320])
# print(img[200:300, 250:400])
img[150:250, 250:500] = (125,  44,  66)

cv2.namedWindow("image", cv2.WINDOW_AUTOSIZE)

cv2.imshow("image", img)

while True:
    if cv2.waitKey() == 27:
        break

cv2.destroyAllWindows()

img width = 640, height = 480
x = 320, y = 240 의 픽셀값
[ 0 14 40]

 

Canvas

# img1 = np.random.randint(0, 255, (200, 200), np.uint8) # int32
img2 = np.ones((1200, 800, 3), dtype = np.uint8)*255
# img3 = np.zeros((200, 200), np.uint8) + 255
# img4 = np.full((200, 200, 3), (255, 0, 255), np.uint8)

# cv2.imshow("rand int", img1)
cv2.imshow("rand ones", img2)
# cv2.imshow("rand zeros", img3)
# cv2.imshow("rand full", img4)


cv2.waitKey()
cv2.destroyAllWindows()

 

영상 복사 (memory copy)

img = cv2.imread(Path(folder, "rose.jpg"), cv2.IMREAD_COLOR)


if img is None:
    print("image read failed")
    sys.exit()

# img2 = img
# deep copy
img2 = img.copy()

img2[100:150, 200:300] = (255, 0, 0)

cv2.namedWindow("rose", cv2.WINDOW_AUTOSIZE)
cv2.imshow("rose", img)
cv2.imshow("rose copy", img2)


while True:
    if cv2.waitKey() == ord("q"):
        break

cv2.destroyAllWindows()

영상합성

# 마스크 영상을 이용한 영상 합성 
# cv2.copyTo(src, mask, dst = None) -> dst
# src: copy 하고자 하는 원본 영상
# mask: mask 영상
# dst: copy 후에 결과 영상
## 부분영상: 영상 합성에 유리

img = cv2.imread(Path(folder, "dog.bmp"), cv2.IMREAD_COLOR)

if img is None:
    print("image read failed")
    sys.exit()

dog_eye = img[150:250, 250:500]

# circle(img, center, radius, color[, thickness[, lineType[, shift]]]) -> img
cv2.circle(dog_eye, (50, 50), 30, (0, 0, 255), 5)
print(dog_eye.shape)


cv2.namedWindow("dog", cv2.WINDOW_NORMAL)
cv2.imshow("dog", img)
cv2.imshow("dog eye", dog_eye)


while True:
    if cv2.waitKey() == 27:
        break

cv2.destroyAllWindows()
(100, 250, 3)

 

## copyTo(): 영상합성

# src = cv2.imread("./fig/airplane.bmp", cv2.IMREAD_COLOR)
# mask = cv2.imread("./fig/mask_plane.bmp", cv2.IMREAD_GRAYSCALE)
# dst = cv2.imread("./fig/field.bmp", cv2.IMREAD_COLOR) #

src = cv2.imread(Path(folder, "airplane.bmp"), cv2.IMREAD_COLOR)
mask = cv2.imread(Path(folder, "mask_plane.bmp"), cv2.IMREAD_GRAYSCALE)
dst = cv2.imread(Path(folder, "field.bmp"), cv2.IMREAD_COLOR) #

print(dst.shape)

if src is None or mask is None or dst is None:
    print("Images read failed")
    sys.exit()

## numpy class
# dst[mask > 0] = src[mask > 0]
cv2.copyTo(src, mask, dst)

cv2.imshow("src", src)
cv2.imshow("mask",mask)
cv2.imshow("dst",dst)

cv2.waitKey()
cv2.destroyAllWindows()
(400, 600, 3)
## 알파채널 영상 일기

# src = cv2.imread('fig/sunglass.png', cv2.IMREAD_UNCHANGED)
src = cv2.imread(Path(folder, "sunglass.png"), cv2.IMREAD_UNCHANGED)


if src is None or src is None:
    print('Image read failed!')
    sys.exit()


mask = src[:,:, -1]    # mask는 알파 채널로 만든 마스크 영상
glass = src[:,:, 0:3]  # glass는 b, g, r 3채널로 구성된 컬러 영상

#cv2.imshow('raw', raw)
cv2.imshow('src', src)
cv2.imshow('glass', glass)
cv2.imshow('mask', mask)

cv2.waitKey()
cv2.destroyAllWindows()

Draw lines

# cv2.line(img, pt1, pt2, color, thickness = None, lineType = None, shift = None) -> img
# flags
    # img:그림을 그릴 영상
    # pt1, pt2: 직선의 시작점, 끝점 
    # color: 직선의 칼라 (B,G,R)의 튜플
    # thinkness: 선두께, 기본은= 1
    # lineType: cv2.LINE_4, cv2.LINE_8, cv2.LINE_AA

# cv2.rectangle(img, pt1, pt2, color, thickness = None, lineType = None) -> img
   # pt1 :좌측 상단,  pt2: 우측하단
# cv2.rectangle(img, rect, color, thickness = None, lineType = None) -> img
    # rect: 사각형의 위치 정보 (x, y, w, h)
# cv2.circle(img, center, radius, color, thickness = None, lineType = None) -> img
    # center: 원의 중심좌표 (x, y)
    # radius : 원의 반지름

# cv2.ellips(img, center, axes, angle, startAngle, endAngle, color[, thickness[, lineType[, shift]]]) -> img
    # center: 원의 중심좌표 (x, y)
    # axis: 축의 반지름(x, y)
    # angle: 타원의 기울기 (예, 10, 오른쪽으로 10도 기울어짐)
    # startAngle: 타원을 그리는 시작 각도 (3시 방향이 0도)
    # endAngle: 타원을 그리는 종료 각도

# cv2.polylines(img, pts, isClosed, color, thickness = None, lineType = None) -> img
    # center: 다각형 점들의 array
    # isClosed : True for 폐곡선
## 그리기

img = np.ones((600, 1200, 3), np.uint8)*255
cv2.line(img, (100, 50), (300 ,50), (0, 0, 255), 10, cv2.LINE_AA)
cv2.line(img, (300 ,50), (200, 300), (0, 0, 255), 20, cv2.LINE_AA)
cv2.arrowedLine(img, (400, 50), (400, 300), (255,  0, 0), 10, cv2.LINE_AA)

# cv2.rectangle(img, (200, 400), (400, 500), (0, 0, 255), 5, cv2.LINE_AA)
cv2.rectangle(img, (200, 400, 200, 100), (0, 0, 255), 5, cv2.LINE_AA)

cv2.circle(img, (700, 300), 100, (255, 0, 255), -1)

cv2.ellipse(img, (500, 100), (100, 50), 10, 0, 360, (255, 0, 0), 2)

pts = np.array([[250, 200], [300, 200], [350, 300], [250, 300]])
cv2.polylines(img, [pts], True, (255, 0, 255), 2, cv2.LINE_AA)

text = "OpenCV version=4.9"
cv2.putText(img, text, (700, 100), cv2.FONT_ITALIC, 1, 
            (0, 0, 255), 2, cv2.LINE_AA)

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

화소점 처리

# add(src1, src2[, dst[, mask[, dtype]]]) -> dst
# src1: 첫번째 입력영상
# src2: 두번째 입력영상
# dst: 덧셈 연산의 결과
# mask: 마스크 영상
# dtype: 출력영상의 타입 (예, cv2.CV_8U, cv2.CV_32F)

## add, subract, addweighted, absdiff, multiply, divivde

# src = cv2.imread("./fig/lenna.png", cv2.IMREAD_COLOR)
src = cv2.imread(Path(folder, "lenna.png"), cv2.IMREAD_COLOR)


if src is None:
    print("image read failed")
    sys.exit()

dst1 = cv2.add(src, 100) # 클리핑
#dst1 = np.clip(src + 100., 0, 255).astype(np.uint8)

dst2 = cv2.add(src, (0, 0, 250, 0)) # 클리핑

cv2.imshow("src", src)
cv2.imshow("dst1", dst1)
cv2.imshow("dst2", dst2)

cv2.waitKey()
cv2.destroyAllWindows()
## 사칙연산

src1 = cv2.imread(Path(folder, "lenna.png"), cv2.IMREAD_GRAYSCALE)
src2 = np.zeros((220, 220), np.uint8)
cv2.circle(src2, (110, 110), 80, 200, -1)
cv2.circle(src2, (110, 110), 40, 50, -1)

if src is None:
    print("image read failed")
    sys.exit()

# cv2.divide, cv2.multiply()
dst1 = cv2.add(src1, src2)

dst2 = cv2.subtract(src1, src2)
dst3 = cv2.addWeighted(src1, 0.8, src2, 0.2, 0.0)
dst4 = cv2.absdiff(src1, src2)
dst5 = cv2.divide(src1, 2)
dst6 = cv2.multiply(src1, 2)

cv2.imshow("src1", src1)
cv2.imshow("src2", src2)
cv2.imshow("add", dst1)
cv2.imshow("subtract", dst2)
cv2.imshow("addWeighted", dst3)
cv2.imshow("absdiff", dst4)
cv2.imshow("divide", dst5)
cv2.imshow("multiply", dst6)

cv2.waitKey()
cv2.destroyAllWindows()
# src = cv2.imread("./fig/rose.jpg", cv2.IMREAD_COLOR)
src = cv2.imread(Path(folder, "rose.jpg"), cv2.IMREAD_COLOR)

background = np.ones_like(src)*255

weight = np.arange(0, 1, 0.01)
# print(weight)

for i in weight:
    dst = cv2.addWeighted(src, i, background, 1-i, 0.0)
    cv2.imshow('dst', dst)

    if cv2.waitKey(100) == 27:
        break

cv2.destroyAllWindows()

영상 히스토 그램

# cv2.calcHist(images, channels, mask, histSize, ranges[, hist[, accumulate]]) -> hist
# images: 입력영상 리스트(리스트로 입력)
# channels: 채널리스트, 3 채널의 경우 [0,1,2]
# mask: 마스크 영상입력, 영상전체는 None으로 지정
# histSize: 히스터그램 빈의 크기
# range: 히스토그램의 최솟값과 최댓값
# hist: 계산된 히스토그램, numpy.ndarray 타입
# accumulate: 기존의 히스토그램을 누적할경우 True
src = cv2.imread(Path(folder, "lenna.png"), cv2.IMREAD_COLOR)

if src is None:
    print("Image read failed")
    sys.exit()

# 채널별 히스토그램
hist_b = cv2.calcHist([src], [0], None, [256], [0, 256]) 
hist_g = cv2.calcHist([src], [1], None, [256], [0, 255])
hist_r = cv2.calcHist([src], [2], None, [256], [0, 255])


plt.bar(np.arange(len(hist_b)), hist_b[:,0], color = "b", alpha = 0.5) # blue channel
plt.bar(np.arange(len(hist_g)), hist_g[:,0], color = "g", alpha = 0.5) # green channel
plt.bar(np.arange(len(hist_r)), hist_r[:,0], color = "r", alpha = 0.5) # red channel
plt.show()

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

 

히스토그램 정규화

# cv2.normalize(src, dst=None, alpha=None, beta=None, norm_type=None, dtype=None, mask=None) -> dst
# src: 입력영상
# dst: 결과영상
# alpha: 정규화 최소값 (예, 0)
# beta: 정규화 최댓값 (예, 155)
# norm_type: cv2.NORM_MINMAX
# dtype =  -1, src와 같은 type
# src = cv2.imread('fig/puppy_shrink.png')
src = cv2.imread(Path(folder, "puppy_shrink.png"))
# src = cv2.imread('fig/autumn.jpg', cv2.IMREAD_REDUCED_COLOR_8)
# src = cv2.imread('fig/manjang.jpg')

if src is None:
    print('Image load failed!')
    sys.exit()

# minMaxLoc(src[, mask]) -> minVal, maxVal, minLoc, maxLoc
# smin, smax, _, _ = cv2.minMaxLoc(src)

dst_norm = cv2.normalize(src, None, 0, 255, cv2.NORM_MINMAX, -1)
# dst = np.clip(255*(src-smin)/(smax-smin) + 0, 0, 255).astype(np.uint8)

cv2.imshow('src', src)
cv2.imshow('dst_norm', dst_norm)

cv2.waitKey()

cv2.destroyAllWindows()
728x90