1. 필터링
-> 커널(filter)이라고 하는 행렬을 정의하고, 이 커널을 이미지 위에서 이동시켜 가면서 커널과 겹쳐진 이미지 영역과 연산을 한 후,
그 결과값을 연산 진행한 이미지 픽셀을 대신하여 새로운 이미지를 만드는 연산
filter2D(영상, 이미지 깊이, 커널, 중심점 좌표, 임계값(추가될 값), 가장자리 화소 자리)
-> 이미지 깊이: -1(입력과 동일)
-> 커널 행렬: 3*3, 5*3, ...
-> 가장자리 화소 처리
=> BORDER_CONSTANT
-> 000abcdefg000
-> 끝자리를 0으로 채운다.
-> 끝자리 색깔이 검은색이 된다.
=> BORDER_REPLICATE
-> aaaabcdefgggg
-> 끝의 자리를 연장시킨다.
2. 블러링(Blurring)
-> 초점이 맞지 않은듯 영상을 흐릿하게 하는 작업
-> 평균 블러링, 가우시안 블러링, 미디엄 블러링
2-1. 평균 블러링
-> 가장 일반적인 필터링 방법으로 균일한 값을 정규화 된 커널을 이용한 이미지 필터링 방법
-> 커널 영역 내에서 평균값으로 해당 픽셀을 대체한다.
-> 주변 픽셀들을 평균값을 적용하면 픽셀 간 차이가 적어져 선명도가 떨어져 전체적으로 흐려진다.
-> 필터의 크기가 클수록 평균 블러링을 적용했을 때 선명도가 떨어진다.
-> cv2.blur(영상, 커널)
2-2. 가우시안 블러링
- 가우시안 분포를 갖는 커널로 블러링 하는 것(정규 분포, 평균 근처에 몰려 있는 값들의 개수가
많고, 평균에서 멀어질수록 그 개수가 적어지는 분포)
- 대상 픽셀에 가까울수록 많은 영향을 주고, 멀어질수록 적은 영향을 주기 때문에 원래의 영상과
비슷하면서도 노이즈를 제거하는 효과가 있음
cv2.GaussianBlur(영상, 출력영상, 커널)
출력영상: (0, 0)이면 입력 영상과 같음
커널: 예) 3, 3*3
2-3. 미디언 블러링
- 커널의 필셀 값 중 중앙값을 선택
- 소금-후추 잡음을 제거하는 효과
cv2.medianBlur(영상, 커널)
2-4. 바이레터럴 필터(Bilateral Filter)
- 기존 블러링의 문제점(잡음을 제거하는 효과는 뛰어났지만, 경계도 흐릿하게 만드는 문제)을
개선하기 위해 나온 필터링 기법
- 경계도 뚜렷하고 노이즈도 제거되는 효과가 있지만 속도가 느리다는 단점이 존재
cv2.bilateralFilter(영상, 픽셀의 거리, 시그마컬러, 시그마 스페이스)
✔ 픽셀의 거리(필터의 직경): -1을 입력하면 자동 결정됨(5보다 크면 매우 느림)
✔ sigmaColor: 색공간의 시그마 값
✔ sigmSpace: 좌표공간의 시그마 값(값이 크면 멀리 떨어져 있는 픽셀들이 서로 영향을 미침)
✅ GPT 설명
블러(Blur)는 이미지에서 노이즈를 감소시키거나 세부 사항을 흐리게 만들어 부드러운 효과를 주는 이미지 필터링 기법입니다.
다양한 블러 필터가 있으며, 각각의 특징과 적용 용도를 설명하겠습니다.
1. 가우시안 블러 (Gaussian Blur):
- 가우시안 블러는 가우시안 함수를 사용하여 이미지를 흐리게 만드는 기법입니다.
- 주변 픽셀들의 가중치를 계산하여 이미지의 픽셀 값을 평균화합니다.
- 픽셀들과의 거리에 따라 가중치가 변하므로, 주변 픽셀들의 영향력이 중심 픽셀에서 멀어질수록 감소합니다.
- 주로 노이즈를 제거하고 이미지를 부드럽게 만들기 위해 사용됩니다.
2. 평균 블러 (Average Blur):
- 평균 블러는 커널 내 모든 픽셀 값을 평균화하여 흐림 효과를 주는 기법입니다.
- 커널 내의 픽셀 값들을 모두 더하고, 픽셀 수로 나누어 평균 값을 구합니다.
- 픽셀 값들이 고르게 퍼지므로 이미지가 일정한 정도로 흐려집니다.
- 가우시안 블러보다 계산이 빠르지만, 흐림 효과의 세세한 조절이 어렵습니다.
3. 메디안 블러 (Median Blur):
- 메디안 블러는 커널 내 픽셀 값들을 정렬하고 중앙 값(중간 값)을 선택하여 이미지를 흐리게 만드는 기법입니다.
- 주로 소금-후추 잡음(점 노이즈)을 제거하는데 효과적입니다.
- 픽셀 값들의 순서를 따로 정렬해야 하므로 계산 비용이 높을 수 있습니다.
4. 바이레터럴 필터 (Bilateral Filter):
- 바이레터럴 필터는 가우시안 블러와 유사하지만, 주변 픽셀들의 거리뿐만 아니라 밝기 차이도 고려하여 흐림 효과를 적용합니다.
- 밝기 차이가 크면 가중치가 감소하여 선명한 에지(경계)를 보존합니다.
- 에지 보존 필터로, 노이즈 제거와 선명도 유지를 동시에 수행할 수 있습니다.
5. 모션 블러 (Motion Blur):
- 모션 블러는 이미지에 일정한 방향으로 블러 효과를 주는 기법입니다.
- 주로 카메라 움직임이나 물체의 움직임을 표현하고자 할 때 사용됩니다.
- 가로 방향이나 세로 방향으로 블러를 적용하여 움직이는 물체의 흔들림 효과를 연출합니다.
이외에도 더 다양한 블러 기법들이 있으며, 각각의 블러는 이미지 처리에서 다양한 용도로 활용됩니다. 블러 기법을 적절하게 선택하면
이미지에 원하는 효과를 부여하거나 노이즈를 감소시킬 수 있습니다.
3. 엣지(Edge) 검출
- 영상에서 화소의 밝기가 급격하게 변하는 부분
- 물체의 윤곽선(경계선)이 해당
- 엣지를 검출할 수 있으면 물체의 윤곽선을 알 수 있음
- "캐니 엣지 검출" 상당한 수준으로 엣지를 신뢰성 있게 검출하는 방법
1. 노이즈 제거: 5*5 가우시안 블러링 필터
2. 경계 그레디언트 방향 계산: 소벨 필터로 경계 및 그레디언트 방향 검출
3. 비최대치 억제: 그레디언트 방향에서 검출된 경계 중 가장 큰 값만 선택하고, 나머지는 제거
4. 이력 스레시홀딩: 두 개의 경계값(Max, Min)을 지정해서 경계 연역에 있는 픽셀들 중
큰 경계 값(Max) 밖의 픽셀과 연결성이 없는 픽셀 제거
cv2.Canny(영상, 최소임계값, 최대임계값, 커널사이즈)
💡 문제.
- 웹캠 영상에서 스페이스바를 누를때 마다 "일반영상", "가우시안 필터영상", "케니 필터영상"으로
변환되는 프로그램을 작성
4. 모폴로지 처리
영상의 밝은 영상이나 어두운 영역을 축소, 확대하는 기법
모폴로지 구조 요소를 생성
cv2.getStructuringElement(구조 요소의 모양, 사이즈)
구조 요소의 모양
cv2.MORPH_RECT: 사각형
cv2.MORPH_EPLIPSE: 타원형
cv2.MORPH_CROSS: 십자형
- 침식(erosion) 연산
-> 이미지를 깎아 내는 연산
-> 객체 크기는 감소하고 배경은 확대
-> 작은 크기의 객체(잡음) 제거 효과가 있음
cv2.erode(영상, 구조요소, 출력영상, 고정점 위치)
- 팽창(dilation) 연산
-> 물체의 주변을 확장하는 연산
-> 팽창 연산은 객체 외곽을 확대시키는 연산
-> 객체 크기는 증가되고 배경은 감소
-> 객체 내부의 홀이 있다면 홀이 채워지는 효과
cv2.dilate(영상, 구조요소, 출력영상, 고정점 위치)
✅ GPT 설명
모폴로지 처리는 영상에서 밝은 영역이나 어두운 영역을 축소하거나 확대하는 기법을 말합니다. 주로 이진화된 영상(흑백 영상)에 적용되며,
객체의 형태를 변경하거나 작은 객체(잡음)를 제거하는 데 사용됩니다. 모폴로지 처리에는 주로 침식과 팽창 연산이 사용됩니다.
1. 침식(Erosion) 연산:
- 침식 연산은 이미지를 깎아 내는 연산입니다.
- 이미지에서 밝은 영역을 줄이고 어두운 영역을 확대하는 효과가 있습니다.
- 객체 크기는 감소하고 배경은 확대됩니다.
- 작은 크기의 객체(잡음)를 제거하는 효과가 있어서 이미지 전처리 과정에서 잡음을 제거하기 위해 사용됩니다.
2. 팽창(Dilation) 연산:
- 팽창 연산은 이미지를 팽창시키는 연산입니다.
- 이미지에서 밝은 영역을 확대하고 어두운 영역을 줄이는 효과가 있습니다.
- 객체 크기가 증가하고 배경은 감소합니다.
- 객체를 확대하거나 구멍을 메우는 데 사용됩니다.
이러한 모폴로지 연산은 구조 요소(structuring element)라고 하는 작은 커널 형태의 마스크를 사용하여 수행됩니다. 구조 요소는 이동시키면서
픽셀과의 연산을 수행하며, 이미지의 특정 지점에 구조 요소를 중심으로 겹쳐 놓는 고정점 위치가 지정됩니다. 침식과 팽창 연산은 이 구조 요소를
이용하여 영상의 특정 지점을 수정하면서 수행됩니다.
예를 들어, 침식 연산은 구조 요소 내 모든 픽셀이 1인 경우에만 해당 픽셀을 1로 만듭니다. 따라서 구조 요소의 크기에 따라 객체가 작아질 수 있습니다.
반면, 팽창 연산은 구조 요소 내 하나 이상의 픽셀이 1인 경우 해당 픽셀을 1로 만듭니다. 따라서 구조 요소의 크기에 따라 객체가 커질 수 있습니다.
모폴로지 처리는 주로 영상에서 객체를 분리하거나 노이즈를 제거하는 등의 전처리 과정에서 활용되며, 이미지의 형태를 변경하는데 유용합니다.
* 침식은 어두운 부분의 노이즈를 제거하는 효과
* 팽창은 밝은 부분의 노이즈를 제거하는 효과
* 노이즈를 제거 효과는 좋으나, 원래 모양이 홀쭉해지거나 뚱뚱해지는 변형이 일어남
- 열림(Opening) 연산
- 팽창 연산과 침식 연산의 조합
- 침식 연산을 적용한 다음, 팽창 연산을 적용
- 침식 연산으로 인해 밝은 영역이 줄어들고, 어두운 영역이 늘어남
- 객체의 크기 감소를 원래대로 복구 할 수 있음
- 닫힘(Closing0 연산
- 팽창 연산과 침식 연산의 조합
- 팽창 연산을 적용한 다음, 침식 연산을 적용
- 어두운 영역이 줄어들고, 밝은 영역이 늘어남
- 늘어난 영역을 다시 복구하기 위해 침식 연산을 적용하면 밝은 영역이 줄어들고 어두운 영역이 늘어남
- 객체 내부의 홀이 사라지면서 발생한 크기 증가를 복구할 수 있음
- 그레디언트(Gradient)
- 팽창 연산과 침식 연산의 조합
- 열림 연산이나 닫힘 연산과 달리 입력 이미지에 각각 팽창 연산과 침식 연산을 적용하고 감산을 진행
cv2.morphologyEx(영상, 연산방법, 구조요소)
연산방법
cv2.MORPH_DILATE : 팽창 연산
cv2.MORPH_ERODE : 침식 연산
cv2.MORP_CLOSE : 닫힘 연산
cv2.MORP_GRADIENT : 그레디언트 연산
5. 레이블링
- 이진화, 모폴로지를 수행하면 객체와 배경 영역을 구분할 수 있게됨
- 객체 단위 분석을 통해 각 객체를 분할하여 특징을 분석하고 객체의 위치, 크기 정보, 모양 분석, ROI 추출 등이 가능함
- 서로 연결되어 있는 객체 픽셀에 고유번호를 할당하여 영역 기반 모양분석, 레이블맵, 바운딩 박스, 픽셀개수, 무게중심, 좌표 등을
반환할 수 있게 함
cv2.connectedComponents(영상, 레이블맵)
✔ 레이블맵: 픽셀 연결 관계(4방향 연결, 8방향 연결)
✔ return: 객체개수, 레이블 맵 행렬
cv2.connectedComponentsWithStats(영상, 레이블맵)
✔ return: 객체개수, 레이블 맵 행렬, (객체위치, 가로세로길이, 면적 등 행렬), 무게중심 정보
6. 객체의 외곽선 검출
- 레이블링과 함께 영상에 객체의 정보를 검출하는 방법 중 하나
- 이진화된 영상에서 검출되며 배경 영역과 당하 있는 픽셀을 찾아 외곽선으로 인식
- 외곽선은 객체 외부 뿐 아니라 내부에도 생길 수 있음
cv2.findContours(영상, 검출모드, 외곽선 좌표 근사화 방법)
✔ 검출모드
RETR_EXTERNAL: 객체 외부 외곽선만 검출
RETR_LIST: 객체 외부, 내부 외곽선 모두 검출
RETR_CCOMP: 모든 외곽선 검출, 2단계 계층 구조를 구성
RETR_TREE: 모든 외곽선 검출, 전체 계층 구조 구성
✔ 외곽선 좌표 근사화 방법
CHAIN_APPROX_NONE: 모든 외곽선 좌표를 저장
CHAIN_APPROX_SIMPLE: 외곽선 중에서 수평, 수직, 대각선 성분은 끝 점만 저장
✔ 외곽선 그리기
cv2.drawContours(영상, 외곽선 좌표정보, 외곽선 인덱스, 색상, 두께)
외곽선 인덱스: -1을 지정하면 모든 외곽선을 그림
✔ 외곽선 길이 구하기
cv2.arclength(외곽선 좌표, 폐곡선 여부)
✔ 면적 구하기
cv2.contourArea(외곽선 좌표, False)
✔ 바운딩 박스 구하기
cv2.boundingRect(외곽선 좌표)
✔ 외곽선 근사화
:검출한 윤곽선 정보를 분석하여 정점수가 적은 윤곽선 또는 다각형으로 표현할 수 있게 만드는 것
cv2.approxPolyDP(외곽선 좌표, 근사화 정밀도 조절, 폐곡선 여부)
- 근사화 정밀도 조절: 입력 컨투어와 근사화된 컨투어 사이의 최대 거리. 값이 작을수록 다각형이
정확해지고, 꼭지점의 수가 늘어남
cv2.isCountourConvex()
contour에 오목한 부분이 있는지 체크(있으면 True, 없으면 False)
cv2.convexHull()
contour에 있는 오목한 부분을 제거
import cv2
import matplotlib.pyplot as plt
import numpy as np
img = cv2.imread('./image/dog.bmp')
dst1 = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
dst2 = cv2.blur(img, (3, 3))
cv2.imshow('img', img)
cv2.imshow('dst2', dst2)
plt.figure(figsize=(10, 5))
for i, k in enumerate([3, 5, 9]):
kernel = np.ones((k, k)) / k ** 2
filtering = cv2.filter2D(dst1, -1, kernel)
plt.subplot(1, 3, i+1)
plt.imshow(filtering)
plt.title('kernel size:{}'.format(k))
plt.axis('off')
plt.show()
cv2.waitKey()
✅ 코드해석
이 코드는 Python에서 OpenCV와 Matplotlib을 사용하여 이미지를 로드하고 필터링하는 간단한 예제입니다. 코드는 다음과 같이 구성됩니다:
1. `import` 문을 사용하여 필요한 라이브러리를 가져옵니다.
2. `cv2.imread('./dog.bmp')`: 'dog.bmp' 파일을 읽어서 이미지 데이터를 `img` 변수에 저장합니다. 해당 이미지는 현재 작업 디렉토리에서 찾아집니다.
3. `cv2.cvtColor(img, cv2.COLOR_BGR2RGB)`: `img`의 색상을 BGR에서 RGB로 변환하여 `dst1`에 저장합니다. OpenCV는 기본적으로 BGR 색상 순서를 사용하지만,
일반적으로 Matplotlib과 같은 다른 라이브러리는 RGB 색상 순서를 사용하므로 변환해야 합니다.
4. `cv2.blur(img, (3, 3))`: `img`를 블러(흐림) 처리하여 `dst2`에 저장합니다. 이는 커널의 크기가 (3, 3)인 평균 블러를 수행합니다.
5. Matplotlib를 사용하여 이미지를 시각화합니다.
- `plt.figure(figsize=(10, 5))`: 새로운 Matplotlib 그림을 생성하고 크기를 설정합니다.
- `for i, k in enumerate([3, 5, 9]):`: 커널 크기가 3, 5, 9인 3가지 필터링 결과를 시각화합니다.
- `kernel = np.ones((k, k)) / k ** 2`: 크기가 (k, k)인 필터 커널을 생성합니다. 이 예제에서는 평균 필터를 사용합니다.
- `filtering = cv2.filter2D(dst1, -1, kernel)`: `dst1` 이미지에 커널을 적용하여 필터링한 결과를 `filtering` 변수에 저장합니다.
- `plt.subplot(1, 3, i+1)`: 현재 그림의 위치를 설정합니다. 1행 3열의 서브플롯 중 i+1 번째를 선택합니다.
- `plt.imshow(filtering)`: `filtering` 이미지를 시각화합니다.
- `plt.title('kernel size:{}'.format(k))`: 서브플롯의 제목을 지정합니다.
- `plt.axis('off')`: 축을 보이지 않도록 설정합니다.
6. `plt.show()`: Matplotlib로 그린 모든 그림을 표시합니다.
7. `cv2.waitKey()`: `cv2.imshow()` 함수로 보여진 이미지들이 화면에서 유지되도록 기다립니다. 아무 키나 누를 때까지 기다립니다.
코드를 실행하면 이미지가 먼저 OpenCV 창에 표시되고, 그 다음 Matplotlib 창에 필터링된 결과가 표시될 것입니다.
필터링 결과는 커널 크기에 따라서 다르게 나타날 것입니다.
✅ 결과해석
이 코드는 주어진 'dog.bmp' 이미지를 불러와서 두 가지 방법으로 필터링하여 결과를 시각화하는 예제입니다. 첫 번째로는 OpenCV를 사용하여 이미지를 블러 처리하고(`cv2.blur`), 두 번째로는 Matplotlib와 NumPy를 사용하여 커널 크기가 3, 5, 9인 평균 필터를 적용하여 이미지를 필터링합니다. 결과를 보면 이미지의 흐림 정도가 커널 크기에 따라 달라지는 것을 확인할 수 있습니다.
1. `cv2.blur`를 사용하여 이미지를 블러 처리한 결과:
- `dst2 = cv2.blur(img, (3, 3))`: (3, 3) 크기의 평균 필터를 적용하여 이미지를 블러 처리합니다. 평균 필터는 커널 내 모든 픽셀의 평균 값을 중심 픽셀의 값으로 설정하여 흐림 효과를 주는 필터입니다.
2. Matplotlib와 NumPy를 사용하여 평균 필터를 적용한 결과:
- `for i, k in enumerate([3, 5, 9]):`: 커널 크기가 3, 5, 9인 평균 필터를 순차적으로 적용합니다.
- `kernel = np.ones((k, k)) / k ** 2`: 크기가 (k, k)인 2차원 배열을 생성하고, 모든 요소를 1로 초기화한 후 k ** 2로 나눠주어 평균 필터 커널을 생성합니다.
- `filtering = cv2.filter2D(dst1, -1, kernel)`: `dst1` 이미지에 커널을 적용하여 평균 필터링한 결과를 `filtering` 변수에 저장합니다.
- `plt.imshow(filtering)`: Matplotlib를 사용하여 `filtering` 이미지를 시각화합니다.
코드의 실행 결과를 해석하면:
1. OpenCV를 사용하여 블러 처리한 결과 (`dst2`):
- `dst2`에는 원본 이미지인 `img`에 (3, 3) 크기의 평균 필터를 적용하여 얻은 블러 처리된 이미지가 저장됩니다.
- 이 결과는 이미지가 흐릿하고 부드럽게 보이는 효과를 줍니다. 따라서 이미지의 세부 사항이 흐려지고 경계가 부드러워집니다.
2. Matplotlib와 NumPy를 사용하여 평균 필터를 적용한 결과:
- 각 커널 크기(3, 5, 9)에 대해 평균 필터를 적용하여 이미지를 필터링한 결과가 시각화됩니다.
- 커널 크기가 커질수록 이미지의 흐림 정도가 더욱 강해지는 것을 볼 수 있습니다. 이는 평균 필터의 크기가 커질수록 주변 픽셀들의 영향을 더 많이 받아 흐려지는 효과가 증가하기 때문입니다.
- `kernel size: 3`: 상대적으로 세밀한 블러 효과를 가지고 있습니다.
- `kernel size: 5`: 블러 효과가 강해지고 이미지의 세부 사항이 흐려집니다.
- `kernel size: 9`: 가장 강한 블러 효과로 이미지의 경계가 더욱 부드러워집니다.
이러한 결과들을 통해 다양한 필터 크기가 이미지에 어떤 영향을 미치는지 이해할 수 있습니다. 필터링은 영상 처리에서 많이 사용되며, 커널의 크기와 형태에 따라 이미지를 부드럽게 하거나 경계를 강조하는 등 다양한 효과를 적용할 수 있습니다.
import cv2
img = cv2.imread('./image/dog.bmp')
dst1= cv2.GaussianBlur(img,(0,0),3)
cv2.imshow('dst1',dst1)
cv2.waitKey()
✅ 코드해석 및 결과해석
이 코드는 OpenCV를 사용하여 'dog.bmp' 이미지를 로드하고 가우시안 블러와 평균 블러를 적용하여 결과를 출력하는 예제입니다.
1. `cv2.imread('./dog.bmp', cv2.IMREAD_GRAYSCALE)`: 'dog.bmp' 파일을 그레이스케일로 읽어서 `img` 변수에 저장합니다.
`cv2.IMREAD_GRAYSCALE` 옵션을 사용하여 이미지를 흑백(그레이스케일)로 읽습니다.
2. `cv2.GaussianBlur(img, (0, 0), 3)`: `img`에 가우시안 블러를 적용하여 `dst1`에 저장합니다. 가우시안 블러는 이미지를
흐리게 만들기 위해 가우시안 커널을 적용하는데, `(0, 0)`은 커널의 크기를 자동으로 계산하도록 하고, `3`은 가우시안 커널의 표준 편차를 의미합니다.
이로 인해 이미지가 흐려지게 됩니다.
3. `cv2.blur(img, (5, 5))`: `img`에 평균 블러를 적용하여 `dst2`에 저장합니다. 평균 블러는 커널 내 모든 픽셀의 평균 값을
중심 픽셀의 값으로 설정하여 흐림 효과를 주는데, `(5, 5)`는 커널의 크기를 (5, 5)로 설정합니다.
4. `cv2.imshow('dst1', dst1)`: `dst1` 이미지를 'dst1'이라는 창에 표시합니다. 이 때, 'dst1' 창에는 가우시안 블러가 적용된 그레이스케일 이미지가 표시됩니다.
5. `cv2.imshow('dst2', dst2)`: `dst2` 이미지를 'dst2'라는 창에 표시합니다. 이 때, 'dst2' 창에는 평균 블러가 적용된 그레이스케일 이미지가 표시됩니다.
6. `cv2.waitKey()`: `cv2.imshow()` 함수로 보여진 이미지들이 화면에서 유지되도록 기다립니다. 아무 키나 누를 때까지 기다립니다.
코드 실행 결과를 해석하면:
1. `dst1`: 가우시안 블러가 적용된 이미지로, 이미지가 흐려지고 부드러워집니다. 가우시안 블러는 주로 노이즈를 감소시키고 이미지를 부드럽게 처리하는데 사용됩니다.
2. `dst2`: 평균 블러가 적용된 이미지로, 이미지의 세부 사항이 더욱 흐려집니다. 평균 블러는 가우시안 블러와 비슷하지만 블러 효과가 더 강하고 부드러워집니다.
따라서 이 코드는 가우시안 블러와 평균 블러를 사용하여 이미지를 다른 방식으로 흐리게 처리하고 결과를 확인하는 예제입니다.
import cv2
img = cv2.imread('./image/noise.bmp',cv2.IMREAD_GRAYSCALE)
dst = cv2.medianBlur(img,3)
cv2.imshow('img',img)
cv2.imshow('dst',dst)
cv2.waitKey()
✅ 코드해석 및 결과해석
이 코드는 OpenCV를 사용하여 'noise.bmp' 이미지를 로드하고 메디안 블러를 적용하여 결과를 출력하는 예제입니다.
1. `cv2.imread('./noise.bmp', cv2.IMREAD_GRAYSCALE)`: 'noise.bmp' 파일을 그레이스케일로 읽어서 `img` 변수에 저장합니다. `cv2.IMREAD_GRAYSCALE` 옵션을 사용하여 이미지를 흑백(그레이스케일)로 읽습니다.
2. `cv2.medianBlur(img, 3)`: `img`에 메디안 블러를 적용하여 `dst`에 저장합니다. 메디안 블러는 커널 내의 픽셀들을 정렬하고 중앙 값(중간 값)을 선택하여 이미지를 흐리게 만드는 기법입니다. `(3, 3)`은 메디안 블러의 커널 크기를 (3, 3)으로 설정합니다. 커널 크기가 홀수인 경우, 중앙 값을 계산하기 용이합니다.
3. `cv2.imshow('img', img)`: `img` 이미지를 'img'라는 창에 표시합니다. 이 때, 'img' 창에는 원본 그레이스케일 이미지가 표시됩니다.
4. `cv2.imshow('dst', dst)`: `dst` 이미지를 'dst'라는 창에 표시합니다. 이 때, 'dst' 창에는 메디안 블러가 적용된 흐림 효과가 표시됩니다.
5. `cv2.waitKey()`: `cv2.imshow()` 함수로 보여진 이미지들이 화면에서 유지되도록 기다립니다. 아무 키나 누를 때까지 기다립니다.
코드 실행 결과를 해석하면:
1. `img`: 'noise.bmp' 파일을 로드하여 원본 그레이스케일 이미지를 표시합니다.
2. `dst`: 메디안 블러가 적용된 흐림 효과가 있는 이미지를 표시합니다. 메디안 블러는 주로 소금-후추 잡음(점 노이즈)을 제거하는데 효과적입니다. 따라서 'noise.bmp' 이미지에 있는 노이즈가 감소되고, 이미지가 흐려져서 부드러워진 것을 확인할 수 있습니다.
메디안 블러는 노이즈 제거에 매우 효과적이며, 에지 보존 필터로서 이미지 선명도를 유지할 수 있는 장점이 있습니다. 이를 통해 이미지 처리에서 소금-후추 잡음 등의 노이즈를 효과적으로 감소시킬 수 있습니다.
import cv2
img = cv2.imread('./image/gaussian_noise.jpg', cv2.IMREAD_GRAYSCALE)
dst1 = cv2.GaussianBlur(img, (5, 5), 0)
dst2 = cv2.bilateralFilter(img, 5, 80, 80)
cv2.imshow('img', img)
cv2.imshow('dst1', dst1)
cv2.imshow('dst2', dst2)
cv2.waitKey()
✅ 코드해석 및 결과해석
이 코드는 OpenCV를 사용하여 'gaussian_noise.jpg' 이미지를 로드하고 가우시안 블러와 바이레터럴 필터를 적용하여 결과를 출력하는 예제입니다.
1. `cv2.imread('./gaussian_noise.jpg', cv2.IMREAD_GRAYSCALE)`: 'gaussian_noise.jpg' 파일을
그레이스케일로 읽어서 `img` 변수에 저장합니다.
`cv2.IMREAD_GRAYSCALE` 옵션을 사용하여 이미지를 흑백(그레이스케일)로 읽습니다.
2. `cv2.GaussianBlur(img, (5, 5), 0)`: `img`에 가우시안 블러를 적용하여 `dst1`에 저장합니다. 가우시안 블러는 이미지를 흐리게 만들기 위해
가우시안 커널을 적용하는데, `(5, 5)`는 커널의 크기를 (5, 5)로 설정하고, `0`은 가우시안 커널의 표준 편차를 의미합니다.
3. `cv2.bilateralFilter(img, 5, 80, 80)`: `img`에 바이레터럴 필터를 적용하여 `dst2`에 저장합니다. 바이레터럴 필터는 가우시안 블러와 유사하지만,
주변 픽셀들의 거리뿐만 아니라 밝기 차이도 고려하여 흐림 효과를 적용합니다. `(5, 5)`는 필터의 크기를 설정하고, `80`은 색상 공간에서의 시그마 값을 의미하며,
`80`은 좌표 공간에서의 시그마 값을 의미합니다.
4. `cv2.imshow('img', img)`: `img` 이미지를 'img'라는 창에 표시합니다. 이 때, 'img' 창에는 원본 그레이스케일 이미지가 표시됩니다.
5. `cv2.imshow('dst1', dst1)`: `dst1` 이미지를 'dst1'라는 창에 표시합니다. 이 때, 'dst1' 창에는 가우시안 블러가 적용된 흐림 효과가 표시됩니다.
6. `cv2.imshow('dst2', dst2)`: `dst2` 이미지를 'dst2'라는 창에 표시합니다. 이 때, 'dst2' 창에는 바이레터럴 필터가 적용된 흐림 효과가 표시됩니다.
7. `cv2.waitKey()`: `cv2.imshow()` 함수로 보여진 이미지들이 화면에서 유지되도록 기다립니다. 아무 키나 누를 때까지 기다립니다.
코드 실행 결과를 해석하면:
1. `img`: 'gaussian_noise.jpg' 파일을 로드하여 원본 그레이스케일 이미지를 표시합니다.
2. `dst1`: 가우시안 블러가 적용된 이미지로, 이미지가 흐려지고 부드러워집니다. 가우시안 블러는 주로 노이즈를 감소시키고
이미지를 부드럽게 만들기 위해 사용됩니다.
3. `dst2`: 바이레터럴 필터가 적용된 이미지로, 가우시안 블러와는 다르게 이미지의 에지(경계)가 보존됩니다. 바이레터럴 필터는
노이즈 제거와 함께 이미지 선명도를 유지할 수 있는 필터로 사용됩니다.
이미지의 세 가지 버전을 통해 각각의 필터링 기법이 이미지에 어떤 영향을 미치는지 확인할 수 있습니다. 블러 필터는 이미지 처리에서
다양한 용도로 활용되며, 이미지에 원하는 효과를 부여하는데 유용합니다.
import cv2
import numpy as np
img = cv2.imread('./image/dog.bmp')
med_val = np.median(img)
lower = int(max(0, 0.7*med_val))
upper = int(min(255, 1.3*med_val))
dst = cv2.GaussianBlur(img, (3, 3), 0, 0)
dst = cv2.Canny(dst, lower, upper, 3)
cv2.imshow('img', img)
cv2.imshow('dst', dst)
cv2.waitKey()
✅ 이 코드는 Python에서 OpenCV(Open Source Computer Vision Library)를 사용하여 이미지 처리를 수행하는 예제입니다. 아래에서 코드의 각 부분을 해석하고 결과를 설명하겠습니다.
1. `cv2.imread('./image/dog.bmp')`: 'dog.bmp'라는 파일을 읽어옵니다. `cv2.imread` 함수는 이미지를 불러오는 함수로, 파일 경로를 지정하여 이미지를 읽어옵니다.
2. `med_val = np.median(img)`: 이미지의 픽셀값 중간값(median)을 계산합니다. 중간값은 픽셀값들을 정렬한 후 중간에 있는 값을 나타냅니다.
3. `lower = int(max(0, 0.7*med_val))` 및 `upper = int(min(255, 1.3*med_val))`: 중간값을 기반으로 경계값(lower와 upper)을 계산합니다. 이 값들은 이후 Canny 에지 검출을 위해 사용됩니다. 경계값은 중간값을 기준으로 일정 비율(0.7과 1.3)을 사용하여 계산하며, 0과 255 사이의 값으로 제한됩니다.
4. `dst = cv2.GaussianBlur(img, (3, 3), 0, 0)`: 이미지에 가우시안 블러(Gaussian Blur)를 적용합니다. 이것은 이미지를 부드럽게 만들어 노이즈를 제거하는데 사용됩니다. `(3, 3)`은 커널 크기를 나타내며, `(0, 0)`은 가우시안 커널의 표준 편차를 나타냅니다.
5. `dst = cv2.Canny(dst, lower, upper, 3)`: Canny 에지 검출 알고리즘을 적용합니다. 이 알고리즘은 이미지에서 엣지(경계)를 감지하는 데 사용됩니다. `lower`와 `upper`는 경계값을 나타내며, `3`은 커널 크기를 나타냅니다.
6. `cv2.imshow('img', img)`: 원본 이미지를 표시합니다.
7. `cv2.imshow('dst', dst)`: Canny 에지 검출 결과를 표시합니다.
8. `cv2.waitKey()`: 키보드 입력을 기다리며, 어떤 키든 누를 때까지 창을 열어 놓습니다.
이 코드는 원본 이미지를 불러와서 중간값을 계산하고, 이를 기반으로 가우시안 블러 및 Canny 에지 검출을 수행합니다. 결과 이미지는 두 개의 창에 표시되며, 사용자가 키를 누를 때까지 창이 열려 있습니다. 결과 이미지에는 Canny 에지 검출 결과가 나타납니다.
💡 문제.
- 웹캠 영상에서 스페이스바를 누를때 마다 "일반영상", "가우시안 필터영상", "케니 필터영상"으로
변환되는 프로그램을 작성
🤷♂️ 내가 짠 코드(캠 모드가 안 됐어서, 영상이미지를 갖고 조작함)
# 영상모드
import cv2
cap = cv2.VideoCapture('./image/tiger.mp4')
isKeypress = 0 # 0: 일반 영상, 1: 가우시안 필터 영상, 2: 케니 필터 영상
while True:
ret, frame = cap.read()
if not ret:
break
if isKeypress == 1:
# 가우시안 필터 적용
frame = cv2.GaussianBlur(frame, (5, 5), 0)
elif isKeypress == 2:
# 케니 필터 적용
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
frame = cv2.Canny(frame, 100, 200)
cv2.imshow('Tiger Video', frame)
key = cv2.waitKey(10)
if key == ord(' '):
isKeypress = (isKeypress + 1) % 3
elif key == 27: # ESC key
break
cap.release()
cv2.destroyAllWindows()
tiger.mp4
8.50MB
🧑🏫 강사님 코드(캠 모드 적용)
# 캠모드
import cv2
import numpy as np
cap = cv2.VideoCapture(0)
def blur_filter(img):
img = cv2.GaussianBlur(img, (0, 0), 3)
return img
def canny_fileter(img):
med_val = np.median(img)
lower = int(max(0, 0.7*med_val))
upper = int(min(255, 1.3*med_val))
img = cv2.GaussianBlur(img, (3, 3), 0, 0)
img = cv2.Canny(img, lower, upper, 3)
return img
cam_mode = 0
while True:
ret, frame = cap.read()
if cam_mode == 1:
frame = blur_filter(frame)
elif cam_mode == 2:
frame = canny_fileter(frame)
cv2.imshow('frame', frame)
key = cv2.waitKey(10)
if key == 27:
break
elif key == ord(' '):
cam_mode += 1
if cam_mode == 3:
cam_mode = 0
cap.release()
✅ 위 변화들은 Space바 키를 통해 이뤄짐!
import cv2
img = cv2.imread('./image/circuit.bmp', cv2.IMREAD_GRAYSCALE)
se = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 3))
dst1 = cv2.erode(img, se)
dst2 = cv2.dilate(img, None) # 3*3
cv2.imshow('img', img)
cv2.imshow('dst1', dst1)
cv2.imshow('dst2', dst2)
cv2.waitKey()
✅ 코드해석 및 결과해석
이 코드는 OpenCV를 사용하여 'circuit.bmp' 이미지를 로드하고, 침식(Erosion) 연산과 팽창(Dilation) 연산을 각각 수행하여 결과를 출력하는 예제입니다.
1. `cv2.imread('./circuit.bmp', cv2.IMREAD_GRAYSCALE)`: 'circuit.bmp' 파일을 그레이스케일로 읽어서 `img` 변수에 저장합니다.
`cv2.IMREAD_GRAYSCALE` 옵션을 사용하여 이미지를 흑백(그레이스케일)로 읽습니다.
2. `cv2.getStructuringElement(cv2.MORPH_RECT, (5, 3))`: `cv2.MORPH_RECT` 모드로 지정된 사각형 형태의 구조 요소(`se`)를 생성합니다.
`(5, 3)`은 사각형 구조 요소의 크기를 (5, 3)로 설정한 것입니다.
3. `cv2.erode(img, se)`: `img` 이미지에 생성한 구조 요소(`se`)를 사용하여 침식 연산을 수행하고, 그 결과를 `dst1`에 저장합니다.
침식 연산은 이미지를 깎아 내는 연산으로, 객체 크기를 감소시키고 배경을 확대하는 효과가 있습니다. 구조 요소 내 모든 픽셀이 1인 경우에만 해당 픽셀을 1로 만들어 영상을 수정합니다.
4. `cv2.dilate(img, None)`: `img` 이미지에 기본적인 구조 요소를 사용하여 팽창 연산을 수행하고, 그 결과를 `dst2`에 저장합니다.
팽창 연산은 이미지를 팽창시키는 연산으로, 객체 크기를 증가시키고 배경을 감소시키는 효과가 있습니다. 이 때, `None`을 입력으로 주면 기본적인 3x3 크기의 구조 요소를 사용합니다.
5. `cv2.imshow('img', img)`: `img` 이미지를 'img'라는 창에 표시합니다. 이 때, 'img' 창에는 원본 그레이스케일 이미지가 표시됩니다.
6. `cv2.imshow('dst1', dst1)`: `dst1` 이미지를 'dst1'라는 창에 표시합니다. 이 때, 'dst1' 창에는 침식 연산이 적용된 흐림 효과가 표시됩니다.
7. `cv2.imshow('dst2', dst2)`: `dst2` 이미지를 'dst2'라는 창에 표시합니다. 이 때, 'dst2' 창에는 팽창 연산이 적용된 효과가 표시됩니다.
8. `cv2.waitKey()`: `cv2.imshow()` 함수로 보여진 이미지들이 화면에서 유지되도록 기다립니다. 아무 키나 누를 때까지 기다립니다.
코드 실행 결과를 해석하면:
1. `img`: 'circuit.bmp' 파일을 로드하여 원본 그레이스케일 이미지를 표시합니다.
2. `dst1`: 침식 연산이 적용된 이미지로, 이미지가 흐려지고 부드러워집니다. 침식 연산은 객체 크기를 감소시키고 배경을 확대하는 효과가 있으므로,
원본 이미지의 선명한 에지(경계)가 흐려지는 결과를 확인할 수 있습니다.
3. `dst2`: 팽창 연산이 적용된 이미지로, 이미지가 팽창되어 객체가 커집니다. 팽창 연산은 객체 크기를 증가시키고 배경을 감소시키는 효과가 있습니다.
이렇게 침식과 팽창 연산은 모폴로지 처리에서 사용되는 기본적인 연산으로서, 객체 분리, 노이즈 제거, 객체 형태 변경 등에 활용됩니다.
import cv2
img = cv2.imread('./image/keyboard.bmp', cv2.IMREAD_GRAYSCALE)
_, img_bin = cv2.threshold(img, 0, 255, cv2.THRESH_OTSU)
dst = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
cnt, labels, stats, centroids = cv2.connectedComponentsWithStats(img_bin)
# print(cnt)
# print(labels)
# print(stats)
# print(centroids)
for i in range(1, cnt):
(x, y, w, h, area) = stats[i]
if area < 20:
continue
cv2.rectangle(dst, (x, y, w, h), (0, 255, 255))
cv2.imshow('img', img)
cv2.imshow('img_bin', img_bin)
cv2.imshow('dst', dst)
cv2.waitKey()
✅ 코드해석
위 코드에서 출력된 결과는 다음과 같습니다:
1. `cnt`: 영상에서 검출된 레이블(객체)의 개수입니다. 총 38개의 객체가 검출되었습니다. 이 중 하나는 배경을 나타내는 레이블이므로 37개의 실제 객체가 있음을 나타냅니다.
2. `labels`: 영상의 픽셀에 할당된 레이블 정보입니다. 각 픽셀은 객체에 속하는 레이블 값으로 구분됩니다. 배경은 0으로 나타내어집니다. 이는 전체 이미지가 레이블 0(배경)을 갖고 있음을 의미합니다.
3. `stats`: 레이블링 된 객체의 특성 정보입니다. 각 행은 각 객체에 대한 특성을 나타내며, 각 열은 아래와 같은 순서대로 정보를 제공합니다:
- 열 0: 객체의 x 좌표 (왼쪽 위 꼭지점)
- 열 1: 객체의 y 좌표 (왼쪽 위 꼭지점)
- 열 2: 객체의 너비 (가로 크기)
- 열 3: 객체의 높이 (세로 크기)
- 열 4: 객체의 픽셀 개수
4. `centroids`: 각 객체의 중심점 좌표입니다. 객체의 무게중심을 나타내며, 각 행은 각 객체에 대한 중심점 좌표를 나타냅니다. 첫 번째 열은 중심점의 x 좌표를, 두 번째 열은 중심점의 y 좌표를 의미합니다.
이렇게 출력된 결과를 통해 'keyboard.bmp' 이미지에서 총 38개의 레이블(객체)이 검출되었으며, 각 객체의 좌표, 크기, 픽셀 개수, 중심점 등의 특성을 확인할 수 있습니다. 레이블링을 통해 객체를 분리하고, 개별 객체의 특성을 추출하여 다양한 영상 처리 작업에 활용할 수 있습니다.
✅ 2차 코드해석
위 코드는 OpenCV를 사용하여 'keyboard.bmp' 이미지를 로드하고, 이진화(thresholding)를 수행한 후, 레이블링된 객체들의 경계 상자를 그리고 결과를 출력하는 예제입니다.
1. `cv2.imread('./keyboard.bmp', cv2.IMREAD_GRAYSCALE)`: 'keyboard.bmp' 파일을 그레이스케일로 읽어서 `img` 변수에 저장합니다. `cv2.IMREAD_GRAYSCALE` 옵션을 사용하여 이미지를 흑백(그레이스케일)로 읽습니다.
2. `cv2.threshold(img, 0, 255, cv2.THRESH_OTSU)`: `img` 이미지를 이진화합니다. Otsu의 이진화 방법을 사용하여 자동으로 임계값을 결정하고, 이에 따라 이진화된 이미지 `img_bin`을 얻습니다.
3. `cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)`: `img` 이미지를 흑백(그레이스케일)에서 BGR 컬러로 변환합니다. 이는 나중에 레이블링된 객체의 경계 상자를 색상으로 그리기 위해서입니다. 변환된 이미지를 `dst`에 저장합니다.
4. `cv2.connectedComponentsWithStats(img_bin)`: `img_bin` 이미지에 레이블링을 수행합니다. 각 객체에 대한 레이블링 된 결과인 `labels`, 각 객체의 특성 정보인 `stats`, 각 객체의 중심점 좌표인 `centroids`를 반환합니다. `cnt`에는 객체의 개수를 저장합니다.
5. 레이블링된 객체들의 경계 상자를 그립니다:
- `for i in range(1, cnt)`: 레이블링 결과에서 배경 레이블인 0을 제외하고, 각 객체에 대해 반복합니다.
- `(x, y, w, h, area) = stats[i]`: `stats` 배열에서 i번째 객체의 특성 정보를 추출합니다. 여기서 (x, y)는 객체의 좌측 상단 꼭지점 좌표, w와 h는 객체의 너비와 높이, area는 객체의 픽셀 개수를 나타냅니다.
- `if area < 20: continue`: 객체의 픽셀 개수가 20보다 작으면 무시하고 다음 객체로 넘어갑니다.
- `cv2.rectangle(dst, (x, y, w, h), (0, 255, 255))`: `dst` 이미지에 (x, y) 좌표를 좌측 상단 꼭지점으로 하는 w x h 크기의 노란색(0, 255, 255) 경계 상자를 그립니다.
6. `cv2.imshow('img', img)`: `img` 이미지를 'img'라는 창에 표시합니다. 이 때, 'img' 창에는 원본 그레이스케일 이미지가 표시됩니다.
7. `cv2.imshow('img_bin', img_bin)`: 이진화된 `img_bin` 이미지를 'img_bin'이라는 창에 표시합니다.
8. `cv2.imshow('dst', dst)`: 객체의 경계 상자가 그려진 `dst` 이미지를 'dst'라는 창에 표시합니다.
9. `cv2.waitKey()`: `cv2.imshow()` 함수로 보여진 이미지들이 화면에서 유지되도록 기다립니다. 아무 키나 누를 때까지 기다립니다.
코드 실행 결과를 해석하면:
- `img`: 'keyboard.bmp' 파일을 로드하여 원본 그레이스케일 이미지를 표시합니다.
- `img_bin`: Otsu 이진화 방법을 사용하여 이진화된 이미지를 표시합니다. 배경과 객체로 이루어진 이진화된 형태를 볼 수 있습니다.
- `dst`: 레이블링된 객체의 경계 상자가 그려진 컬러 이미지를 표시합니다. 객체의 픽셀 개수가 20 이상인 객체들의 경계 상자가 노란색으로 표시되었습니다.
import cv2
import random
img = cv2.imread('./image/contours.bmp', cv2.IMREAD_GRAYSCALE)
contours, _ = cv2.findContours(img, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_NONE)
dst = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
cv2.drawContours(dst, contours, -1, color, 3)
cv2.imshow('img', img)
cv2.imshow('dst', dst)
cv2.waitKey()
✅ 코드해석 및 결과해석
위 코드는 'contours.bmp' 이미지에서 윤곽선(Contours)을 찾아내고, 랜덤한 색상으로 찾아낸 윤곽선을 그리는 예제입니다.
1. `cv2.imread('./contours.bmp', cv2.IMREAD_GRAYSCALE)`: 'contours.bmp' 파일을 흑백(그레이스케일)로 읽어 `img` 변수에 저장합니다.
2. `cv2.findContours(img, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_NONE)`: `img` 이미지에서 윤곽선을 찾아냅니다. `cv2.RETR_CCOMP`는 윤곽선을 계층 구조로 반환하며, `cv2.CHAIN_APPROX_NONE`는 윤곽선의 모든 점을 반환합니다. 윤곽선 정보는 `contours` 변수에 저장되고, 두 번째 반환 값은 계층 구조 정보이므로 사용하지 않습니다.
3. `cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)`: `img` 이미지를 흑백(그레이스케일)에서 BGR 컬러로 변환합니다. 윤곽선을 그리기 위해서 컬러 이미지가 필요하기 때문에 변환된 이미지를 `dst`에 저장합니다.
4. `color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))`: 랜덤한 색상을 생성합니다. 랜덤한 RGB 값으로 이루어진 튜플 `color`을 생성합니다.
5. `cv2.drawContours(dst, contours, -1, color, 3)`: `dst` 이미지에 찾아낸 모든 윤곽선을 랜덤한 색상으로 그립니다. `-1`은 모든 윤곽선을 의미하며, `color`은 앞서 생성한 랜덤한 색상을 사용합니다. 두 번째 `3`은 윤곽선의 두께를 나타냅니다.
6. `cv2.imshow('img', img)`: `img` 이미지를 'img'라는 창에 표시합니다. 이 때, 'img' 창에는 원본 흑백 이미지가 표시됩니다.
7. `cv2.imshow('dst', dst)`: 윤곽선이 그려진 컬러 이미지를 'dst'라는 창에 표시합니다.
8. `cv2.waitKey()`: `cv2.imshow()` 함수로 보여진 이미지들이 화면에서 유지되도록 기다립니다. 아무 키나 누를 때까지 기다립니다.
코드 실행 결과를 해석하면:
- `img`: 'contours.bmp' 파일을 로드하여 원본 흑백 이미지를 표시합니다.
- `dst`: 원본 이미지 위에 랜덤한 색상으로 찾아낸 모든 윤곽선을 그렸습니다. 윤곽선들이 다양한 색상으로 표시되어 시각적으로 확인할 수 있습니다.
import cv2
import random
# 이미지 파일 경로
img_path = './image/milkdrop.bmp'
# 'Malgun Gothic' 폰트를 사용하여 한글 지원
font_path = 'C:/Windows/Fonts/malgun.ttf'
font = cv2.FONT_HERSHEY_SIMPLEX
img = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE)
# 이미지 처리를 위해 가우시안 블러와 캐니 에지 검출을 적용합니다.
blurred_img = cv2.GaussianBlur(img, (5, 5), 0)
edges = cv2.Canny(blurred_img, 30, 150)
# 에지 검출된 이미지에서 윤곽선을 검출합니다.
contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
# 윤곽선을 그리기 위해 새로운 빈 이미지를 생성합니다.
dst = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
# 랜덤한 색상으로 윤곽선을 그립니다.
for contour in contours:
color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
cv2.drawContours(dst, [contour], -1, color, 3)
# 윈도우에 이미지 출력
cv2.imshow('원본 이미지', img)
cv2.imshow('에지 검출', edges)
cv2.imshow('외곽선 추출 결과', dst)
cv2.waitKey()
✅ 코드해석 및 결과해석
이 코드는 Python에서 OpenCV (Open Source Computer Vision Library)를 사용하여 이미지 처리를 수행하는 예제입니다. 주어진 이미지 파일 'milkdrop.bmp'를 로드하고, 해당 이미지에 가우시안 블러(Gaussian Blur) 및 캐니 에지 검출(Canny Edge Detection)을 적용하여 에지를 검출하고, 검출된 에지 주변에 랜덤한 색상으로 윤곽선을 그립니다. 마지막으로 세 개의 이미지 창을 표시하여 처리 결과를 확인합니다.
각 부분을 자세히 설명하겠습니다:
1. `import cv2` 및 `import random`: OpenCV와 랜덤 모듈을 가져옵니다.
2. `img_path`: 처리할 이미지 파일의 경로를 지정합니다.
3. `font_path`: 한글을 지원하기 위해 'Malgun Gothic' 폰트의 경로를 지정합니다.
4. `font`: 텍스트를 그릴 때 사용할 폰트를 설정합니다.
5. `img = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE)`: 지정된 경로에서 이미지를 그레이스케일(흑백)로 읽어옵니다.
6. 이미지 처리를 위해 가우시안 블러(Gaussian Blur) 및 캐니 에지 검출을 수행합니다.
- `blurred_img = cv2.GaussianBlur(img, (5, 5), 0)`: 가우시안 블러를 적용하여 이미지를 흐릿하게 만듭니다.
- `edges = cv2.Canny(blurred_img, 30, 150)`: 캐니 에지 검출을 사용하여 에지를 검출합니다.
7. `contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)`: 에지 검출된 이미지에서 외곽 윤곽선을 찾습니다. 이때, 외곽 윤곽선만 검출하도록 설정하며, 윤곽선의 근사값을 사용하지 않도록 합니다.
8. `dst = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)`: 원본 그레이스케일 이미지를 BGR 형식으로 변환하여 새로운 빈 이미지를 생성합니다.
9. `for contour in contours:`: 각 윤곽선에 대해 다음을 수행합니다.
- `color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))`: 랜덤한 색상을 생성합니다.
- `cv2.drawContours(dst, [contour], -1, color, 3)`: 빈 이미지에 랜덤한 색상으로 윤곽선을 그립니다. `3`은 윤곽선의 두께를 나타냅니다.
10. 마지막으로, `cv2.imshow()` 함수를 사용하여 세 개의 이미지 창에 원본 이미지, 캐니 에지 검출 결과, 외곽선 추출 결과를 표시합니다.
11. `cv2.waitKey()`: 사용자가 어떤 키를 누를 때까지 창을 열어 둡니다. 모든 작업이 완료된 후, 창을 닫을 수 있습니다.
이 코드를 실행하면 '원본 이미지', '에지 검출', '외곽선 추출 결과'라는 세 개의 창이 나타나며, 각각의 이미지 처리 단계를 시각적으로 확인할 수 있습니다. 각 윤곽선은 랜덤한 색상으로 표시됩니다.
# milkdrop.bmp를 이용하여 외곽선만 검출 후 영상 만들기
import cv2
import random
import numpy as np
img = cv2.imread('./image/milkdrop.bmp', cv2.IMREAD_GRAYSCALE)
_, img_bin = cv2.threshold(img, 0, 255, cv2.THRESH_OTSU)
contours, _ = cv2.findContours(img_bin, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
h, w = img.shape[:2]
dst = np.zeros((h, w, 3), np.uint8)
for i in range(len(contours)):
color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
cv2.drawContours(dst, contours, i, color, 2)
cv2.imshow('img', img)
cv2.imshow('img_bin', img_bin)
cv2.imshow('dst', dst)
cv2.waitKey()
✅ 코드해석 및 결과해석
위 코드는 'milkdrop.bmp' 이미지에서 외곽선을 검출한 후, 검출된 외곽선들을 랜덤한 색상으로 그려서 새로운 영상을 생성하는 코드입니다.
1. 이미지 전처리:
```python
_, img_bin = cv2.threshold(img, 0, 255, cv2.THRESH_OTSU)
```
입력 이미지를 이진화합니다. `cv2.threshold()` 함수를 사용하여 오츠의 이진화 알고리즘을 적용합니다. 이진화된 결과는 `img_bin`에 저장됩니다.
2. 외곽선 검출:
```python
contours, _ = cv2.findContours(img_bin, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
```
이진화된 이미지에서 외곽선을 검출합니다. `cv2.findContours()` 함수를 사용하여 외곽선을 검출하고, 검출된 외곽선은 `contours`에 저장됩니다. `cv2.RETR_LIST`는 모든 외곽선을 검출하도록 지정하며, `cv2.CHAIN_APPROX_NONE`은 모든 외곽선의 점을 반환하도록 지정합니다.
3. 새로운 영상 생성:
```python
h, w = img.shape[:2]
dst = np.zeros((h, w, 3), np.uint8)
```
입력 이미지와 동일한 크기의 빈 새로운 이미지 `dst`를 생성합니다.
4. 외곽선 그리기:
```python
for i in range(len(contours)):
color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
cv2.drawContours(dst, contours, i, color, 2)
```
랜덤한 색상으로 외곽선을 그립니다. `cv2.drawContours()` 함수를 사용하여 `dst` 이미지에 외곽선을 그리는데, `contours` 리스트에 저장된 외곽선 중 하나씩을 선택하여 그리게 됩니다. `color` 변수에 랜덤한 BGR 값(색상)을 지정하고, 두께를 2로 설정하여 외곽선을 그립니다.
5. 결과 출력:
```python
cv2.imshow('img', img)
cv2.imshow('img_bin', img_bin)
cv2.imshow('dst', dst)
cv2.waitKey()
```
원본 이미지, 이진화된 이미지(`img_bin`), 외곽선이 그려진 새로운 이미지(`dst`)를 차례로 화면에 출력합니다. `cv2.waitKey()` 함수를 사용하여 키 입력을 기다리고, 아무 키나 누르면 창이 닫힙니다.
이 코드를 실행하면 'milkdrop.bmp' 이미지에서 외곽선이 검출되고, 랜덤한 색상으로 그려진 새로운 영상이 생성됩니다. 외곽선이 뚜렷하게 표시되어 이미지 내의 객체 구분이 쉽게 되도록 처리된 것을 확인할 수 있습니다.
# 근사화 정밀도 조절에서 if문을 이용하여 사진 속 도형들의 Label 이름 넣기
import cv2
def get_shape_label(num_sides):
if num_sides == 3:
return 'Triangle'
elif num_sides == 4:
return 'Rectangle'
elif num_sides == 5:
return 'Pentagon'
elif num_sides == 6:
return 'Hexagon'
else:
return 'Unknown'
img = cv2.imread('./image/polygon.bmp', cv2.IMREAD_GRAYSCALE)
_, img_bin = cv2.threshold(img, 128, 255, cv2.THRESH_BINARY_INV)
contours, _ = cv2.findContours(img_bin, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for contour in contours:
epsilon = 0.04 * cv2.arcLength(contour, True)
approx = cv2.approxPolyDP(contour, epsilon, True)
num_sides = len(approx)
if num_sides >= 3:
shape_label = get_shape_label(num_sides)
moment = cv2.moments(contour)
cx = int(moment["m10"] / moment["m00"])
cy = int(moment["m01"] / moment["m00"])
cv2.putText(img, shape_label, (cx, cy), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 255, 255), 2)
cv2.imshow('labeled_img', img)
cv2.waitKey()
✅ 코드해석 및 결과해석
이 코드는 주어진 이미지에서 도형을 검출하고, 각 도형에 해당하는 Label 이름을 이미지 상에 표시하는 작업을 수행합니다.
1. `get_shape_label(num_sides)` 함수 정의:
- 이 함수는 도형의 변의 개수(`num_sides`)를 기반으로 해당 도형의 Label을 반환하는 역할을 합니다. 예를 들어, 삼각형, 사각형, 오각형, 육각형 이외의 도형은 'Unknown'으로 처리됩니다.
2. 이미지 로드 및 이진화:
- `img = cv2.imread('./image/polygon.bmp', cv2.IMREAD_GRAYSCALE)`를 통해 주어진 이미지를 그레이스케일로 읽습니다.
- `_, img_bin = cv2.threshold(img, 128, 255, cv2.THRESH_BINARY_INV)`를 사용하여 이미지를 이진화합니다. THRESH_BINARY_INV 옵션을 사용하여 밝기 값이 128 이상인 부분을 검정색으로 만듭니다.
3. 외곽 윤곽선 검출:
- `cv2.findContours()` 함수를 사용하여 이미지에서 외곽 윤곽선을 검출합니다.
- 검출된 윤곽선은 `contours` 변수에 저장됩니다.
4. 각 윤곽선에 대한 처리:
- `cv2.approxPolyDP()` 함수를 사용하여 윤곽선을 근사화합니다. 근사화 정밀도는 `epsilon` 매개변수에 의해 조절됩니다.
- `len(approx)`를 사용하여 도형의 변의 개수를 계산합니다.
- `get_shape_label()` 함수를 호출하여 도형의 Label을 얻습니다.
- `cv2.moments()` 함수를 사용하여 도형의 중심 좌표를 계산합니다.
- `cv2.putText()` 함수를 사용하여 도형의 중심에 Label을 표시합니다.
5. 이미지 표시:
- `cv2.imshow('labeled_img', img)`를 통해 Label이 표시된 이미지를 표시합니다.
- `cv2.waitKey()`를 사용하여 사용자가 키를 누를 때까지 이미지 창을 유지합니다.
실행 결과로 'labeled_img'라는 창에는 이미지 속 도형에 해당하는 Label이 표시된 이미지가 표시됩니다. 이를 통해 도형 검출 및 Label 표시 작업을 시각적으로 확인할 수 있습니다.
import math
import cv2
def setLevel(img, pts, label):
(x, y, w, h) = cv2.boundingRect(pts)
pt1 = (x, y)
pt2 = (x + w, y + h)
cv2.rectangle(img, pt1, pt2, (0, 0, 255), 2)
cv2.putText(img, label, pt1, cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255))
img = cv2.imread('./image/polygon.bmp')
gray = cv2.cvtColor(img, cv2.COLOR_BGRA2GRAY)
_, img_bin = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)
contours, _ = cv2.findContours(img_bin, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
print(contours)
for pts in contours:
if cv2.contourArea(pts) < 200:
continue
approx = cv2.approxPolyDP(pts, cv2.arcLength(pts, True) * 0.02, True)
print(approx)
vtc = len(approx)
print(vtc)
if vtc == 3:
setLevel(img, pts, 'TRI')
elif vtc == 4:
setLevel(img, pts, 'RECT')
else:
length = cv2.arcLength(pts, True)
area = cv2.contourArea(pts)
ratio = 4. * math.pi * area / (length * length)
if ratio > 0.70:
setLevel(img, pts, 'CIR')
else:
setLevel(img, pts, 'NONAME')
# cv2.imshow('gray', gray)
# cv2.imshow('img_bin', img_bin)
cv2.imshow('img', img)
cv2.waitKey()
✅ GPT 설명
위의 코드는 이미지에서 다양한 도형을 인식하고 해당 도형에 대한 레이블을 이미지 상에 표시하는 예제입니다.
1. 이미지 읽기와 전처리:
- `cv2.imread('./image/polygon.bmp')`: 'polygon.bmp'라는 이미지를 읽어옵니다.
- `cv2.cvtColor(img, cv2.COLOR_BGRA2GRAY)`: 읽어온 이미지를 흑백 이미지로 변환합니다.
- `cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)`: 흑백 이미지를 이진화합니다. 이진화된 이미지가
`img_bin`에 저장됩니다.
2. 외곽선 검출:
- `cv2.findContours(img_bin, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)`: 이진화된 이미지에서 외곽선을 검출합니다. `contours`에
검출된 외곽선들의 리스트가 저장됩니다.
3. 도형 분류와 레이블링:
- `for pts in contours:`
- 각각의 외곽선 `pts`에 대해 아래 과정을 수행합니다.
- `cv2.contourArea(pts)`: 외곽선의 면적을 계산합니다.
- `cv2.approxPolyDP(pts, cv2.arcLength(pts, True) * 0.02, True)`: 외곽선을 근사화하여 다각형 형태를 더 적은 점으로 근사화합니다.
`approx`에 근사화된 결과가 저장됩니다.
- `len(approx)`: 근사화된 다각형의 꼭지점 수를 계산합니다.
- 꼭지점 수에 따라 객체를 삼각형, 사각형 또는 원으로 분류하고, `cv2.rectangle()` 함수로 객체 영역을 감싸고, `cv2.putText()` 함수로 레이블을 표시합니다.
- 객체 영역은 `cv2.boundingRect()` 함수를 사용하여 경계 사각형으로 둘러싸고, 레이블은 해당 사각형의 좌상단에 표시됩니다.
- 레이블 이름은 'TRI' (삼각형), 'RECT' (사각형), 'CIR' (원), 'NONAME' (위 모양에 해당하지 않는 도형) 중 하나로 표시됩니다.
4. 결과 확인:
- `cv2.imshow('img', img)`: 레이블이 표시된 이미지를 화면에 표시합니다.
- `cv2.waitKey()`: 사용자의 키 입력을 기다립니다.
이 코드는 이미지에 포함된 도형들을 인식하고, 삼각형, 사각형, 원으로 분류하여 해당 도형의 레이블을 이미지에 표시하는 간단한 예제입니다.
주석 처리된 부분을 통해 이미지 전처리과정인 이진화 또는 이진화된 이미지를 확인하고 싶다면 해당 코드 부분의 주석을 해제하고 실행하면 됩니다.
import cv2
img = cv2.imread('./image/hat.png')
cpy = img.copy()
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_, thr = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
contour, _ = cv2.findContours(thr, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
print(contour[1])
cnt = contour[1]
cv2.drawContours(img, [cnt], -1, (255, 0, 0), 2)
check = cv2.isContourConvex(cnt)
print(check)
✅ 코드해석 및 결과해석
이 코드는 주어진 이미지에서 경계선을 찾아 그리고 해당 경계선이 볼록(convex)한지 아닌지를 확인하는 작업을 수행합니다. 코드를 단계별로 설명하겠습니다.
1. `cv2.imread('./image/hat.png')`: 'hat.png' 이미지를 읽어옵니다.
2. `cpy = img.copy()`: 원본 이미지를 복사하여 `cpy` 변수에 저장합니다. 이렇게 함으로써 원본 이미지와 복사본을 독립적으로 처리할 수 있습니다.
3. `cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)`: 원본 이미지를 흑백 이미지로 변환합니다.
4. `_, thr = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)`: 흑백 이미지를 이진화합니다. 픽셀 값이 127보다 크면 255(흰색), 그렇지 않으면 0(검은색)으로 설정됩니다. 이진화된 이미지는 `thr`에 저장됩니다.
5. `cv2.findContours(thr, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)`: 이진화된 이미지에서 경계선을 찾습니다. `cv2.RETR_TREE` 플래그는 모든 경계선을 계층 구조로 반환하고, `cv2.CHAIN_APPROX_SIMPLE` 플래그는 경계선의 꼭짓점 좌표만 저장합니다. 경계선 정보는 `contour`에 저장됩니다.
6. `print(contour[1])`: 경계선 리스트에서 두 번째 경계선(인덱스 1)의 정보를 출력합니다.
7. `cnt = contour[1]`: 두 번째 경계선을 `cnt` 변수에 저장합니다.
8. `cv2.drawContours(img, [cnt], -1, (255, 0, 0), 2)`: 원본 이미지에 `cnt` 경계선을 그립니다. `(-1)`은 모든 경계선을 그리라는 의미이며, `(255, 0, 0)`은 그릴 선의 색상을 나타냅니다. `2`는 선의 두께를 지정합니다.
9. `cv2.isContourConvex(cnt)`: `cnt` 경계선이 볼록(convex)한지 아닌지를 확인합니다. 결과값을 `check` 변수에 저장합니다.
10. `print(check)`: `check` 값을 출력하여 해당 경계선이 볼록한 경우 `True`, 아닌 경우 `False`를 출력합니다.
결과 해석:
- 코드는 'hat.png' 이미지를 읽고, 흑백 이미지로 변환한 뒤 이진화하여 경계선을 찾습니다.
- 이 코드에서는 `contour[1]`을 출력하고 이 경계선을 그려냅니다.
- 마지막으로 해당 경계선이 볼록한지 여부를 확인하고 결과를 출력합니다. 결과에 따라 `True` 또는 `False`가 출력됩니다.