import numpy as np
def mat_access1(mat):
for i in range(mat.shape[0]):
for j in range(mat.shape[1]):
k = mat[i, j]
mat[i,j] = k * 2
def mat_access2(mat):
for i in range(mat.shape[0]):
for j in range(mat.shape[1]):
k = mat.item(i,j)
mat.itemset((i,j), k*2)
mat1 = np.arange(10).reshape(2, 5)
mat2 = np.arange(10).reshape(2, 5)
print("원소 처리 전: \n%s\n" % mat1)
mat_access1(mat1)
print("원소 처리 후: \n%s\n" % mat1)
print("원소 처리 전: \n%s\n" % mat2)
mat_access2(mat2)
print("원소 처리 후: \n%s" % mat2)

- 높은 대비: 시각적으로 더 명확히 보임
- 낮은 대비: 밝기의 차이가 크지 않아, 시각적으로 명확 X

import cv2
image = cv2.imread("C:/Open CV/chap06/images/bright.jpg", cv2.IMREAD_GRAYSCALE) # 영상 읽기
if image is None: raise Exception("영상 파일 읽기 오류")
# OpenCV 함수 이용
dst1 = cv2.add(image, 100) # 밝게
dst2 = cv2.subtract(image, 100) # 어둡게
# numpy.ndarray 이용
dst3 = image + 100 # 밝게
dst4 = image - 10 # 어둡게
cv2.imshow("original image", image)
cv2.imshow("dst1- bright: OpenCV", dst1)
cv2.imshow("dst2- dark: OpenCV", dst2)
cv2.imshow("dst3- bright: numpy", dst3)
cv2.imshow("dst4- dark: numpy", dst4);
cv2.waitKey(0)
# 행렬 덧셈, 곱셈 이용한 영상 합성
import numpy as np, cv2
image1 = cv2.imread("C:/Open CV/chap06/images/add1.jpg", cv2.IMREAD_GRAYSCALE) # 영상 읽기
image2 = cv2.imread("C:/Open CV/chap06/images/add2.jpg", cv2.IMREAD_GRAYSCALE)
if image1 is None or image2 is None: raise Exception("영상 파일 읽기 오류 발생")
# 영상 합성
alpha, beta = 0.6, 0.7 # 곱셈 비율
add_img1 = cv2.add(image1, image2) # 단순 더하기
add_img2 = cv2.add(image1*alpha, image2*beta) # 비율에 따른 더하기
add_img2 = np.clip(add_img2, 0, 255).astype('uint8') # saturation 처리
add_img3 = cv2.addWeighted(image1, alpha, image2, beta, 0) # 두 영상 비율에 따른 더하기
titles = ['image1','image2','add_img1','add_img2','add_img3']
for t in titles: cv2.imshow(t, eval(t)) # 영상 표시
cv2.waitKey(0)

- 대비: 같은 색도 인접한 색의 밝기에 따라 다르게 보임
import numpy as np, cv2
image = cv2.imread("C:/Open CV/chap06/images/contrast.jpg", cv2.IMREAD_GRAYSCALE) # 영상 읽기
if image is None: raise Exception("영상 파일 읽기 오류 발생")
noimage = np.zeros(image.shape[:2], image.dtype) # 더미 영상
avg = cv2.mean(image)[0]/2.0
dst1 = cv2.scaleAdd(image, 0.5, noimage) # 명암 대비 감소
dst2 = cv2.scaleAdd(image, 2.0, noimage) # 명암 대비 증가
dst3 = cv2.addWeighted(image, 0.5, noimage, 0, avg) # 명암 대비 감소
dst4 = cv2.addWeighted(image, 2.0, noimage, 0, -avg) # 명암 대비 증가
# 영상 띄우기
cv2.imshow("image", image)
cv2.imshow("dst1 - decrease contrast", dst1)
cv2.imshow("dst2 - increase contrast", dst2)
cv2.imshow("dst3 - decrease contrast using average", dst3)
cv2.imshow("dst4 - increase contrast using average", dst4)
cv2.imwrite("dst.jpg",dst1)
cv2.waitKey(0)

