[OpenCV] OpenCV-Python으로 배우는 영상 처리 및 응용 - 5장 연습문제 풀이

2025. 6. 30. 09:14·Programming/Python

1. OpenCV의 채널 처리 함수에 대해 아는 대로 기술하시오.

컬러 영상은 파란색, 녹색, 빨간색의 각기 독립적인 2창원 정보를 합쳐 놓은 배열로 정의가 가능하며, 이를 표현하기 위해 채널이라는 개념이 도입됐다. 일련의 3개 원소로 하나의 컬러 화소가 구성되며, numpy에서는 화소 단위로 순회한다. 이 컬러 배열을 분리하면 각 채널을 단일채널 행렬로 구성할 수 있으며, 세부적인 영상처리에 이용될 수 있다. (교재 162p) 

cv2의 채널 처리 함수로는 cv2.merge()와 cv2.split()이 있으며, 각 함수는 아래와 같다. 

cv2.merge(mv[,dst]) → dst
▪ 설명: 여러 개의 단일채널 배열을 다채널 배열로 합성한다.
인수 설명 mv 합성될 입력 혹은 배열 벡터, 합성될 단일채널 배열들의 크기와 깊이(depth)가 동일해야 함
dst 입력 배열과 같은 크기와 같은 깊이의 출력 배열
cv2.split(m[, mv]) → mv
▪ 설명: 다채널 배열을 여러 개의 단일채널 배열로 분리한다.
인수 설명 m 입력되는 다채널 배열
mv 분리되어 반환되는 단일채널 배열들의 벡터

(교재 165p)

 

2. OpenCV의 사칙 연산을 수행하는 함수와 연산의 수행 방법에 대해 기술하시오.

두 배열의 원소간(per-element) 사칙 연산을 수행하도록 cv2.add(), cv2.substract(), cv2.multiply(), cv2.divide() 함수를 제공한다. 이 함수들은 두 행렬의 원소간에 연산을 수행한다. 이때, 마스크 행렬을 이용해서 특정 영역만 연산을 수행할 수 있다.

(교재 208p)

cv2.add(src, src2[,dst[, mask[, dtype]]]) → dst
▪ 설명: 두 개의 배열 혹은 배열과 스칼라의 각 원소 간 합을 계산한다. 입력 인수 src1, src2 중 하나는 스칼라값일 수 있다.
▪ 수식: 
dsti=saturatesrc1i+src2i    if maski≠0
dsti=saturatesrc1+src2i    if maski≠0
dsti=saturatesrc1i+src2    if maski≠0

인수 설명 src1 첫 번째 입력 배열 혹은 스칼라
src2 두 번째 입력 배열 혹은 스칼라
dst 계산된 결과의 출력 배열
mask 연산 마스크: 0이 아닌 마스크 원소의 위치만 연산 수행(8비트 단일채널)
dtype 출력 배열의 깊이
cv2.substract(src1, src2[, dst[, mask[, dtype]]]) → dst
▪ 설명: 두 개의 배열 혹은 배열과 스칼라의 각 원소 간 차분을 계산한다. add()함수의 인수와 동일하다.
▪ 수식: 
dsti=saturatesrc1i-src2i    if maski≠0
dsti=saturatesrc1-src2i    if maski≠0
dsti=saturatesrc1i-src2    if maski≠0

cv2.multiply(src1, src2[, dst[, scale[, dtype]]]) → dst
▪ 설명: 두 배열의 각 원소 간 곱을 계산한다.
▪ 수식: 
dsti=saturatescale⋅src1i⋅src2i

인수 설명 scale 두 배열의 운소 간 곱할 때 추가로 곱해주는 배율
cv2.divide(src1, src2[, dst[, scale[, dtype]]]) → dst
▪ 설명: 두 배열의 각 원소 간 나눗샘을 수행한다.
▪ 수식: 
dsti=saturatescale⋅src1i/src2(i)

cv2.divide(scale, src2[, dst[, dtype]]) → dst
▪ 설명: 스칼라값과 행렬원소간 나눗셈을 수행한다.
▪ 수식: 
dsti=scale/src2(i)

