DBILITY

python opencv 기초 학습 정리 본문

python

python opencv 기초 학습 정리

DBILITY 2026. 5. 20. 16:23
반응형

학습 내용을 정리한다. 정리해야 흐린 기억이라도 그려지니까.

설치부터 한다.pip install opencv-python

C:\Dev64\workspace\python_execise>pip install opencv-python
Collecting opencv-python
  Downloading opencv_python-4.13.0.92-cp37-abi3-win_amd64.whl.metadata (20 kB)
Requirement already satisfied: numpy>=2 in C:\Python\Python313\Lib\site-packages (from opencv-python) (2.4.0)
Downloading opencv_python-4.13.0.92-cp37-abi3-win_amd64.whl (40.2 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 40.2/40.2 MB 9.0 MB/s  0:00:04
Installing collected packages: opencv-python
Successfully installed opencv-python-4.13.0.92


C:\Dev64\workspace\python_execise>py -c "import cv2; print(cv2.__version__)"
4.13.0

이미지를 읽어 출력하고 키입력이 있으면 창을 닫는 코드다.

import cv2

img = cv2.imread("sample.png") #이미지 읽기

cv2.imshow("img",img) #이미지 출력

cv2.waitKey(0) #키보드입력 대기

cv2.imwrite("copy_sample.png",img) #이미지 저장

cv2.destroyAllWindows() # 모든창 종료

opencv의 색상은 RGB가 아닌 BGR순서

import cv2

img = cv2.imread("sample.png")

height, width, channel = img.shape; #이미지 크기 확인

print(f"image size : {width}x{height}, channel : {channel}")

b, g, r = cv2.split(img) #색상 채널 분리 (B,G,R)

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

img = cv2.merge([b,g,r]) #색상 채널 병합, 이경우는 원복색상
cv2.imshow("img", img)

img = cv2.merge([r, g, b]) #색상 채널 병합, r/g/b로 치환?
cv2.imshow("img", img)

cv2.waitKey(0)
cv2.destroyAllWindows()

이미지크기 조절

import cv2

img = cv2.imread("sample.png")
height, width, channel = img.shape;

resized = cv2.resize(img, (width * 2, height * 2))

cv2.imshow("resized", resized)

resized_ratio = cv2.resize(img, (0, 0), fx=0.5, fy=0.5)

cv2.imshow("resized_ratio", resized_ratio)

resized_fixed = cv2.resize(img, (300, 300))
cv2.imshow("resized_fixed", resized_fixed)

cv2.waitKey(0)
cv2.destroyAllWindows()

이미지 회전

import cv2

img = cv2.imread("sample.png")

cv2.imshow("img",img)

rotated = cv2.rotate(img, cv2.ROTATE_90_CLOCKWISE)
cv2.imshow("rotated", rotated)

cv2.waitKey(0)
cv2.destroyAllWindows()

이미지 자르기

import cv2

img = cv2.imread("sample.png")

cv2.imshow("img", img)

height, width, channel = img.shape;
# 좌표 : img[ y_start:y_end, x_start:x_end ]
cropped = img[0:int(height / 2), 0:int(width / 2)]
cv2.imshow("cropped", cropped)

cv2.waitKey(0)
cv2.destroyAllWindows()

그레이스케일 변환 ( 연산속도증가, 에지(윤곽선) 탐지 용이 , 조명변화민감도 저감 장점 )

import cv2

img = cv2.imread("sample.png")

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv2.imshow("gray", gray)

cv2.waitKey(0)
cv2.destroyAllWindows()

이진화(Thresholding) - 그레이스케일 이미지를 흑백(0,255)로 구분, 기준값(127)보다 밝으면 흰색, 어두우면 검은색 변환하여
전경(객체)와 배경을 분리.

retval, dst = cv2.threshold(src, thresh, maxval, type[, dst])

  • src: 입력 이미지로, 단일 채널 (그레이스케일) 이미지
  • thresh: 임계값으로, 이 값을 기준으로 픽셀 값을 분류.
  • maxval: 임계값 이상일 때 적용할 값입니다. 보통 255로 설정.
  • type: 임계값을 적용하는 방법을 지정하는 플래그. 주요 유형으로는 cv2.THRESH_BINARY, cv2.THRESH_BINARY_INV, cv2.THRESH_TRUNC, cv2.THRESH_TOZERO, cv2.THRESH_TOZERO_INV 등.
  • dst: 선택적으로 출력 이미지. 원본 이미지와 동일한 크기와 타입을 가져야 함.

이 함수는 두 개의 반환 값 존재:

  • retval: 사용된 임계값.
  • dst: 이진화된 결과 이미지.
import cv2

img = cv2.imread("sample.png")

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
retval, thresholded = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY);
print(retval) # 임계기준값 127.0