import numpy as np, cv2
image1 = cv2.imread("C:/Open CV/chap06/images/add1.jpg", cv2.IMREAD_GRAYSCALE) # 영상 읽기
image2 = cv2.imread("C:/Open CV/chap06/images/add2.jpg", cv2.IMREAD_GRAYSCALE)
if image1 is None or image2 is None: raise Exception("영상 파일 읽기 오류 발생")
# 영상 합성
#alpha, beta = 0.6, 0.7
alpha = float(input())
beta = float(input())
add_img1 = cv2.addWeighted(image1, alpha, image2, beta, 0)
cv2.imshow("dst", add_img1)
cv2.waitKey(0)


컬러 공간: 색 표시계의 모든 색들을 색 공간에서 3차원 좌표로 표현한 것
-> 컬러들과의 관계를 표현하는 논리적인 방법 제공
영상 처리에서의 활용
- 색상이 다른 객체 분리
- 전체 영상을 컬러 영역별 분리
- 전선의 연결 오류 검사 목적
- 색상 정보를 이용한 특정 물체 검색
RGB 컬러 공간: 빛의 삼원색(빨, 초, 파) 사용
CMY(K) 컬러 공간: RGB 컬러 공간과 보색 관계, 색의 삼원색(청록, 자홍, 노랑) 사용
CMYK 컬러 공간: 순수한 검정색 사용 -> 뛰어난 대비 제공
# CMY(K) 컬러 공간 변환
import numpy as np, cv2
BGR_img = cv2.imread("C:/Open CV/chap06/images/color_model.jpg", cv2.IMREAD_COLOR) # 컬러 영상 읽기
if BGR_img is None: raise Exception("영상 파일 읽기 오류")
white = np.array([255,255,255], np.uint8)
CMY_img = white - BGR_img
Yellow, Magenta, Cyan = cv2.split(CMY_img)
titles = ['BGR_img','CMY_img','Cyan','Magenta','Yellow']
[cv2.imshow(t, eval(t)) for t in titles]
cv2.waitKey(0)

import numpy as np
import cv2
def on_trackbar_change(val):
global alpha, beta
alpha = cv2.getTrackbarPos("Alpha", "dst") / 100
beta = cv2.getTrackbarPos("Beta", "dst") / 100
update_blend()
def update_blend():
global alpha, beta, image1, image2
add_img = cv2.addWeighted(image1, alpha, image2, beta, 0)
cv2.imshow("dst", add_img)
# Read images
image1 = cv2.imread("C:/Open CV/chap06/images/add1.jpg", cv2.IMREAD_GRAYSCALE)
image2 = cv2.imread("C:/Open CV/chap06/images/add2.jpg", cv2.IMREAD_GRAYSCALE)
if image1 is None or image2 is None:
raise Exception("영상 파일 읽기 오류 발생")
# Initial alpha and beta values
alpha = 0.5
beta = 0.5
# Create a window and add trackbars
cv2.namedWindow("dst")
cv2.createTrackbar("Alpha", "dst", int(alpha * 100), 100, on_trackbar_change)
cv2.createTrackbar("Beta", "dst", int(beta * 100), 100, on_trackbar_change)
# Display initial result
update_blend()
# Wait for a key event
cv2.waitKey(0)
<코드 설명>