cv2.addWeighted(src1, alpha, src2, beta, gamma[, dst[, dtype]]) → dst
▪ 설명: 두 배열의 각 원소에 가중치를 곱한 수에 각 원소 간 합 즉, 가중된(weighted) 합을 계산한다.
▪ 수식: 
dsti=saturatesrc1i⋅alpha+src2i⋅beta+gamma

인수 설명 alpha 첫 번째 배열의 모든 원소에 대한 가중치
beta 두 번째 배열의 모든 원소에 대한 가중치
gamma 두 배열의 원소 간 합에 추가로 더해주는 스칼라

(교재 170-171p)

 

3. 행렬(ndarray)을 초기화하는 방법들에 대해서 기술하고, 각 방법으로 선언하시오.

numpy에서 다양한 행렬 초기화 메소드를 제공한다. np.zeros()는 0으로 채워진 행렬을 초기화하며, np.ones()는 1로 채워진 행렬, np.full()은 지정된 값으로 채워진 행렬을 반환한다.

np.zeros() np.zeros((2,4), np.uint8)
# 0으로 채워진 2행 4열 uint8 자료형의 행렬 생성 
np.ones() np.ones((2,4), np.uint8)
# 1으로 채워진 2행 4열 uint8 자료형의 행렬 생성
np.full() np.full((2,4), 30, np.uint8)
# 30으로 채워진 2행 4열 uint8 자료형의 행렬 생성



4. 사칙 연산이나 논리 비트 연산에서 마스킹(masking)을 사용할 수 있다. 마스크 행렬에 대한 의미와 사용법에 대해서 설명하시오.

사칙 연산 함수, 논리 비트 연산 함수에서 입력 인수로 mask를 제공한다. Mask는 8비트 단일채널 배열을 가지며, 마스크 배열의 원소가 0이 아닌 좌표만 계산을 수행한다. 

예를 들어 마스크 배열이 [[0, 1], [1, 1]]의 구조를 가진다면 값이 0인 (0, 0) 좌표는 해당 함수가 수행하는 연산을 수행하지 않는다.

 

[사용 예시]

소스코드
import numpy as np, cv2

src1 = np.arange(4, dtype=np.uint8).reshape(2,2)
src2 = np.arange(4, 8, dtype=np.uint8).reshape(2,2)
mask = np.array([0,1,1,1], dtype=np.uint8).reshape(2,2)

add_without_mask = cv2.add(src1, src2)
add_with_mask = cv2.add(src1, src2, mask=mask)

print('add_without_mask =\n', add_without_mask)
print('add_with_mask =\n', add_with_mask)



5. cv2.reduce() 함수에 대해서 설명하고, 특히 축소 시에 사용하는 연산 옵션에 대해서 상세히 설명하시오.

cv2.reduce(src, dim, rtype[, dst[, dtype]]) → dst
▪ 설명: 행렬을 열방향/행방향으로 옵션 상수(rtype)에 따라 축소한다.
인수 설명 src 2차원 입력 배열(np.float32, np.float64에서만 수행 가능)
dst 출력 벡터, 감소방향과 타입은 dim, dtype 인수에 따라 정해짐
dim 행렬이 축소소딜 때 차원 감소 첨자
  • 0 : 열 방향으로 연산하여 1행으로 축소
  • 1 : 행 방향으로 연산하여 1열로 감소
rtype 축소 연산 종류
 
dtype 감소된 벡터의 자료형



6. 다음 예시 코드는 컴파일 에러가 발생한다. 에러가 발생하는 부분을 수정하고 실행 결과를 적으시오.

소스코드
import numpy as np, cv2

# m1과 m2를 list에서 ndarray로 수정
m1 = np.array([1,2,3,1,2,3])
m2 = np.array([3,3,4,2,2,3]) 
m3 = m1 + m2
m4 = m1 - m2

print("[m1] = %s" % m1)
print("[m2] = %s" % m2)
print("[m3] = %s" % m3)
print("[m3] = %s" % m3)

소스코드
import numpy as np, cv2