cv2.imshow("thresholded", thresholded)

cv2.waitKey(0)
cv2.destroyAllWindows()

적응형 이진화(Adaptive Thresholding) - 조명변화가 심한 환경, 픽셀주변 기준으로 동적 임계값 계산

source는 grayscale , blockSize는 적용영역크기로 홀수로 지정, 마지막값 C 계산된 경계값에서 차감할 값

cv2.adaptiveThreshold(source, maxValue, adaptiveMethod, thresholdType, blockSize, C)

  • source = grayscaled image
  • maxValue = 임계값
  • adaptiveMethod = threshold값을 계산하는 방법( ADAPTIVE_THRESH_MEAN_C = 일반노이즈제거  , ADAPTIVE_THRESH_GAUSSIAN_C = 중심 강조 및 엣지 보존 )
  • thresholdType = THRESH_BINARY , THRESH_BINARY_INV
  • blockSize = thresholding 적용할 영역 크기, 홀수로 지정, 너무 작으면 노이즈에 민감
  • C = 계산된 경계값(평균,가중평균)에서 차감할 값 - 보정용 상수 양수인 경우 작은 전경(객체) 검출 음수일 경우 배경일부도 검출
import cv2

img = cv2.imread("sample.png")

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
adaptive = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2)
cv2.imshow("adaptive", adaptive)

cv2.waitKey(0)
cv2.destroyAllWindows()

블러링(Blurring) - 부드럽게 만들어 노이즈 필터링(제거), 필터사이즈가 클수록 더 흐려짐

dst = cv2.GaussianBlur(source, ksize, sigmaX, dst=None, sigmaY=None, borderType=None) 

  • source: 입력 영상. 각 채널 별로 처리됨.
  • dst: 출력 영상. source와 같은 크기, 같은 타입.
  • ksize: 가우시안 커널 크기. (0, 0)을 지정하면 sigma 값에 의해 자동 결정됨
  • sigmaX: x방향 sigma.
  • sigmaY: y방향 sigma. 0이면 sigmaX와 같게 설정.
  • borderType: 가장자리 픽셀 확장 방식.
import cv2

img = cv2.imread("../sample.png")

mean_blur = cv2.blur(img, (5, 5)) #평균 블러링
cv2.imshow("mean_blur", mean_blur)

gaussian_blur = cv2.GaussianBlur(img,(5,5),0) #가우시안 블러링
cv2.imshow("gaussian_blur", gaussian_blur)

median_blur =cv2.medianBlur(img,5)
cv2.imshow("median_blur", median_blur)


bilateral_blur = cv2.bilateralFilter(img, 9, 75, 75) #양방향 블러링 - 자연스럽게 노이즈 제거 경계선 유지
cv2.imshow("bilateral_blur", bilateral_blur)

cv2.waitKey(0)
cv2.destroyAllWindows()

 

사용자정의 필터 적용 - 이미지의 세부 사항을 강조하거나 경계를 감지하는 등 다양한 이미지 처리 작업에 사용

dst = cv2.filter2D(source, ddepth, kernel, anchor, delta, borderType)

  • source: 입력 이미지. numpy 배열로 표현.
  • ddepth: 결과 이미지의 깊이(비트 단위). -1로 지정하면 입력 이미지와 동일한 깊이를 사용.
  • kernel: 필터링에 사용될 커널. numpy 배열로 정의, 일반적으로 부동소수점 값으로 구성.
  • anchor: 선택적으로 커널의 중심을 지정하는 점. 기본값은 (-1, -1)로, 커널의 중심을 사용.
  • delta: 필터링된 픽셀에 추가적으로 더해질 값. 기본값은 0.
  • borderType: 이미지 가장자리 픽셀을 확장하는 방식을 결정 ( cv2.BORDER_CONSTANT, cv2.BORDER_REFLECT, cv2.BORDER_WRAP 등 )