: https://github.com/UB-Mannheim/tesseract/wiki
import cv2
import numpy as np
import pytesseract
TESSERACT_PATH = "C:/Program Files/Tesseract-OCR" # 테서렉트 설치 경로
imgpath = 'images/2.JPG' # 이미지 파일 경로
win_name = "Image To Text" # OpenCV 창 이름
img = cv2.imread(imgpath) # 이미지 읽어오기
img = cv2.resize(img, dsize=(0,0), fx=0.7, fy=0.7, interpolation=cv2.INTER_AREA) # 크기 조절! 안해주면 밑에 잘림
image = img.copy()
rows, cols = img.shape[:2]
count = 0
rect = np.zeros((4,2), dtype=np.float32)
cv2.imshow(win_name, img)
#마우스 이벤트 처리 함수
def onMouse(event, x, y, flags, param):
global win_name, image, count, img
if event == cv2.EVENT_LBUTTONUP:
if count < 4:
cv2.circle(image, (x,y), 10, (100,255,0), -1)
cv2.imshow(win_name, image)
rect[count] = [x,y]
count+=1
if count == 4:
sm = rect.sum(axis=1)
diff = np.diff(rect, axis = 1)
topLeft = rect[np.argmin(sm)]
bottomRight = rect[np.argmax(sm)]
topRight = rect[np.argmin(diff)]
bottomLeft = rect[np.argmax(diff)]
pts1 = np.float32([topLeft, topRight, bottomRight , bottomLeft])
w1 = abs(bottomRight[0] - bottomLeft[0])
w2 = abs(topRight[0] - topLeft[0])
h1 = abs(topRight[1] - bottomRight[1])
h2 = abs(topLeft[1] - bottomLeft[1])
width = max([w1, w2])
height = max([h1, h2])
pts2 = np.float32([[0,0], [width-1,0],
[width-1,height-1], [0,height-1]])
mtrx = cv2.getPerspectiveTransform(pts1, pts2)
result = cv2.warpPerspective(img, mtrx, (int(width), int(height)))
image = result
print(GetOCR())
count=0
image = img.copy()
return 0
#OCR 함수
def GetOCR():
#이미지 불러오기
global image
image = cv2.threshold(cv2.cvtColor(image, cv2.COLOR_BGR2GRAY), 130, 255, cv2.THRESH_BINARY_INV)[1]
#OCR모델 불러오기
pytesseract.pytesseract.tesseract_cmd = TESSERACT_PATH
#OCR모델로 글자 추출
text = pytesseract.image_to_string(image, lang='kor+eng')
cv2.imshow("OCR", image)
return text
cv2.setMouseCallback(win_name, onMouse)
#cv2.imshow(win_name, img) #이미지 출력
cv2.waitKey(0) #입력 대기
<코드 설명>
- onMouse 함수: 마우스 클릭 이벤트를 처리하는 함수로, 사용자가 이미지에서 4개의 점을 선택할 수 있게 함. 이 점들들 바탕으로 perspective 변환을 수행.
- Perspective 변환: 사용자가 선택한 4개의 점을 이용하여 perspective 변환 행렬을 계산하고, cv2.warpPerspective 함수를 사용하여 이미지를 변환
- GetOCR 함수: Tesseract OCR을 사용하여 이미지에서 텍스트를 추출. 이미지를 그레이스케일로 변환하고 이진화 처리를 수행한 후, Tesseract를 이용하여 텍스트를 추출.
- 마우스 이벤트 및 OCR 결과 출력: cv2.setMouseCallback 함수를 통해 마우스 이벤트를 처리하고, 추출된 텍스트는 GetOCR 함수를 통해 얻어지며, 결과는 콘솔에 출력됨.
화소의 영역 처리
- 디지털 영상 처리 시스템: 선형 시불변 시스템
회선 수행 방법
- 가중치를 포함한 회선 마스크가 이동(왼쪽 위 -> 오른쪽)하며 수행
회선 마스크 특징
- 크기: 행, 열 모두 홀수 크기 사용
영상에서 화소값이 급격하게 변하는 부분들을 감소시켜 점진적으로 변하게
함으로써 영상이 전체적으로 부드러운 느낌이 나게 하는 기술
import numpy as np, cv2, time
# 회선 수행 함수 - 행렬 처리 방식(속도 면에서 유리)
def filter(image, mask):
rows, cols = image.shape[:2]
dst = np.zeros((rows, cols), np.float32)
xcenter, ycenter = mask.shape[1]//2, mask.shape[0]//2
for i in range(ycenter, rows - ycenter):
for j in range(xcenter, cols - xcenter):
y1, y2 = i - ycenter, i + ycenter + 1
x1, x2 = i - xcenter, i + xcenter + 1
roi = image[y1:y2, x1:x2].astype('float32')
tmp = cv2.multiply(roi, mask)
dst[i,j] = cv2.sumElems(tmp)[0]
return dst # 자료형 변환하여 반환
# 회선 수행 함수 - 화소 직접 근접
def filter2(image, mask):
rows, cols = image.shape[:2]
dst = np.zeros((rows, cols), np.float32)
xcenter, ycenter = mask.shape[1]//2, mask.shape[0]//2
for i in range(ycenter, rows - ycenter):
for j in range(xcenter, cols - xcenter):
sum = 0.0
for u in range(mask.shape[0]):
for v in range(mask.shape[1]):
y, x = i + u - ycenter, j + v - xcenter
sum += image[y,x] * mask[u, v]
dst[i, j] = sum
return dst
image = cv2.imread("C:/Open CV/chap07/images/filter_blur.jpg", cv2.IMREAD_GRAYSCALE) # 영상 읽기
if image is None: raise Exception("영상파일 읽기 오류")
# 블러링 마스크 원소 지정
data = [ 1/9, 1/9, 1/9,
1/9, 1/9, 1/9,
1/9, 1/9, 1/9 ]
mask = np.array(data, np.float32).reshape(3, 3)
blur1 = filter(image, mask) # 회선 수행 - 화소 직접 접근
blur2 = filter2(image, mask) # 회선 수행
cv2.imshow("image", image)
cv2.imshow("blur1", blur1.astype("uint8"))
cv2.imshow("blur2", cv2.convertScaleAbs(blur2))
cv2.waitKey(0)