data = [1,2,3,4,5,6,7,8,9,10,11,12]
# reshape(2,3,2)를 하면 2채널이 되어 rgb 3개의 채널로 분리가 불가함. 따라서 reshape(2,2,3)으로 수정
m1 = np.array(data).reshape(2,2,3) 

r,g,b = cv2.split(m1)

print("[m1] = %s" % m1)
print("[r, g, b] = %s, %s, %s" % (r,g,b))



7. 다음의 컬러 영상파일(logo.jpg)을 입력 받아서 RGB의 3개 채널을 분리하고, 각 채널을 컬러 영상을 윈도우에 표시해 보자. 즉 Red 채널은 빨간색으로, green 채널은 초록색으로, Blue 채널은 파란색으로 표현되도록 다음의 프로그램을 완성하시오.

소스코드
import numpy as np, cv2

logo = cv2.imread('images/logo.jpg', cv2.IMREAD_COLOR)
if logo is None: raise Exception("영상파일 읽기 오류")

blue, green, red = cv2.split(logo)

zeros = np.zeros(blue.shape, dtype=np.uint8)

blue_img = cv2.merge([blue, zeros, zeros])
green_img = cv2.merge([zeros, green, zeros])
red_img = cv2.merge([zeros, zeros, red])


# 윈도우 자동 정렬
titles = ['logo']+[_+"_img" for _ in ["blue", "green", "red"]]
x, y = 100, 100
for title in titles:
    cv2.namedWindow(title, cv2.WINDOW_AUTOSIZE)
    cv2.moveWindow(title, x, y)
    x += blue.shape[1] + 10
    cv2.imshow(title, eval(title))

cv2.waitKey(0)
cv2.destroyAllWindows()



8. 다음 영상에서 특정 영역의 타원반을 복사하여 새 창에 표시하는 프로그램을 완성하시오.

소스코드
import numpy as np, cv2

image = cv2.imread("images/color.jpg", cv2.IMREAD_COLOR)
if image is None: raise Exception("영상파일 읽기 오류")

mask = np.zeros(image.shape[:2], np.uint8)
center = (190, 170)
cv2.ellipse(mask, center, (30,60), 0,0,360,255, -1)
dst = cv2.bitwise_and(image, image, mask=mask)

# 윈도우 정렬
x = y = 100
for title in ['image', 'dst']:
    cv2.namedWindow(title, 1)
    cv2.moveWindow(title, x, y)
    x += image.shape[1] + 10
    cv2.imshow(title, eval(title))
    
cv2.waitKey(0)
cv2.destroyAllWindows()



9. 3행, 6열의 행렬을 생성하고, 행렬의 원소를 초기화한 후에 cv2.reduce() 함수를 이용해서 가로 방향과 세로 방향으로 감축하여 평균을 구한 결과를 출력하시오.

소스코드
import numpy as np, cv2

arr = np.random.rand(3, 6) * 1000//10
col_avg = cv2.reduce(arr, dim=0, rtype=cv2.REDUCE_AVG) # 행방향 축소 -> 열 평균
row_avg = cv2.reduce(arr, dim=1, rtype=cv2.REDUCE_AVG) # 열방향 축소 -> 행 평균

print('arr = \n', arr)
print('열 평균 = ', col_avg.flatten().round(2))
print('행 평균 = ', row_avg.flatten().round(2))



10. PC 카메라로 영상을 읽어서 특정 부분(관심 영역)의 합과 평균을 구하는 프로그램을 작성하시오.

소스코드
import numpy as np, cv2

capture = cv2.VideoCapture(1)
if capture.isOpened() == False:
    raise Exception("카메라 연결 안됨")

def print_info(frame, slices=(slice(200, 400), slice(100, 300))):
    target = frame[slices]
    cv2_mean = cv2.mean(target)

    target_sum = np.zeros(3)
    for y in range(target.shape[0]):
        for x in range(target.shape[1]):
            target_sum += target[y][x]

    user_mean = target_sum / (target.shape[0] * target.shape[1])
    print("cv2로 구한 평균 = ", cv2_mean)
    print("원소 순회로 구한 평균 = ", tuple(user_mean))
    print("관심영역 합 = ", target_sum)