샤프닝(Sharpening) - 선명하게 만들어 엣지강조, 객체경계를 명확히 함

import cv2
import numpy as np

img = cv2.imread("../sample.png")
cv2.imshow("img", img)

#kernel = np.ones((5,5), np.float32) / 25 #사용자 정의 커널( 평균필터 )
#blurred = cv2.filter2D(img, -1, kernel)
#cv2.imshow("blurred", blurred)
kernel = np.array([[0, -1, 0],
          [-1, 5, -1],
          [0, -1, 0]])
sharp = cv2.filter2D(img, -1, kernel)
cv2.imshow("sharp", sharp)

cv2.waitKey(0)
cv2.destroyAllWindows()

경계검출(Edge Detection) - 엣지는 이미지에서 밝기 변화가 큰 경계부분을 의미한다고 대표적으로 Sobel, Canny, Laplacian Filter가 있음

Sobel필터 - 미분을 이용 수평/수직으로 미분 연산한다고

import cv2
import numpy as np

img = cv2.imread("../sample.png")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

sobelx = cv2.Sobel(gray, cv2.CV_64F, 1, 0, ksize=3)
sobely = cv2.Sobel(gray, cv2.CV_64F, 0, 1, ksize=3)

edge_sobel = cv2.magnitude(sobelx, sobely)
edge_sobel = np.clip(edge_sobel, 0, 255).astype(np.uint8)
cv2.imshow("edge_sobel", edge_sobel)
cv2.waitKey(0)
cv2.destroyAllWindows()

Laplacian필터 - 2차미분 연산, 노이즈에 민감, 더 강한 경계검출 성능

Cany필터 - 노이즈제거, 그라디언트 연산, 비최대억제, 이중 임계값을 활용한 정교한 검출

cv2.Canny(source, threshold1, threshold2[, edges[, apertureSize[, L2gradient]]])

  • image:  그레이스케일 이미지
  • threshold1: 엣지 검출에서 사용되는 최소 임계값. 이 값보다 낮은 그라디언트 값은 엣지로 간주되지 않음
  • threshold2: 엣지 검출에서 사용되는 최대 임계값. 이 값보다 높은 그라디언트 값은 확실한 엣지로 간주됨
  • edges: 선택적으로 출력 엣지 이미지
  • apertureSize: 선택적으로 소벨 연산자에 사용되는 커널 크기 지정. 기본값은 3
  • L2gradient: 선택적으로 그라디언트 크기를 계산할 때 사용할 방법을 지정. 기본값은 False, 그라디언트 크기를 계산할 때 L1 norm을 사용. True로 설정하면 L2 norm을 사용.

threshhold1,2는 1:2 또는 1:3 비율이 적당한 수준이라고

import cv2

img = cv2.imread("../sample.png")

edges = cv2.Canny(img, 100, 200)

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

 

형태학적 변환(Morphology) 

binary나 Grayscale이미지를 Segmentation하여 단순화, 제거, 보정을 통해 형태를 파악한다.

팽창(Dilation), 침식(Erosion) 이 두가지를 조합한 Openinig, Closing이 있음

연산효과용도는 다음과 같다.

침식(Erode) 객체 축소 노이즈(작은 객체) 제거
팽창(Dilate) 객체 확장 끊어진 경계 복원
열기(Open) 침식 → 팽창 작은 점 제거
닫기(Close) 팽창 → 침식 구멍 채우기

getStructuringElement  = 모폴로지 구조 요소(커널) 생성 함수 

retval = cv2.getStructuringElement(shape, ksize[, anchor])

  • shape : 구조요소모양 ( MORPH_RECT, MORPH_CROSS, MORPH_ELLIPSE )
  • ksize : 구조요소크기 (width,height) tuple
  • anchor : MORPH_CROSS 구조일때 고정점 좌표
  • retval = 0과 1로 구성된 CV_8UC1 타입 행렬 ( 1의 위치가 구조요소모양 결정)
import cv2

img = cv2.imread("../sample.png")
cv2.imshow("img", img)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))

eroded = cv2.erode(gray, kernel, iterations=1)
cv2.imshow("eroded", eroded)

dilated = cv2.dilate(gray, kernel, iterations=1)
cv2.imshow("dilated", dilated)