- 출력 화소에서 이웃 화소끼리 차이를 크게 하여 날카로운 느낌이 나도록 만드는 것
- 영상의 세세한 부분 강조 가능
샤프닝 마스크: 마스크 원소들의 값 차이가 커지도록 구성 & 원소 전체 합이 1이 되도록
블러링과 마스크만 다름!
import numpy as np, cv2
from Common.filters import filter
image = cv2.imread("images/filter_sharpen.jpg", cv2.IMREAD_GRAYSCALE) # 영상 읽기
if image is None: raise Exception("영상파일 읽기 오류")
# 샤프닝 마스크 원소 지정
data1 = [ 0, -1, 0,
-1, 5, -1,
0, -1, 0]
data2 = [[-1, -1, -1],
[-1, 9, -1],
[-1, -1, -1]]
mask1 = np.array(data1, np.float32).reshape(3, 3)
mask2 = np.array(data2, np.float32)
sharpen1 = filter(image, mask1)
sharpen2 = filter(image, mask2)
sharpen1 = cv2.convertScaleAbs(sharpen1)
sharpen2 = cv2.convertScaleAbs(sharpen2)
cv2.imshow("image", image)
cv2.imshow("sharpen1", cv2.convertScaleAbs(sharpen1)) # 윈도우 표시 위한 형변환
cv2.imshow("sharpen2", cv2.convertScaleAbs(sharpen2))
cv2.waitKey(0)

- 디지털 영상의 밝기가 낮은 값 -> 높은 값 or 높은 값 -> 낮은 값으로 변하는 지점
- 디지털 영상을 구성하는 객체 간의 경계
에지가 화소의 밝기 변화율에 관여
1차 미분 이용 or 2차 미분 이용
예시: 자동차 번호판 검색, 도로 차선 검출