while True:
    ret, frame = capture.read()
    if not ret: break
    if cv2.waitKey(30) >= 0: break

    print('[밝은 부분]')
    print_info(frame, (slice(200, 400), slice(100, 300)))
    print('[어두운 부분]')
    print_info(frame, (slice(-200, -100), slice(-200, -100)))


    exposure = capture.get(cv2.CAP_PROP_EXPOSURE)
    title = "View Frame from Camera"
    cv2.imshow(title, frame)  # 윈도우에 영상 띄우기

capture.release()

cv2.destroyAllWindows()



11. PC 카메라로 영상을 받아들여서 다음과 같이 윈도우의 특정 영역에서 재생하시오.

소스코드
import numpy as np, cv2

capture = cv2.VideoCapture(1)
if capture.isOpened() == False:
    raise Exception("카메라 연결 안됨")

bg = np.zeros((300, 400, 3), dtype=np.uint8)
mask = np.zeros((300, 400), dtype=np.uint8)
cv2.rectangle(mask, (30, 30), (30+320, 30+240), 255, -1)

while True:
    ret, frame = capture.read()
    if not ret: break
    if cv2.waitKey(30) >= 0: break
    target = cv2.resize(frame, (400, 300))

    dst = cv2.bitwise_and(target, target, mask=mask)
    cv2.rectangle(dst, (30, 30), (30+320, 30+240), (0,0,255), 2)


    exposure = capture.get(cv2.CAP_PROP_EXPOSURE)
    title = "View Frame from Camera"
    cv2.imshow(title, dst)  # 윈도우에 영상 띄우기
capture.release()

cv2.destroyAllWindows()

 

12. 영상파일을 읽어서 메인 윈도우에 다음과 같이 출력하시오.

소스코드
image = cv2.imread('images/abs_test1.jpg', cv2.IMREAD_GRAYSCALE)
if image is None: raise Exception("영상파일 읽기 오류")

mask1 = np.zeros(image.shape[:2], image.dtype)
cv2.rectangle(mask1, (50, 50, 100, 100), 255, -1)
cv2.add(image, 50, image, mask1)


target = image[200:300, 200:300]
noimage = np.zeros(target.shape[:2], target.dtype)
avg = cv2.mean(image)[0]/2.0

target = cv2.addWeighted(target, 2.0, noimage, 0, -avg)
image[200:300, 200:300] = target

cv2.imshow("12", image)
cv2.waitKey(0)
cv2.destroyAllWindows()



13. cv2.sortIdx() 함수를 활용해서 다음의 조건에 부합하도록 벡터의 원소를 정렬하시오.

소스코드
import numpy as np, cv2

def print_rects(rects):
    print("-" * 46)                             
    print("사각형 원소\t\t랜덤 사각형 정보\t\t   넓이")
    print("-" * 46)
    for i, (x,y, w,h, a) in enumerate(rects):
         print("rects[%i] = [(%3d,%3d) from (%3d,%3d)] %5d" %(i, w, h, x, y, a))
    print()

rands = np.zeros((10, 5), np.uint16)       
starts = cv2.randn(rands[:, :2 ], 100, 50)    
ends = cv2.randn(rands[:, 2:-1], 300, 50)      
sizes = cv2.absdiff(starts, ends)

areas = sizes[:, 0] * sizes[:, 1]
rects = rands.copy()
rects[:, 2:-1] = sizes
rects[:,-1] = areas

idx = cv2.sortIdx(areas, cv2.SORT_EVERY_COLUMN + cv2.SORT_ASCENDING).flatten()

print_rects(rects)
print_rects(rects[idx.astype('int')])

 

 

14. 다음의 연립방정식을 가우시안 소거법의 역함수를 계산해서 해를 구하는 프로그램을 작성하시오.

소스코드
import numpy as np, cv2

data = [ 3, 6, 3, -5, 6, 1, 2,-3, 5]
m1 = np.array(data, np.float32).reshape(3,3)
m2 = np.array([2, 10, 28], np.float32)

ret, inv = cv2.invert(m1, cv2.DECOMP_LU)               
if ret:
    ret, dst = cv2.solve(m1, m2, cv2.DECOMP_LU)        # 연립방정식 풀이

    print("[inv] = \n%s\n" % inv)
    print("[dst] =", dst.flatten())                   # 행렬을 벡터로 변환
