Mask 이미지
- 이미지 전처리를 수행하거나, 딥러닝을 위한 Segmentation을 수행할 때, Mask라는 것을 사용할 때가 있다.
- 원본 이미지에서 사용자가 관심이 있는 영역(ROI)은 255 픽셀 값으로 채우고, 그 이외의 영역은 0픽셀 값으로 채워서 만든 흑백 이미지를 Binary Mask라고 한다.
- RGB Mask도 있다.
이미지 합성
- OpenCV에서는 원본 이미지, Mask 이미지를 활용하여 합성을 할 수 있다.
- 08.bitwise_overlap.py
import numpy as np, cv2
image = cv2.imread("images/bit_test.jpg", cv2.IMREAD_COLOR) # 원본 영상 읽기
logo = cv2.imread("images/logo.jpg", cv2.IMREAD_COLOR) # 로고 영상 읽기
# threshold : 이진화처리를 할 때, 기준이 되는 임계값을 결정할 때 사용하는 함수
# 이진화 : 영상을 흑/백으로 분류하여 처리하는 것
# 임계값보다 크면 백, 작으면 흑으로 분류
# 임계값 함수 / 임계값을 잘 설정하면 두 영상을 구분할 수 있다.
# cv2.threshold(src, thresh, maxval, type, dst=None) -> retval, dst
# src : 입력 영상. 다채널, 8비트 또는 32비트 실수형
# thresh : 사용자 지정 임계값
# maxval : cv2.THRESH_BINARY 또는 cv2.THRESH_BINARY_INV 방법 사용시 최댓값. 보토 255
# type : cv2.THRESH_로 시작하는 플래그. 임계값 함수 동작 지정 또는 자동 임계값 결정 방법 지정
# retval : 사용된 임계값
# dst : 출력 영상. src와 동일 크기, 동일 타입, 같은 채널 수
masks = cv2.threshold(logo, 220, 255, cv2.THRESH_BINARY)[1] # 로고 영상 이진화
print(len(masks))
masks = cv2.split(masks)
print(len(masks))
fg_pass_mask = cv2.bitwise_or(masks[0], masks[1])
fg_pass_mask = cv2.bitwise_or(masks[2], fg_pass_mask) # 전경 통과 마스크
bg_pass_mask = cv2.bitwise_not(fg_pass_mask) # 배경 통과 마스크
(H, W), (h, w) = image.shape[:2], logo.shape[:2] # 전체 영상, 로고 영상 크기
x, y = (W - w) // 2, (H - h) // 2 # 시작 좌표 계산
roi = image[y : y + h, x : x + w]
# 행렬 논리곱과 마스킹을 이용한 관심 영역 복사
foreground = cv2.bitwise_and(logo, logo, mask=fg_pass_mask) # 로고의 전경만 복사
background = cv2.bitwise_and(roi, roi, mask=bg_pass_mask) # 원본 roi의 배경만 복사
dst = cv2.add(background, foreground) # 로고 전경과 원본 배경 간 합성
image[y : y + h, x : x + w] = dst # 합성 영상을 원본에 복사
cv2.imshow("background", background)
cv2.imshow("foreground", foreground)
cv2.imshow("dst", dst)
cv2.imshow("image", image)
cv2.waitKey()
- practice01.py
import cv2
import numpy as np
# circle사진을 BGR로 불러온다.
circle = cv2.imread("images/circle.jpg", cv2.IMREAD_COLOR)
# 특정 색상을 추출할 때는 HSV 색공간을 이용하는게 좋다고 한다. (H, S 색상 조절. V는 밝기 조절)
# 하지만 여기서는 RGB로 해보도록 하자.
if circle is None:
raise Exception("Error: Unable to read the image.")
else:
# 색상의 범위를 정한다. (파랑)
lower_blue = np.array([100, 0, 0])
upper_blue = np.array([255, 50, 50])
# 색상의 범위를 정한다. (빨강)
lower_red = np.array([0, 0, 100])
upper_red = np.array([50, 50, 255])
# 색상의 범위를 정한다. (초록)
lower_green = np.array([0, 100, 0])
upper_green = np.array([50, 255, 50])
# inRange함수를 사용하면, 특정 색상 영역을 추출할 수 있다.
# cv2.inRange(src, lowerb, upperb, dst=None) -> dst
# 각 컬러의 원들에 대한 마스크를 생성한다.
# src: 입력 행렬
# lowerb: 하한 값 행렬 또는 스칼라
# upperb: 상한 값 행렬 또는 스칼라
# dst: 입력 영상과 같은 크기의 마스크 영상. (numpy.uint8) 범위 안에 들어가는 픽셀은 255, 나머지는 0으로 설정
mask_blue = cv2.inRange(circle, lower_blue, upper_blue)
mask_red = cv2.inRange(circle, lower_red, upper_red)
mask_green = cv2.inRange(circle, lower_green, upper_green)
# 컨투어는 등고선을 의미한다. 외곽선을 따는 함수라고 생각하자.
# cv2.findContours(src, mode, contours, hierarchy, offset)
# src : 입력 영상, 검장과 흰색으로 구성된 바이너리 이미지
# mode : 컨투어 제공 방식 (cv2.RETR_EXTERNAL-가장바깥쪽 라인만 생성)
# method : 근사 값 방식 (cv2.CHAIN_APPROX_NONE-근사 없이 모든 좌표 제공)
# contours : 검출한 컨투어 좌표(list type)
# hierarchy : 컨투어 계층 정보(Nextm Prev, FirstChild, Parent, -1 [해당없음])
# offset : ROI 등으로 인해 이동한 컨투어 좌표의 오프셋
contours_blue, _ = cv2.findContours(
mask_blue, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE
)
contours_red, _ = cv2.findContours(
mask_red, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE
)
contours_green, _ = cv2.findContours(
mask_green, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE
)
# 원에 사각형 그리기
# boundingRect : Contour에 외접하는 사각형의 시작점과 width, height를 얻는다.
# rectangle함수로 사각형을 그린다.
for contour in contours_blue:
x, y, w, h = cv2.boundingRect(contour)
cv2.rectangle(
circle, (x, y), (x + w, y + h), (255, 0, 0), 2
) # Blue rectangle (BGR color format)
for contour in contours_red:
x, y, w, h = cv2.boundingRect(contour)
cv2.rectangle(
circle, (x, y), (x + w, y + h), (0, 0, 255), 2
) # Red rectangle (BGR color format)
for contour in contours_green:
x, y, w, h = cv2.boundingRect(contour)
cv2.rectangle(
circle, (x, y), (x + w, y + h), (0, 255, 0), 2
) # Green rectangle (BGR color format)
# Display the original image with rectangles
cv2.imshow("Rectangles around circles", circle)
# Wait until a key is pressed and then close the window
cv2.waitKey(0)
cv2.destroyAllWindows()
히스토그램 스트레칭
- 명암 대비를 향상시키는 연산으로, 낮은 명암 대비를 보이는 영상의 화질을 향상시키는 방법
import cv2
import numpy as np
def calc_histo(image, histSize, ranges=[0, 256]): # 행렬 원소의 1차원 히스토그램 계산
hist = np.zeros((histSize, 1), np.float32) # 히스토그램 누적 행렬
gap = ranges[1] / histSize # 계급 간격
for i in range(image.shape[0]): # 2차원 행렬 순회 방식
for j in range(image.shape[1]):
idx = int(image.item(i, j) / gap)
hist[idx] += 1
return hist
image = cv2.imread("images/dv.jpg", cv2.IMREAD_GRAYSCALE)
if image is None:
raise Exception("영상 파일 읽기 오류 발생")
hsize, ranges = [32], [0, 256] # 히스토그램 간격 수(범위), 값 범위
gap = ranges[1] / hsize[0]
ranges_gap = np.arange(0, ranges[1] + 1, gap)
hist1 = calc_histo(image, hsize[0], ranges)
hist2 = cv2.calcHist([image], [0], None, hsize, ranges) # OpenCV 함수 사용
hist3, bins = np.histogram(image, ranges_gap)
print("User 함수 : \n", hist1.flatten())
print("OpenCV 함수: \n", hist2.flatten())
print("numpy 함수 : \n", hist3)
cv2.imshow("image", image)
cv2.waitKey()
# 이미지를 고르고(어두운 영상이나 명임이 한쪽으로 치우친 영상)
# 스트레칭 기법을 이용해서 영상을 개선시켜보자.
```python
# 이미지를 고르고(어두운 영상이나 명임이 한쪽으로 치우친 영상)
# 스트레칭 기법을 이용해서 영상을 개선시켜보자.
import numpy as np
import cv2
def draw_histo(hist, shape=(200, 256)):
hist_img = np.full(shape, 255, np.uint8)
cv2.normalize(hist, hist, 0, shape[0]) # 정규화
gap = hist_img.shape[1] / hist.shape[0] # 한 계급 너비
for i, h in enumerate(hist):
x = int(round(i * gap)) # 막대 사각형 시작 x좌표
w = int(round(gap))
cv2.rectangle(hist_img, (x, 0, w, int(h)), 0, cv2.FILLED)
return cv2.flip(hist_img, 0) # 영상 상하 뒤집기 후 반환
def search_value_idx(hist, bias=0): # 값 있는 첫 계급 검색 함수
for i in range(hist.shape[0]):
idx = np.abs(bias - i)
if hist[idx] > 0:
return idx # 위치 반환
return -1 # 대상이 없으면 반환
image = cv2.imread("images/hist_stretch.jpg", cv2.IMREAD_GRAYSCALE)
if image is None:
raise Exception("영상파일 읽기 오류")
bsize, ranges = [64], [0, 256] # 계급 개수 및 화소 범위
hist = cv2.calcHist([image], [0], None, bsize, ranges)
bin_width = ranges[1] / bsize[0] # 한 계급 너비
low = search_value_idx(hist, 0) * bin_width # 최저 화소값
high = search_value_idx(hist, bsize[0] - 1) * bin_width # 최고 화소값
idx = np.arange(0, 256) # 룩업 인덱스 (0~255) 생성
idx = (idx - low) / (high - low) * 255 # 수치 적용하여 룩업 인덱스 완성
idx[0 : int(low)] = 0 # 히스토그램 하위 부분
idx[int(high + 1) :] = 255 # 히스토그램 상위 부분
dst = cv2.LUT(image, idx.astype("uint8")) # 룩업 테이블 사용
"""
룩업 테이블을 사용하지 않고 직접 구현
dst = np.zeroes(image.shape, dtype=image.dtype)
for i in range(dst.shape[0]):
for j in range(dst.shape[1]):
dst[i,j] = idx[image[i, j]]
"""
hist_dst = cv2.calcHist([dst], [0], None, bsize, ranges) # 결과 영상 히스토그램 재계산
hist_img = draw_histo(hist, (200, 360)) # 원본 영상 히스토그램 그리기
hist_dst_img = draw_histo(hist_dst, (200, 360)) # 결과 영상 히스토그램 그리기
print("high vlue =", high)
print("low_vlue =", low)
cv2.imshow("image", image)
cv2.imshow("hist_img", hist_img)
cv2.imshow("dst", dst)
cv2.imshow("hist_dst_img", hist_dst_img)
cv2.waitKey(0)
화소 영역 처리
- 한 화소와 근처 화소를 포함하여 9개의 화소가 서로 관여하여 한 가운데에 새로운 화소를 생성하는 것을 화소 영역 처리라고 함(개수는 때에따라 다름)
- 화소의 원 값이나 위치를 바탕으로 화소 값을 변경하는 화소의 점 처리와 달리, 해당 입력 화소 뿐만 아니라 그 주위의 화소 값도 함께 고려하는 공간 영역 연산
- 회선 기법(또는 컨볼루션 기법)으로 수행하므로, 화소의 영역 처리를 회선 처리(Convolution Processing) 또는 컨볼루션 처리라고 한다.
- 원시 화소와 이웃한 각 화소에 가중치를 곱한 합을 출력 화소로 생성
화소 영역 기반 처리
- 엠보싱 효과, 블러링, 샤프닝(엣지), 경계선 검출(Edge detection), 잡음 제거 등의 기술이 있다.
회선 마스크
- 필터링을 이용한 영상처리는 2차원의 컨볼루션을 수행하게 되는데, 이때 사용되는 필터 마스크를 컨보룰션 마스크 또는 회선 마스크라고 한다.
회선 마스크 특징
- 주변 화소의 값을 각 방향에서 대칭적으로 고려해야 함. 이것은 각 방향에 있는 같은 수의 이웃 화소에 기반을 두고 새로운 화소 값을 생성하기 때문
- 회선 마스크의 크기는 행과 열 모두 홀수의 크기를 사용하여 3x3, 5x5, 7x7등
- 회선 처리 기법으로 생성된 출력 영상은 밝기 에너지를 보존해야 하므로 영상의 평균 밝기를 원 영상과 똑같이 유지해야 함.
- 회선된 영상의 평균 밝기 값이 원본 영상과 같도록 많은 회선 마스크의 계수 합이 1이 되도록 해야함. (항상 그런것은 아니다)
블러링
- 디지털 카메라로 사진을 찍을 때, 초점이 맞지 않으면 사진이 흐려짐
- 이러한 현상을 이용해서 영상의 디테일한 부분을 제거하는 아웃 포커싱 기법
- 포토샵의 뽀샤시 기능
- *블러링(blurring)
- 영상에서 화소값이 급격하게 변하는 부분들을 감소시켜 점진적으로 변하게 함으로써 영상이 전체적으로 부드러운 느낌이 나게 하는 기술
- 화소값이 급격이 변화하는 것을 점진적으로 변하게 하는 방법
- 블러링 마크스로 회선 수행
샤프닝
- 적절하게 쓰면 샤프닝, 극단적으로 쓰면 엣지 디텍션
- 출력 화소에서 이웃 화소끼리 차이를 크게 해서 날카로운 느낌이 나게 만드는 것
- 영상의 세세한 부분을 강조할 수 있으며, 경계 부분에서 명암대비가 증가되는 효과
샤프닝 마스크
- 마스크 원소들의 값 차이가 커지도록 구성
- 마스크 원소 전체합이 1이 되어야 입력영상 밝기가 손실 없이 출력영상 밝기로 유지
그리고 마지막으로 오늘은 호프데이여서 보라매 근처 BHC 치킨집가서 치킨을 마음껏 먹었다 ㅎㅎ
'프로그램 > SKT FLY AI' 카테고리의 다른 글
SKT FLY AI : 29일차 (0) | 2023.08.03 |
---|---|
SKT FLY AI : 28일차 - 딥러닝(강화학습) (0) | 2023.08.03 |
SKT FLY AI : 26일차 - OpenCV (0) | 2023.07.31 |
SKT FLY AI 3기 : 번외편 - 일상 (7) | 2023.07.31 |
SKT FLY AI 3기 번외편 : 23일차 - 번외 : SKT 보라매 사옥 밥과 간식들 (0) | 2023.07.30 |