장점: 크기가 작아서 매우 빠른 속도로 동작
단점: 돌출된 값 평균 어렵 + 잡음에 민감
import numpy as np, cv2
from Common.filters import filter
def differential(image, data1, data2):
mask1 = np.array(data1, np.float32).reshape(3,3)
mask2 = np.array(data2, np.float32).reshape(3,3)
dst1 = filter(image, mask1)
dst2 = filter(image, mask2)
dst1, dst2 = np.abs(dst1), np.abs(dst2)
dst = cv2.magnitude(dst1, dst2)
dst = np.clip(dst, 0, 255).astype('uint8')
dst1 = np.clip(dst1, 0, 255).astype('uint8')
dst2= np.clip(dst2, 0, 255).astype('uint8')
return dst, dst1, dst2
image = cv2.imread("images/edge.jpg", cv2.IMREAD_GRAYSCALE)
if image is None: raise Exception("영상파일 읽기 오류")
data1 = [-1, 0, 0,
0, 1, 0,
0, 0, 0]
data2 = [ 0, 0, -1,
0, 1, 0,
0, 0, 0]
dst, dst1, dst2 = differential(image, data1, data2) # 회선 수행 및 두 방향의 크기 계산
cv2.imshow("image", image)
cv2.imshow("roberts edge", dst)
cv2.imshow("dst1", dst1)
cv2.imshow("dst2", dst2)
cv2.waitKey(0)
프리윗(Prewitt) 마스크
- 로버츠 마스크의 단점 보완 위해 고안
- 수직 마스크: 원소의 배치가 수직 방향으로 구성, 에지의 방향도 수직
- 수평 마스크: 원소의 배치가 수평 방향으로 구성, 에지의 방향도 수평
- 장점: 돌출된 값을 비교적 잘 평균화
- 단점: 대각선보다 수평, 수직에 놓인 에지에 더 민감하게 반응
소벨(Sobel) 마스크
- 프리윗 마스크와 유사
- 중심 화소의 처분에 대한 비중을 2배 키움 -> 대각선 방향 에지 검출 가능
- 장점: 돌출된 값을 비교적 잘 평균화
- 단점: 대각선 방향에 놓인 에지에 더 민감하게 반응
import numpy as np, cv2
image = cv2.imread("images/edge.jpg", cv2.IMREAD_GRAYSCALE)
if image is None: raise Exception("영상파일 읽기 오류")
# OpenCV 제공 소벨 에지 계산
# x축방향 미분 - 수직 마스크, ksize: 커널 크기
dst1 = cv2.Sobel(np.float32(image), cv2.CV_32F, 1, 0, ksize=3)
# y방향 미분 - 수평 마스크
dst2 = cv2.Sobel(np.float32(image), cv2.CV_32F, 0, 1, 3)
dst1 = cv2.convertScaleAbs(dst1)
dst2 = cv2.convertScaleAbs(dst2)
cv2.imshow("edge- sobel edge", image)
cv2.imshow("dst1- vertical_OpenCV", dst1)
cv2.imshow("dst2- horizontal_OpenCV", dst2)
cv2.waitKey(0)
4. 2차 미분 마스크
- 라플라시안 필터를 적용한 이미지에서 0을 기준으로 양수 -> 음수 or 음수 -> 양수 픽셀 찾아냄
- cv2.Laplacians(src, ddepth, scale, delta~)
import numpy as np, cv2
image = cv2.imread("images\laplacian.jpg", cv2.IMREAD_GRAYSCALE)
if image is None: raise Exception("영상파일 읽기 오류")
data1 = [[0, 1, 0],
[1, -4, 1],
[0, 1, 0]]
data2 = [[-1, -1, -1],
[-1 ,8, -1],
[-1, -1, -1]]
mask4 = np.array(data1, np.int16)
mask8 = np.array(data2, np.int16)
# OpenCV 함수 cv2.filter2D() 통한 라플라시안 수행
dst1 = cv2.filter2D(image, cv2.CV_16S, mask4)
dst2 = cv2.filter2D(image, cv2.CV_16S, mask8)
dst3 = cv2.Laplacian(image, cv2.CV_16S, 1)
cv2.imshow("image", image)
cv2.imshow("filter2D 4-direction", cv2.convertScaleAbs(dst1))
cv2.imshow("filter2D 8-direction", cv2.convertScaleAbs(dst2))
cv2.imshow("Laplacian_OpenCV", cv2.convertScaleAbs(dst3))
cv2.waitKey(0)

