printf("ho_tari\n");
11일차 본문
2025.04.28
창(window) 관리
cv2.namedWindow(winname, flags) 함수 : winname이라는 이름을 갖는 창을 생성
- winname : 창 구분자로 활용될 창 이름
- flags : 창 옵션 (cv2.WINDOW_NORMAL : 사용자가 창 크기를 조정할 수 있음, cv2.WINDOW_AUTOSIZE : 이미지와 동일한 크기로 창 크기를 재조정할 수 없음
cv2.moveWindow(winname, x, y) 함수 : 원하는 위치로 창을 옮길 수 있음
- winname : 위치를 변경할 창 이름
- x, y : 변경할 위치 (x, y 좌표)
cv2.resizeWindow(winname, width, height) 함수 : winname 창의 크기를 (width, height) 크기로 변경
cv2.destroyWindow(winname) 함수 : winname에 해당하는 창을 닫음
cv2.destroyAllwindows() 함수 : 열린 모든 창을 닫음
imread() : 파일 읽기 함수
- `image = cv2.imread(fileName[, flags])`->retval
- fileName:읽어올 파일명
- flags : 이미지를 초기에 불러올 때 적용할 초기 상태를 의미합니다.
- cv2.IMREAD_UNCHANGED : 원본 사용(-1), alpha channel까지 포함해읽음(png파일)
- cv2.IMREAD_GRAYSCALE : 그레이스케일로 읽음(0), 1 채널, 실제 이미지 처리시 중간단계로 많이 사용한다.
- cv2.IMREAD_COLOR : COLOR로 읽음(1) , 3 채널, 투명한 부분은 무시되며, flag디폴트 값이다.
imshow() : 화면 표시 함수
- 이미지 배열을 창(window)에 표시하며, 창 이름과 이미지 데이터를 인수로 받음
- 이미지를 출력한 후에는 반드시 cv2.waitKey로 사용자 입력을 기다리거나, 창이 유지되어야 함함
- `cv2.imshow(Title, imageObject)`
- Title (Required): 이미지를 보여주는 Window 창의 이름임.
- imageObject (Required): 이미지 객체행렬로 cv2.imread()의 반환값을 입력하면 됨.
- Google Colab에서는 cv2_imshow() 사용
imwrite() : 이미지 파일 저장
-cv2.imwrite(filename, img[, params])
이미지 이해
- shape : 이미지의 height, width, channel 정보 - 저장된 이미지의 Numpy 배열 크기(높이, 너비, 채널)
img = [
[ [B,G,R], [B,G,R], [B,G,R], ..., [B,G,R] ], ← img[0]: 첫 번째 행 (y = 0)
[ [B,G,R], [B,G,R], [B,G,R], ..., [B,G,R] ], ← img[1]: 두 번째 행 (y = 1)
...
[ ... ] ← img[389]: 마지막 행
]
온라인에 있는 이미지 파일 읽기
- JPEG 바이트 (압축된 데이터) → [bytearray] → cv2.imdecode() → 3차원 배열 (H x W x 3)
VideoCapture(index)
VideoCapture(index) 클래스
- index = 0 시스템 기본 카메라
- 카메라가 열렸는지 확인
if not cap.isOpened():
print("Camera open failed!") # 열리지 않았으면 문자열 출력
sys.exit()
- ret, frame = cap.read() # 열리지 않았으면 문자열 출력
- return value - true/false
if not ret: # 새로운 프레임을 못받아 왔을 때 braek
break
도형 그리기
빈 스케치북 만들기
- 크기와 초깃값으로 생성
Numpy 배열을 생성할 때 사용할 값을 가지고 있지 않은 경우가 많기 때문에 초기 값을 지정해서 생성하는 방법을 사용
- numpy.empty(shape [, dtype]) : 초기화되지 않는 값(쓰레기 값)으로 배열 생성
- numpy.zeros(shape [,dtype]) : 0으로 초기화된 배열 생성
- numpy.ones(shape [,dtype]) : 1로 초기화된 배열 생성
- numpy.full(shape, fill_value [,dtype]) : fill_value로 초기화된 배열 생성
- 시퀀스와 난수로 생성
Numpy 배열을 생성하는 방법 중에는 일정한 범위 내에서 순차적인 값을 갖게하는 방법과 난수로 채우는 방법
- numpy.arange([start=0, ] stop [, step=1, dtype = float64]) : 순차적인 값으로 생성
- start : 시작 값
- stop : 종료 값, 범위에 포함되는 수는 ~ stop -1
- step : 증가 값
- dtype : 데이터 타입
- numpy.random.rand(array크기) : 0과 1 사이의 무작위 수 생성
array크기를 생략하면 난수 1개 반환, 나머지는 해당 크기만큼 값을 반환
- numpy.random.randn(array크기) : 표준 정규 분포를 따르는 무작위 수 생성
직선
직선의 종류(line type)
1. cv2.LINE_4 : 상하좌우 4 방향으로 연결된 선
2. cv2.LINE_8 : 대각선을 포함한 8방향으로 연결된 선(기본값)
3. cv2.LINE_AA : 부드러운 선(anit-aliasing)
그림판에서 확인 : 그림판은 LINE_8을 사용하고 있음(확대하면 확인 가능)
텍스트
- cv2.putText(img, 'Coding Simplex', (20, 50), cv2.FONT_HERSHEY_SIMPLEX, SCALE, COLOR, THICKNESS)
- 그릴 위치, 텍스트 내용, 시작위치, 폰트 종류, 크기, 색깔, 두께
OpenCV에서 사용하는 글꼴 종류
1. cv2.FONT_HERSHEY_SIMPLEX : 보통 크기의 산 세리프(sans-serif)글꼴
2. cv2.FONT_HERSHEY_PLAIN : 작은 크기의 산 세리프 글꼴
3. cv2.FONT_HERSHEY_SCRIPT_SIMPLEX : 필기체 스타일 글꼴
4. cv2.FONT_HERSHEY_TRIPLEX : 보통 크기의 산 세리프 글꼴
5. cv2.FONT_ITALIC : 기울림(이탤릭체)
관심 영역(Region of Interest, ROI)
- 이미지 내에서 원하는 피사체를 따로 분리하여 특정 처리를 하고싶을 때 사용하는 방법
- 연산할 데이터의 양을 줄이고 수행 시간을 단축시키기 때문에 특정 연산을 적용해 새로운 이미지와 정보를 획득할 때 전체 이미지로 연산을 하는 것보다 관심이 있는 부분만 연산하는 것이 효과적임
1. Numpy 이용한 ROI 지정
2. 함수 활용하여 ROI 지정
- `cv2.selectROI([win_name,], img[,showCrossHair=True, fromCenter=False])`
- win_name : ROI 선택을 진행할 창의 이름
- img : ROI 선택을 진행할 이미지
- showCrossHair : 선택 영역 중심에 십자 모양 표시 여부
- fromCenter : 마우스 시작 지점을 영역의 중심으로 지정
- ret : 선택한 영역 좌표와 크기
이미지색 공간변환
색공간 변환하기
- cv2.cvtColor(img, 옵션값)
- 색상 공간 변환(Convert Color)은 본래의 색상 공간에서 다른 색상 공간으로 변환할 때 사용
- 입력된 이미지는 8 비트, 16 비트, 32 비트의 정밀도를 갖는 배열을 사용할 수 있음
- 데이터 값이 변경되거나 채널 순서가 변경될 수 있음
- COLOR_BGR2GRAY, COLOR_GRAY2BGR, COLOR_RGB2GRAY, COLOR_GRAY2RGB...
주피터 노트북에 나타내기 - matplotlib 이용
- OpenCV : 다차원 NumPy 배열로 RGB 영상을 표현하지만 순서가 BRG로 반대임
- <b> Matplotlib 에서 opencv 로 읽은 파일 사용하려면 BGR을 RGB로 순서 변경하고 그래프를 그려야함 </b>
- `plt.imshow (src, cmap='plt.cm.원하는 색깔', interpolation='')`
2차원 배열 객체를 색깔로 표시해하는 이미지를 출력할 수 있는 함수임.
[Interpolations for imshow]( https://matplotlib.org/stable/gallery/images_contours_and_fields/interpolation_methods.html)
- `plt.show()`
그림을 표시하고 사용 중인 GUI 백엔드의 메인 루프로 들어갑니다. 플롯을 만들고 표시되는 것을 보고 싶을 때까지 호출하면 안 됩니다.
크기 조정
- `cv2.resize(원본이미지, (new_width, new_height))`
- img.shape → (height, width, channels) : (width, height) 순서로 지정
보간법
이미지를 변경할 때 자연스럽게 하는 방법
1. cv2.INTER_AREA : 크기 줄일 때 사용
2. cv2.INTER_CUBIC : 크기 늘일 때 사용 (속도 느림, 퀄리티 좋음)
3. cv2.INTER_LINEAR : 크기 늘릴 때 사용 (기본값)
이미지 연산
비트와이즈(bitwise) 연산
- bitwise_and(img1, img2, mask=None) : 각 픽셀에 대한 비트와이즈 AND 연산
- bitwise_or(img1, img2, mask=None) : 각 픽셀에 대한 비트와이즈 OR 연산
- bitwise_xor(img1, img2, mask=None) : 각 픽셀에 대한 비트와이즈 XOR 연산
- bitwise_not(img1, mask=None) : 각 픽셀에 대한 비트와이즈 NOT 연산
이미지 변형
이진화
- 이진화(Binary)는 어느 지점을 기준으로 값이 높거나 낮은 픽셀의 값을 대상으로 특정 연산을 수행할 때 사용
- 일반적으로 값이 높거나 낮은 픽셀을 검은색 또는 흰색의 값으로 변경
- 기준값에 따라 이분법적으로 구분해 픽셀을 참 또는 거짓으로 나누는 연산이며, 이미지 행렬에서 모든 픽셀에 대해 연산이 수행됩니다.
- 이진화하면 어떠한 경곗값을 기준으로 이진화하면 물체가 선명(뚜렷해짐)해지고 처리해야할 화소가 줄게되어 영상의 용량도 줄어듬
임계처리(Thresholing)
- 임계처리(thresholding)는 이미지 행렬에서 하나의 픽셀값을 사용자가 지정한 기준값(threshold)를 사용하여 이진화(binarization)하는 가장 단순한 필터임. 이진화는 이름에서 알 수 있듯이, 영상(사진)을 이진법처럼 두 가지로만 분류하는 것입니다.
- openCV에서 이진화는 기존의 영상을 검은색과 흰색으로만 이루어진 영상으로 바꾸어주는 작업
- <font color=blue>임계처리(thresholding)는 이미지를 그레이스케일로 변환한 후에 주로 수행</font>됩니다.
- `ret, dst = threshold(src, thresh, maxval, type)`
- src : 그레이 스케일 이미지
- thresh : 기준값
- maxval : 기준값을 넘었을 때 적용할 최대값
- type : 임계처리 유형
- THRESH_BINARY : 임계값 이상 = 최댓값, 임계값 이하 = 0
- THRESH_BINARY_INV : 위의 반전, 임계값 이상 = 0, 임계값 이하 = 최댓값
- THRESH_TRUNC : 임계값 이상 = 임계값, 임계값 이하 = 원본값
- THRESH_TOZERO : 임계값 이상 = 원본값, 임계값 이하 = 0
- THRESH_TOZERO_INV : 위의 반전, 임계값 이상 = 0, 임계값 이하 = 원본값
- ret : 임계값 반환
- dst : 이진화된 영상이 저장
Adaptive Threshold (적응형 스레스홀딩)
- 이미지를 작은 영역으로 나누어서 임계치 적용 - 이진화 처리가 어려운경우
(한쪽은 밝거나 한쪽은 어두운경우, 반사가 심하거나조명이 일정하지 않아 밝고 어둡고 한경우)
- `cv2.adaptiveThreshold(img, value, method, type_flag, block_size, C)`
- img: 원본 이미지
- value: 임계값을 만족하는 픽셀에 적용할 값
- method: 임계값 설정 방법
- cv2.ADAPTIVE_THRESH_MEAN_C: 이웃 픽셀의 평균으로 결정
- cv2.ADAPTIVE_THRESH_GAUSSIAN_C: 가우시안 분포에 따른 가중치의 합으로 결정
- type_flag: 스레시홀딩 적용 방법
- block_size: 영역으로 나눌 이웃의 크기(n x n), 홀수
- C: 계산된 임계값 결과에서 가감할 상수(음수 가능)
오츠 알고리즘
최적의 임계값 찾기 - trackbar 사용 안해도 됨 모든 이미지에 최적의 임계값을 찾는 건 아님 Bimodal Image에 사용하기에 적합(최적의 임계치를 자동으로 발견)
히스토그램 분석
- 히스토그램은 특정한 값을 가진 화소가 영상 안에 몇 개나 있는지를 막대그래프로 표시한 것으로 이미지의 픽셀 값(밝기 또는 색상)을 X축으로, 해당 값을 가진 픽셀의 개수를 Y축으로 표현합니다.
- 그레이스케일 히스토그램: 0(검정)부터 255(흰색)까지의 밝기 값 분포를 보여줍니다.
- 컬러 히스토그램: RGB 각 채널별로 별도의 히스토그램이 존재합니다
- 히스토그램으로 알 수 있는 정보
- 전체 밝기 분포: 이미지가 전반적으로 어두운지, 밝은지, 중간 톤인지 판단할 수 있습니다.
- 대비(Contrast): 히스토그램이 넓게 분포되어 있으면 대비가 높고, 좁게 모여있으면 대비가 낮습니다.
- 노출 상태: 히스토그램이 오른쪽으로 치우쳐 있으면 과노출, 왼쪽으로 치우쳐 있으면 저노출입니다.
- 다이내믹 레인지: 픽셀 값이 분포된 범위로, 이미지가 표현하는 밝기의 범위를 나타냅니다.
- 이미지 유형에 따른 히스토그램 해석석
- 1. 일반적인 고품질 이미지
- 픽셀 값이 전체 범위(0~255)에 골고루 분포
- 히스토그램이 양 끝(0이나 255)에 과도하게 집중되지 않음
- 2. 저대비 이미지
- 히스토그램이 중앙 부분에 좁게 집중됨
- 검정과 흰색 부분이 거의 없고 회색조가 대부분
- 3. 고대비 이미지
- 히스토그램이 넓은 범위에 분포함
- 어두운 부분과 밝은 부분의 차이가 뚜렷함
- 4. 저노출(어두운) 이미지
- 히스토그램이 왼쪽(어두운 부분)에 집중됨
- 오른쪽 부분(밝은 값)이 거의 비어있음
- 5. 과노출(밝은) 이미지
- 히스토그램이 오른쪽(밝은 부분)에 집중됨
- 왼쪽 부분(어두운 값)이 거의 비어있음
- cv2.calcHist(img, channel, mask, histSize, ranges)
- img: 히스토그램을 구하고 싶은 이미지 영상, [img]와 같이 리스트로 입력해주어야 함
- channel: 히스토그램을 구할 영상의 채널, grayscale 이미지의 경우 [0]을 인자로 입력하고 color 이미지일 경우 B, G, R에 대한 히스토그램을 구하기 위해서 [0], [1], [2]를 인자로 입력
- mask: 히스토그램을 구할 영역을 지정하는 마스크, None을 입력하면 전체 영상에서 히스토그램을 구함
- histSize: 히스토그램의 칸의 수를 지정, 보통 한 pixel당 0~255까지의 값을 가져 명암단계가 L = 256이기 때문에 [256]과 같이 리스트로 전달해주면 됨. 128로 지정하면 0과 1을 0, 2와 3을 1, ...로 간주해 128개의 칸을 가진 히스토그램을 구함.
- ranges: 각 픽셀값이 가질 수 있는 범위, 보통 [0,256]으로 지정, 만약 [0,128]로 지정했다면 128 이상인 값은 세지 않음.
- cv2.equalizeHist()
히스토그램 평활화(Histogram Equalization)
- 특정 영역에 집중되어 있는 영상의 히스토그램 분포를 평평하게 만들어 명암 대비를 높이는 기법
- 명암 값이 몰려 있어서 어둡기만 한 영상 또는 밝기만 한 영상을 평활화하여 좀 더 선명한 영상을 얻음음
- 영상의 명암 대비가 높아지면 영상에 있는 물체를 더 잘 식별할 수 있게됨
< L = 8인 4 x 4 크기의 영상 >
1) 계산된 히스토그램 분포 h(g)에 전체 크기인 16씩을 나눠주어 정규화 히스토그램 p(g)를 계산
2) 각 명암값 별로 이전까지의 정규화 히스토그램 p(g)값을 합쳐 누적 정규화 히스토그램 cdf(g)를 계산 : 마지막 1
3) 각 누적 정규화 히스토그램 값 cdf(g)에 최대 명암값(LmaxLmaxL_{max})인 7씩을 곱하고 반올림
- 이미지의 전반적인 대비를 개선하기 위해 사용되는 방법
- 특정 밝기 계급에 픽셀이 지나치게 집중되어 있을 때, 이 방식은 몇 가지 문제점을 초래할 수 있다. 예를 들면, 평활화 후의 이미지에서 나머지 계급의 세부 정보가 손실되거나, 비자연스러운 노이즈나 패턴이 발생할 수 있음
- 히스토그램 매칭(Histogram Matching)은 원하는 히스토그램 분포를 가진 참조 이미지를 사용하여, 타겟 이미지의 분포를 조정하는 방법(입력 이미지에 참조 이미지의 색감을 입히는 기법)
- **히스토그램 평활화 효과**
- 히스토그램이 너무 한쪽(어두운 쪽)에 몰려 있으면 전체적으로 밝게 펴주는 효과가 있음 => 하지만 무조건 밝게 만드는 게 아니라, 명암 대비(contrast)를 전체적으로 넓게 분포시키는 게 목적임.
- 히스토그램 평활화는 밝고 어두운 영역의 구분을 명확하게 해줍니다. => 흐릿하거나 뿌연 이미지를 더 뚜렷하게(선명하게) 보이게 만들 수 있음.
- `cv2.equalizeHist(img, dst)`
- img: 히스토그램 평활화를 적용시키고자 하는 영상
- dst: 결과 이미지(입력 안해도됨)
히스토그램 평활화 : 컬러 이미지
- 컬러영상에 히스토그램 평활화를 적용할 때 RGB 채널 각각에 히스토그램 평활화를 적용한 후 합치면 색이 변하는 문제가 일어날 수 있음(색이 왜곡되어 부자연스러운 이미지가 되기 때문)
- RGB는 색상(Hue), 명도(Value), 채도(Saturation)가 섞여 있어서, 각 채널을 독립적으로 평활화하면 원래 색상 관계가 깨져버리기 때문
- 먼저 RGB로 받은 이미지를 HSV 또는 YCrCb 형태의 이미지로 변경한 다음에 밝기값(V(Value)) 채널에 해당하는 V 또는 Y 채널에 대해서만 히스토그램 평활화를 적용해야 색을 변경하지 않고 선명하게 만들 수 있음
- HSV의 V만 평활화 : 색상 유지, 명도만 개선
- YCrCb의 Y만 평활화 : 방송용 영상에 적합
어핀 변환(Affine Transform)
- 평행 이동, 확대 및 축소, 회전, 스케일 변경, 뒤틀기 등 다양한 방식으로 변환할 수 있게 해주는 기법.
- 이 과정에서 이미지의 병렬성은 유지되지만, 각도와 크기는 변할 수 있음
- 영상에 어파인 변환을 적용할 경우 직선은 그대로 직선으로 나타나고,
- 직선 간의 길이 비율과 평행 관계가 그대로 유지된다.
- 직사각형 형태의 영상은 어파인 변환에 의해 평행사변형에 해당하는 모습으로 변경된다.
- 영상을 구성하는 픽셀의 배치 구조를 변경함으로써 전체 영상의 모양을 바꾸는 작업
1. 어파인 변환 행렬 구하기
- `martix = cv2.getAffineTransform(pts1, pts2)`
- pts1: 변환 전 영상의 좌표 3개, 3 x 2 배열
- pts2: 변환 후 영상의 좌표 3개, 3 x 2 배열
- matrix: 변환 행렬 반환, 2 x 3 행렬
2. 어파인 변환하기
- warpAffine() : src 영상을 어파인 변환하여 dst 영상을 생성하는 함수
- `cv2.warpAffine(src, M, dsize, dst=None, flags=None, borderMode=None, borderValue=None) -> dst`
• src: 입력 영상
• M: 2x3 어파인 변환 행렬. 실수형.
• dsize: 결과 영상 크기. (w, h) 튜플. (0, 0)이면 src와 같은 크기로 설정.
• dst: 출력 영상
• flags: 보간법. 기본값은 cv2.INTER_LINEAR.
• borderMode: 가장자리 픽셀 확장 방식. 기본값은 cv2.BORDER_CONSTANT.
• borderValue: cv2.BORDER_CONSTANT일 때 사용할 상수 값. 기본값은 0(검정색).
원근 변환(Perspective Transform) : 원근 이미지 ↔ 평면 이미지
스마트폰으로 문서를 찍으면 주변이 삐둘거리거나 사다리꼴형으로 되는데 이런 이미지를 직사각형으로 펼치는 방법
원근 변환은 이미지를 3차원으로 변환 - 원근법의 원리를 적용해 변환
- mtrx = cv2.getPerspectiveTransform(pts1, pts2)
- pts1: 변환 이전 영상의 좌표 4개, 4 x 2 배열
- pts2: 변환 이후 영상의 좌표 4개, 4 x 2 배열
- mtrx: 변환행렬 반환, 3 x 3 행렬
- cv2.warpPerspective()
영상 필터링 및 이미지 향상
블러링, 샤프닝, 에지 검출, 컨투어 검출 및 외곽선 그리기
특징 추출 및 고급 처리
SIFT, HOG, Haar