opening = cv2.morphologyEx(gray, cv2.MORPH_OPEN, kernel);
cv2.imshow("opening", opening)

closing = cv2.morphologyEx(gray, cv2.MORPH_CLOSE, kernel);
cv2.imshow("closing", closing)

cv2.waitKey(0)
cv2.destroyAllWindows()

 

그레이스케일 cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 명도 기반 처리
이진화 cv2.threshold, cv2.adaptiveThreshold 밝기 기준 분리
블러링 cv2.blur, cv2.GaussianBlur 노이즈 감소
샤프닝 cv2.filter2D 엣지 강조
에지 검출 cv2.Canny 윤곽선 탐지
형태학 연산 cv2.erode, cv2.dilate 구조 정제
히스토그램 평활화 cv2.equalizeHist 대비 향상

도형 윤곽선 검출( Contour ) - 윤곽선은 동일한 밝기나 색상 경계를 따라 연결된 점들의 집합

이진화된 이미지에서 윤곽선을 찾아 구성하는 점들을 반환

contours, hierarchy = cv2.findContours(image, mode, method[, contours[, hierarchy[, offset]]])

  • image: 그레이스케일 또는 이진화된 이미지를 사용.
  • mode: 윤곽선을 찾는 방법을 지정. cv2.RETR_EXTERNAL, cv2.RETR_LIST, cv2.RETR_TREE 등.
  • method: 윤곽선 근사화 방법. 
    cv2.CHAIN_APPROX_SIMPLE, cv2.CHAIN_APPROX_TC89_L1, cv2.CHAIN_APPROX_TC89_KCOS 
  • contours: 검출된 윤곽선을 저장할 리스트.
  • hierarchy: 윤곽선의 계층 구조를 저장할 배열.
  • offset: 윤곽선의 좌표를 변환할 때 사용되는 오프셋.
import cv2

img = cv2.imread("../sample.png")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) #grayscale
_, thresholded = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) #이진화

#윤곽선 찾기
contours, hierarchy = cv2.findContours(thresholded, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

#찾은 윤곽선 그리기
cv2.drawContours(img, contours, -1, (0, 255, 0), 2)
cv2.imshow("img", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
import cv2

img = cv2.imread("../sample.png")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_, thresholded = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY);

contours, hierarchy = cv2.findContours(thresholded, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

for contour in contours:
    area = cv2.contourArea(contour) #면적
    perimeter = cv2.arcLength(contour, True) #둘레
    M = cv2.moments(contour) #중심점계산

    x, y, w, h = cv2.boundingRect(contour) #직사각형 검출
    cv2.rectangle(img, (x, y), (x+w, y+h), (0,255,0), 2)

    if M["m00"] != 0:
        cx = int(M["m10"] / M["m00"])
        cy = int(M["m01"] / M["m00"])
        cv2.circle(img, (cx, cy), 5, (255, 0, 0), -1)

    print(f"면적={area:.1f}, 둘레={perimeter:.1f}")

#cv2.drawContours(img, contours, -1, (0, 255, 0), 2)
cv2.imshow("img", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
  • cv2.arcLength(외곽선좌표, 폐곡선여부) : 외곽선 둘레 길이 반환
  • cv2.contourArea(외곽선좌표, 외곽선 진행방향에 따라 부호 있는 면적반환여부 기본 False) : 외곽선으로 구성된 면적반환
  • cv2.boundingRect(외곽선좌표) : 외곽선을 외접하여 둘러싸는 가장 작은 사각형 반환
  • cv2.approxPolDP(곡선좌표, 근사화정밀도, 폐곡선인식여부) : 외곽선 근사화 반환
  • cv2.moments(외곽선좌표) :  윤곽선(Contour)이나 이미지의 면적, 중심 좌표, 방향 등의 기하학적 특성을 쉽게 계산
    면적(Area) : M['m00'] 내부픽셀수
    공간 모멘트 (Spatial Moments): M['m00'], M['m10'], M['m01'], M['m20'], M['m11'], M['m02'] 등
    중심 모멘트 (Central Moments): 질량 중심을 기준으로 계산 (mu20, mu11, mu02 등)
    중심점 (Centroid): 질량의 평균 위치 cx = m10/m00, cy = m01/m00
반응형
Comments