- 잡음은 다른 부분과 경계를 이루는 경우가 많아서 대부분의 에지 검출 방법이 이 잡음들을 에지로 검출
- 위의 문제를 보안한 방법이 캐니 에지 검출 기법
import numpy as np, cv2
image = cv2.imread("images\canny.jpg", cv2.IMREAD_GRAYSCALE)
if image is None: raise Exception("영상 파일 읽기 오류")
canny2 = cv2.Canny(image, 100, 150) # OpenCV 캐니 에지
cv2.imshow("image", image)
cv2.imshow("OpenCV_Canny", canny2) # OpenCV 캐니 에지
cv2.waitKey(0)

입력 영상의 중심 화소에서 마스크로 씌워진 영역의 입력 화소들을 가져와서 최댓값, 최솟값을 출력 화소로 결정하는 방법
최댓값 필터링: 가장 큰 값인 밝은 색들로 출력 화소가 구성
-> 돌출되는 어두운 값이 제거됨 + 전체적으로 밝은 영상
최솟값 필터링: 가장 작은 값들인 어두운 색들로 출력화소가 구성
-> 돌출되는 밝은 값들이 제거 + 전체적으로 어두운 여상
import numpy as np, cv2
def minmax_filter(image, ksize, mode):
rows, cols = image.shape[:2]
dst = np.zeros((rows,cols), np.uint8)
center = ksize // 2
for i in range(center, rows - center):
for j in range(center, cols - center):
# 마스크 영역 행렬 처리 방식
y1, y2 = i - center, i + center + 1
x1, x2 = j - center, j + center + 1
mask = image[y1:y2, x1:x2]
dst[i, j] = cv2.minMaxLoc(mask)[mode]
return dst
image = cv2.imread("images/min_max.jpg", cv2.IMREAD_GRAYSCALE)
if image is None: raise Exception("영상파일 읽기 오류")
minfilter_img = minmax_filter(image, 3, 0)
maxfilter_img = minmax_filter(image, 3, 1)
cv2.imshow("image", image)
cv2.imshow("minfilter_img", minfilter_img)
cv2.imshow("maxfilter_img", maxfilter_img)
cv2.waitKey(0)

import numpy as np, cv2
image = cv2.imread("images/filter_avg.jpg", cv2.IMREAD_GRAYSCALE)
if image is None: raise Exception("영상파일 읽기 오류")
blur_img = cv2.blur(image, (5,5), borderType=cv2.BORDER_CONSTANT)
box_img = cv2.boxFilter(image, ddepth=-1, ksize=(5,5))
cv2.imshow("image", image),
cv2.imshow("blur_img", blur_img)
cv2.imshow("box_img", box_img)
cv2.waitKey(0)

import numpy as np, cv2
def salt_pepper_noise(img, n):
h, w = img.shape[:2]
x, y = np.random.randint(0, w, n), np.random.randint(0, h, n)
noise = img.copy()
for (x,y) in zip(x,y):
noise[y,x] = 0 if np.random.rand() < 0.5 else 255
return noise
image = cv2.imread("images/median2.jpg", cv2.IMREAD_GRAYSCALE)
if image is None: raise Exception("영상파일 읽기 오류")
noise = salt_pepper_noise(image, 500)
med_img2 = cv2.medianBlur(noise, 3)
cv2.imwrite('chap07/images/noise.jpg', noise)
cv2.imshow("image", image),
cv2.imshow("noise", noise),
cv2.imshow("median - OpenCV", med_img2)
cv2.waitKey(0)