else:
    print("역행렬이 존재하지 않습니다.")

 

 

15. 5.6절에서 예제_5.6.2의 사각형 회전하기 예제를 확장하여 그 사각형의 중심점을 기준으로 45도 회전시키는 프로그램을 완성하시오.

소스코드
import numpy as np, cv2

pts1 = np.array([(200,50,1), (400, 50, 1), (400, 250, 1), (200, 250, 1)], np.float32)

theta = 45 * np.pi / 180
m = np.array([[np.cos(theta), -np.sin(theta), 0], 
             [np.sin(theta), np.cos(theta), 0],
             [0,0,1]], np.float32)

delta = (pts1[2] - pts1[0])// 2
center = pts1[0] + delta
print('center=',center)

t1 = np.eye(3, dtype=np.float32)
t2 = np.eye(3, dtype=np.float32)

t1[:2, 2] = -center[:2]
t2[:2, 2] = center[:2]

m2 = cv2.gemm(t2, m, 1, None, 0) 
m2 = cv2.gemm(m2, t1, 1, None, 0)

pts2 = cv2.gemm(pts1, m2, 1,None, 1, flags=cv2.GEMM_2_T)

for i, (pt1, pt2) in enumerate(zip(pts1, pts2)):
    print("pts1[%d] = %s, pts2[%d] = %s"%(i, pt1, i, pt2))

image = np.full((400, 500, 3), 255, np.uint8)
cv2.polylines(image, [np.int32(pts1[:,:2])], True, (0, 255, 0), 2)
cv2.polylines(image, [np.int32(pts2[:,:2])], True, (255, 0, 0), 3)
cv2.imshow("image", image)
cv2.waitKey(0)
cv2.destroyAllWindows()


 

 


Docs에서 쓴거 그대로 옮겼더니 수식이 다 깨졌다.

'Programming > Python' 카테고리의 다른 글

[OpenCV] OpenCV-Python으로 배우는 영상 처리 및 응용 - 6장 연습문제 풀이  (1) 2025.07.01
[OpenCV] OpenCV-Python으로 배우는 영상 처리 및 응용 - 4장 연습문제 풀이  (6) 2025.06.30
[Jupyter extension] Jupyter 확장프로그램 개발 환경 구축  (1) 2024.09.02
[OpenCV] 채널 별 배열 구조 + 이미지 투명화  (1) 2023.10.17
'Programming/Python' 카테고리의 다른 글
  • [OpenCV] OpenCV-Python으로 배우는 영상 처리 및 응용 - 6장 연습문제 풀이
  • [OpenCV] OpenCV-Python으로 배우는 영상 처리 및 응용 - 4장 연습문제 풀이
  • [Jupyter extension] Jupyter 확장프로그램 개발 환경 구축
  • [OpenCV] 채널 별 배열 구조 + 이미지 투명화
FoO__511
FoO__511
  • FoO__511
    FoO의 개발 블로그
    FoO__511
  • 전체
    오늘
    어제
    • 분류 전체보기 (17)
      • Programming (13)
        • Java (1)
        • Python (5)
        • Algorithm (2)
        • FE (5)
      • 학과공부 (2)
        • 데이터통신 (1)
        • 기계학습 (1)
        • 기타 (0)
      • 회고 (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    Java
    nextjs
    kde plasma
    리눅스 카톡
    jupyter extension
    결측치 제거
    개방 시스템 상호 연결
    연습문제 풀이
    opencv-python
    function barrowing
    seaborn
    백준
    script tag
    opencv-python으로 배우는 영상처리 및 응용
    dinamic programming
    javascript
    partial application
    결손치 제거
    git workflow
    연습문제 6장
    함수 빌려쓰기
    GA4
    사용자 속성
    TDZ
    Git Action
    utm parameter
    Priority Queue
    multi boot
    yarn berry
    렉시컬 스코프
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.4
FoO__511
[OpenCV] OpenCV-Python으로 배우는 영상 처리 및 응용 - 5장 연습문제 풀이
상단으로

티스토리툴바