import numpy as np
import cv2
def on_trackbar1(pos):
global low_threshold
low_threshold = pos
update_canny()
def on_trackbar2(pos):
global high_threshold
high_threshold = pos
update_canny()
def update_canny():
canny_result = cv2.Canny(image, low_threshold, high_threshold)
cv2.imshow("OpenCV_Canny", canny_result)
image = cv2.imread("C:/Open CV/chap07/images/cannay_tset.jpg", cv2.IMREAD_GRAYSCALE)
if image is None:
raise Exception("영상 파일 읽기 오류")
low_threshold = 100
high_threshold = 150
cv2.namedWindow("image")
cv2.imshow("image", image)
cv2.createTrackbar("Low Threshold", "image", low_threshold, 255, on_trackbar1)
cv2.createTrackbar("High Threshold", "image", high_threshold, 255, on_trackbar2)
update_canny()
cv2.waitKey(0)
cv2.destroyAllWindows()


import numpy as np, cv2
def erode(img, mask=None):
dst = np.zeros(img.shape, np.uint8)
if mask is None: mask = np.ones((3, 3), np.uint8)
ycenter, xcenter = np.divmod(mask.shape[:2], 2)[0]
mcnt = cv2.countNonZero(mask) #0이 아닌 요소의 개수를 반환
for i in range(ycenter, img.shape[0] - ycenter): # 입력 행렬 반복 순회
for j in range(xcenter, img.shape[1] - xcenter):
y1, y2 = i - ycenter, i + ycenter + 1 # 마스크 높이 범위
x1, x2 = j - xcenter, j + xcenter + 1 # 마스크 너비 범위
roi = img[y1:y2, x1:x2] # 마스크 영역
temp = cv2.bitwise_and(roi, mask)
cnt = cv2.countNonZero(temp) # 일치한 화소수 계산
dst[i, j] = 255 if (cnt == mcnt) else 0 # 출력 화소에 저장
return dst
image = cv2.imread("C:/Open CV/chap07/images/morph.jpg", cv2.IMREAD_GRAYSCALE)
if image is None: raise Exception("영상파일 읽기 오류")
data = [0, 1, 0, # 마스크 선언 및 초기화
1, 1, 1,
0, 1, 0]
mask = np.array(data, np.uint8).reshape(3, 3)
th_img = cv2.threshold(image, 128, 255, cv2.THRESH_BINARY)[1] # 영상 이진화
dst1 = erode(th_img, mask) # 사용자 정의 침식 함수
dst2 = cv2.erode(th_img, mask)
# dst2 = cv2.morphologyEx(th_img, cv2.MORPH_ERODE, mask) # OpenCV의 침식 함수
cv2.imshow("image", image)
cv2.imshow("binary image", th_img)
cv2.imshow("User erode", dst1)
cv2.imshow("OpenCV erode", dst2)
cv2.waitKey(0)

import numpy as np, cv2
def dilate(img, mask):
dst = np.zeros(img.shape, np.uint8)
if mask is None: mask = np.ones((3, 3), np.uint8)
ycenter, xcenter = np.divmod(mask.shape[:2], 2)[0]
for i in range(ycenter, img.shape[0] - ycenter): # 입력 행렬 반복 순회
for j in range(xcenter, img.shape[1] - xcenter):
y1, y2 = i - ycenter, i + ycenter + 1 # 마스크 높이 범위
x1, x2 = j - xcenter, j + xcenter + 1 # 마스크 너비 범위
roi = img[y1:y2, x1:x2] # 마스크 영역
temp = cv2.bitwise_and(roi, mask)
cnt = cv2.countNonZero(temp)
dst[i, j] = 0 if (cnt == 0) else 255 # 출력 화소에 저장
return dst
image = cv2.imread("C:/Open CV/chap07/images/morph.jpg", cv2.IMREAD_GRAYSCALE)
if image is None: raise Exception("영상파일 읽기 오류")
mask = np.array([[0, 1, 0], # 마스크 초기화
[1, 1, 1],
[0, 1, 0]]).astype("uint8")
th_img = cv2.threshold(image, 128, 255, cv2.THRESH_BINARY)[1] # 영상 이진화
dst1 = dilate(th_img, mask) # 사용자 정의 팽창 함수
dst2 = cv2.morphologyEx(th_img, cv2.MORPH_DILATE, mask) # OpenCV의 팽창 함수
# dst2 = cv2.dilate(th_img, mask)
cv2.imshow("User dilate", dst1)
cv2.imshow("OpenCV dilate", dst2)
cv2.waitKey(0)

import numpy as np
import cv2
def salt_pepper_noise(img, n):
h, w = img.shape[:2]
x, y = np.random.randint(0, w, n), np.random.randint(0, h, n)
noise = img.copy()
for (x, y) in zip(x, y):
noise[y, x] = 0 if np.random.rand() < 0.5 else 255
return noise
image = cv2.imread("C:/Open CV/chap07/images/median2.jpg", cv2.IMREAD_GRAYSCALE)
if image is None:
raise Exception("영상파일 읽기 오류")
# 소금-후추 노이즈 추가
noise = salt_pepper_noise(image, 500)
# 중간값 필터 적용
med_img2 = cv2.medianBlur(noise, 3)
# 침식 연산 적용
kernel = np.ones((3, 3), np.uint8)
erosion_result = cv2.erode(noise, kernel, iterations=1)
# 팽창 연산 적용
dilation_result = cv2.dilate(noise, kernel, iterations=1)
# 결과 이미지 저장
cv2.imwrite('images/noise.jpg', noise)
cv2.imwrite('images/erosion.jpg', erosion_result)
cv2.imwrite('images/dilation.jpg', dilation_result)
# 이미지 출력
cv2.imshow("Original Image", image)
cv2.imshow("Salt-and-Pepper Noise", noise)
cv2.imshow("Median Filter - OpenCV", med_img2)
cv2.imshow("Erosion", erosion_result)
cv2.imshow("Dilation", dilation_result)
cv2.waitKey(0)
cv2.destroyAllWindows()
import numpy as np, cv2
from Common.filters import erode, dilate
def opening(img, mask): # 열림 연산
tmp = erode(img, mask) # 침식
dst = dilate(tmp, mask) # 팽창
return dst
def closing(img, mask): # 닫힘 연산
tmp = dilate(img, mask)
dst = erode(tmp, mask)
return dst
image = cv2.imread("C:/Open CV/chap07/images/morph.jpg", cv2.IMREAD_GRAYSCALE)
if image is None: raise Exception("영상파일 읽기 오류")
mask = np.array([[0, 1, 0], # 마스크 초기화
[1, 1, 1],
[0, 1, 0]]).astype("uint8")
th_img = cv2.threshold(image, 128, 255, cv2.THRESH_BINARY)[1] # 영상 이진화
dst1 = opening(th_img, mask) # 사용자 정의 열림 함수 호출
dst2 = closing(th_img, mask) # 사용자 정의 닫힘 함수 호출
dst3 = cv2.morphologyEx(th_img, cv2.MORPH_OPEN, mask) # OpenCV의 열림 함수
dst4 = cv2.morphologyEx(th_img, cv2.MORPH_CLOSE, mask, iterations = 1) # OpenCV의 닫힘 함수
cv2.imshow("User opening", dst1); cv2.imshow("User closing", dst2)
cv2.imshow("OpenCV opening", dst3); cv2.imshow("OpenCV closing", dst4)
cv2.waitKey(0)
