├── 09.ml ├── plane_bike_dict.npy ├── plane_bike_dict_4000.npy ├── k-means_handwritten.py ├── kNN_mnist.py ├── k-means_color.py ├── k-means_random.py ├── haar_face.py ├── workshop_face_mosaic.py ├── lbp_face2_train.py ├── kNN_random.py ├── haar_face_cam.py ├── svm_random.py ├── svm_hog_pedestrian.py ├── kNN_movie.py ├── kNN_handwritten.py ├── bow_plane_bike_test.py ├── workshop_hannibal_mask.py ├── svm_handwritten.py ├── lbp_face1_collect.py ├── lbp_face3_recognize.py ├── svm_mnist_hog_train.py ├── mnist.py ├── workhop_face_distotion_camera.py └── bow_plane_bike_train.py ├── 04.img_processing ├── cropped2.jpg ├── roi_select_img.py ├── histo_rgb.py ├── roi.py ├── arithmatic_mask.py ├── histo_gray.py ├── roi_copy.py ├── arithmatic.py ├── bitwise_masking.py ├── bitwise_masking2.py ├── bgr2gray.py ├── rgba.py ├── thresholds.py ├── blending_alpha.py ├── blending_simple.py ├── blending_alpha_trackbar.py ├── bgr2yuv.py ├── histo_equalize_yuv.py ├── seamlessclone.py ├── threshold_otsu.py ├── bgr2hsv.py ├── diff_absolute.py ├── histo_clahe.py ├── bitwise.py ├── threshold.py ├── threshold_flag.py ├── histo_2d.py ├── addition_rgba_mask.py ├── histo_normalize.py ├── threshold_adpted.py ├── histo_equalize.py ├── workshop_two_face.py ├── chromakey.py ├── histo_compare.py ├── hsv_color_mask.py ├── histo_backproject.py ├── roi_crop_mouse.py └── workshop_cctv_motion_sensor.py ├── 03.numpy_matplotlib ├── np_index.py ├── np_create_arange.py ├── plt_imshow.py ├── np_broadcat.py ├── plt_plot.py ├── np_create_like.py ├── np_dtype.py ├── plt_color.py ├── plt_simple.py ├── np_scalar_operation.py ├── plt_style.py ├── np_img.py ├── plt_imgshow_rgb.py ├── np_create_size.py ├── plt_subplot.py ├── np_create_array.py ├── np_reshape.py ├── np_gray.py ├── plt_imshow_subplot.py └── np_bgr.py ├── 06.filter ├── edge_canny.py ├── edge_laplacian.py ├── blur_median.py ├── pyramid_gaussian.py ├── morph_erode.py ├── morph_dilate.py ├── blur_bilateral.py ├── blur_avg_api.py ├── morph_gradient.py ├── edge_differential.py ├── edge_roberts.py ├── morph_hat.py ├── edge_prewitt.py ├── pyramid_laplacian.py ├── workshop_mosic2.py ├── edge_scharr.py ├── morph_open_close.py ├── blur_avg_kernel.py ├── blur_gaussian.py ├── edge_sobel.py └── workshop_painting_cam.py ├── 02.interface ├── img_show_gray.py ├── img_write.py ├── draw_rect.py ├── img_show.py ├── video_cam_take_pic.py ├── video_cam.py ├── video_play.py ├── event_mouse_circle.py ├── video_play_fps.py ├── event_key.py ├── draw_poly.py ├── video_cam_resize.py ├── video_cam_rec.py ├── event_trackbar.py ├── draw_line.py ├── win.py ├── event_mouse_circle_flag.py ├── draw_circle.py └── draw_text.py ├── 08.match_track ├── kpt_fast.py ├── kpt_gftt.py ├── kpt_blob.py ├── desc_orb.py ├── corner_goodFeature.py ├── track_bgsub_mog2.py ├── track_bgsub_mog.py ├── desc_surf.py ├── desc_sift.py ├── avg_hash.py ├── match_bf_surf.py ├── corner_harris.py ├── match_bf_orb.py ├── match_bf_sift.py ├── match_flann_sift.py ├── match_flann_surf.py ├── kpt_blob_param.py ├── match_good_knn.py ├── match_flann_orb.py ├── match_good.py ├── avg_hash_matching.py ├── template_matching.py ├── track_optical_farneback.py ├── workshop_panorama.py ├── match_homography.py ├── match_homography_accuracy.py ├── track_opticalLK.py ├── track_camsifht_cam.py ├── track_meanshift_cam.py ├── track_trackingAPI.py ├── match_camera.py └── workshop_booksearcher.py ├── 05.geometric_transform ├── rotate_getmatrix.py ├── scale_resize.py ├── workshop_mosaic.py ├── undistort_barrel.py ├── rotate_matrix.py ├── getAffine.py ├── perspective.py ├── remap_barrel.py ├── translate.py ├── remap_flip.py ├── remap_sin_cos.py ├── remap_lens.py ├── scale_matrix.py ├── triangle_affine.py ├── perspective_scan.py ├── workhop_distotion_camera.py └── workshop_liquify_tool.py ├── 07.segmentation ├── hough_lineP.py ├── distanceTrans.py ├── connected_label.py ├── mean_shift.py ├── hough_circle.py ├── flood_fill.py ├── cntr_approximate.py ├── hough_line.py ├── cntr_moment.py ├── cntr_convexhull.py ├── cntr_hierarchy.py ├── cntr_find.py ├── cntr_bound_fit.py ├── cntr_matchShape.py ├── workshop_shape.py ├── watershed.py ├── grabcut.py ├── workshop_paper_scan.py └── workshop_coin_count.py └── README.md /09.ml/plane_bike_dict.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BaekKyunShin/OpenCV_Project_Python/HEAD/09.ml/plane_bike_dict.npy -------------------------------------------------------------------------------- /04.img_processing/cropped2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BaekKyunShin/OpenCV_Project_Python/HEAD/04.img_processing/cropped2.jpg -------------------------------------------------------------------------------- /09.ml/plane_bike_dict_4000.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BaekKyunShin/OpenCV_Project_Python/HEAD/09.ml/plane_bike_dict_4000.npy -------------------------------------------------------------------------------- /03.numpy_matplotlib/np_index.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | a = np.arange(10) # [0,1,2,3,4,5,6,7,8,9] 4 | a[5] # 5 5 | b = np.arange(12).reshape(4,3) 6 | -------------------------------------------------------------------------------- /03.numpy_matplotlib/np_create_arange.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | a = np.arange(5) 4 | print(a.shape) 5 | print(a.dtype) 6 | 7 | b = np.arange(3.0) 8 | print(b.dtype) 9 | -------------------------------------------------------------------------------- /03.numpy_matplotlib/plt_imshow.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | from matplotlib import pyplot as plt 3 | 4 | img = cv2.imread('../img/girl.jpg') 5 | 6 | plt.imshow(img) # 이미지 표시 7 | plt.show() -------------------------------------------------------------------------------- /03.numpy_matplotlib/np_broadcat.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | mylist = list(range(10)) 4 | print(mylist) 5 | 6 | for i in range(len(mylist)): 7 | mylist[i] = mylist[i] + 1 8 | print(mylist) -------------------------------------------------------------------------------- /03.numpy_matplotlib/plt_plot.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import numpy as np 3 | 4 | a = np.array([2,6,7,3,12,8,4,5]) # 배열 생성 5 | plt.plot(a) # plot 생성 6 | plt.show() # plot 그리기 -------------------------------------------------------------------------------- /03.numpy_matplotlib/np_create_like.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | img = cv2.imread('./img/girl.jpg') 5 | a = np.empty_like(img) 6 | b = np.zeros_like(img) 7 | c = np.ones_like(img) 8 | d = np.full_like(img, 255) 9 | 10 | print(a, a.shape, a.dtype) -------------------------------------------------------------------------------- /03.numpy_matplotlib/np_dtype.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | a = np.arange(10) 4 | print(a, a.dtype) 5 | 6 | b = a.astype('float32') 7 | print(b, b.dtype) 8 | 9 | c = np.uint8(b) 10 | print(c, c.dtype) 11 | 12 | d = c.astype(np.float64) 13 | print(d, d.dtype) -------------------------------------------------------------------------------- /03.numpy_matplotlib/plt_color.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import numpy as np 3 | 4 | x = np.arange(10) # 0,1,2,3,4,5,6,7,8,9 5 | y = x **2 # 0,1,4,9,16,25,36,49,64,81 6 | plt.plot(x,y, 'r') # plot 생성 --- ① 7 | plt.show() # plot 화면에 표시 8 | -------------------------------------------------------------------------------- /03.numpy_matplotlib/plt_simple.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import numpy as np 3 | 4 | x = np.arange(10) # 0,1,2,3,4,5,6,7,8,9 5 | y = x**2 # 0,1,4,9,16,25,36,49,64,81 6 | plt.plot(x,y) # plot 생성 --- ① 7 | plt.show() # plot 화면에 표시 --- ② 8 | -------------------------------------------------------------------------------- /06.filter/edge_canny.py: -------------------------------------------------------------------------------- 1 | import cv2, time 2 | import numpy as np 3 | 4 | img = cv2.imread("../img/sudoku.jpg") 5 | 6 | # 케니 엣지 적용 7 | edges = cv2.Canny(img,100,200) 8 | 9 | # 결과 출력 10 | cv2.imshow('Original', img) 11 | cv2.imshow('Canny', edges) 12 | cv2.waitKey(0) 13 | cv2.destroyAllWindows() 14 | -------------------------------------------------------------------------------- /06.filter/edge_laplacian.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | img = cv2.imread("../img/sudoku.jpg") 5 | 6 | # 라플라시안 필터 적용 ---① 7 | edge = cv2.Laplacian(img, -1) 8 | 9 | # 결과 출력 10 | merged = np.hstack((img, edge)) 11 | cv2.imshow('Laplacian', merged) 12 | cv2.waitKey(0) 13 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /02.interface/img_show_gray.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | 3 | img_file = "../img/yeosu.jpg" 4 | img = cv2.imread(img_file, cv2.IMREAD_GRAYSCALE) #그레이 스케일로 읽기 5 | 6 | if img is not None: 7 | cv2.imshow('IMG', img) 8 | cv2.waitKey() 9 | cv2.destroyAllWindows() 10 | else: 11 | print('No image file.') 12 | -------------------------------------------------------------------------------- /06.filter/blur_median.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | img = cv2.imread("../img/salt_pepper_noise.jpg") 5 | 6 | # 미디언 블러 적용 --- ① 7 | blur = cv2.medianBlur(img, 5) 8 | 9 | # 결과 출력 10 | merged = np.hstack((img,blur)) 11 | cv2.imshow('media', merged) 12 | cv2.waitKey(0) 13 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /03.numpy_matplotlib/np_scalar_operation.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | a = np.arange(5) 4 | 5 | b = a + 5 6 | c = a - 2 7 | d = a * 2 8 | e = a / 2 9 | f = b ** 2 10 | g = b > 2 11 | 12 | print(a) 13 | print(b) 14 | print(c) 15 | print(d) 16 | print(e) 17 | print(f) 18 | print(g) 19 | print(h) 20 | print(i) 21 | print(j) -------------------------------------------------------------------------------- /03.numpy_matplotlib/plt_style.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import numpy as np 3 | 4 | x = np.arange(10) 5 | f1 = x * 5 6 | f2 = x **2 7 | f3 = x **2 + x*2 8 | 9 | plt.plot(x,'r--') # 빨강색 이음선 10 | plt.plot(f1, 'g.') # 초록색 점 11 | plt.plot(f2, 'bv') # 파랑색 역 삼각형 12 | plt.plot(f3, 'ks' ) # 검정색 사각형 13 | plt.show() -------------------------------------------------------------------------------- /03.numpy_matplotlib/np_img.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | 3 | img = cv2.imread('../img/blank_500.jpg') # OpenCV로 이미지 읽기 4 | print( type(img)) # img의 데이타 타입 5 | print(img.ndim) # 배열의 차원 수 6 | print( img.shape) # 각 차원의 크기 7 | print(img.size) # 전체 요소의 갯수 8 | print( img.dtype) # 데이타 타입 9 | print(img.itemsize) # 각 요소의 바이트 크기 -------------------------------------------------------------------------------- /03.numpy_matplotlib/plt_imgshow_rgb.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | from matplotlib import pyplot as plt 3 | 4 | img = cv2.imread('../img/girl.jpg') 5 | 6 | plt.imshow(img[:,:,::-1]) # 이미지 컬러 채널 변경해서 표시 --- ① 7 | plt.xticks([]) # x좌표 눈금 제거 ---② 8 | plt.yticks([]) # y좌표 눈금 제거 ---③ 9 | plt.show() -------------------------------------------------------------------------------- /02.interface/img_write.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | 3 | img_file = '../img/yeosu.jpg' 4 | save_file = '../img/yeosu_gray.jpg' 5 | 6 | img = cv2.imread(img_file, cv2.IMREAD_GRAYSCALE) 7 | cv2.imshow(img_file, img) 8 | cv2.imwrite(save_file, img) #파일로 저장, 포맷은 확장에 따름 9 | cv2.waitKey() 10 | cv2.destroyAllWindows() 11 | -------------------------------------------------------------------------------- /06.filter/pyramid_gaussian.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | 3 | img = cv2.imread('../img/yeosu_small.jpg') 4 | 5 | # 가우시안 이미지 피라미드 축소 6 | smaller = cv2.pyrDown(img) # img x 1/4 7 | # 가우시안 이미지 피라미드 확대 8 | bigger = cv2.pyrUp(img) # img x 4 9 | 10 | # 결과 출력 11 | cv2.imshow('img', img) 12 | cv2.imshow('pyrDown', smaller) 13 | cv2.imshow('pyrUp', bigger) 14 | cv2.waitKey(0) 15 | cv2.destroyAllWindows() 16 | -------------------------------------------------------------------------------- /03.numpy_matplotlib/np_create_size.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | a = np.empty( (2,3)) 4 | b = np.empty( (2,3), dtype=np.int16) 5 | c = np.zeros( (2,3)) 6 | d = np.ones( (2,3), dtype=np.float32) 7 | e = np.full( (2,3,4), 255, dtype=np.uint8) 8 | print(a, a.dtype, a.shape) 9 | print(b, b.dtype, b.shape) 10 | print(c, c.dtype, c.shape) 11 | print(d, d.dtype, d.shape) 12 | print(e, e.dtype, e.shape) -------------------------------------------------------------------------------- /06.filter/morph_erode.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | img = cv2.imread('../img/morph_dot.png') 5 | 6 | # 구조화 요소 커널, 사각형 (3x3) 생성 ---① 7 | k = cv2.getStructuringElement(cv2.MORPH_RECT, (3,3)) 8 | # 침식 연산 적용 ---② 9 | erosion = cv2.erode(img, k) 10 | 11 | # 결과 출력 12 | merged = np.hstack((img, erosion)) 13 | cv2.imshow('Erode', merged) 14 | cv2.waitKey(0) 15 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /06.filter/morph_dilate.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | img = cv2.imread('../img/morph_hole.png') 5 | 6 | # 구조화 요소 커널, 사각형 (3x3) 생성 ---① 7 | k = cv2.getStructuringElement(cv2.MORPH_RECT, (3,3)) 8 | # 팽창 연산 적용 ---② 9 | dst = cv2.dilate(img, k) 10 | 11 | # 결과 출력 12 | merged = np.hstack((img, dst)) 13 | cv2.imshow('Dilation', merged) 14 | cv2.waitKey(0) 15 | cv2.destroyAllWindows() 16 | -------------------------------------------------------------------------------- /03.numpy_matplotlib/plt_subplot.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import numpy as np 3 | 4 | x = np.arange(10) 5 | 6 | plt.subplot(2,2,1) #2행 2열 중에 1번째 7 | plt.plot(x,x**2) 8 | 9 | plt.subplot(2,2,2) #2행 2열 중에 2번째 10 | plt.plot(x,x*5) 11 | 12 | plt.subplot(223) #2행 2열 중에 3번째 13 | plt.plot(x, np.sin(x)) 14 | 15 | plt.subplot(224) #2행 2열 중에 4번째 16 | plt.plot(x,np.cos(x)) 17 | 18 | plt.show() -------------------------------------------------------------------------------- /06.filter/blur_bilateral.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | img = cv2.imread("../img/gaussian_noise.jpg") 5 | 6 | # 가우시안 필터 적용 ---① 7 | blur1 = cv2.GaussianBlur(img, (5,5), 0) 8 | 9 | # 바이레터럴 필터 적용 ---② 10 | blur2 = cv2.bilateralFilter(img, 5, 75, 75) 11 | 12 | # 결과 출력 13 | merged = np.hstack((img, blur1, blur2)) 14 | cv2.imshow('bilateral', merged) 15 | cv2.waitKey(0) 16 | cv2.destroyAllWindows() 17 | -------------------------------------------------------------------------------- /06.filter/blur_avg_api.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | file_name = '../img/taekwonv1.jpg' 5 | img = cv2.imread(file_name) 6 | 7 | # blur() 함수로 블러링 ---① 8 | blur1 = cv2.blur(img, (10,10)) 9 | # boxFilter() 함수로 블러링 적용 ---② 10 | blur2 = cv2.boxFilter(img, -1, (10,10)) 11 | 12 | # 결과 출력 13 | merged = np.hstack( (img, blur1, blur2)) 14 | cv2.imshow('blur', merged) 15 | cv2.waitKey(0) 16 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /06.filter/morph_gradient.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | img = cv2.imread('../img/morphological.png') 5 | 6 | # 구조화 요소 커널, 사각형 (3x3) 생성 ---① 7 | k = cv2.getStructuringElement(cv2.MORPH_RECT, (3,3)) 8 | # 열림 연산 적용 ---② 9 | gradient = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, k) 10 | 11 | # 결과 출력 12 | merged = np.hstack((img, gradient)) 13 | cv2.imshow('gradient', merged) 14 | cv2.waitKey(0) 15 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /04.img_processing/roi_select_img.py: -------------------------------------------------------------------------------- 1 | import cv2, numpy as np 2 | 3 | img = cv2.imread('../img/sunset.jpg') 4 | 5 | x,y,w,h = cv2.selectROI('img', img, False) 6 | if w and h: 7 | roi = img[y:y+h, x:x+w] 8 | cv2.imshow('cropped', roi) # ROI 지정 영역을 새창으로 표시 9 | cv2.moveWindow('cropped', 0, 0) # 새창을 화면 좌측 상단에 이동 10 | cv2.imwrite('./cropped2.jpg', roi) # ROI 영역만 파일로 저장 11 | 12 | cv2.waitKey(0) 13 | cv2.destroyAllWindows() 14 | -------------------------------------------------------------------------------- /04.img_processing/histo_rgb.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | import matplotlib.pylab as plt 4 | 5 | #--① 이미지 읽기 및 출력 6 | img = cv2.imread('../img/mountain.jpg') 7 | cv2.imshow('img', img) 8 | 9 | #--② 히스토그램 계산 및 그리기 10 | channels = cv2.split(img) 11 | colors = ('b', 'g', 'r') 12 | for (ch, color) in zip (channels, colors): 13 | hist = cv2.calcHist([ch], [0], None, [256], [0, 256]) 14 | plt.plot(hist, color = color) 15 | plt.show() 16 | -------------------------------------------------------------------------------- /04.img_processing/roi.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | img = cv2.imread('../img/sunset.jpg') 5 | 6 | x=320; y=150; w=50; h=50 # roi 좌표 7 | roi = img[y:y+h, x:x+w] # roi 지정 ---① 8 | 9 | print(roi.shape) # roi shape, (50,50,3) 10 | cv2.rectangle(roi, (0,0), (h-1, w-1), (0,255,0)) # roi 전체에 사각형 그리기 ---② 11 | cv2.imshow("img", img) 12 | 13 | key = cv2.waitKey(0) 14 | print(key) 15 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /04.img_processing/arithmatic_mask.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | #---① 연산에 사용할 배열 생성 5 | a = np.array([[1, 2]], dtype=np.uint8) 6 | b = np.array([[10, 20]], dtype=np.uint8) 7 | #---② 2번째 요소가 0인 마스크 배열 생성 8 | mask = np.array([[1, 0]], dtype=np.uint8) 9 | 10 | #---③ 누적 할당과의 비교 연산 11 | c1 = cv2.add(a, b, None, mask) 12 | print(c1) 13 | c2 = cv2.add(a, b, b.copy(), mask) 14 | print(c2, b) 15 | c3 = cv2.add(a, b, b, mask) 16 | print(c3, b) 17 | -------------------------------------------------------------------------------- /08.match_track/kpt_fast.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | img = cv2.imread('../img/house.jpg') 5 | gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 6 | 7 | # FASt 특징 검출기 생성 ---① 8 | fast = cv2.FastFeatureDetector_create(50) 9 | # 키 포인트 검출 ---② 10 | keypoints = fast.detect(gray, None) 11 | # 키 포인트 그리기 ---③ 12 | img = cv2.drawKeypoints(img, keypoints, None) 13 | # 결과 출력 ---④ 14 | cv2.imshow('FAST', img) 15 | cv2.waitKey() 16 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /03.numpy_matplotlib/np_create_array.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | a = np.array([1,2,3,4]) # 정수를 갖는 리스트로 생성 4 | b = np.array([[1,2,3,4], # 2차원 리스트로 생성 5 | [5,6,7,8]]) 6 | c = np.array([1,2,3.14,4]) # 정수와 소수점이 혼재된 리스트 7 | d = np.array([1,2,3,4], dtype=np.float64) # dtype을 지정해서 생성 8 | 9 | print(a, a.dtype, a.shape) # --- ① 10 | print(b, b.dtype, b.shape) # --- ② 11 | print(c, c.dtype, c.shape) # --- ③ 12 | print(d, d.dtype, d.shape) # --- ④ -------------------------------------------------------------------------------- /03.numpy_matplotlib/np_reshape.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | 4 | a = np.arange(6) 5 | b = a.reshape(2,3) 6 | 7 | c = np.arange(24).reshape(2,3,4) 8 | 9 | d = np.arange(100).reshape(2, -1) 10 | e = np.arange(100).reshape(-1, 5) 11 | 12 | 13 | f = np.ravel(c) 14 | 15 | g = np.arange(10).reshape(2,-1) 16 | 17 | print(a, a.shape) 18 | print(b, b.shape) 19 | print(c, c.shape) 20 | print(d, d.shape) 21 | print(e, e.shape) 22 | print(f, f.shape) 23 | print(g.T) 24 | -------------------------------------------------------------------------------- /06.filter/edge_differential.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | img = cv2.imread("../img/sudoku.jpg") 5 | 6 | #미분 커널 생성 ---① 7 | gx_kernel = np.array([[ -1, 1]]) 8 | gy_kernel = np.array([[ -1],[ 1]]) 9 | 10 | # 필터 적용 ---② 11 | edge_gx = cv2.filter2D(img, -1, gx_kernel) 12 | edge_gy = cv2.filter2D(img, -1, gy_kernel) 13 | # 결과 출력 14 | merged = np.hstack((img, edge_gx, edge_gy)) 15 | cv2.imshow('edge', merged) 16 | cv2.waitKey(0) 17 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /02.interface/draw_rect.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | 3 | img = cv2.imread('../img/blank_500.jpg') 4 | 5 | # 좌상, 우하 좌표로 사각형 그리기, 선 두께는 default 1 6 | cv2.rectangle(img, (50, 50), (150, 150), (255,0,0) ) 7 | # 우하, 좌상 좌표로 사각형 그리기, 선 두께 10 8 | cv2.rectangle(img, (300, 300), (100, 100), (0,255,0), 10 ) 9 | # 우상, 좌하 좌표로 사각형 채워 그리기 ---① 10 | cv2.rectangle(img, (450, 200), (200, 450), (0,0,255), -1 ) 11 | 12 | cv2.imshow('rectangle', img) 13 | cv2.waitKey(0) 14 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /08.match_track/kpt_gftt.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | img = cv2.imread("../img/house.jpg") 5 | gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 6 | 7 | # Good feature to trac 검출기 생성 ---① 8 | gftt = cv2.GFTTDetector_create() 9 | # 키 포인트 검출 ---② 10 | keypoints = gftt.detect(gray, None) 11 | # 키 포인트 그리기 ---③ 12 | img_draw = cv2.drawKeypoints(img, keypoints, None) 13 | 14 | # 결과 출력 ---④ 15 | cv2.imshow('GFTTDectector', img_draw) 16 | cv2.waitKey(0) 17 | cv2.destrolyAllWindows() -------------------------------------------------------------------------------- /06.filter/edge_roberts.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | img = cv2.imread("../img/sudoku.jpg") 5 | 6 | # 로버츠 커널 생성 ---① 7 | gx_kernel = np.array([[1,0], [0,-1]]) 8 | gy_kernel = np.array([[0, 1],[-1,0]]) 9 | 10 | # 커널 적용 ---② 11 | edge_gx = cv2.filter2D(img, -1, gx_kernel) 12 | edge_gy = cv2.filter2D(img, -1, gy_kernel) 13 | 14 | # 결과 출력 15 | merged = np.hstack((img, edge_gx, edge_gy, edge_gx+edge_gy)) 16 | cv2.imshow('roberts cross', merged) 17 | cv2.waitKey(0) 18 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /04.img_processing/histo_gray.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | import matplotlib.pylab as plt 4 | 5 | #--① 이미지 그레이 스케일로 읽기 및 출력 6 | img = cv2.imread('../img/mountain.jpg', cv2.IMREAD_GRAYSCALE) 7 | cv2.imshow('img', img) 8 | 9 | #--② 히스토그램 계산 및 그리기 10 | hist = cv2.calcHist([img], [0], None, [256], [0,256]) 11 | plt.plot(hist) 12 | 13 | print("hist.shape:", hist.shape) #--③ 히스토그램의 shape (256,1) 14 | print("hist.sum():", hist.sum(), "img.shape:",img.shape) #--④ 히스토그램 총 합계와 이미지의 크기 15 | plt.show() 16 | -------------------------------------------------------------------------------- /08.match_track/kpt_blob.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | img = cv2.imread("../img/house.jpg") 5 | gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 6 | 7 | # SimpleBlobDetector 생성 ---① 8 | detector = cv2.SimpleBlobDetector_create() 9 | # 키 포인트 검출 ---② 10 | keypoints = detector.detect(gray) 11 | # 키 포인트를 빨간색으로 표시 ---③ 12 | img = cv2.drawKeypoints(img, keypoints, None, (0,0,255),\ 13 | flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS) 14 | 15 | cv2.imshow("Blob", img) 16 | cv2.waitKey(0) -------------------------------------------------------------------------------- /06.filter/morph_hat.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | img = cv2.imread('../img/moon_gray.jpg') 5 | 6 | # 구조화 요소 커널, 사각형 (5x5) 생성 ---① 7 | k = cv2.getStructuringElement(cv2.MORPH_RECT, (9,9)) 8 | # 탑햇 연산 적용 ---② 9 | tophat = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, k) 10 | # 블랫햇 연산 적용 ---③ 11 | blackhat = cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, k) 12 | 13 | # 결과 출력 14 | merged = np.hstack((img, tophat, blackhat)) 15 | cv2.imshow('tophat blackhat', merged) 16 | cv2.waitKey(0) 17 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /08.match_track/desc_orb.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | img = cv2.imread('../img/house.jpg') 5 | gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 6 | 7 | # ORB 추출기 생성 8 | orb = cv2.ORB_create() 9 | # 키 포인트 검출과 서술자 계산 10 | keypoints, descriptor = orb.detectAndCompute(img, None) 11 | # 키 포인트 그리기 12 | img_draw = cv2.drawKeypoints(img, keypoints, None, \ 13 | flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS) 14 | # 결과 출력 15 | cv2.imshow('ORB', img_draw) 16 | cv2.waitKey() 17 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /04.img_processing/roi_copy.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | img = cv2.imread('../img/sunset.jpg') 5 | 6 | x=320; y=150; w=50; h=50 7 | roi = img[y:y+h, x:x+w] # roi 지정 8 | img2 = roi.copy() # roi 배열 복제 ---① 9 | 10 | img[y:y+h, x+w:x+w+w] = roi # 새로운 좌표에 roi 추가, 태양 2개 만들기 11 | cv2.rectangle(img, (x,y), (x+w+w, y+h), (0,255,0)) # 2개의 태양 영역에 사각형 표시 12 | 13 | cv2.imshow("img", img) # 원본 이미지 출력 14 | cv2.imshow("roi", img2) # roi 만 따로 출력 15 | 16 | cv2.waitKey(0) 17 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /08.match_track/corner_goodFeature.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | img = cv2.imread('../img/house.jpg') 5 | gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 6 | 7 | # 시-토마스의 코너 검출 메서드 8 | corners = cv2.goodFeaturesToTrack(gray, 80, 0.01, 10) 9 | # 실수 좌표를 정수 좌표로 변환 10 | corners = np.int32(corners) 11 | 12 | # 좌표에 동그라미 표시 13 | for corner in corners: 14 | x, y = corner[0] 15 | cv2.circle(img, (x, y), 5, (0,0,255), 1, cv2.LINE_AA) 16 | 17 | cv2.imshow('Corners', img) 18 | cv2.waitKey() 19 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /06.filter/edge_prewitt.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | file_name = "../img/sudoku.jpg" 5 | img = cv2.imread(file_name) 6 | 7 | # 프리윗 커널 생성 8 | gx_k = np.array([[-1,0,1], [-1,0,1],[-1,0,1]]) 9 | gy_k = np.array([[-1,-1,-1],[0,0,0], [1,1,1]]) 10 | 11 | # 프리윗 커널 필터 적용 12 | edge_gx = cv2.filter2D(img, -1, gx_k) 13 | edge_gy = cv2.filter2D(img, -1, gy_k) 14 | 15 | # 결과 출력 16 | merged = np.hstack((img, edge_gx, edge_gy, edge_gx+edge_gy)) 17 | cv2.imshow('prewitt', merged) 18 | cv2.waitKey(0) 19 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /04.img_processing/arithmatic.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | # ---① 연산에 사용할 배열 생성 5 | a = np.uint8([[200, 50]]) 6 | b = np.uint8([[100, 100]]) 7 | 8 | #---② NumPy 배열 직접 연산 9 | add1 = a + b 10 | sub1 = a - b 11 | mult1 = a * 2 12 | div1 = a / 3 13 | 14 | # ---③ OpenCV API를 이용한 연산 15 | add2 = cv2.add(a, b) 16 | sub2 = cv2.subtract(a, b) 17 | mult2 = cv2.multiply(a , 2) 18 | div2 = cv2.divide(a, 3) 19 | 20 | #---④ 각 연산 결과 출력 21 | print(add1, add2) 22 | print(sub1, sub2) 23 | print(mult1, mult2) 24 | print(div1, div2) 25 | -------------------------------------------------------------------------------- /04.img_processing/bitwise_masking.py: -------------------------------------------------------------------------------- 1 | import numpy as np, cv2 2 | import matplotlib.pylab as plt 3 | 4 | #--① 이미지 읽기 5 | img = cv2.imread('../img/yeosu_small.jpg') 6 | 7 | #--② 마스크 만들기 8 | mask = np.zeros_like(img) 9 | cv2.circle(mask, (260,210), 100, (255,255,255), -1) 10 | #cv2.circle(대상이미지, (원점x, 원점y), 반지름, (색상), 채우기) 11 | 12 | #--③ 마스킹 13 | masked = cv2.bitwise_and(img, mask) 14 | 15 | #--④ 결과 출력 16 | cv2.imshow('original', img) 17 | cv2.imshow('mask', mask) 18 | cv2.imshow('masked', masked) 19 | cv2.waitKey() 20 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /02.interface/img_show.py: -------------------------------------------------------------------------------- 1 | ''' 2 | GitHub : https://github.com/dltpdn/book_opencv_prject_using_python 3 | Author : Lee Sewoo(이세우, dltpdn@gmail.com) 4 | ''' 5 | import cv2 6 | 7 | img_file = "../img/yeosu.jpg" # 표시할 이미지 경로 ---① 8 | img = cv2.imread(img_file) # 이미지를 읽어서 img 변수에 할당 ---② 9 | 10 | if img is not None: 11 | cv2.imshow('IMG', img) # 읽은 이미지를 화면에 표시 --- ③ 12 | cv2.waitKey() # 키가 입력될 때 까지 대기 --- ④ 13 | cv2.destroyAllWindows() # 창 모두 닫기 --- ⑤ 14 | else: 15 | print('No image file.') 16 | -------------------------------------------------------------------------------- /04.img_processing/bitwise_masking2.py: -------------------------------------------------------------------------------- 1 | import numpy as np, cv2 2 | import matplotlib.pylab as plt 3 | 4 | #--① 이미지 읽기 5 | img = cv2.imread('../img/girl.jpg') 6 | 7 | #--② 마스크 만들기 8 | mask = np.zeros(img.shape[:2], dtype=np.uint8) 9 | cv2.circle(mask, (150,140), 100, (255), -1) 10 | #cv2.circle(대상이미지, (원점x, 원점y), 반지름, (색상), 채우기) 11 | 12 | #--③ 마스킹 13 | masked = cv2.bitwise_and(img, img, mask=mask) 14 | 15 | #--④ 결과 출력 16 | cv2.imshow('original', img) 17 | cv2.imshow('mask', mask) 18 | cv2.imshow('masked', masked) 19 | cv2.waitKey() 20 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /06.filter/pyramid_laplacian.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | img = cv2.imread('../img/taekwonv1.jpg') 5 | 6 | # 원본 영상을 가우시안 피라미드로 축소 7 | smaller = cv2.pyrDown(img) 8 | # 축소한 영상을 가우시안 피라미드로 확대 9 | bigger = cv2.pyrUp(smaller) 10 | 11 | # 원본에서 확대한 영상 빼기 12 | laplacian = cv2.subtract(img, bigger) 13 | # 확대 한 영상에 라플라시안 영상 더해서 복원 14 | restored = bigger + laplacian 15 | 16 | # 결과 출력 (원본 영상, 라플라시안, 확대 영상, 복원 영상) 17 | merged = np.hstack((img, laplacian, bigger, restored)) 18 | cv2.imshow('Laplacian Pyramid', merged) 19 | cv2.waitKey(0) 20 | cv2.destroyAllWindows() 21 | -------------------------------------------------------------------------------- /06.filter/workshop_mosic2.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | 3 | ksize = 30 # 블러 처리에 사용할 커널 크기 4 | win_title = 'mosaic' # 창 제목 5 | img = cv2.imread('../img/taekwonv1.jpg') # 이미지 읽기 6 | 7 | while True: 8 | x,y,w,h = cv2.selectROI(win_title, img, False) # 관심영역 선택 9 | if w > 0 and h > 0: # 폭과 높이가 음수이면 드래그 방향이 옳음 10 | roi = img[y:y+h, x:x+w] # 관심영역 지정 11 | roi = cv2.blur(roi, (ksize, ksize)) # 블러(모자이크) 처리 12 | img[y:y+h, x:x+w] = roi # 원본 이미지에 적용 13 | cv2.imshow(win_title, img) 14 | else: 15 | break 16 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /04.img_processing/bgr2gray.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | img = cv2.imread('../img/yeosu_small.jpg') 5 | 6 | img2 = img.astype(np.uint16) # dtype 변경 ---① 7 | b,g,r = cv2.split(img2) # 채널 별로 분리 ---② 8 | #b,g,r = img2[:,:,0], img2[:,:,1], img2[:,:,2] 9 | gray1 = ((b + g + r)/3).astype(np.uint8) # 평균 값 연산후 dtype 변경 ---③ 10 | 11 | gray2 = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # BGR을 그레이 스케일로 변경 ---④ 12 | cv2.imshow('original', img) 13 | cv2.imshow('gray1', gray1) 14 | cv2.imshow('gray2', gray2) 15 | 16 | cv2.waitKey(0) 17 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /04.img_processing/rgba.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | # 기본 값 옵션 5 | img = cv2.imread('../img/opencv_logo.png') 6 | # IMREAD_COLOR 옵션 7 | bgr = cv2.imread('../img/opencv_logo.png', cv2.IMREAD_COLOR) 8 | # IMREAD_UNCHANGED 옵션 9 | bgra = cv2.imread('../img/opencv_logo.png', cv2.IMREAD_UNCHANGED) 10 | # 각 옵션에 따른 이미지 shape 11 | print("default", img.shape, "color", bgr.shape, "unchanged", bgra.shape) 12 | 13 | cv2.imshow('bgr', bgr) 14 | cv2.imshow('bgra', bgra) 15 | cv2.imshow('alpha', bgra[:,:,3]) # 알파 채널만 표시 16 | cv2.waitKey(0) 17 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /08.match_track/track_bgsub_mog2.py: -------------------------------------------------------------------------------- 1 | import numpy as np, cv2 2 | 3 | cap = cv2.VideoCapture('../img/walking.avi') 4 | fps = cap.get(cv2.CAP_PROP_FPS) # 프레임 수 구하기 5 | delay = int(1000/fps) 6 | # 배경 제거 객체 생성 --- ① 7 | fgbg = cv2.createBackgroundSubtractorMOG2() 8 | while cap.isOpened(): 9 | ret, frame = cap.read() 10 | if not ret: 11 | break 12 | # 배경 제거 마스크 계산 --- ② 13 | fgmask = fgbg.apply(frame) 14 | cv2.imshow('frame',frame) 15 | cv2.imshow('bgsub',fgmask) 16 | if cv2.waitKey(delay) & 0xff == 27: 17 | break 18 | cap.release() 19 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /03.numpy_matplotlib/np_gray.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | img = np.zeros((120,120), dtype=np.uint8) # 120x120 2차원 배열 생성, 검은색 흑백 이미지 5 | img[25:35, :] = 45 # 25~35행 모든 열에 45 할당 6 | img[55:65, :] = 115 # 55~65행 모든 열에 115 할당 7 | img[85:95, :] = 160 # 85~95행 모든 열에 160 할당 8 | img[:, 35:45] = 205 # 모든행 35~45 열에 205 할당 9 | img[:, 75:85] = 255 # 모든행 75~85 열에 255 할당 10 | cv2.imshow('Gray', img) 11 | if cv2.waitKey(0) & 0xFF == 27: 12 | cv2.destroyAllWindows() 13 | -------------------------------------------------------------------------------- /08.match_track/track_bgsub_mog.py: -------------------------------------------------------------------------------- 1 | import numpy as np, cv2 2 | 3 | cap = cv2.VideoCapture('../img/walking.avi') 4 | fps = cap.get(cv2.CAP_PROP_FPS) # 프레임 수 구하기 5 | delay = int(1000/fps) 6 | # 배경 제거 객체 생성 --- ① 7 | fgbg = cv2.bgsegm.createBackgroundSubtractorMOG() 8 | while cap.isOpened(): 9 | ret, frame = cap.read() 10 | if not ret: 11 | break 12 | # 배경 제거 마스크 계산 --- ② 13 | fgmask = fgbg.apply(frame) 14 | cv2.imshow('frame',frame) 15 | cv2.imshow('bgsub',fgmask) 16 | if cv2.waitKey(1) & 0xff == 27: 17 | break 18 | cap.release() 19 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /03.numpy_matplotlib/plt_imshow_subplot.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import numpy as np 3 | import cv2 4 | 5 | img1 = cv2.imread('../img/model.jpg') 6 | img2 = cv2.imread('../img/model2.jpg') 7 | img3 = cv2.imread('../img/model3.jpg') 8 | 9 | 10 | plt.subplot(1,3,1) #1행 3열 중에 1번째 11 | plt.imshow(img1[:,:,(2,1,0)]) 12 | plt.xticks([]); plt.yticks([]) 13 | 14 | plt.subplot(1,3,2) #1행 3열 중에 2번째 15 | plt.imshow(img2[:,:,(2,1,0)]) 16 | plt.xticks([]); plt.yticks([]) 17 | 18 | plt.subplot(1,3,3) #1행 3열 중에 3번째 19 | plt.imshow(img3[:,:,(2,1,0)]) 20 | plt.xticks([]); plt.yticks([]) 21 | 22 | plt.show() -------------------------------------------------------------------------------- /05.geometric_transform/rotate_getmatrix.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | 3 | img = cv2.imread('../img/fish.jpg') 4 | rows,cols = img.shape[0:2] 5 | 6 | #---① 회전을 위한 변환 행렬 구하기 7 | # 회전축:중앙, 각도:45, 배율:0.5 8 | m45 = cv2.getRotationMatrix2D((cols/2,rows/2),45,0.5) 9 | # 회전축:중앙, 각도:90, 배율:1.5 10 | m90 = cv2.getRotationMatrix2D((cols/2,rows/2),90,1.5) 11 | 12 | #---② 변환 행렬 적용 13 | img45 = cv2.warpAffine(img, m45,(cols, rows)) 14 | img90 = cv2.warpAffine(img, m90,(cols, rows)) 15 | 16 | #---③ 결과 출력 17 | cv2.imshow('origin',img) 18 | cv2.imshow("45", img45) 19 | cv2.imshow("90", img90) 20 | cv2.waitKey(0) 21 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /04.img_processing/thresholds.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | import matplotlib.pylab as plt 4 | 5 | img = cv2.imread('../img/scaned_paper.jpg', cv2.IMREAD_GRAYSCALE) #이미지를 그레이 스케일로 읽기 6 | thresholds = [80, 100, 120, 140, 150, 170, 190] 7 | imgs = {'Original' : img} 8 | for t in thresholds: 9 | _, t_img = cv2.threshold(img, t, 255, cv2.THRESH_BINARY) 10 | imgs['t:%d'%t] = t_img 11 | 12 | for i , (key, value) in enumerate(imgs.items()): 13 | plt.subplot(2, 4, i+1) 14 | plt.title(key) 15 | plt.imshow(value, cmap='gray') 16 | plt.xticks([]); plt.yticks([]) 17 | 18 | plt.show() 19 | 20 | -------------------------------------------------------------------------------- /08.match_track/desc_surf.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | img = cv2.imread('../img/house.jpg') 5 | gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 6 | 7 | # SURF 추출기 생성 ( 경계:1000, 피라미드:3, 서술자확장:True, 방향적용:True) 8 | surf = cv2.xfeatures2d.SURF_create(1000, 3, True, True) 9 | # 키 포인트 검출 및 서술자 계산 10 | keypoints, desc = surf.detectAndCompute(gray, None) 11 | print(desc.shape, desc) 12 | # 키포인트 이미지에 그리기 13 | img_draw = cv2.drawKeypoints(img, keypoints, None, \ 14 | flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS) 15 | 16 | cv2.imshow('SURF', img_draw) 17 | cv2.waitKey() 18 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /07.segmentation/hough_lineP.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | img = cv2.imread('../img/sudoku.jpg') 5 | img2 = img.copy() 6 | # 그레이 스케일로 변환 및 엣지 검출 ---① 7 | imgray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 8 | edges = cv2.Canny(imgray, 50, 200 ) 9 | 10 | # 확율 허프 변환 적용 ---② 11 | lines = cv2.HoughLinesP(edges, 1, np.pi/180, 10, None, 20, 2) 12 | for line in lines: 13 | # 검출된 선 그리기 ---③ 14 | x1, y1, x2, y2 = line[0] 15 | cv2.line(img2, (x1,y1), (x2, y2), (0,255,0), 1) 16 | 17 | merged = np.hstack((img, img2)) 18 | cv2.imshow('Probability hough line', merged) 19 | cv2.waitKey() 20 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /04.img_processing/blending_alpha.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | alpha = 0.5 # 합성에 사용할 알파 값 5 | 6 | #---① 합성에 사용할 영상 읽기 7 | img1 = cv2.imread('../img/wing_wall.jpg') 8 | img2 = cv2.imread('../img/yate.jpg') 9 | 10 | # ---② NumPy 배열에 수식을 직접 연산해서 알파 블렌딩 적용 11 | blended = img1 * alpha + img2 * (1-alpha) 12 | blended = blended.astype(np.uint8) # 소수점 발생을 제거하기 위함 13 | cv2.imshow('img1 * alpha + img2 * (1-alpha)', blended) 14 | 15 | # ---③ addWeighted() 함수로 알파 블렌딩 적용 16 | dst = cv2.addWeighted(img1, alpha, img2, (1-alpha), 0) 17 | cv2.imshow('cv2.addWeighted', dst) 18 | 19 | cv2.waitKey(0) 20 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /04.img_processing/blending_simple.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | import matplotlib.pylab as plt 4 | 5 | # ---① 연산에 사용할 이미지 읽기 6 | img1 = cv2.imread('../img/wing_wall.jpg') 7 | img2 = cv2.imread('../img/yate.jpg') 8 | 9 | # ---② 이미지 덧셈 10 | img3 = img1 + img2 # 더하기 연산 11 | img4 = cv2.add(img1, img2) # OpenCV 함수 12 | 13 | imgs = {'img1':img1, 'img2':img2, 'img1+img2': img3, 'cv.add(img1, img2)': img4} 14 | 15 | # ---③ 이미지 출력 16 | for i, (k, v) in enumerate(imgs.items()): 17 | plt.subplot(2,2, i + 1) 18 | plt.imshow(v[:,:,::-1]) 19 | plt.title(k) 20 | plt.xticks([]); plt.yticks([]) 21 | 22 | plt.show() -------------------------------------------------------------------------------- /02.interface/video_cam_take_pic.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | 3 | cap = cv2.VideoCapture(0) # 0번 카메라 연결 4 | if cap.isOpened() : 5 | while True: 6 | ret, frame = cap.read() # 카메라 프레임 읽기 7 | if ret: 8 | cv2.imshow('camera',frame) # 프레임 화면에 표시 9 | if cv2.waitKey(1) != -1: # 아무 키나 누르면 10 | cv2.imwrite('photo.jpg', frame) # 프레임을 'photo.jpg'에 저장 11 | break 12 | else: 13 | print('no frame!') 14 | break 15 | else: 16 | print('no camera!') 17 | cap.release() 18 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /08.match_track/desc_sift.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | img = cv2.imread('../img/house.jpg') 5 | gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 6 | 7 | # SIFT 추출기 생성 8 | sift = cv2.xfeatures2d.SIFT_create() 9 | # 키 포인트 검출과 서술자 계산 10 | keypoints, descriptor = sift.detectAndCompute(gray, None) 11 | print('keypoint:',len(keypoints), 'descriptor:', descriptor.shape) 12 | print(descriptor) 13 | 14 | # 키 포인트 그리기 15 | img_draw = cv2.drawKeypoints(img, keypoints, None, \ 16 | flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS) 17 | # 결과 출력 18 | cv2.imshow('SIFT', img_draw) 19 | cv2.waitKey() 20 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /09.ml/k-means_handwritten.py: -------------------------------------------------------------------------------- 1 | import cv2, numpy as np 2 | import matplotlib.pyplot as plt 3 | import mnist 4 | 5 | # 공통 모듈로 부터 MINST 전체 이미지 데이타 읽기 ---① 6 | data, _ = mnist.getData() 7 | # 중지 요건 8 | criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0) 9 | # 평균 클러스터링 적용, 10개의 그룹으로 묶음 ---② 10 | ret,label,center=cv2.kmeans(data,10,None,criteria,10,cv2.KMEANS_RANDOM_CENTERS) 11 | # 중앙점 이미지 출력 12 | for i in range(10): 13 | # 각 중앙점 값으로 이미지 생성 ---③ 14 | cent_img = center[i].reshape(20,20).astype(np.uint8) 15 | plt.subplot(2,5, i+1) 16 | plt.imshow(cent_img, 'gray') 17 | plt.xticks([]);plt.yticks([]) 18 | plt.show() -------------------------------------------------------------------------------- /02.interface/video_cam.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | 3 | cap = cv2.VideoCapture(0) # 0번 카메라 장치 연결 ---① 4 | if cap.isOpened(): # 캡쳐 객체 연결 확인 5 | while True: 6 | ret, img = cap.read() # 다음 프레임 읽기 7 | if ret: 8 | cv2.imshow('camera', img) # 다음 프레임 이미지 표시 9 | if cv2.waitKey(1) != -1: # 1ms 동안 키 입력 대기 ---② 10 | break # 아무 키라도 입력이 있으면 중지 11 | else: 12 | print('no frame') 13 | break 14 | else: 15 | print("can't open camera.") 16 | cap.release() # 자원 반납 17 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /04.img_processing/blending_alpha_trackbar.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | win_name = 'Alpha blending' # 창 이름 5 | trackbar_name = 'fade' # 트렉바 이름 6 | 7 | # ---① 트렉바 이벤트 핸들러 함수 8 | def onChange(x): 9 | alpha = x/100 10 | dst = cv2.addWeighted(img1, 1-alpha, img2, alpha, 0) 11 | cv2.imshow(win_name, dst) 12 | 13 | 14 | # ---② 합성 영상 읽기 15 | img1 = cv2.imread('../img/man_face.jpg') 16 | img2 = cv2.imread('../img/lion_face.jpg') 17 | 18 | # ---③ 이미지 표시 및 트렉바 붙이기 19 | cv2.imshow(win_name, img1) 20 | cv2.createTrackbar(trackbar_name, win_name, 0, 100, onChange) 21 | 22 | cv2.waitKey() 23 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /09.ml/kNN_mnist.py: -------------------------------------------------------------------------------- 1 | import numpy as np, cv2 2 | import mnist 3 | 4 | # 훈련 데이타와 테스트 데이타 가져오기 ---① 5 | train, train_labels = mnist.getTrain() 6 | test, test_labels = mnist.getTest() 7 | # kNN 객체 생성 및 훈련 ---② 8 | knn = cv2.ml.KNearest_create() 9 | knn.train(train, cv2.ml.ROW_SAMPLE, train_labels) 10 | # k값을 1~10까지 변경하면서 예측 ---③ 11 | for k in range(1, 11): 12 | # 결과 예측 ---④ 13 | ret, result, neighbors, distance = knn.findNearest(test, k=k) 14 | # 정확도 계산 및 출력 ---⑤ 15 | correct = np.sum(result == test_labels) 16 | accuracy = correct / result.size * 100.0 17 | print("K:%d, Accuracy :%.2f%%(%d/%d)" % (k, accuracy, correct, result.size) ) 18 | -------------------------------------------------------------------------------- /05.geometric_transform/scale_resize.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | img = cv2.imread('../img/fish.jpg') 5 | height, width = img.shape[:2] 6 | 7 | #--① 크기 지정으로 축소 8 | #dst1 = cv2.resize(img, (int(width*0.5), int(height*0.5)),\ 9 | # None, 0, 0, cv2.INTER_AREA) 10 | dst1 = cv2.resize(img, (int(width*0.5), int(height*0.5)), \ 11 | interpolation=cv2.INTER_AREA) 12 | 13 | #--② 배율 지정으로 확대 14 | dst2 = cv2.resize(img, None, None, 2, 2, cv2.INTER_CUBIC) 15 | #--③ 결과 출력 16 | cv2.imshow("original", img) 17 | cv2.imshow("small", dst1) 18 | cv2.imshow("big", dst2) 19 | cv2.waitKey(0) 20 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /05.geometric_transform/workshop_mosaic.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | 3 | rate = 15 # 모자이크에 사용할 축소 비율 (1/rate) 4 | win_title = 'mosaic' # 창 제목 5 | img = cv2.imread('../img/taekwonv1.jpg') # 이미지 읽기 6 | 7 | while True: 8 | x,y,w,h = cv2.selectROI(win_title, img, False) # 관심영역 선택 9 | if w and h: 10 | roi = img[y:y+h, x:x+w] # 관심영역 지정 11 | roi = cv2.resize(roi, (w//rate, h//rate)) # 1/rate 비율로 축소 12 | # 원래 크기로 확대 13 | roi = cv2.resize(roi, (w,h), interpolation=cv2.INTER_AREA) 14 | img[y:y+h, x:x+w] = roi # 원본 이미지에 적용 15 | cv2.imshow(win_title, img) 16 | else: 17 | break 18 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /08.match_track/avg_hash.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | 3 | #영상 읽어서 그레이 스케일로 변환 4 | img = cv2.imread('../img/pistol.jpg') 5 | gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 6 | 7 | # 8x8 크기로 축소 ---① 8 | gray = cv2.resize(gray, (16,16)) 9 | # 영상의 평균값 구하기 ---② 10 | avg = gray.mean() 11 | # 평균값을 기준으로 0과 1로 변환 ---③ 12 | bin = 1 * (gray > avg) 13 | print(bin) 14 | 15 | # 2진수 문자열을 16진수 문자열로 변환 ---④ 16 | dhash = [] 17 | for row in bin.tolist(): 18 | s = ''.join([str(i) for i in row]) 19 | dhash.append('%02x'%(int(s,2))) 20 | dhash = ''.join(dhash) 21 | print(dhash) 22 | 23 | cv2.namedWindow('pistol', cv2.WINDOW_GUI_NORMAL) 24 | cv2.imshow('pistol', img) 25 | cv2.waitKey(0) 26 | 27 | -------------------------------------------------------------------------------- /03.numpy_matplotlib/np_bgr.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | img = np.zeros((120,120, 3), dtype=np.uint8) # 120x120 2차원 배열 생성, 3채널 컬러 이미지 5 | img[25:35, :] = [255,0,0] # 25~35행 모든 열에 [255,0,0], 파랑색 할당 6 | img[55:65, :] = [0, 255, 0] # 55~65행 모든 열에 [0,255,0], 초록색 할당 7 | img[85:95, :] = [0,0,255] # 85~95행 모든 열에 [0,0,255], 빨강색 할당 8 | img[:, 35:45] = [255,255,0] # 모든행 35~45 열에 [255,255,0], 하늘색 할당 9 | img[:, 75:85] = [255,0,255] # 모든행 75~85 열에 [255,0,255], 분홍색 할당 10 | cv2.imshow('BGR', img) 11 | if cv2.waitKey(0) & 0xFF == 27: 12 | cv2.destroyAllWindows() 13 | -------------------------------------------------------------------------------- /04.img_processing/bgr2yuv.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | #---① BGR 컬러 스페이스로 3가지 밝기의 픽셀 생성 5 | dark = np.array([[[0,0,0]]], dtype=np.uint8) # 3 채널 모두 0인 가장 어두운 픽셀 6 | middle = np.array([[[127,127,127]]], dtype=np.uint8) # 3 채널 모두 127인 중간 밝기 픽셀 7 | bright = np.array([[[255,255,255]]], dtype=np.uint8) # 3 채널 모두 255인 가장 밝은 픽셀 8 | 9 | #---② BGR 컬러 스페이스를 YUV 컬러 스페이스로 변환 10 | dark_yuv = cv2.cvtColor(dark, cv2.COLOR_BGR2YUV) 11 | middle_yuv = cv2.cvtColor(middle, cv2.COLOR_BGR2YUV) 12 | bright_yuv = cv2.cvtColor(bright, cv2.COLOR_BGR2YUV) 13 | 14 | #---③ YUV로 변환한 픽셀 출력 15 | print("dark:",dark_yuv) 16 | print("middle:", middle_yuv) 17 | print("bright", bright_yuv) 18 | -------------------------------------------------------------------------------- /04.img_processing/histo_equalize_yuv.py: -------------------------------------------------------------------------------- 1 | import numpy as np, cv2 2 | 3 | img = cv2.imread('../img/yate.jpg') #이미지 읽기, BGR 스케일 4 | 5 | #--① 컬러 스케일을 BGR에서 YUV로 변경 6 | img_yuv = cv2.cvtColor(img, cv2.COLOR_BGR2YUV) 7 | # img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) 8 | 9 | #--② YUV 컬러 스케일의 첫번째 채널에 대해서 이퀄라이즈 적용 10 | img_yuv[:,:,0] = cv2.equalizeHist(img_yuv[:,:,0]) 11 | # img_hsv[:,:,2] = cv2.equalizeHist(img_hsv[:,:,2]) 12 | 13 | #--③ 컬러 스케일을 YUV에서 BGR로 변경 14 | img2 = cv2.cvtColor(img_yuv, cv2.COLOR_YUV2BGR) 15 | # img2 = cv2.cvtColor(img_yuv, cv2.COLOR_HSV2BGR) 16 | 17 | cv2.imshow('Before', img) 18 | cv2.imshow('After', img2) 19 | cv2.waitKey() 20 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /06.filter/edge_scharr.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | img = cv2.imread("../img/sudoku.jpg") 5 | 6 | # 샤르 커널을 직접 생성해서 엣지 검출 ---① 7 | gx_k = np.array([[-3,0,3], [-10,0,10],[-3,0,3]]) 8 | gy_k = np.array([[-3,-10,-3],[0,0,0], [3,10,3]]) 9 | edge_gx = cv2.filter2D(img, -1, gx_k) 10 | edge_gy = cv2.filter2D(img, -1, gy_k) 11 | 12 | # 샤르 API로 엣지 검출 ---② 13 | scharrx = cv2.Scharr(img, -1, 1, 0) 14 | scharry = cv2.Scharr(img, -1, 0, 1) 15 | 16 | # 결과 출력 17 | merged1 = np.hstack((img, edge_gx, edge_gy)) 18 | merged2 = np.hstack((img, scharrx, scharry)) 19 | merged = np.vstack((merged1, merged2)) 20 | cv2.imshow('Scharr', merged) 21 | cv2.waitKey(0) 22 | cv2.destroyAllWindows() 23 | -------------------------------------------------------------------------------- /06.filter/morph_open_close.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | img1 = cv2.imread('../img/morph_dot.png', cv2.IMREAD_GRAYSCALE) 5 | img2 = cv2.imread('../img/morph_hole.png', cv2.IMREAD_GRAYSCALE) 6 | 7 | # 구조화 요소 커널, 사각형 (5x5) 생성 ---① 8 | k = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5)) 9 | # 열림 연산 적용 ---② 10 | opening = cv2.morphologyEx(img1, cv2.MORPH_OPEN, k) 11 | # 닫힘 연산 적용 ---③ 12 | closing = cv2.morphologyEx(img2, cv2.MORPH_CLOSE, k) 13 | 14 | # 결과 출력 15 | merged1 = np.hstack((img1, opening)) 16 | merged2 = np.hstack((img2, closing)) 17 | merged3 = np.vstack((merged1, merged2)) 18 | cv2.imshow('opening, closing', merged3) 19 | cv2.waitKey(0) 20 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /06.filter/blur_avg_kernel.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | img = cv2.imread('../img/yeosu_small.jpg') 5 | ''' 6 | #5x5 평균 필터 커널 생성 ---① 7 | kernel = np.array([[0.04, 0.04, 0.04, 0.04, 0.04], 8 | [0.04, 0.04, 0.04, 0.04, 0.04], 9 | [0.04, 0.04, 0.04, 0.04, 0.04], 10 | [0.04, 0.04, 0.04, 0.04, 0.04], 11 | [0.04, 0.04, 0.04, 0.04, 0.04]]) 12 | ''' 13 | # 5x5 평균 필터 커널 생성 ---② 14 | kernel = np.ones((5,5))/5**2 15 | # 필터 적용 ---③ 16 | blured = cv2.filter2D(img, -1, kernel) 17 | 18 | # 결과 출력 19 | cv2.imshow('origin', img) 20 | cv2.imshow('avrg blur', blured) 21 | cv2.waitKey() 22 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /06.filter/blur_gaussian.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | img = cv2.imread('../img/gaussian_noise.jpg') 5 | 6 | # 가우시안 커널을 직접 생성해서 블러링 ---① 7 | k1 = np.array([[1, 2, 1], 8 | [2, 4, 2], 9 | [1, 2, 1]]) *(1/16) 10 | blur1 = cv2.filter2D(img, -1, k1) 11 | 12 | # 가우시안 커널을 API로 얻어서 블러링 ---② 13 | k2 = cv2.getGaussianKernel(3, 0) 14 | blur2 = cv2.filter2D(img, -1, k2*k2.T) 15 | 16 | # 가우시안 블러 API로 블러링 ---③ 17 | blur3 = cv2.GaussianBlur(img, (3, 3), 0) 18 | 19 | # 결과 출력 20 | print('k1:', k1) 21 | print('k2:', k2*k2.T) 22 | merged = np.hstack((img, blur1, blur2, blur3)) 23 | cv2.imshow('gaussian blur', merged) 24 | cv2.waitKey(0) 25 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /04.img_processing/seamlessclone.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | import matplotlib.pylab as plt 4 | 5 | #--① 합성 대상 영상 읽기 6 | img1 = cv2.imread("../img/drawing.jpg") 7 | img2= cv2.imread("../img/my_hand.jpg") 8 | 9 | #--② 마스크 생성, 합성할 이미지 전체 영역을 255로 셋팅 10 | mask = np.full_like(img1, 255) 11 | 12 | #--③ 합성 대상 좌표 계산(img2의 중앙) 13 | height, width = img2.shape[:2] 14 | center = (width//2, height//2) 15 | 16 | #--④ seamlessClone 으로 합성 17 | normal = cv2.seamlessClone(img1, img2, mask, center, cv2.NORMAL_CLONE) 18 | mixed = cv2.seamlessClone(img1, img2, mask, center, cv2.MIXED_CLONE) 19 | 20 | #--⑤ 결과 출력 21 | cv2.imshow('normal', normal) 22 | cv2.imshow('mixed', mixed) 23 | cv2.waitKey() 24 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /02.interface/video_play.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | 3 | video_file = "../img/big_buck.avi" # 동영상 파일 경로 4 | 5 | cap = cv2.VideoCapture(video_file) # 동영상 캡쳐 객체 생성 ---① 6 | if cap.isOpened(): # 캡쳐 객체 초기화 확인 7 | while True: 8 | ret, img = cap.read() # 다음 프레임 읽기 --- ② 9 | if ret: # 프레임 읽기 정상 10 | cv2.imshow(video_file, img) # 화면에 표시 --- ③ 11 | cv2.waitKey(25) # 25ms 지연(40fps로 가정) --- ④ 12 | else: # 다음 프레임 읽을 수 없슴, 13 | break # 재생 완료 14 | else: 15 | print("can't open video.") # 캡쳐 객체 초기화 실패 16 | cap.release() # 캡쳐 자원 반납 17 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /02.interface/event_mouse_circle.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | 3 | title = 'mouse event' # 창 제목 4 | img = cv2.imread('../img/blank_500.jpg') # 백색 이미지 읽기 5 | cv2.imshow(title, img) # 백색 이미지 표시 6 | 7 | def onMouse(event, x, y, flags, param): # 아무스 콜백 함수 구현 ---① 8 | print(event, x, y, ) # 파라미터 출력 9 | if event == cv2.EVENT_LBUTTONDOWN: # 왼쪽 버튼 누름인 경우 ---② 10 | cv2.circle(img, (x,y), 30, (0,0,0), -1) # 지름 30 크기의 검은색 원을 해당 좌표에 그림 11 | cv2.imshow(title, img) # 그려진 이미지를 다시 표시 ---③ 12 | 13 | cv2.setMouseCallback(title, onMouse) # 마우스 콜백 함수를 GUI 윈도우에 등록 ---④ 14 | 15 | while True: 16 | if cv2.waitKey(0) & 0xFF == 27: # esc로 종료 17 | break 18 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /07.segmentation/distanceTrans.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | # 이미지를 읽어서 바이너리 스케일로 변환 5 | img = cv2.imread('../img/full_body.jpg', cv2.IMREAD_GRAYSCALE) 6 | _, biimg = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY_INV) 7 | 8 | # 거리 변환 ---① 9 | dst = cv2.distanceTransform(biimg, cv2.DIST_L2, 5) 10 | # 거리 값을 0 ~ 255 범위로 정규화 ---② 11 | dst = (dst/(dst.max()-dst.min()) * 255).astype(np.uint8) 12 | # 거리 값에 쓰레시홀드로 완전한 뼈대 찾기 ---③ 13 | skeleton = cv2.adaptiveThreshold(dst, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, \ 14 | cv2.THRESH_BINARY, 7, -3) 15 | # 결과 출력 16 | cv2.imshow('origin', img) 17 | cv2.imshow('dist', dst) 18 | cv2.imshow('skel', skeleton) 19 | cv2.waitKey(0) 20 | cv2.destroyAllWindows() 21 | -------------------------------------------------------------------------------- /07.segmentation/connected_label.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | # 이미지 읽기 5 | img = cv2.imread('../img/shapes_donut.png') 6 | # 결과 이미지 생성 7 | img2 = np.zeros_like(img) 8 | # 그레이 스케일과 바이너리 스케일 변환 9 | gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 10 | _, th = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) 11 | 12 | # 연결된 요소 레이블링 적용 ---① 13 | cnt, labels = cv2.connectedComponents(th) 14 | #retval, labels, stats, cent = cv2.connectedComponentsWithStats(th) 15 | 16 | # 레이블 갯수 만큼 순회 17 | for i in range(cnt): 18 | # 레이블이 같은 영역에 랜덤한 색상 적용 ---② 19 | img2[labels==i] = [int(j) for j in np.random.randint(0,255, 3)] 20 | 21 | # 결과 출력 22 | cv2.imshow('origin', img) 23 | cv2.imshow('labeled', img2) 24 | cv2.waitKey(0) 25 | cv2.destroyAllWindows() 26 | -------------------------------------------------------------------------------- /06.filter/edge_sobel.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | img = cv2.imread("../img/sudoku.jpg") 5 | 6 | # 소벨 커널을 직접 생성해서 엣지 검출 ---① 7 | ## 소벨 커널 생성 8 | gx_k = np.array([[-1,0,1], [-2,0,2],[-1,0,1]]) 9 | gy_k = np.array([[-1,-2,-1],[0,0,0], [1,2,1]]) 10 | ## 소벨 필터 적용 11 | edge_gx = cv2.filter2D(img, -1, gx_k) 12 | edge_gy = cv2.filter2D(img, -1, gy_k) 13 | 14 | # 소벨 API를 생성해서 엣지 검출 15 | sobelx = cv2.Sobel(img, -1, 1, 0, ksize=3) 16 | sobely = cv2.Sobel(img, -1, 0, 1, ksize=3) 17 | 18 | # 결과 출력 19 | merged1 = np.hstack((img, edge_gx, edge_gy, edge_gx+edge_gy)) 20 | merged2 = np.hstack((img, sobelx, sobely, sobelx+sobely)) 21 | merged = np.vstack((merged1, merged2)) 22 | cv2.imshow('sobel', merged) 23 | cv2.waitKey(0) 24 | cv2.destroyAllWindows() 25 | 26 | -------------------------------------------------------------------------------- /04.img_processing/threshold_otsu.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | import matplotlib.pylab as plt 4 | 5 | # 이미지를 그레이 스케일로 읽기 6 | img = cv2.imread('../img/scaned_paper.jpg', cv2.IMREAD_GRAYSCALE) 7 | # 경계 값을 130으로 지정 ---① 8 | _, t_130 = cv2.threshold(img, 130, 255, cv2.THRESH_BINARY) 9 | # 경계 값을 지정하지 않고 OTSU 알고리즘 선택 ---② 10 | t, t_otsu = cv2.threshold(img, -1, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU) 11 | print('otsu threshold:', t) # Otsu 알고리즘으로 선택된 경계 값 출력 12 | 13 | imgs = {'Original': img, 't:130':t_130, 'otsu:%d'%t: t_otsu} 14 | for i , (key, value) in enumerate(imgs.items()): 15 | plt.subplot(1, 3, i+1) 16 | plt.title(key) 17 | plt.imshow(value, cmap='gray') 18 | plt.xticks([]); plt.yticks([]) 19 | 20 | plt.show() -------------------------------------------------------------------------------- /07.segmentation/mean_shift.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | img = cv2.imread('../img/taekwonv1.jpg') 5 | # 트랙바 이벤트 처리 함수 6 | def onChange(x): 7 | #sp, sr, level 선택 값 수집 8 | sp = cv2.getTrackbarPos('sp', 'img') 9 | sr = cv2.getTrackbarPos('sr', 'img') 10 | lv = cv2.getTrackbarPos('lv', 'img') 11 | 12 | # 평균 이동 필터 적용 ---① 13 | mean = cv2.pyrMeanShiftFiltering(img, sp, sr, None, lv) 14 | # 변환 이미지 출력 15 | cv2.imshow('img', np.hstack((img, mean))) 16 | 17 | # 초기 화면 출력 18 | cv2.imshow('img', np.hstack((img, img))) 19 | # 트랙바 이벤트 함수 연결 20 | cv2.createTrackbar('sp', 'img', 0,100, onChange) 21 | cv2.createTrackbar('sr', 'img', 0,100, onChange) 22 | cv2.createTrackbar('lv', 'img', 0,5, onChange) 23 | cv2.waitKey(0) 24 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /09.ml/k-means_color.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import cv2 3 | 4 | K = 16 # 군집화 갯수(16컬러) ---① 5 | img = cv2.imread('../img/taekwonv1.jpg') 6 | # 군집화를 위한 데이타 구조와 형식 변환 ---② 7 | data = img.reshape((-1,3)).astype(np.float32) 8 | # 반복 중지 요건 ---③ 9 | criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0) 10 | # 평균 클러스터링 적용 ---④ 11 | ret,label,center=cv2.kmeans(data,K,None,criteria,10,cv2.KMEANS_RANDOM_CENTERS) 12 | # 중심 값을 정수형으로 변환 ---⑤ 13 | center = np.uint8(center) 14 | print(center) 15 | # 각 레이블에 해당하는 중심값으로 픽셀 값 선택 ---⑥ 16 | res = center[label.flatten()] 17 | print(label.flatten()) 18 | # 원본 영상의 형태로 변환 ---⑦ 19 | res = res.reshape((img.shape)) 20 | # 결과 출력 ---⑧ 21 | merged = np.hstack((img, res)) 22 | cv2.imshow('KMeans Color',merged) 23 | cv2.waitKey(0) 24 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /05.geometric_transform/undistort_barrel.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import cv2 3 | 4 | # 격자 무늬 영상 생성 ---① 5 | img = np.full((300,400,3), 255, np.uint8) 6 | img[::10, :, :] = 0 7 | img[:, ::10, :] = 0 8 | width = img.shape[1] 9 | height = img.shape[0] 10 | 11 | # 왜곡 계수 설정 ---② 12 | k1, k2, p1, p2 = 0.001, 0, 0, 0 # 배럴 왜곡 13 | #k1, k2, p1, p2 = -0.0005, 0, 0, 0 # 핀쿠션 왜곡 14 | distCoeff = np.float64([k1, k2, p1, p2]) 15 | 16 | # 임의의 값으로 카메라 매트릭스 설정 ---③ 17 | fx, fy = 10, 10 18 | cx, cy = width/2, height/2 19 | camMtx = np.float32([[fx,0, cx], 20 | [0, fy, cy], 21 | [0 ,0 ,1]]) 22 | 23 | # 왜곡 변형 ---④ 24 | dst = cv2.undistort(img,camMtx,distCoeff) 25 | 26 | cv2.imshow('original', img) 27 | cv2.imshow('dst',dst) 28 | cv2.waitKey(0) 29 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /07.segmentation/hough_circle.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | img = cv2.imread('../img/coins_connected.jpg') 5 | # 그레이 스케일 변환 ---① 6 | gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 7 | # 노이즈 제거를 위한 가우시안 블러 ---② 8 | blur = cv2.GaussianBlur(gray, (3,3), 0) 9 | # 허프 원 변환 적용( dp=1.5, minDist=30, cany_max=200 ) ---③ 10 | circles = cv2.HoughCircles(blur, cv2.HOUGH_GRADIENT, 1.2, 30, None, 200) 11 | if circles is not None: 12 | circles = np.uint16(np.around(circles)) 13 | for i in circles[0,:]: 14 | # 원 둘레에 초록색 원 그리기 15 | cv2.circle(img,(i[0], i[1]), i[2], (0, 255, 0), 2) 16 | # 원 중심점에 빨강색 원 그리기 17 | cv2.circle(img, (i[0], i[1]), 2, (0,0,255), 5) 18 | 19 | # 결과 출력 20 | cv2.imshow('hough circle', img) 21 | cv2.waitKey(0) 22 | cv2.destroyAllWindows() 23 | -------------------------------------------------------------------------------- /02.interface/video_play_fps.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | 3 | video_file = "../img/big_buck.avi" # 동영상 파일 경로 4 | 5 | cap = cv2.VideoCapture(video_file) # 동영상 캡쳐 객체 생성 6 | if cap.isOpened(): # 캡쳐 객체 초기화 확인 7 | fps = cap.get(cv2.CAP_PROP_FPS) # 프레임 수 구하기 8 | delay = int(1000/fps) 9 | print("FPS: %f, Delay: %dms" %(fps, delay)) 10 | 11 | while True: 12 | ret, img = cap.read() # 다음 프레임 읽기 13 | if ret: # 프레임 읽기 정상 14 | cv2.imshow(video_file, img) # 화면에 표시 15 | cv2.waitKey(delay) # fps에 맞게 시간 지연 16 | else: 17 | break # 다음 프레임 읽을 수 없슴, 재생 완료 18 | else: 19 | print("can't open video.") # 캡쳐 객체 초기화 실패 20 | cap.release() # 캡쳐 자원 반납 21 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /04.img_processing/bgr2hsv.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | #---① BGR 컬러 스페이스로 원색 픽셀 생성 5 | red_bgr = np.array([[[0,0,255]]], dtype=np.uint8) # 빨강 값만 갖는 픽셀 6 | green_bgr = np.array([[[0,255,0]]], dtype=np.uint8) # 초록 값만 갖는 픽셀 7 | blue_bgr = np.array([[[255,0,0]]], dtype=np.uint8) # 파랑 값만 갖는 픽셀 8 | yellow_bgr = np.array([[[0,255,255]]], dtype=np.uint8) # 노랑 값만 갖는 픽셀 9 | 10 | #---② BGR 컬러 스페이스를 HSV 컬러 스페이스로 변환 11 | red_hsv = cv2.cvtColor(red_bgr, cv2.COLOR_BGR2HSV); 12 | green_hsv = cv2.cvtColor(green_bgr, cv2.COLOR_BGR2HSV); 13 | blue_hsv = cv2.cvtColor(blue_bgr, cv2.COLOR_BGR2HSV); 14 | yellow_hsv = cv2.cvtColor(yellow_bgr, cv2.COLOR_BGR2HSV); 15 | 16 | #---③ HSV로 변환한 픽셀 출력 17 | print("red:",red_hsv) 18 | print("green:", green_hsv) 19 | print("blue", blue_hsv) 20 | print("yellow", yellow_hsv) 21 | -------------------------------------------------------------------------------- /07.segmentation/flood_fill.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | img = cv2.imread('../img/taekwonv1.jpg') 5 | rows, cols = img.shape[:2] 6 | # 마스크 생성, 원래 이미지 보다 2픽셀 크게 ---① 7 | mask = np.zeros((rows+2, cols+2), np.uint8) 8 | # 채우기에 사용할 색 ---② 9 | newVal = (255,255,255) 10 | # 최소 최대 차이 값 ---③ 11 | loDiff, upDiff = (10,10,10), (10,10,10) 12 | 13 | # 마우스 이벤트 처리 함수 14 | def onMouse(event, x, y, flags, param): 15 | global mask, img 16 | if event == cv2.EVENT_LBUTTONDOWN: 17 | seed = (x,y) 18 | # 색 채우기 적용 ---④ 19 | retval = cv2.floodFill(img, mask, seed, newVal, loDiff, upDiff) 20 | # 채우기 변경 결과 표시 ---⑤ 21 | cv2.imshow('img', img) 22 | 23 | # 화면 출력 24 | cv2.imshow('img', img) 25 | cv2.setMouseCallback('img', onMouse) 26 | cv2.waitKey(0) 27 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /05.geometric_transform/rotate_matrix.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | img = cv2.imread('../img/fish.jpg') 5 | rows,cols = img.shape[0:2] 6 | 7 | # ---① 라디안 각도 계산(60진법을 호도법으로 변경) 8 | d45 = 45.0 * np.pi / 180 # 45도 9 | d90 = 90.0 * np.pi / 180 # 90도 10 | 11 | # ---② 회전을 위한 변환 행렬 생성 12 | m45 = np.float32( [[ np.cos(d45), -1* np.sin(d45), rows//2], 13 | [np.sin(d45), np.cos(d45), -1*cols//4]]) 14 | m90 = np.float32( [[ np.cos(d90), -1* np.sin(d90), rows], 15 | [np.sin(d90), np.cos(d90), 0]]) 16 | 17 | # ---③ 회전 변환 행렬 적용 18 | r45 = cv2.warpAffine(img,m45,(cols,rows)) 19 | r90 = cv2.warpAffine(img,m90,(rows,cols)) 20 | 21 | # ---④ 결과 출력 22 | cv2.imshow("origin", img) 23 | cv2.imshow("45", r45) 24 | cv2.imshow("90", r90) 25 | cv2.waitKey(0) 26 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /04.img_processing/diff_absolute.py: -------------------------------------------------------------------------------- 1 | import numpy as np, cv2 2 | 3 | #--① 연산에 필요한 영상을 읽고 그레이스케일로 변환 4 | img1 = cv2.imread('../img/robot_arm1.jpg') 5 | img2 = cv2.imread('../img/robot_arm2.jpg') 6 | img1_gray = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY) 7 | img2_gray = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY) 8 | 9 | #--② 두 영상의 절대값 차 연산 10 | diff = cv2.absdiff(img1_gray, img2_gray) 11 | 12 | #--③ 차 영상을 극대화 하기 위해 쓰레시홀드 처리 및 컬러로 변환 13 | _, diff = cv2.threshold(diff, 1, 255, cv2.THRESH_BINARY) 14 | diff_red = cv2.cvtColor(diff, cv2.COLOR_GRAY2BGR) 15 | diff_red[:,:,2] = 0 16 | 17 | #--④ 두 번째 이미지에 변화 부분 표시 18 | spot = cv2.bitwise_xor(img2, diff_red) 19 | 20 | #--⑤ 결과 영상 출력 21 | cv2.imshow('img1', img1) 22 | cv2.imshow('img2', img2) 23 | cv2.imshow('diff', diff) 24 | cv2.imshow('spot', spot) 25 | cv2.waitKey() 26 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /05.geometric_transform/getAffine.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | from matplotlib import pyplot as plt 4 | 5 | file_name = '../img/fish.jpg' 6 | img = cv2.imread(file_name) 7 | rows, cols = img.shape[:2] 8 | 9 | # ---① 변환 전, 후 각 3개의 좌표 생성 10 | pts1 = np.float32([[100, 50], [200, 50], [100, 200]]) 11 | pts2 = np.float32([[80, 70], [210, 60], [250, 120]]) 12 | 13 | # ---② 변환 전 좌표를 이미지에 표시 14 | cv2.circle(img, (100,50), 5, (255,0), -1) 15 | cv2.circle(img, (200,50), 5, (0,255,0), -1) 16 | cv2.circle(img, (100,200), 5, (0,0,255), -1) 17 | 18 | #---③ 짝지은 3개의 좌표로 변환 행렬 계산 19 | mtrx = cv2.getAffineTransform(pts1, pts2) 20 | #---④ 어핀 변환 적용 21 | dst = cv2.warpAffine(img, mtrx, (int(cols*1.5), rows)) 22 | 23 | #---⑤ 결과 출력 24 | cv2.imshow('origin',img) 25 | cv2.imshow('affine', dst) 26 | cv2.waitKey(0) 27 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /04.img_processing/histo_clahe.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | import matplotlib.pylab as plt 4 | 5 | #--①이미지 읽어서 YUV 컬러스페이스로 변경 6 | img = cv2.imread('../img/bright.jpg') 7 | img_yuv = cv2.cvtColor(img, cv2.COLOR_BGR2YUV) 8 | 9 | #--② 밝기 채널에 대해서 이퀄라이즈 적용 10 | img_eq = img_yuv.copy() 11 | img_eq[:,:,0] = cv2.equalizeHist(img_eq[:,:,0]) 12 | img_eq = cv2.cvtColor(img_eq, cv2.COLOR_YUV2BGR) 13 | 14 | #--③ 밝기 채널에 대해서 CLAHE 적용 15 | img_clahe = img_yuv.copy() 16 | clahe = cv2.createCLAHE(clipLimit=3.0, tileGridSize=(8,8)) #CLAHE 생성 17 | img_clahe[:,:,0] = clahe.apply(img_clahe[:,:,0]) #CLAHE 적용 18 | img_clahe = cv2.cvtColor(img_clahe, cv2.COLOR_YUV2BGR) 19 | 20 | #--④ 결과 출력 21 | cv2.imshow('Before', img) 22 | cv2.imshow('CLAHE', img_clahe) 23 | cv2.imshow('equalizeHist', img_eq) 24 | cv2.waitKey() 25 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /02.interface/event_key.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | 3 | img_file = "../img/yeosu.jpg" 4 | img = cv2.imread(img_file) 5 | title = 'IMG' # 창 이름 6 | x, y = 100, 100 # 최초 좌표 7 | 8 | while True: 9 | cv2.imshow(title, img) 10 | key = cv2.waitKey(0) & 0xFF # 키보드 입력을 무한 대기, 8비트 마스크처리 11 | print(key, chr(key)) # 키보드 입력 값, 문자 값 출력 12 | if key == ord('h'): # 'h' 키 이면 좌로 이동 13 | x -= 10 14 | elif key == ord('j'): # 'j' 키 이면 아래로 이동 15 | y += 10 16 | elif key == ord('k'): # 'k' 키 이면 위로 이동 17 | y -= 10 18 | elif key == ord('l'): # 'l' 키 이면 오른쪽으로 이동 19 | x += 10 20 | elif key == ord('q') or key == 27: # 'q' 이거나 'esc' 이면 종료 21 | break 22 | cv2.destroyAllWindows() 23 | cv2.moveWindow(title, x, y ) # 새로운 좌표로 창 이동 24 | -------------------------------------------------------------------------------- /04.img_processing/bitwise.py: -------------------------------------------------------------------------------- 1 | import numpy as np, cv2 2 | import matplotlib.pylab as plt 3 | 4 | #--① 연산에 사용할 이미지 생성 5 | img1 = np.zeros( ( 200,400), dtype=np.uint8) 6 | img2 = np.zeros( ( 200,400), dtype=np.uint8) 7 | img1[:, :200] = 255 # 왼쪽은 흰색(255), 오른쪽은 검정색(0) 8 | img2[100:200, :] = 255 # 위쪽은 검정색(0), 아래쪽은 흰색(255) 9 | 10 | #--② 비트와이즈 연산 11 | bitAnd = cv2.bitwise_and(img1, img2) 12 | bitOr = cv2.bitwise_or(img1, img2) 13 | bitXor = cv2.bitwise_xor(img1, img2) 14 | bitNot = cv2.bitwise_not(img1) 15 | 16 | #--③ Plot으로 결과 출력 17 | imgs = {'img1':img1, 'img2':img2, 'and':bitAnd, 18 | 'or':bitOr, 'xor':bitXor, 'not(img1)':bitNot} 19 | for i, (title, img) in enumerate(imgs.items()): 20 | plt.subplot(3,2,i+1) 21 | plt.title(title) 22 | plt.imshow(img, 'gray') 23 | plt.xticks([]); plt.yticks([]) 24 | 25 | plt.show() -------------------------------------------------------------------------------- /04.img_processing/threshold.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | import matplotlib.pylab as plt 4 | 5 | img = cv2.imread('../img/gray_gradient.jpg', cv2.IMREAD_GRAYSCALE) #이미지를 그레이 스케일로 읽기 6 | 7 | # --- ① NumPy API로 바이너리 이미지 만들기 8 | thresh_np = np.zeros_like(img) # 원본과 동일한 크기의 0으로 채워진 이미지 9 | thresh_np[ img > 127] = 255 # 127 보다 큰 값만 255로 변경 10 | 11 | # ---② OpenCV API로 바이너리 이미지 만들기 12 | ret, thresh_cv = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY) 13 | print(ret) # 127.0, 바이너리 이미지에 사용된 문턱 값 반환 14 | 15 | # ---③ 원본과 결과물을 matplotlib으로 출력 16 | imgs = {'Original': img, 'NumPy API':thresh_np, 'cv2.threshold': thresh_cv} 17 | for i , (key, value) in enumerate(imgs.items()): 18 | plt.subplot(1, 3, i+1) 19 | plt.title(key) 20 | plt.imshow(value, cmap='gray') 21 | plt.xticks([]); plt.yticks([]) 22 | 23 | plt.show() 24 | 25 | -------------------------------------------------------------------------------- /05.geometric_transform/perspective.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | file_name = "../img/fish.jpg" 5 | img = cv2.imread(file_name) 6 | rows, cols = img.shape[:2] 7 | 8 | #---① 원근 변환 전 후 4개 좌표 9 | pts1 = np.float32([[0,0], [0,rows], [cols, 0], [cols,rows]]) 10 | pts2 = np.float32([[100,50], [10,rows-50], [cols-100, 50], [cols-10,rows-50]]) 11 | 12 | #---② 변환 전 좌표를 원본 이미지에 표시 13 | cv2.circle(img, (0,0), 10, (255,0,0), -1) 14 | cv2.circle(img, (0,rows), 10, (0,255,0), -1) 15 | cv2.circle(img, (cols,0), 10, (0,0,255), -1) 16 | cv2.circle(img, (cols,rows), 10, (0,255,255), -1) 17 | 18 | #---③ 원근 변환 행렬 계산 19 | mtrx = cv2.getPerspectiveTransform(pts1, pts2) 20 | #---④ 원근 변환 적용 21 | dst = cv2.warpPerspective(img, mtrx, (cols, rows)) 22 | 23 | cv2.imshow("origin", img) 24 | cv2.imshow('perspective', dst) 25 | cv2.waitKey(0) 26 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /08.match_track/match_bf_surf.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | img1 = cv2.imread('../img/taekwonv1.jpg') 5 | img2 = cv2.imread('../img/figures.jpg') 6 | gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY) 7 | gray2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY) 8 | 9 | # SURF 서술자 추출기 생성 ---① 10 | detector = cv2.xfeatures2d.SURF_create() 11 | kp1, desc1 = detector.detectAndCompute(gray1, None) 12 | kp2, desc2 = detector.detectAndCompute(gray2, None) 13 | 14 | # BFMatcher 생성, L2 거리, 상호 체크 ---③ 15 | matcher = cv2.BFMatcher(cv2.NORM_L2, crossCheck=True) 16 | # 매칭 계산 ---④ 17 | matches = matcher.match(desc1, desc2) 18 | # 매칭 결과 그리기 ---⑤ 19 | res = cv2.drawMatches(img1, kp1, img2, kp2, matches, None, \ 20 | flags=cv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS) 21 | 22 | cv2.imshow('BF + SURF', res) 23 | cv2.waitKey() 24 | cv2.destroyAllWindows() 25 | -------------------------------------------------------------------------------- /04.img_processing/threshold_flag.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | import matplotlib.pylab as plt 4 | 5 | img = cv2.imread('../img/gray_gradient.jpg', cv2.IMREAD_GRAYSCALE) 6 | 7 | _, t_bin = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY) 8 | _, t_bininv = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY_INV) 9 | _, t_truc = cv2.threshold(img, 127, 255, cv2.THRESH_TRUNC) 10 | _, t_2zr = cv2.threshold(img, 127, 255, cv2.THRESH_TOZERO) 11 | _, t_2zrinv = cv2.threshold(img, 127, 255, cv2.THRESH_TOZERO_INV) 12 | 13 | imgs = {'origin':img, 'BINARY':t_bin, 'BINARY_INV':t_bininv, \ 14 | 'TRUNC':t_truc, 'TOZERO':t_2zr, 'TOZERO_INV':t_2zrinv} 15 | for i, (key, value) in enumerate(imgs.items()): 16 | plt.subplot(2,3, i+1) 17 | plt.title(key) 18 | plt.imshow(value, cmap='gray') 19 | plt.xticks([]); plt.yticks([]) 20 | 21 | plt.show() 22 | -------------------------------------------------------------------------------- /08.match_track/corner_harris.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | img = cv2.imread('../img/house.jpg') 5 | gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 6 | 7 | # 해리스 코너 검출 ---① 8 | corner = cv2.cornerHarris(gray, 2, 3, 0.04) 9 | # 변화량 결과의 최대값 10% 이상의 좌표 구하기 ---② 10 | coord = np.where(corner > 0.1* corner.max()) 11 | print(coord) 12 | print(coord[0]) 13 | coord = np.stack((coord[1], coord[0]), axis=-1) 14 | print(coord) 15 | 16 | # 코너 좌표에 동그리미 그리기 ---③ 17 | for x, y in coord: 18 | cv2.circle(img, (x,y), 5, (0,0,255), 1, cv2.LINE_AA) 19 | 20 | # 변화량을 영상으로 표현하기 위해서 0~255로 정규화 ---④ 21 | corner_norm = cv2.normalize(corner, None, 0, 255, cv2.NORM_MINMAX, cv2.CV_8U) 22 | # 화면에 출력 23 | corner_norm = cv2.cvtColor(corner_norm, cv2.COLOR_GRAY2BGR) 24 | merged = np.hstack((corner_norm, img)) 25 | cv2.imshow('Harris Corner', merged) 26 | cv2.waitKey() 27 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /09.ml/k-means_random.py: -------------------------------------------------------------------------------- 1 | import numpy as np, cv2 2 | import matplotlib.pyplot as plt 3 | 4 | # 0~150 임의의 2수, 25개 ---① 5 | a = np.random.randint(0,150,(25,2)) 6 | # 128~255 임의의 2수, 25개 ---② 7 | b = np.random.randint(128, 255,(25,2)) 8 | # a, b를 병합 ---③ 9 | data = np.vstack((a,b)).astype(np.float32) 10 | # 중지 요건 ---④ 11 | criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0) 12 | # 평균 클러스터링 적용 ---⑤ 13 | ret,label,center=cv2.kmeans(data,2,None,criteria,10,cv2.KMEANS_RANDOM_CENTERS) 14 | # label에 따라 결과 분류 ---⑥ 15 | red = data[label.ravel()==0] 16 | blue = data[label.ravel()==1] 17 | 18 | # plot에 결과 출력 ---⑦ 19 | plt.scatter(red[:,0],red[:,1], c='r') 20 | plt.scatter(blue[:,0],blue[:,1], c='b') 21 | # 각 그룹의 중앙점 출력 ---⑧ 22 | plt.scatter(center[0,0],center[0,1], s=100, c='r', marker='s') 23 | plt.scatter(center[1,0],center[1,1], s=100, c='b', marker='s') 24 | plt.show() -------------------------------------------------------------------------------- /04.img_processing/histo_2d.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import matplotlib.pylab as plt 3 | 4 | plt.style.use('classic') # --①컬러 스타일을 1.x 스타일로 사용 5 | img = cv2.imread('../img/mountain.jpg') 6 | 7 | plt.subplot(131) 8 | hist = cv2.calcHist([img], [0,1], None, [32,32], [0,256,0,256]) #--② 9 | p = plt.imshow(hist) #--③ 10 | plt.title('Blue and Green') #--④ 11 | plt.colorbar(p) #--⑤ 12 | 13 | 14 | plt.subplot(132) 15 | hist = cv2.calcHist([img], [1,2], None, [32,32], [0,256,0,256]) #--⑥ 16 | p = plt.imshow(hist) 17 | plt.title('Green and Red') 18 | plt.colorbar(p) 19 | 20 | plt.subplot(133) 21 | hist = cv2.calcHist([img], [0,2], None, [32,32], [0,256,0,256]) #--⑦ 22 | p = plt.imshow(hist) 23 | plt.title('Blue and Red') 24 | plt.colorbar(p) 25 | 26 | plt.show() 27 | -------------------------------------------------------------------------------- /08.match_track/match_bf_orb.py: -------------------------------------------------------------------------------- 1 | import cv2, numpy as np 2 | 3 | img1 = cv2.imread('../img/taekwonv1.jpg') 4 | img2 = cv2.imread('../img/figures.jpg') 5 | gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY) 6 | gray2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY) 7 | 8 | # SIFT 서술자 추출기 생성 ---① 9 | detector = cv2.ORB_create() 10 | # 각 영상에 대해 키 포인트와 서술자 추출 ---② 11 | kp1, desc1 = detector.detectAndCompute(gray1, None) 12 | kp2, desc2 = detector.detectAndCompute(gray2, None) 13 | 14 | # BFMatcher 생성, Hamming 거리, 상호 체크 ---③ 15 | matcher = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True) 16 | # 매칭 계산 ---④ 17 | matches = matcher.match(desc1, desc2) 18 | # 매칭 결과 그리기 ---⑤ 19 | res = cv2.drawMatches(img1, kp1, img2, kp2, matches, None, \ 20 | flags=cv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS) 21 | 22 | cv2.imshow('BFMatcher + ORB', res) 23 | cv2.waitKey() 24 | cv2.destroyAllWindows() 25 | -------------------------------------------------------------------------------- /08.match_track/match_bf_sift.py: -------------------------------------------------------------------------------- 1 | import cv2, numpy as np 2 | 3 | img1 = cv2.imread('../img/taekwonv1.jpg') 4 | img2 = cv2.imread('../img/figures.jpg') 5 | gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY) 6 | gray2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY) 7 | 8 | # SIFT 서술자 추출기 생성 ---① 9 | detector = cv2.xfeatures2d.SIFT_create() 10 | # 각 영상에 대해 키 포인트와 서술자 추출 ---② 11 | kp1, desc1 = detector.detectAndCompute(gray1, None) 12 | kp2, desc2 = detector.detectAndCompute(gray2, None) 13 | 14 | # BFMatcher 생성, L1 거리, 상호 체크 ---③ 15 | matcher = cv2.BFMatcher(cv2.NORM_L1, crossCheck=True) 16 | # 매칭 계산 ---④ 17 | matches = matcher.match(desc1, desc2) 18 | # 매칭 결과 그리기 ---⑤ 19 | res = cv2.drawMatches(img1, kp1, img2, kp2, matches, None, \ 20 | flags=cv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS) 21 | # 결과 출력 22 | cv2.imshow('BFMatcher + SIFT', res) 23 | cv2.waitKey() 24 | cv2.destroyAllWindows() 25 | -------------------------------------------------------------------------------- /05.geometric_transform/remap_barrel.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | # 왜곡 계수 설정 ---① 5 | # k1, k2, k3 = 0.5, 0.2, 0.0 # 배럴 왜곡 6 | k1, k2, k3 = -0.3, 0, 0 # 핀큐션 왜곡 7 | 8 | img = cv2.imread('../img/yeosu_small.jpg') 9 | rows, cols = img.shape[:2] 10 | 11 | # 매핑 배열 생성 ---② 12 | mapy, mapx = np.indices((rows, cols),dtype=np.float32) 13 | 14 | # 중앙점 좌표로 -1~1 정규화 및 극좌표 변환 ---③ 15 | mapx = 2*mapx/(cols-1)-1 16 | mapy = 2*mapy/(rows-1)-1 17 | r, theta = cv2.cartToPolar(mapx, mapy) 18 | 19 | # 방사 왜곡 변영 연산 ---④ 20 | ru = r*(1+k1*(r**2) + k2*(r**4) + k3*(r**6)) 21 | 22 | # 직교좌표 및 좌상단 기준으로 복원 ---⑤ 23 | mapx, mapy = cv2.polarToCart(ru, theta) 24 | mapx = ((mapx + 1)*cols-1)/2 25 | mapy = ((mapy + 1)*rows-1)/2 26 | # 리매핑 ---⑥ 27 | distored = cv2.remap(img,mapx,mapy,cv2.INTER_LINEAR) 28 | 29 | cv2.imshow('original', img) 30 | cv2.imshow('distorted', distored) 31 | cv2.waitKey() 32 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /07.segmentation/cntr_approximate.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | img = cv2.imread('../img/bad_rect.png') 5 | img2 = img.copy() 6 | 7 | # 그레이스케일과 바이너리 스케일 변환 8 | imgray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 9 | ret, th = cv2.threshold(imgray, 127, 255, cv2.THRESH_BINARY) 10 | 11 | # 컨투어 찾기 ---① 12 | temp, contours, hierachy = cv2.findContours(th, cv2.RETR_EXTERNAL, \ 13 | cv2.CHAIN_APPROX_SIMPLE) 14 | contour = contours[0] 15 | # 전체 둘레의 0.05로 오차 범위 지정 ---② 16 | epsilon = 0.05 * cv2.arcLength(contour, True) 17 | # 근사 컨투어 계산 ---③ 18 | approx = cv2.approxPolyDP(contour, epsilon, True) 19 | 20 | # 각각 컨투어 선 그리기 ---④ 21 | cv2.drawContours(img, [contour], -1, (0,255,0), 3) 22 | cv2.drawContours(img2, [approx], -1, (0,255,0), 3) 23 | 24 | # 결과 출력 25 | cv2.imshow('contour', img) 26 | cv2.imshow('approx', img2) 27 | cv2.waitKey() 28 | cv2.destroyAllWindows() 29 | 30 | -------------------------------------------------------------------------------- /05.geometric_transform/translate.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | img = cv2.imread('../img/fish.jpg') 5 | rows,cols = img.shape[0:2] # 영상의 크기 6 | 7 | dx, dy = 100, 50 # 이동할 픽셀 거리 8 | 9 | # ---① 변환 행렬 생성 10 | mtrx = np.float32([[1, 0, dx], 11 | [0, 1, dy]]) 12 | # ---② 단순 이동 13 | dst = cv2.warpAffine(img, mtrx, (cols+dx, rows+dy)) 14 | 15 | # ---③ 탈락된 외곽 픽셀을 파랑색으로 보정 16 | dst2 = cv2.warpAffine(img, mtrx, (cols+dx, rows+dy), None, \ 17 | cv2.INTER_LINEAR, cv2.BORDER_CONSTANT, (255,0,0) ) 18 | 19 | # ---④ 탈락된 외곽 픽셀을 원본을 반사 시켜서 보정 20 | dst3 = cv2.warpAffine(img, mtrx, (cols+dx, rows+dy), None, \ 21 | cv2.INTER_LINEAR, cv2.BORDER_REFLECT) 22 | 23 | cv2.imshow('original', img) 24 | cv2.imshow('trans',dst) 25 | cv2.imshow('BORDER_CONSTATNT', dst2) 26 | cv2.imshow('BORDER_FEFLECT', dst3) 27 | cv2.waitKey(0) 28 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /05.geometric_transform/remap_flip.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | import time 4 | 5 | img = cv2.imread('../img/yeosu_small.jpg') 6 | rows, cols = img.shape[:2] 7 | 8 | # 뒤집기 변환 행렬로 구현 ---① 9 | st = time.time() 10 | mflip = np.float32([ [-1, 0, cols-1],[0, -1, rows-1]]) # 변환 행렬 생성 11 | fliped1 = cv2.warpAffine(img, mflip, (cols, rows)) # 변환 적용 12 | print('matrix:', time.time()-st) 13 | 14 | # remap 함수로 뒤집기 구현 ---② 15 | st2 = time.time() 16 | mapy, mapx = np.indices((rows, cols),dtype=np.float32) # 매핑 배열 초기화 생성 17 | mapx = cols - mapx -1 # x축 좌표 뒤집기 연산 18 | mapy = rows - mapy -1 # y축 좌표 뒤집기 연산 19 | fliped2 = cv2.remap(img,mapx,mapy,cv2.INTER_LINEAR) # remap 적용 20 | print('remap:', time.time()-st2) 21 | 22 | # 결과 출력 ---③ 23 | cv2.imshow('origin', img) 24 | cv2.imshow('fliped1',fliped1) 25 | cv2.imshow('fliped2',fliped2) 26 | cv2.waitKey() 27 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /05.geometric_transform/remap_sin_cos.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | l = 20 # 파장(wave length) 5 | amp = 15 # 진폭(amplitude) 6 | 7 | img = cv2.imread('../img/taekwonv1.jpg') 8 | rows, cols = img.shape[:2] 9 | 10 | # 초기 매핑 배열 생성 ---① 11 | mapy, mapx = np.indices((rows, cols),dtype=np.float32) 12 | 13 | # sin, cos 함수를 적용한 변형 매핑 연산 ---② 14 | sinx = mapx + amp * np.sin(mapy/l) 15 | cosy = mapy + amp * np.cos(mapx/l) 16 | 17 | # 영상 매핑 ---③ 18 | 19 | img_sinx=cv2.remap(img, sinx, mapy, cv2.INTER_LINEAR) # x축만 sin 곡선 적용 20 | img_cosy=cv2.remap(img, mapx, cosy, cv2.INTER_LINEAR) # y축만 cos 곡선 적용 21 | # x,y 축 모두 sin, cos 곡선 적용 및 외곽 영역 보정 22 | img_both=cv2.remap(img, sinx, cosy, cv2.INTER_LINEAR, \ 23 | None, cv2.BORDER_REPLICATE) 24 | # 결과 출력 25 | cv2.imshow('origin', img) 26 | cv2.imshow('sin x', img_sinx) 27 | cv2.imshow('cos y', img_cosy) 28 | cv2.imshow('sin cos', img_both) 29 | 30 | cv2.waitKey() 31 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /07.segmentation/hough_line.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | img = cv2.imread('../img/sudoku.jpg') 5 | img2 = img.copy() 6 | h, w = img.shape[:2] 7 | # 그레이 스케일 변환 및 엣지 검출 ---① 8 | imgray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 9 | edges = cv2.Canny(imgray, 100, 200 ) 10 | # 허프 선 검출 ---② 11 | lines = cv2.HoughLines(edges, 1, np.pi/180, 130) 12 | for line in lines: # 검출된 모든 선 순회 13 | r,theta = line[0] # 거리와 각도 14 | tx, ty = np.cos(theta), np.sin(theta) # x, y축에 대한 삼각비 15 | x0, y0 = tx*r, ty*r #x, y 기준(절편) 좌표 16 | # 기준 좌표에 빨강색 점 그리기 17 | cv2.circle(img2, (abs(x0), abs(y0)), 3, (0,0,255), -1) 18 | # 직선 방정식으로 그리기 위한 시작점, 끝점 계산 19 | x1, y1 = int(x0 + w*(-ty)), int(y0 + h * tx) 20 | x2, y2 = int(x0 - w*(-ty)), int(y0 - h * tx) 21 | # 선그리기 22 | cv2.line(img2, (x1, y1), (x2, y2), (0,255,0), 1) 23 | 24 | #결과 출력 25 | merged = np.hstack((img, img2)) 26 | cv2.imshow('hough line', merged) 27 | cv2.waitKey() 28 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /09.ml/haar_face.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import cv2 3 | 4 | # 얼굴 검출을 위한 케스케이드 분류기 생성 --- ① 5 | face_cascade = cv2.CascadeClassifier('./data/haarcascade_frontalface_default.xml') 6 | # 눈 검출을 위한 케스케이드 분류기 생성 ---② 7 | eye_cascade = cv2.CascadeClassifier('./data/haarcascade_eye.xml') 8 | # 검출할 이미지 읽고 그레이 스케일로 변환 ---③ 9 | img = cv2.imread('../img/children.jpg') 10 | gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 11 | # 얼굴 검출 ---④ 12 | faces = face_cascade.detectMultiScale(gray) 13 | # 검출된 얼굴 순회 ---⑤ 14 | for (x,y,w,h) in faces: 15 | # 검출된 얼굴에 사각형 표시 ---⑥ 16 | cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2) 17 | # 얼굴 영역을 ROI로 설정 ---⑦ 18 | roi = gray[y:y+h, x:x+w] 19 | # ROI에서 눈 검출 ---⑧ 20 | eyes = eye_cascade.detectMultiScale(roi) 21 | # 검출된 눈에 사각형 표 ---⑨ 22 | for (ex,ey,ew,eh) in eyes: 23 | cv2.rectangle(img[y:y+h, x:x+w],(ex,ey),(ex+ew,ey+eh),(0,255,0),2) 24 | # 결과 출력 25 | cv2.imshow('img',img) 26 | cv2.waitKey(0) 27 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /02.interface/draw_poly.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np # 좌표 표현을 위한 numpy 모듈 ---① 3 | 4 | img = cv2.imread('../img/blank_500.jpg') 5 | 6 | # Numpy array로 좌표 생성 ---② 7 | # 번개 모양 선 좌표 8 | pts1 = np.array([[50,50], [150,150], [100,140],[200,240]], dtype=np.int32) 9 | # 삼각형 좌표 10 | pts2 = np.array([[350,50], [250,200], [450,200]], dtype=np.int32) 11 | # 삼각형 좌표 12 | pts3 = np.array([[150,300], [50,450], [250,450]], dtype=np.int32) 13 | # 5각형 좌표 14 | pts4 = np.array([[350,250], [450,350], [400,450], [300,450], [250,350]],\ 15 | dtype=np.int32) 16 | 17 | # 다각형 그리기 ---③ 18 | cv2.polylines(img, [pts1], False, (255,0,0)) # 번개 모양 선 그리기 19 | cv2.polylines(img, [pts2], False, (0,0,0), 10) # 3각형 열린 선 그리기 ---④ 20 | cv2.polylines(img, [pts3], True, (0,0,255), 10) # 3각형 닫힌 도형 그리기 ---⑤ 21 | cv2.polylines(img, [pts4], True, (0,0,0)) # 5각형 닫힌 도형 그리기 22 | 23 | cv2.imshow('polyline', img) 24 | cv2.waitKey(0) 25 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /08.match_track/match_flann_sift.py: -------------------------------------------------------------------------------- 1 | import cv2, numpy as np 2 | 3 | img1 = cv2.imread('../img/taekwonv1.jpg') 4 | img2 = cv2.imread('../img/figures.jpg') 5 | gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY) 6 | gray2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY) 7 | 8 | # SIFT 생성 9 | detector = cv2.xfeatures2d.SIFT_create() 10 | # 키 포인트와 서술자 추출 11 | kp1, desc1 = detector.detectAndCompute(gray1, None) 12 | kp2, desc2 = detector.detectAndCompute(gray2, None) 13 | 14 | # 인덱스 파라미터와 검색 파라미터 설정 ---① 15 | FLANN_INDEX_KDTREE = 1 16 | index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5) 17 | search_params = dict(checks=50) 18 | 19 | # Flann 매처 생성 ---③ 20 | matcher = cv2.FlannBasedMatcher(index_params, search_params) 21 | # 매칭 계산 ---④ 22 | matches = matcher.match(desc1, desc2) 23 | # 매칭 그리기 24 | res = cv2.drawMatches(img1, kp1, img2, kp2, matches, None, \ 25 | flags=cv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS) 26 | 27 | cv2.imshow('Flann + SIFT', res) 28 | cv2.waitKey() 29 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /08.match_track/match_flann_surf.py: -------------------------------------------------------------------------------- 1 | import cv2, numpy as np 2 | 3 | img1 = cv2.imread('../img/taekwonv1.jpg') 4 | img2 = cv2.imread('../img/figures.jpg') 5 | gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY) 6 | gray2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY) 7 | 8 | # SURF 생성 9 | detector = cv2.xfeatures2d.SURF_create() 10 | # 키 포인트와 서술자 추출 11 | kp1, desc1 = detector.detectAndCompute(gray1, None) 12 | kp2, desc2 = detector.detectAndCompute(gray2, None) 13 | 14 | # 인덱스 파라미터와 검색 파라미터 설정 ---① 15 | FLANN_INDEX_KDTREE = 1 16 | index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5) 17 | search_params = dict(checks=50) 18 | 19 | # Flann 매처 생성 ---③ 20 | matcher = cv2.FlannBasedMatcher(index_params, search_params) 21 | # 매칭 계산 ---④ 22 | matches = matcher.match(desc1, desc2) 23 | # 매칭 그리기 24 | res = cv2.drawMatches(img1, kp1, img2, kp2, matches, None, \ 25 | flags=cv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS) 26 | 27 | cv2.imshow('Flann + SURF', res) 28 | cv2.waitKey() 29 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /02.interface/video_cam_resize.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | 3 | cap = cv2.VideoCapture(0) # 카메라 0번 장치 연결 4 | width = cap.get(cv2.CAP_PROP_FRAME_WIDTH) # 프레임 폭 값 구하기 5 | height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT) # 프레임 높이 값 구하기 6 | print("Original width: %d, height:%d" % (width, height) ) 7 | 8 | cap.set(cv2.CAP_PROP_FRAME_WIDTH, 320) # 프레임 폭을 320으로 설정 9 | cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 240) # 프레임 높이를 240으로 설정 10 | width = cap.get(cv2.CAP_PROP_FRAME_WIDTH) # 재지정한 프레임 폭 값 구하기 11 | height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT) # 재지정한 프레임 폭 값 구하기 12 | 13 | print("Resized width: %d, height:%d" % (width, height) ) 14 | if cap.isOpened(): 15 | while True: 16 | ret, img = cap.read() 17 | if ret: 18 | cv2.imshow('camera', img) 19 | if cv2.waitKey(1) != -1: 20 | break 21 | else: 22 | print('no frame!') 23 | break 24 | else: 25 | print("can't open camera!") 26 | cap.release() 27 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /08.match_track/kpt_blob_param.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | img = cv2.imread("../img/house.jpg") 5 | gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 6 | 7 | # blob 검출 필터 파라미터 생성 ---① 8 | params = cv2.SimpleBlobDetector_Params() 9 | 10 | # 경계값 조정 ---② 11 | params.minThreshold = 10 12 | params.maxThreshold = 240 13 | params.thresholdStep = 5 14 | # 면적 필터 켜고 최소 값 지정 ---③ 15 | params.filterByArea = True 16 | params.minArea = 200 17 | 18 | # 컬러, 볼록 비율, 원형비율 필터 옵션 끄기 ---④ 19 | params.filterByColor = False 20 | params.filterByConvexity = False 21 | params.filterByInertia = False 22 | params.filterByCircularity = False 23 | 24 | # 필터 파라미터로 blob 검출기 생성 ---⑤ 25 | detector = cv2.SimpleBlobDetector_create(params) 26 | # 키 포인트 검출 ---⑥ 27 | keypoints = detector.detect(gray) 28 | # 키 포인트 그리기 ---⑦ 29 | img_draw = cv2.drawKeypoints(img, keypoints, None, None,\ 30 | cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS) 31 | # 결과 출력 ---⑧ 32 | cv2.imshow("Blob with Params", img_draw) 33 | cv2.waitKey(0) -------------------------------------------------------------------------------- /05.geometric_transform/remap_lens.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | img = cv2.imread('../img/taekwonv1.jpg') 5 | print(img.shape) 6 | rows, cols = img.shape[:2] 7 | 8 | # ---① 설정 값 셋팅 9 | exp = 0.5 # 볼록, 오목 지수 (오목 : 0.1 ~ 1, 볼록 : 1.1~) 10 | scale = 1 # 변환 영역 크기 (0 ~ 1) 11 | 12 | # 매핑 배열 생성 ---② 13 | mapy, mapx = np.indices((rows, cols),dtype=np.float32) 14 | 15 | # 좌상단 기준좌표에서 -1~1로 정규화된 중심점 기준 좌표로 변경 ---③ 16 | mapx = 2*mapx/(cols-1)-1 17 | mapy = 2*mapy/(rows-1)-1 18 | 19 | # 직교좌표를 극 좌표로 변환 ---④ 20 | r, theta = cv2.cartToPolar(mapx, mapy) 21 | 22 | # 왜곡 영역만 중심확대/축소 지수 적용 ---⑤ 23 | r[r< scale] = r[r= 2: 23 | break 24 | cv2.rectangle(img[y:y+h, x:x+w], (ex,ey), (ex+ew, ey+eh), \ 25 | (255,0,0),2) 26 | cv2.imshow('face detect', img) 27 | else: 28 | break 29 | if cv2.waitKey(5) == 27: 30 | break 31 | cv2.destroyAllWindows() 32 | -------------------------------------------------------------------------------- /04.img_processing/histo_equalize.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | import matplotlib.pylab as plt 4 | 5 | #--① 대상 영상으로 그레이 스케일로 읽기 6 | img = cv2.imread('../img/yate.jpg', cv2.IMREAD_GRAYSCALE) 7 | rows, cols = img.shape[:2] 8 | 9 | #--② 이퀄라이즈 연산을 직접 적용 10 | hist = cv2.calcHist([img], [0], None, [256], [0, 256]) #히스토그램 계산 11 | cdf = hist.cumsum() # 누적 히스토그램 12 | cdf_m = np.ma.masked_equal(cdf, 0) # 0(zero)인 값을 NaN으로 제거 13 | cdf_m = (cdf_m - cdf_m.min()) /(rows * cols) * 255 # 이퀄라이즈 히스토그램 계산 14 | cdf = np.ma.filled(cdf_m,0).astype('uint8') # NaN을 다시 0으로 환원 15 | print(cdf.shape) 16 | img2 = cdf[img] # 히스토그램을 픽셀로 맵핑 17 | 18 | #--③ OpenCV API로 이퀄라이즈 히스토그램 적용 19 | img3 = cv2.equalizeHist(img) 20 | 21 | #--④ 이퀄라이즈 결과 히스토그램 계산 22 | hist2 = cv2.calcHist([img2], [0], None, [256], [0, 256]) 23 | hist3 = cv2.calcHist([img3], [0], None, [256], [0, 256]) 24 | 25 | #--⑤ 결과 출력 26 | cv2.imshow('Before', img) 27 | cv2.imshow('Manual', img2) 28 | cv2.imshow('cv2.equalizeHist()', img3) 29 | hists = {'Before':hist, 'Manual':hist2, 'cv2.equalizeHist()':hist3} 30 | for i, (k, v) in enumerate(hists.items()): 31 | plt.subplot(1,3,i+1) 32 | plt.title(k) 33 | plt.plot(v) 34 | plt.show() -------------------------------------------------------------------------------- /04.img_processing/workshop_two_face.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | # 영상의 15%를 알파 블렌딩의 범위로 지정 5 | alpha_width_rate = 15 6 | 7 | # 합성할 두 영상 읽기 8 | img_face = cv2.imread('../img/man_face.jpg') 9 | img_skull = cv2.imread('../img/skull.jpg') 10 | 11 | # 입력 영상과 같은 크기의 결과 영상 준비 12 | img_comp = np.zeros_like(img_face) 13 | 14 | # 연산에 필요한 좌표 계산 15 | height, width = img_face.shape[:2] 16 | middle = width//2 # 영상의 중앙 좌표 17 | alpha_width = width * alpha_width_rate // 100 # 알파 블렌딩 범위 18 | start = middle - alpha_width//2 # 알파 블렌딩 시작 지점 19 | step = 100/alpha_width # 알파 값 간격 20 | 21 | # 입력 영상의 절반씩 복사해서 결과 영상에 합성 22 | img_comp[:, :middle, : ] = img_face[:, :middle, :].copy() 23 | img_comp[:, middle:, :] = img_skull[:, middle:, :].copy() 24 | cv2.imshow('half', img_comp) 25 | 26 | # 알파 값을 바꾸면서 알파 블렌딩 적용 27 | for i in range(alpha_width+1 ): 28 | alpha = (100 - step * i) / 100 # 증감 간격에 따른 알파 값 (1~0) 29 | beta = 1 - alpha # 베타 값 (0~1) 30 | # 알파 블렌딩 적용 31 | img_comp[:, start+i] = img_face[:, start+i] * \ 32 | alpha + img_skull[:, start+i] * beta 33 | print(i, alpha, beta) 34 | 35 | cv2.imshow('half skull', img_comp) 36 | cv2.waitKey() 37 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /02.interface/event_mouse_circle_flag.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | 3 | title = 'mouse event' # 창 제목 4 | img = cv2.imread('../img/blank_500.jpg') # 백색 이미지 읽기 5 | cv2.imshow(title, img) # 백색 이미지 표시 6 | 7 | colors = {'black':(0,0,0), 8 | 'red' : (0,0,255), 9 | 'blue':(255,0,0), 10 | 'green': (0,255,0) } # 색상 미리 정의 11 | 12 | def onMouse(event, x, y, flags, param): # 아무스 콜백 함수 구현 ---① 13 | print(event, x, y, flags) # 파라미터 출력 14 | color = colors['black'] 15 | if event == cv2.EVENT_LBUTTONDOWN: # 왼쪽 버튼 누름인 경우 ---② 16 | # 컨트롤키와 쉬프트 키를 모두 누른 경우 17 | if flags & cv2.EVENT_FLAG_CTRLKEY and flags & cv2.EVENT_FLAG_SHIFTKEY : 18 | color = colors['green'] 19 | elif flags & cv2.EVENT_FLAG_SHIFTKEY : # 쉬프트 키를 누른 경우 20 | color = colors['blue'] 21 | elif flags & cv2.EVENT_FLAG_CTRLKEY : # 컨트롤 키를 누른 경우 22 | color = colors['red'] 23 | # 지름 30 크기의 검은색 원을 해당 좌표에 그림 24 | cv2.circle(img, (x,y), 30, color, -1) 25 | cv2.imshow(title, img) # 그려진 이미지를 다시 표시 ---③ 26 | 27 | cv2.setMouseCallback(title, onMouse) # 마우스 콜백 함수를 GUI 윈도우에 등록 ---④ 28 | 29 | while True: 30 | if cv2.waitKey(0) & 0xFF == 27: # esc로 종료 31 | break 32 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /04.img_processing/chromakey.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | import matplotlib.pylab as plt 4 | 5 | #--① 크로마키 배경 영상과 합성할 배경 영상 읽기 6 | img1 = cv2.imread('../img/man_chromakey.jpg') 7 | img2 = cv2.imread('../img/street.jpg') 8 | 9 | #--② ROI 선택을 위한 좌표 계산 10 | height1, width1 = img1.shape[:2] 11 | height2, width2 = img2.shape[:2] 12 | x = (width2 - width1)//2 13 | y = height2 - height1 14 | w = x + width1 15 | h = y + height1 16 | 17 | #--③ 크로마키 배경 영상에서 크로마키 영역을 10픽셀 정도로 지정 18 | chromakey = img1[:10, :10, :] 19 | offset = 20 20 | 21 | #--④ 크로마키 영역과 영상 전체를 HSV로 변경 22 | hsv_chroma = cv2.cvtColor(chromakey, cv2.COLOR_BGR2HSV) 23 | hsv_img = cv2.cvtColor(img1, cv2.COLOR_BGR2HSV) 24 | 25 | #--⑤ 크로마키 영역의 H값에서 offset 만큼 여유를 두어서 범위 지정 26 | # offset 값은 여러차례 시도 후 결정 27 | #chroma_h = hsv_chroma[0] 28 | chroma_h = hsv_chroma[:,:,0] 29 | lower = np.array([chroma_h.min()-offset, 100, 100]) 30 | upper = np.array([chroma_h.max()+offset, 255, 255]) 31 | 32 | #--⑥ 마스크 생성 및 마스킹 후 합성 33 | mask = cv2.inRange(hsv_img, lower, upper) 34 | mask_inv = cv2.bitwise_not(mask) 35 | roi = img2[y:h, x:w] 36 | fg = cv2.bitwise_and(img1, img1, mask=mask_inv) 37 | bg = cv2.bitwise_and(roi, roi, mask=mask) 38 | img2[y:h, x:w] = fg + bg 39 | 40 | #--⑦ 결과 출력 41 | cv2.imshow('chromakey', img1) 42 | cv2.imshow('added', img2) 43 | cv2.waitKey() 44 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /08.match_track/match_good.py: -------------------------------------------------------------------------------- 1 | import cv2, numpy as np 2 | 3 | img1 = cv2.imread('../img/taekwonv1.jpg') 4 | img2 = cv2.imread('../img/figures.jpg') 5 | gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY) 6 | gray2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY) 7 | 8 | # ORB로 서술자 추출 ---① 9 | detector = cv2.ORB_create() 10 | kp1, desc1 = detector.detectAndCompute(gray1, None) 11 | kp2, desc2 = detector.detectAndCompute(gray2, None) 12 | # BF-Hamming으로 매칭 ---② 13 | matcher = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True) 14 | matches = matcher.match(desc1, desc2) 15 | 16 | # 매칭 결과를 거리기준 오름차순으로 정렬 ---③ 17 | matches = sorted(matches, key=lambda x:x.distance) 18 | # 최소 거리 값과 최대 거리 값 확보 ---④ 19 | min_dist, max_dist = matches[0].distance, matches[-1].distance 20 | # 최소 거리의 15% 지점을 임계점으로 설정 ---⑤ 21 | ratio = 0.2 22 | good_thresh = (max_dist - min_dist) * ratio + min_dist 23 | # 임계점 보다 작은 매칭점만 좋은 매칭점으로 분류 ---⑥ 24 | good_matches = [m for m in matches if m.distance < good_thresh] 25 | print('matches:%d/%d, min:%.2f, max:%.2f, thresh:%.2f' \ 26 | %(len(good_matches),len(matches), min_dist, max_dist, good_thresh)) 27 | # 좋은 매칭점만 그리기 ---⑦ 28 | res = cv2.drawMatches(img1, kp1, img2, kp2, good_matches, None, \ 29 | flags=cv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS) 30 | # 결과 출력 31 | cv2.imshow('Good Match', res) 32 | cv2.waitKey() 33 | cv2.destroyAllWindows() 34 | -------------------------------------------------------------------------------- /07.segmentation/cntr_moment.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | img = cv2.imread("../img/shapes.png") 5 | # 그레이 스케일 변환 6 | imgray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 7 | # 바이너리 스케일 변환 8 | ret, th = cv2.threshold(imgray, 127, 255, cv2.THRESH_BINARY_INV) 9 | # 컨투어 찾기 10 | img2, contours, hierachy = cv2.findContours(th, cv2.RETR_EXTERNAL, \ 11 | cv2.CHAIN_APPROX_SIMPLE) 12 | 13 | # 각 도형의 컨투어에 대한 루프 14 | for c in contours: 15 | # 모멘트 계산 16 | mmt = cv2.moments(c) 17 | # m10/m00, m01/m00 중심점 계산 18 | cx = int(mmt['m10']/mmt['m00']) 19 | cy = int(mmt['m01']/mmt['m00']) 20 | # 영역 넓이 21 | a = mmt['m00'] 22 | # 영역 외곽선 길이 23 | l = cv2.arcLength(c, True) 24 | # 중심점에 노란색 점 그리기 25 | cv2.circle(img, (cx, cy), 5, (0, 255, 255), -1) 26 | # 중심점 근처에 넓이 그리기 27 | cv2.putText(img, "A:%.0f"%a, (cx, cy+20) , cv2.FONT_HERSHEY_PLAIN, \ 28 | 1, (0,0,255)) 29 | # 컨투어 시작점에 길이 그리기 30 | cv2.putText(img, "L:%.2f"%l, tuple(c[0][0]), cv2.FONT_HERSHEY_PLAIN, \ 31 | 1, (255,0,0)) 32 | # 함수로 컨투어 넓이 계산해서 출력 33 | print("area:%.2f"%cv2.contourArea(c, False)) 34 | 35 | # 결과 출력 36 | cv2.imshow('center', img) 37 | cv2.waitKey(0) 38 | cv2.destroyAllWindows() 39 | 40 | -------------------------------------------------------------------------------- /08.match_track/avg_hash_matching.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | import glob 4 | 5 | # 영상 읽기 및 표시 6 | img = cv2.imread('../img/pistol.jpg') 7 | cv2.imshow('query', img) 8 | 9 | # 비교할 영상들이 있는 경로 ---① 10 | search_dir = '../img/101_ObjectCategories' 11 | 12 | # 이미지를 16x16 크기의 평균 해쉬로 변환 ---② 13 | def img2hash(img): 14 | gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 15 | gray = cv2.resize(gray, (16, 16)) 16 | avg = gray.mean() 17 | bi = 1 * (gray > avg) 18 | return bi 19 | 20 | # 해밍거리 측정 함수 ---③ 21 | def hamming_distance(a, b): 22 | a = a.reshape(1,-1) 23 | b = b.reshape(1,-1) 24 | # 같은 자리의 값이 서로 다른 것들의 합 25 | distance = (a !=b).sum() 26 | return distance 27 | 28 | # 권총 영상의 해쉬 구하기 ---④ 29 | query_hash = img2hash(img) 30 | 31 | # 이미지 데이타 셋 디렉토리의 모든 영상 파일 경로 ---⑤ 32 | img_path = glob.glob(search_dir+'/**/*.jpg') 33 | for path in img_path: 34 | # 데이타 셋 영상 한개 읽어서 표시 ---⑥ 35 | img = cv2.imread(path) 36 | cv2.imshow('searching...', img) 37 | cv2.waitKey(5) 38 | # 데이타 셋 영상 한개의 해시 ---⑦ 39 | a_hash = img2hash(img) 40 | # 해밍 거리 산출 ---⑧ 41 | dst = hamming_distance(query_hash, a_hash) 42 | if dst/256 < 0.25: # 해밍거리 25% 이내만 출력 ---⑨ 43 | print(path, dst/256) 44 | cv2.imshow(path, img) 45 | cv2.destroyWindow('searching...') 46 | cv2.waitKey(0) 47 | cv2.destroyAllWindows() 48 | 49 | -------------------------------------------------------------------------------- /09.ml/svm_random.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | import matplotlib.pylab as plt 4 | 5 | # 0~158 구간 임의의 수 25 x 2 생성 ---① 6 | a = np.random.randint(0,158,(25,2)) 7 | # 98~255 구간 임의의 수 25 x 2 생성 ---② 8 | b = np.random.randint(98, 255,(25,2)) 9 | # a, b를 병합, 50 x 2의 임의의 수 생성 ---③ 10 | trainData = np.vstack((a, b)).astype(np.float32) 11 | # 0으로 채워진 50개 배열 생성 ---④ 12 | responses = np.zeros((50,1), np.int32) 13 | # 25 ~ 50 까지 1로 변경 ---⑤ 14 | responses[25:] = 1 15 | 16 | # 0과 같은 자리의 학습 데이타는 빨강색 삼각형으로 분류 및 표시 ---⑥ 17 | red = trainData[responses.ravel()==0] 18 | plt.scatter(red[:,0],red[:,1],80,'r','^') 19 | # 1과 같은 자리의 학습 데이타는 파랑색 사각형으로 분류 및 표시 ---⑦ 20 | blue = trainData[responses.ravel()==1] 21 | plt.scatter(blue[:,0],blue[:,1],80,'b','s') 22 | # 0~255 구간의 새로운 임의의 수 생성 및 초록색 원으로 표시 ---⑧ 23 | newcomer = np.random.randint(0,255,(1,2)).astype(np.float32) 24 | plt.scatter(newcomer[:,0],newcomer[:,1],80,'g','o') 25 | # SVM 알고리즘 객체 생성 및 훈련---⑨ 26 | svm = cv2.ml.SVM_create() 27 | 28 | svm.trainAuto(trainData, cv2.ml.ROW_SAMPLE, responses) 29 | # svm_random.xml 로 저장 ---⑩ 30 | svm.save('./svm_random.xml') 31 | # 저장한 모델을 다시 읽기 ---⑪ 32 | svm2 = cv2.ml.SVM_load('./svm_random.xml') 33 | # 새로운 임의의 수 예측 ---⑫ 34 | ret, results = svm2.predict(newcomer) 35 | # 결과 표시 ---⑬ 36 | plt.annotate('red' if results[0]==0 else 'blue', xy=newcomer[0], xytext=(newcomer[0]+1)) 37 | print("return:%s, results:%s"%(ret, results)) 38 | plt.show() -------------------------------------------------------------------------------- /08.match_track/template_matching.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | # 입력이미지와 템플릿 이미지 읽기 5 | img = cv2.imread('../img/figures.jpg') 6 | template = cv2.imread('../img/taekwonv1.jpg') 7 | th, tw = template.shape[:2] 8 | cv2.imshow('template', template) 9 | 10 | # 3가지 매칭 메서드 순회 11 | methods = ['cv2.TM_CCOEFF_NORMED', 'cv2.TM_CCORR_NORMED', \ 12 | 'cv2.TM_SQDIFF_NORMED'] 13 | for i, method_name in enumerate(methods): 14 | img_draw = img.copy() 15 | method = eval(method_name) 16 | # 템플릿 매칭 ---① 17 | res = cv2.matchTemplate(img, template, method) 18 | # 최대, 최소값과 그 좌표 구하기 ---② 19 | min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res) 20 | print(method_name, min_val, max_val, min_loc, max_loc) 21 | 22 | # TM_SQDIFF의 경우 최소값이 좋은 매칭, 나머지는 그 반대 ---③ 23 | if method in [cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED]: 24 | top_left = min_loc 25 | match_val = min_val 26 | else: 27 | top_left = max_loc 28 | match_val = max_val 29 | # 매칭 좌표 구해서 사각형 표시 ---④ 30 | bottom_right = (top_left[0] + tw, top_left[1] + th) 31 | cv2.rectangle(img_draw, top_left, bottom_right, (0,0,255),2) 32 | # 매칭 포인트 표시 ---⑤ 33 | cv2.putText(img_draw, str(match_val), top_left, \ 34 | cv2.FONT_HERSHEY_PLAIN, 2,(0,255,0), 1, cv2.LINE_AA) 35 | cv2.imshow(method_name, img_draw) 36 | cv2.waitKey(0) 37 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /07.segmentation/cntr_convexhull.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | img = cv2.imread('../img/hand.jpg') 5 | img2 = img.copy() 6 | # 그레이 스케일 및 바이너리 스케일 변환 ---① 7 | gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 8 | ret, th = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY_INV) 9 | 10 | # 컨투어 찾기와 그리기 ---② 11 | temp, contours, heiarchy = cv2.findContours(th, cv2.RETR_EXTERNAL, \ 12 | cv2.CHAIN_APPROX_SIMPLE) 13 | cntr = contours[0] 14 | cv2.drawContours(img, [cntr], -1, (0, 255,0), 1) 15 | 16 | # 볼록 선체 찾기(좌표 기준)와 그리기 ---③ 17 | hull = cv2.convexHull(cntr) 18 | cv2.drawContours(img2, [hull], -1, (0,255,0), 1) 19 | # 볼록 선체 만족 여부 확인 ---④ 20 | print(cv2.isContourConvex(cntr), cv2.isContourConvex(hull)) 21 | 22 | # 볼록 선체 찾기(인덱스 기준) ---⑤ 23 | hull2 = cv2.convexHull(cntr, returnPoints=False) 24 | # 볼록 선체 결함 찾기 ---⑥ 25 | defects = cv2.convexityDefects(cntr, hull2) 26 | # 볼록 선체 결함 순회 27 | for i in range(defects.shape[0]): 28 | # 시작, 종료, 가장 먼 지점, 거리 ---⑦ 29 | startP, endP, farthestP, distance = defects[i, 0] 30 | # 가장 먼 지점의 좌표 구하기 ---⑧ 31 | farthest = tuple(cntr[farthestP][0]) 32 | # 거리를 부동 소수점으로 변환 ---⑨ 33 | dist = distance/256.0 34 | # 거리가 1보다 큰 경우 ---⑩ 35 | if dist > 1 : 36 | # 빨강색 점 표시 37 | cv2.circle(img2, farthest, 3, (0,0,255), -1) 38 | # 결과 이미지 표시 39 | cv2.imshow('contour', img) 40 | cv2.imshow('convex hull', img2) 41 | cv2.waitKey(0) 42 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /07.segmentation/cntr_hierarchy.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | # 영상 읽기 5 | img = cv2.imread('../img/shapes_donut.png') 6 | img2 = img.copy() 7 | # 바이너리 이미지로 변환 8 | imgray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 9 | ret, imthres = cv2.threshold(imgray, 127, 255, cv2.THRESH_BINARY_INV) 10 | 11 | # 가장 바깥 컨투어만 수집 --- ① 12 | im2, contour, hierarchy = cv2.findContours(imthres, cv2.RETR_EXTERNAL, \ 13 | cv2.CHAIN_APPROX_NONE) 14 | # 컨투어 갯수와 계층 트리 출력 --- ② 15 | print(len(contour), hierarchy) 16 | 17 | # 모든 컨투어를 트리 계층 으로 수집 ---③ 18 | im2, contour2, hierarchy = cv2.findContours(imthres, cv2.RETR_TREE, \ 19 | cv2.CHAIN_APPROX_SIMPLE) 20 | # 컨투어 갯수와 계층 트리 출력 ---④ 21 | print(len(contour2), hierarchy) 22 | 23 | # 가장 바깥 컨투어만 그리기 ---⑤ 24 | cv2.drawContours(img, contour, -1, (0,255,0), 3) 25 | # 모든 컨투어 그리기 ---⑥ 26 | for idx, cont in enumerate(contour2): 27 | # 랜덤한 컬러 추출 ---⑦ 28 | color = [int(i) for i in np.random.randint(0,255, 3)] 29 | # 컨투어 인덱스 마다 랜덤한 색상으로 그리기 ---⑧ 30 | cv2.drawContours(img2, contour2, idx, color, 3) 31 | # 컨투어 첫 좌표에 인덱스 숫자 표시 ---⑨ 32 | cv2.putText(img2, str(idx), tuple(cont[0][0]), cv2.FONT_HERSHEY_PLAIN, \ 33 | 1, (0,0,255)) 34 | 35 | # 화면 출력 36 | cv2.imshow('RETR_EXTERNAL', img) 37 | cv2.imshow('RETR_TREE', img2) 38 | cv2.waitKey(0) 39 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /09.ml/svm_hog_pedestrian.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | 3 | # default 디덱터를 위한 HOG 객체 생성 및 설정--- ① 4 | hogdef = cv2.HOGDescriptor() 5 | hogdef.setSVMDetector(cv2.HOGDescriptor_getDefaultPeopleDetector()) 6 | 7 | # dailer 디덱터를 위한 HOG 객체 생성 및 설정--- ② 8 | hogdaim = cv2.HOGDescriptor((48,96), (16,16), (8,8), (8,8), 9) 9 | hogdaim.setSVMDetector(cv2.HOGDescriptor_getDaimlerPeopleDetector()) 10 | 11 | cap = cv2.VideoCapture('../img/walking.avi') 12 | mode = True # 모드 변환을 위한 플래그 변수 13 | print('Toggle Space-bar to change mode.') 14 | while cap.isOpened(): 15 | ret, img = cap.read() 16 | if ret : 17 | if mode: 18 | # default 디텍터로 보행자 검출 --- ③ 19 | found, _ = hogdef.detectMultiScale(img) 20 | for (x,y,w,h) in found: 21 | cv2.rectangle(img, (x,y), (x+w, y+h), (0,255,255)) 22 | else: 23 | # daimler 디텍터로 보행자 검출 --- ④ 24 | found, _ = hogdaim.detectMultiScale(img) 25 | for (x,y,w,h) in found: 26 | cv2.rectangle(img, (x,y), (x+w, y+h), (0,255,0)) 27 | cv2.putText(img, 'Detector:%s'%('Default' if mode else 'Daimler'), \ 28 | (10,50 ), cv2.FONT_HERSHEY_DUPLEX,1, (0,255,0),1) 29 | cv2.imshow('frame', img) 30 | key = cv2.waitKey(1) 31 | if key == 27: 32 | break 33 | elif key == ord(' '): 34 | mode = not mode 35 | else: 36 | break 37 | cap.release() 38 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /02.interface/draw_circle.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | 3 | img = cv2.imread('../img/blank_500.jpg') 4 | 5 | # 원점(150,150), 반지름 100 ---① 6 | cv2.circle(img, (150, 150), 100, (255,0,0)) 7 | # 원점(300,150), 반지름 70 ---② 8 | cv2.circle(img, (300, 150), 70, (0,255,0), 5) 9 | # 원점(400,150), 반지름 50, 채우기 ---③ 10 | cv2.circle(img, (400, 150), 50, (0,0,255), -1) 11 | 12 | # 원점(50,300), 반지름(50), 회전 0, 0도 부터 360도 그리기 ---④ 13 | cv2.ellipse(img, (50, 300), (50, 50), 0, 0, 360, (0,0,255)) 14 | # 원점(150, 300), 아래 반원 그리기 ---⑤ 15 | cv2.ellipse(img, (150, 300), (50, 50), 0, 0, 180, (255,0,0)) 16 | #원점(200, 300), 윗 반원 그리기 ---⑥ 17 | cv2.ellipse(img, (200, 300), (50, 50), 0, 181, 360, (0,0,255)) 18 | 19 | # 원점(325, 300), 반지름(75,50) 납작한 타원 그리기 ---⑦ 20 | cv2.ellipse(img, (325, 300), (75, 50), 0, 0, 360, (0,255,0)) 21 | # 원점(450,300), 반지름(50,75) 홀쭉한 타원 그리기 ---⑧ 22 | cv2.ellipse(img, (450, 300), (50, 75), 0, 0, 360, (255,0,255)) 23 | 24 | # 원점(50, 425), 반지름(50,75), 회전 15도 ---⑨ 25 | cv2.ellipse(img, (50, 425), (50, 75), 15, 0, 360, (0,0,0)) 26 | # 원점(200,425), 반지름(50,75), 회전 45도 ---⑩ 27 | cv2.ellipse(img, (200, 425), (50, 75), 45, 0, 360, (0,0,0)) 28 | 29 | # 원점(350,425), 홀쭉한 타원 45도 회전 후 아랫 반원 그리기 ---⑪ 30 | cv2.ellipse(img, (350, 425), (50, 75), 45, 0, 180, (0,0,255)) 31 | # 원점(400,425), 홀쭉한 타원 45도 회전 후 윗 반원 그리기 ---⑫ 32 | cv2.ellipse(img, (400, 425), (50, 75), 45, 181, 360, (255,0,0)) 33 | 34 | cv2.imshow('circle', img) 35 | cv2.waitKey(0) 36 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /07.segmentation/cntr_find.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | img = cv2.imread('../img/shapes.png') 5 | img2 = img.copy() 6 | 7 | # 그레이 스케일로 변환 ---① 8 | imgray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 9 | # 스레시홀드로 바이너리 이미지로 만들어서 검은배경에 흰색전경으로 반전 ---② 10 | ret, imthres = cv2.threshold(imgray, 127, 255, cv2.THRESH_BINARY_INV) 11 | 12 | # 가장 바깥쪽 컨투어에 대해 모든 좌표 반환 ---③ 13 | im2, contour, hierarchy = cv2.findContours(imthres, cv2.RETR_EXTERNAL, \ 14 | cv2.CHAIN_APPROX_NONE) 15 | # 가장 바깥쪽 컨투어에 대해 꼭지점 좌표만 반환 ---④ 16 | im2, contour2, hierarchy = cv2.findContours(imthres, cv2.RETR_EXTERNAL, \ 17 | cv2.CHAIN_APPROX_SIMPLE) 18 | # 각각의 컨투의 갯수 출력 ---⑤ 19 | print('도형의 갯수: %d(%d)'% (len(contour), len(contour2))) 20 | 21 | # 모든 좌표를 갖는 컨투어 그리기, 초록색 ---⑥ 22 | cv2.drawContours(img, contour, -1, (0,255,0), 4) 23 | # 꼭지점 좌표만을 갖는 컨투어 그리기, 초록색 ---⑦ 24 | cv2.drawContours(img2, contour2, -1, (0,255,0), 4) 25 | 26 | # 컨투어 모든 좌표를 작은 파랑색 점(원)으로 표시 ---⑧ 27 | for i in contour: 28 | for j in i: 29 | cv2.circle(img, tuple(j[0]), 1, (255,0,0), -1) 30 | 31 | # 컨투어 꼭지점 좌표를 작은 파랑색 점(원)으로 표시 ---⑨ 32 | for i in contour2: 33 | for j in i: 34 | cv2.circle(img2, tuple(j[0]), 1, (255,0,0), -1) 35 | 36 | # 결과 출력 ---⑩ 37 | cv2.imshow('ORIGIN', imgray) 38 | cv2.imshow('CHAIN_APPROX_NONE', img) 39 | cv2.imshow('CHAIN_APPROX_SIMPLE', img2) 40 | cv2.waitKey(0) 41 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /09.ml/kNN_movie.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | import matplotlib.pyplot as plt 4 | 5 | # 0~99 사이의 랜덤 값 25x2 ---① 6 | trainData = np.random.randint(0,100,(25,2)).astype(np.float32) 7 | # trainDatat[0]:kick, trainData[1]:kiss, kick > kiss ? 1 : 0 ---② 8 | responses = (trainData[:, 0] >trainData[:,1]).astype(np.float32) 9 | # 0: action : 1romantic ---③ 10 | action = trainData[responses==0] 11 | romantic = trainData[responses==1] 12 | # action은 파랑 삼각형, romantic은 빨강색 동그라미로 표시 ---④ 13 | plt.scatter(action[:,0],action[:,1], 80, 'b', '^', label='action') 14 | plt.scatter(romantic[:,0],romantic[:,1], 80, 'r', 'o',label="romantic") 15 | # 새로운 데이타 생성, 0~99 랜덤 수 1X2, 초록색 사각형으로 표시 ---⑤ 16 | newcomer = np.random.randint(0,100,(1,2)).astype(np.float32) 17 | plt.scatter(newcomer[:,0],newcomer[:,1],200,'g','s', label="new") 18 | 19 | # Knearest 알고리즘 생성 및 훈련 --- ⑥ 20 | knn = cv2.ml.KNearest_create() 21 | knn.train(trainData, cv2.ml.ROW_SAMPLE, responses) 22 | # 결과 예측 ---⑦ 23 | ret, results, neighbours ,dist = knn.findNearest(newcomer, 3)#K=3 24 | print("ret:%s, result:%s, neighbours:%s, dist:%s" \ 25 | %(ret, results, neighbours, dist)) 26 | # 새로운 결과에 화살표로 표시 ---⑧ 27 | anno_x, anno_y = newcomer.ravel() 28 | label = "action" if results == 0 else "romantic" 29 | plt.annotate(label, xy=(anno_x + 1, anno_y+1), \ 30 | xytext=(anno_x+5, anno_y+10), arrowprops={'color':'black'}) 31 | plt.xlabel('kiss');plt.ylabel('kick') 32 | plt.legend(loc="upper right") 33 | plt.show() -------------------------------------------------------------------------------- /09.ml/kNN_handwritten.py: -------------------------------------------------------------------------------- 1 | import numpy as np, cv2 2 | import mnist 3 | 4 | # 훈련 데이타 가져오기 ---① 5 | train, train_labels = mnist.getData() 6 | # Knn 객체 생성 및 학습 ---② 7 | knn = cv2.ml.KNearest_create() 8 | knn.train(train, cv2.ml.ROW_SAMPLE, train_labels) 9 | 10 | # 인식시킬 손글씨 이미지 읽기 ---③ 11 | image = cv2.imread('../img/4027.png') 12 | cv2.imshow("image", image) 13 | cv2.waitKey(0) 14 | 15 | # 그레이 스케일 변환과 스레시홀드 ---④ 16 | gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY) 17 | gray = cv2.GaussianBlur(gray, (5, 5), 0) 18 | _, gray = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY_INV) 19 | # 최외곽 컨투어만 찾기 ---⑤ 20 | img, contours, _ = cv2.findContours(gray, cv2.RETR_EXTERNAL, \ 21 | cv2.CHAIN_APPROX_SIMPLE) 22 | # 모든 컨투어 순회 ---⑥ 23 | for c in contours: 24 | # 컨투어를 감싸는 외접 사각형으로 숫자 영역 좌표 구하기 ---⑦ 25 | (x, y, w, h) = cv2.boundingRect(c) 26 | # 외접 사각형의 크기가 너무 작은것은 제외 ---⑧ 27 | if w >= 5 and h >= 25: 28 | # 숫자 영역만 roi로 확보하고 사각형 그리기 ---⑨ 29 | roi = gray[y:y + h, x:x + w] 30 | cv2.rectangle(image, (x, y), (x + w, y + h), (0, 255, 0), 1) 31 | # 테스트 데이타 형식으로 변환 ---⑩ 32 | data = mnist.digit2data(roi) 33 | # 결과 예측해서 이미지에 표시---⑪ 34 | ret, result, neighbours, dist = knn.findNearest(data, k=1) 35 | cv2.putText(image, "%d"%ret, (x , y + 155), \ 36 | cv2.FONT_HERSHEY_DUPLEX, 2, (255, 0, 0), 2) 37 | cv2.imshow("image", image) 38 | cv2.waitKey(0) 39 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /08.match_track/track_optical_farneback.py: -------------------------------------------------------------------------------- 1 | import cv2, numpy as np 2 | 3 | # 플로우 결과 그리기 ---① 4 | def drawFlow(img,flow,step=16): 5 | h,w = img.shape[:2] 6 | # 16픽셀 간격의 그리드 인덱스 구하기 ---② 7 | idx_y,idx_x = np.mgrid[step/2:h:step,step/2:w:step].astype(np.int) 8 | indices = np.stack( (idx_x,idx_y), axis =-1).reshape(-1,2) 9 | 10 | for x,y in indices: # 인덱스 순회 11 | # 각 그리드 인덱스 위치에 점 그리기 ---③ 12 | cv2.circle(img, (x,y), 1, (0,255,0), -1) 13 | # 각 그리드 인덱스에 해당하는 플로우 결과 값 (이동 거리) ---④ 14 | dx,dy = flow[y, x].astype(np.int) 15 | # 각 그리드 인덱스 위치에서 이동한 거리 만큼 선 그리기 ---⑤ 16 | cv2.line(img, (x,y), (x+dx, y+dy), (0,255, 0),2, cv2.LINE_AA ) 17 | 18 | 19 | prev = None # 이전 프레임 저장 변수 20 | 21 | cap = cv2.VideoCapture('../img/walking.avi') 22 | fps = cap.get(cv2.CAP_PROP_FPS) # 프레임 수 구하기 23 | delay = int(1000/fps) 24 | 25 | while cap.isOpened(): 26 | ret,frame = cap.read() 27 | if not ret: break 28 | gray = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY) 29 | # 최초 프레임 경우 30 | if prev is None: 31 | prev = gray # 첫 이전 프레임 --- ⑥ 32 | else: 33 | # 이전, 이후 프레임으로 옵티컬 플로우 계산 ---⑦ 34 | flow = cv2.calcOpticalFlowFarneback(prev,gray,None,\ 35 | 0.5,3,15,3,5,1.1,cv2.OPTFLOW_FARNEBACK_GAUSSIAN) 36 | # 계산 결과 그리기, 선언한 함수 호출 ---⑧ 37 | drawFlow(frame,flow) 38 | # 다음 프레임을 위해 이월 ---⑨ 39 | prev = gray 40 | 41 | cv2.imshow('OpticalFlow-Farneback', frame) 42 | if cv2.waitKey(delay) == 27: 43 | break 44 | cap.release() 45 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /06.filter/workshop_painting_cam.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | # 카메라 장치 연결 5 | cap = cv2.VideoCapture(0) 6 | while cap.isOpened(): 7 | # 프레임 읽기 8 | ret, frame = cap.read() 9 | # 속도 향상을 위해 영상크기를 절반으로 축소 10 | frame = cv2.resize(frame, None, fx=0.7, fy=0.7, \ 11 | interpolation=cv2.INTER_AREA) 12 | if cv2.waitKey(1) == 27: # esc키로 종료 13 | break 14 | # 그레이 스케일로 변경 15 | img_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) 16 | # 잡음 제거를 위해 가우시안 플러 필터 적용(라플라시안 필터 적용 전에 필수) 17 | img_gray = cv2.GaussianBlur(img_gray, (9,9), 0) 18 | # 라플라시안 필터로 엣지 검출 19 | edges = cv2.Laplacian(img_gray, -1, None, 5) 20 | # 스레시홀드로 경계 값 만 남기고 제거하면서 화면 반전(흰 바탕 검은 선) 21 | ret, sketch = cv2.threshold(edges, 70, 255, cv2.THRESH_BINARY_INV) 22 | 23 | # 경계선 강조를 위해 침식 연산 24 | kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (3,3)) 25 | sketch = cv2.erode(sketch, kernel) 26 | # 경계선 자연스럽게 하기 위해 미디언 블러 필터 적용 27 | sketch = cv2.medianBlur(sketch, 5) 28 | # 그레이 스케일에서 BGR 컬러 스케일로 변경 29 | img_sketch = cv2.cvtColor(sketch, cv2.COLOR_GRAY2BGR) 30 | 31 | # 컬러 이미지 선명선을 없애기 위해 평균 블러 필터 적용 32 | img_paint = cv2.blur(frame, (10,10) ) 33 | # 컬러 영상과 스케치 영상과 합성 34 | img_paint = cv2.bitwise_and(img_paint, img_paint, mask=sketch) 35 | 36 | # 결과 출력 37 | merged = np.hstack((img_sketch, img_paint)) 38 | cv2.imshow('Sketch Camera', merged) 39 | 40 | cap.release() 41 | cv2.destroyAllWindows() 42 | -------------------------------------------------------------------------------- /04.img_processing/histo_compare.py: -------------------------------------------------------------------------------- 1 | import cv2, numpy as np 2 | import matplotlib.pylab as plt 3 | 4 | img1 = cv2.imread('../img/taekwonv1.jpg') 5 | img2 = cv2.imread('../img/taekwonv2.jpg') 6 | img3 = cv2.imread('../img/taekwonv3.jpg') 7 | img4 = cv2.imread('../img/dr_ochanomizu.jpg') 8 | 9 | cv2.imshow('query', img1) 10 | imgs = [img1, img2, img3, img4] 11 | hists = [] 12 | for i, img in enumerate(imgs) : 13 | plt.subplot(1,len(imgs),i+1) 14 | plt.title('img%d'% (i+1)) 15 | plt.axis('off') 16 | plt.imshow(img[:,:,::-1]) 17 | #---① 각 이미지를 HSV로 변환 18 | hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) 19 | #---② H,S 채널에 대한 히스토그램 계산 20 | hist = cv2.calcHist([hsv], [0,1], None, [180,256], [0,180,0, 256]) 21 | #---③ 0~1로 정규화 22 | cv2.normalize(hist, hist, 0, 1, cv2.NORM_MINMAX) 23 | hists.append(hist) 24 | 25 | 26 | query = hists[0] 27 | methods = {'CORREL' :cv2.HISTCMP_CORREL, 'CHISQR':cv2.HISTCMP_CHISQR, 28 | 'INTERSECT':cv2.HISTCMP_INTERSECT, 29 | 'BHATTACHARYYA':cv2.HISTCMP_BHATTACHARYYA} 30 | for j, (name, flag) in enumerate(methods.items()): 31 | print('%-10s'%name, end='\t') 32 | for i, (hist, img) in enumerate(zip(hists, imgs)): 33 | #---④ 각 메서드에 따라 img1과 각 이미지의 히스토그램 비교 34 | ret = cv2.compareHist(query, hist, flag) 35 | if flag == cv2.HISTCMP_INTERSECT: #교차 분석인 경우 36 | ret = ret/np.sum(query) #비교대상으로 나누어 1로 정규화 37 | print("img%d:%7.2f"% (i+1 , ret), end='\t') 38 | print() 39 | plt.show() -------------------------------------------------------------------------------- /07.segmentation/cntr_bound_fit.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | # 이미지 읽어서 그레이스케일 변환, 바이너리 스케일 변환 5 | img = cv2.imread("../img/lightning.png") 6 | imgray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 7 | ret, th = cv2.threshold(imgray, 127,255,cv2.THRESH_BINARY_INV) 8 | 9 | # 컨튜어 찾기 10 | im, contours, hr = cv2.findContours(th, cv2.RETR_EXTERNAL, \ 11 | cv2.CHAIN_APPROX_SIMPLE) 12 | contr = contours[0] 13 | 14 | # 감싸는 사각형 표시(검정색) 15 | x,y,w,h = cv2.boundingRect(contr) 16 | cv2.rectangle(img, (x,y), (x+w, y+h), (0,0,0), 3) 17 | 18 | # 최소한의 사각형 표시(초록색) 19 | rect = cv2.minAreaRect(contr) 20 | box = cv2.boxPoints(rect) # 중심점과 각도를 4개의 꼭지점 좌표로 변환 21 | box = np.int0(box) # 정수로 변환 22 | cv2.drawContours(img, [box], -1, (0,255,0), 3) 23 | 24 | # 최소한의 원 표시(파랑색) 25 | (x,y), radius = cv2.minEnclosingCircle(contr) 26 | cv2.circle(img, (int(x), int(y)), int(radius), (255,0,0), 2) 27 | 28 | # 최소한의 삼각형 표시(분홍색) 29 | ret, tri = cv2.minEnclosingTriangle(contr) 30 | cv2.polylines(img, [np.int32(tri)], True, (255,0,255), 2) 31 | 32 | # 최소한의 타원 표시(노랑색) 33 | ellipse = cv2.fitEllipse(contr) 34 | cv2.ellipse(img, ellipse, (0,255,255), 3) 35 | 36 | # 중심점 통과하는 직선 표시(빨강색) 37 | [vx,vy,x,y] = cv2.fitLine(contr, cv2.DIST_L2,0,0.01,0.01) 38 | cols,rows = img.shape[:2] 39 | cv2.line(img,(0, 0-x*(vy/vx) + y), (cols-1, (cols-x)*(vy/vx) + y), \ 40 | (0,0,255),2) 41 | 42 | # 결과 출력 43 | cv2.imshow('Bound Fit shapes', img) 44 | cv2.waitKey(0) 45 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /08.match_track/workshop_panorama.py: -------------------------------------------------------------------------------- 1 | import cv2, numpy as np 2 | 3 | # 왼쪽 오른쪽 사진 읽기 4 | imgL = cv2.imread('../img/restaurant1.jpg') # train 5 | imgR = cv2.imread('../img/restaurant2.jpg') # query 6 | hl, wl = imgL.shape[:2] 7 | hr, wr = imgR.shape[:2] 8 | 9 | grayL = cv2.cvtColor(imgL, cv2.COLOR_BGR2GRAY) 10 | grayR = cv2.cvtColor(imgR, cv2.COLOR_BGR2GRAY) 11 | 12 | # SIFT 특징 검출기 생성 및 특징점 검출 13 | descriptor = cv2.xfeatures2d.SIFT_create() 14 | (kpsL, featuresL) = descriptor.detectAndCompute(imgL, None) 15 | (kpsR, featuresR) = descriptor.detectAndCompute(imgR, None) 16 | # BF 매칭기 생성 및 knn매칭 17 | matcher = cv2.DescriptorMatcher_create("BruteForce") 18 | matches = matcher.knnMatch(featuresR, featuresL, 2) 19 | 20 | # 좋은 매칭점 선별 21 | good_matches = [] 22 | for m in matches: 23 | if len(m) == 2 and m[0].distance < m[1].distance * 0.75: 24 | good_matches.append(( m[0].trainIdx, m[0].queryIdx)) 25 | 26 | # 좋은 매칭점이 4개 이상 원근 변환 행렬 구하기 27 | if len(good_matches) > 4: 28 | ptsL = np.float32([kpsL[i].pt for (i, _) in good_matches]) 29 | ptsR = np.float32([kpsR[i].pt for (_, i) in good_matches]) 30 | mtrx, status = cv2.findHomography(ptsR,ptsL, cv2.RANSAC, 4.0) 31 | #원근 변환 행렬로 오른쪽 사진을 원근 변환, 결과 이미지 크기는 사진 2장 크기 32 | panorama = cv2.warpPerspective(imgR, mtrx, (wr + wl, hr)) 33 | # 왼쪽 사진을 원근 변환한 왼쪽 영역에 합성 34 | panorama[0:hl, 0:wl] = imgL 35 | else: 36 | panorama = imgL 37 | cv2.imshow("Image Left", imgL) 38 | cv2.imshow("Image Right", imgR) 39 | cv2.imshow("Panorama", panorama) 40 | cv2.waitKey(0) -------------------------------------------------------------------------------- /09.ml/bow_plane_bike_test.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | categories = ['airplanes', 'Motorbikes' ] 5 | dict_file = './plane_bike_dict.npy' 6 | #dict_file = './plane_bike_dict_4000.npy' 7 | svm_model_file = './plane_bike_svm.xml' 8 | #svm_model_file = './plane_bike_svm_4000.xml' 9 | 10 | # 테스트 할 이미지 경로 --- ① 11 | imgs = ['../img/aircraft.jpg','../img/jetstar.jpg', 12 | '../img/motorcycle.jpg', '../img/motorbike.jpg'] 13 | 14 | # 특징 추출기(SIFT) 생성 ---② 15 | detector = cv2.xfeatures2d.SIFT_create() 16 | # BOW 추출기 생성 및 사전 로딩 ---③ 17 | bowextractor = cv2.BOWImgDescriptorExtractor(detector, \ 18 | cv2.BFMatcher(cv2.NORM_L2)) 19 | bowextractor.setVocabulary(np.load(dict_file)) 20 | # 훈련된 모델 읽어서 SVM 객체 생성 --- ④ 21 | svm = cv2.ml.SVM_load(svm_model_file) 22 | 23 | # 4개의 이미지 테스트 24 | for i, path in enumerate(imgs): 25 | img = cv2.imread(path) 26 | gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 27 | # 테스트 이미지에서 BOW 히스토그램 추출 ---⑤ 28 | hist = bowextractor.compute(gray, detector.detect(gray)) 29 | # SVM 예측 ---⑥ 30 | ret, result = svm.predict(hist) 31 | # 결과 표시 32 | name = categories[int(result[0][0])] 33 | txt, base = cv2.getTextSize(name, cv2.FONT_HERSHEY_PLAIN, 2, 3) 34 | x,y = 10, 50 35 | cv2.rectangle(img, (x,y-base-txt[1]), (x+txt[0], y+txt[1]), (30,30,30), -1) 36 | cv2.putText(img, name, (x,y), cv2.FONT_HERSHEY_PLAIN, \ 37 | 2, (0,255,0), 2, cv2.LINE_AA) 38 | cv2.imshow(path, img) 39 | cv2.waitKey(0) 40 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /07.segmentation/cntr_matchShape.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | # 매칭을 위한 이미지 읽기 5 | target = cv2.imread('../img/4star.jpg') # 매칭 대상 6 | shapes = cv2.imread('../img/shapestomatch.jpg') # 여러 도형 7 | # 그레이 스케일 변환 8 | targetGray = cv2.cvtColor(target, cv2.COLOR_BGR2GRAY) 9 | shapesGray = cv2.cvtColor(shapes, cv2.COLOR_BGR2GRAY) 10 | # 바이너리 스케일 변환 11 | ret, targetTh = cv2.threshold(targetGray, 127, 255, cv2.THRESH_BINARY_INV) 12 | ret, shapesTh = cv2.threshold(shapesGray, 127, 255, cv2.THRESH_BINARY_INV) 13 | # 컨투어 찾기 14 | _, cntrs_target, _ = cv2.findContours(targetTh, cv2.RETR_EXTERNAL, \ 15 | cv2.CHAIN_APPROX_SIMPLE) 16 | _, cntrs_shapes, _ = cv2.findContours(shapesTh, cv2.RETR_EXTERNAL, \ 17 | cv2.CHAIN_APPROX_SIMPLE) 18 | 19 | # 각 도형과 매칭을 위한 반복문 20 | matchs = [] # 컨투어와 매칭 점수를 보관할 리스트 21 | for contr in cntrs_shapes: 22 | # 대상 도형과 여러 도형 중 하나와 매칭 실행 ---① 23 | match = cv2.matchShapes(cntrs_target[0], contr, cv2.CONTOURS_MATCH_I2, 0.0) 24 | # 해당 도형의 매칭 점수와 컨투어를 쌍으로 저장 ---② 25 | matchs.append( (match, contr) ) 26 | # 해당 도형의 컨투어 시작지점에 매칭 점수 표시 ---③ 27 | cv2.putText(shapes, '%.2f'%match, tuple(contr[0][0]),\ 28 | cv2.FONT_HERSHEY_PLAIN, 1,(0,0,255),1 ) 29 | # 매칭 점수로 정렬 ---④ 30 | matchs.sort(key=lambda x : x[0]) 31 | # 가장 적은 매칭 점수를 얻는 도형의 컨투어에 선 그리기 ---⑤ 32 | cv2.drawContours(shapes, [matchs[0][1]], -1, (0,255,0), 3) 33 | cv2.imshow('target', target) 34 | cv2.imshow('Match Shape', shapes) 35 | cv2.waitKey() 36 | cv2.destroyAllWindows() 37 | -------------------------------------------------------------------------------- /04.img_processing/hsv_color_mask.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | import matplotlib.pylab as plt 4 | 5 | #--① 큐브 영상 읽어서 HSV로 변환 6 | img = cv2.imread("../img/cube.jpg") 7 | hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) 8 | 9 | #--② 색상별 영역 지정 10 | blue1 = np.array([90, 50, 50]) 11 | blue2 = np.array([120, 255,255]) 12 | green1 = np.array([45, 50,50]) 13 | green2 = np.array([75, 255,255]) 14 | red1 = np.array([0, 50,50]) 15 | red2 = np.array([15, 255,255]) 16 | red3 = np.array([165, 50,50]) 17 | red4 = np.array([180, 255,255]) 18 | yellow1 = np.array([20, 50,50]) 19 | yellow2 = np.array([35, 255,255]) 20 | 21 | # --③ 색상에 따른 마스크 생성 22 | mask_blue = cv2.inRange(hsv, blue1, blue2) 23 | mask_green = cv2.inRange(hsv, green1, green2) 24 | mask_red = cv2.inRange(hsv, red1, red2) 25 | mask_red2 = cv2.inRange(hsv, red3, red4) 26 | mask_yellow = cv2.inRange(hsv, yellow1, yellow2) 27 | 28 | #--④ 색상별 마스크로 색상만 추출 29 | res_blue = cv2.bitwise_and(img, img, mask=mask_blue) 30 | res_green = cv2.bitwise_and(img, img, mask=mask_green) 31 | res_red1 = cv2.bitwise_and(img, img, mask=mask_red) 32 | res_red2 = cv2.bitwise_and(img, img, mask=mask_red2) 33 | res_red = cv2.bitwise_or(res_red1, res_red2) 34 | res_yellow = cv2.bitwise_and(img, img, mask=mask_yellow) 35 | 36 | #--⑤ 결과 출력 37 | imgs = {'original': img, 'blue':res_blue, 'green':res_green, 38 | 'red':res_red, 'yellow':res_yellow} 39 | for i, (k, v) in enumerate(imgs.items()): 40 | plt.subplot(2,3, i+1) 41 | plt.title(k) 42 | plt.imshow(v[:,:,::-1]) 43 | plt.xticks([]); plt.yticks([]) 44 | plt.show() 45 | -------------------------------------------------------------------------------- /09.ml/workshop_hannibal_mask.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | # 마스크 이미지 읽기 5 | face_mask = cv2.imread('../img/mask_hannibal.png') 6 | h_mask, w_mask = face_mask.shape[:2] 7 | # 얼굴 검출기 생성 8 | face_cascade = cv2.CascadeClassifier('../data/haarcascade_frontalface_alt.xml') 9 | 10 | cap = cv2.VideoCapture(0) 11 | while True: 12 | ret, frame = cap.read() 13 | gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) 14 | # 얼굴 영역 검출 15 | face_rects = face_cascade.detectMultiScale(gray, 1.3, 5) 16 | for (x,y,w,h) in face_rects: 17 | if h > 0 and w > 0: 18 | # 마스크 위치 보정 19 | x = int(x + 0.1*w) 20 | y = int(y + 0.4*h) 21 | w = int(0.8 * w) 22 | h = int(0.8 * h) 23 | 24 | frame_roi = frame[y:y+h, x:x+w] 25 | # 마스크 이미지를 얼굴 크기에 맞게 조정 26 | face_mask_small = cv2.resize(face_mask, (w, h), \ 27 | interpolation=cv2.INTER_AREA) 28 | # 마스크 이미지 합성 29 | gray_mask = cv2.cvtColor(face_mask_small, cv2.COLOR_BGR2GRAY) 30 | ret, mask = cv2.threshold(gray_mask, 50, 255, cv2.THRESH_BINARY) 31 | mask_inv = cv2.bitwise_not(mask) 32 | masked_face = cv2.bitwise_and(face_mask_small, face_mask_small,\ 33 | mask=mask) 34 | masked_frame = cv2.bitwise_and(frame_roi, frame_roi, mask=mask_inv) 35 | frame[y:y+h, x:x+w] = cv2.add(masked_face, masked_frame) 36 | 37 | cv2.imshow('Hanibal Mask', frame) 38 | if cv2.waitKey(1) == 27: 39 | break 40 | cap.release() 41 | cv2.destroyAllWindows() 42 | -------------------------------------------------------------------------------- /08.match_track/match_homography.py: -------------------------------------------------------------------------------- 1 | import cv2, numpy as np 2 | 3 | img1 = cv2.imread('../img/taekwonv1.jpg') 4 | img2 = cv2.imread('../img/figures.jpg') 5 | gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY) 6 | gray2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY) 7 | 8 | # ORB, BF-Hamming 로 knnMatch ---① 9 | detector = cv2.ORB_create() 10 | kp1, desc1 = detector.detectAndCompute(gray1, None) 11 | kp2, desc2 = detector.detectAndCompute(gray2, None) 12 | matcher = cv2.BFMatcher(cv2.NORM_HAMMING2) 13 | matches = matcher.knnMatch(desc1, desc2, 2) 14 | 15 | # 이웃 거리의 75%로 좋은 매칭점 추출---② 16 | ratio = 0.75 17 | good_matches = [first for first,second in matches \ 18 | if first.distance < second.distance * ratio] 19 | print('good matches:%d/%d' %(len(good_matches),len(matches))) 20 | print(good_matches) 21 | 22 | # 좋은 매칭점의 queryIdx로 원본 영상의 좌표 구하기 ---③ 23 | src_pts = np.float32([ kp1[m.queryIdx].pt for m in good_matches ]) 24 | # 좋은 매칭점의 trainIdx로 대상 영상의 좌표 구하기 ---④ 25 | dst_pts = np.float32([ kp2[m.trainIdx].pt for m in good_matches ]) 26 | # 원근 변환 행렬 구하기 ---⑤ 27 | mtrx, mask = cv2.findHomography(src_pts, dst_pts) 28 | # 원본 영상 크기로 변환 영역 좌표 생성 ---⑥ 29 | h,w, = img1.shape[:2] 30 | pts = np.float32([ [[0,0]],[[0,h-1]],[[w-1,h-1]],[[w-1,0]] ]) 31 | # 원본 영상 좌표를 원근 변환 ---⑦ 32 | dst = cv2.perspectiveTransform(pts,mtrx) 33 | # 변환 좌표 영역을 대상 영상에 그리기 ---⑧ 34 | img2 = cv2.polylines(img2,[np.int32(dst)],True,255,3, cv2.LINE_AA) 35 | 36 | # 좋은 매칭 그려서 출력 ---⑨ 37 | res = cv2.drawMatches(img1, kp1, img2, kp2, good_matches, None, \ 38 | flags=cv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS) 39 | cv2.imshow('Matching Homography', res) 40 | cv2.waitKey() 41 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /09.ml/svm_handwritten.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | import mnist 4 | import svm_mnist_hog_train 5 | 6 | 7 | # 훈련해서 저장한 SVM 객체 읽기 ---① 8 | svm = cv2.ml.SVM_load('./svm_mnist.xml') 9 | # 인식할 손글씨 이미지 읽기 ---② 10 | image = cv2.imread('../img/4027.png') 11 | cv2.imshow("image", image) 12 | cv2.waitKey(0) 13 | 14 | # 인식할 이미지를 그레이 스케일로 변환 및 스레시홀드 적용 ---③ 15 | gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY) 16 | gray = cv2.GaussianBlur(gray, (5, 5), 0) 17 | _, gray = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY_INV) 18 | 19 | # 최외곽 컨투어만 찾기 ---④ 20 | img, contours, _ = cv2.findContours(gray, cv2.RETR_EXTERNAL, \ 21 | cv2.CHAIN_APPROX_SIMPLE) 22 | for c in contours: 23 | # 컨투어를 감싸는 외접 사각형 구하기 ---⑤ 24 | (x, y, w, h) = cv2.boundingRect(c) 25 | # 외접 사각형의 크기가 너무 작은것은 제외 ---⑥ 26 | if w >= 5 and h >= 25: 27 | # 숫자 영역만 roi로 확보하고 사각형 그리기 ---⑦ 28 | roi = gray[y:y + h, x:x + w] 29 | cv2.rectangle(image, (x, y), (x + w, y + h), (0, 255, 0), 1) 30 | # 테스트 데이타 형식으로 변환 ---⑧ 31 | px20 = mnist.digit2data(roi, False) 32 | # 기울어진 숫자를 바로 세우기 ---⑨ 33 | deskewed = svm_mnist_hog_train.deskew(px20) 34 | # 인식할 숫자에 대한 HOG 디스크립터 계산 ---⑩ 35 | hogdata = svm_mnist_hog_train.hogDesc.compute(deskewed) 36 | testData = np.float32(hogdata).reshape(-1, hogdata.shape[0]) 37 | # 결과 예측해서 표시 ---⑪ 38 | ret, result = svm.predict(testData) 39 | cv2.putText(image, "%d"%result[0], (x , y + 155), \ 40 | cv2.FONT_HERSHEY_COMPLEX, 2, (255, 0, 0), 2) 41 | cv2.imshow("image", image) 42 | cv2.waitKey(0) 43 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /02.interface/draw_text.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | 3 | img = cv2.imread('../img/blank_500.jpg') 4 | 5 | # sans-serif small 6 | cv2.putText(img, "Plain", (50, 30), cv2.FONT_HERSHEY_PLAIN, 1, (0, 0,0)) 7 | # sans-serif normal 8 | cv2.putText(img, "Simplex", (50, 70), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0,0)) 9 | # sans-serif bold 10 | cv2.putText(img, "Duplex", (50, 110), cv2.FONT_HERSHEY_DUPLEX, 1, (0, 0,0)) 11 | # sans-serif normall X2 ---① 12 | cv2.putText(img, "Simplex", (200, 110), cv2.FONT_HERSHEY_SIMPLEX, 2, (0,0,250)) 13 | 14 | # serif small 15 | cv2.putText(img, "Complex Small", (50, 180), cv2.FONT_HERSHEY_COMPLEX_SMALL, \ 16 | 1, (0, 0,0)) 17 | # serif normal 18 | cv2.putText(img, "Complex", (50, 220), cv2.FONT_HERSHEY_COMPLEX, 1, (0, 0,0)) 19 | # serif bold 20 | cv2.putText(img, "Triplex", (50, 260), cv2.FONT_HERSHEY_TRIPLEX, 1, (0, 0,0)) 21 | # serif normal X2 ---② 22 | cv2.putText(img, "Complex", (200, 260), cv2.FONT_HERSHEY_TRIPLEX, 2, (0,0,255)) 23 | 24 | # hand-wringing sans-serif 25 | cv2.putText(img, "Script Simplex", (50, 330), cv2.FONT_HERSHEY_SCRIPT_SIMPLEX, \ 26 | 1, (0, 0,0)) 27 | # hand-wringing serif 28 | cv2.putText(img, "Script Complex", (50, 370), cv2.FONT_HERSHEY_SCRIPT_COMPLEX, \ 29 | 1, (0, 0,0)) 30 | 31 | # sans-serif + italic ---③ 32 | cv2.putText(img, "Plain Italic", (50, 430), \ 33 | cv2.FONT_HERSHEY_PLAIN | cv2.FONT_ITALIC, 1, (0, 0,0)) 34 | # sarif + italic 35 | cv2.putText(img, "Complex Italic", (50, 470), \ 36 | cv2.FONT_HERSHEY_COMPLEX | cv2.FONT_ITALIC, 1, (0, 0,0)) 37 | 38 | cv2.imshow('draw text', img) 39 | cv2.waitKey() 40 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /05.geometric_transform/triangle_affine.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | img = cv2.imread("../img/taekwonv1.jpg") 5 | img2 = img.copy() 6 | draw = img.copy() 7 | 8 | # 변환 전,후 삼각형 좌표 ---① 9 | pts1 = np.float32([[188,14], [85,202], [294,216]]) 10 | pts2 = np.float32([[128,40], [85,307], [306,167]]) 11 | 12 | # 각 삼각형을 완전히 감싸는 사각형 좌표 구하기 ---② 13 | x1,y1,w1,h1 = cv2.boundingRect(pts1) 14 | x2,y2,w2,h2 = cv2.boundingRect(pts2) 15 | 16 | # 사각형을 이용한 관심영역 설정 ---③ 17 | roi1 = img[y1:y1+h1, x1:x1+w1] 18 | roi2 = img2[y2:y2+h2, x2:x2+w2] 19 | 20 | # 관심영역을 기준으로 좌표 계산 ---④ 21 | offset1 = np.zeros((3,2), dtype=np.float32) 22 | offset2 = np.zeros((3,2), dtype=np.float32) 23 | for i in range(3): 24 | offset1[i][0], offset1[i][1] = pts1[i][0]-x1, pts1[i][1]-y1 25 | offset2[i][0], offset2[i][1] = pts2[i][0]-x2, pts2[i][1]-y2 26 | 27 | # 관심 영역을 주어진 삼각형 좌표로 어핀 변환 ---⑤ 28 | mtrx = cv2.getAffineTransform(offset1, offset2) 29 | warped = cv2.warpAffine( roi1, mtrx, (w2, h2), None, \ 30 | cv2.INTER_LINEAR, cv2.BORDER_REFLECT_101) 31 | 32 | # 어핀 변환 후 삼각형만 골라 내기 위한 마스크 생성 ---⑥ 33 | mask = np.zeros((h2, w2), dtype = np.uint8) 34 | cv2.fillConvexPoly(mask, np.int32(offset2), (255)) 35 | 36 | # 삼각형 영역만 마스킹해서 합성 ---⑦ 37 | warped_masked = cv2.bitwise_and(warped, warped, mask=mask) 38 | roi2_masked = cv2.bitwise_and(roi2, roi2, mask=cv2.bitwise_not(mask)) 39 | roi2_masked = roi2_masked + warped_masked 40 | img2[y2:y2+h2, x2:x2+w2] = roi2_masked 41 | 42 | # 관심 영역과 삼각형에 선 그려서 출력 ---⑧ 43 | cv2.rectangle(draw, (x1, y1), (x1+w1, y1+h1), (0,255,0), 1) 44 | cv2.polylines(draw, [pts1.astype(np.int32)], True, (255,0,0), 1) 45 | cv2.rectangle(img2, (x2, y2), (x2+w2, y2+h2), (0,255,0), 1) 46 | cv2.imshow('origin', draw) 47 | cv2.imshow('warped triangle', img2) 48 | cv2.waitKey(0) 49 | cv2.destroyAllWindows() 50 | 51 | -------------------------------------------------------------------------------- /08.match_track/match_homography_accuracy.py: -------------------------------------------------------------------------------- 1 | import cv2, numpy as np 2 | 3 | img1 = cv2.imread('../img/taekwonv1.jpg') 4 | img2 = cv2.imread('../img/figures2.jpg') 5 | gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY) 6 | gray2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY) 7 | 8 | # ORB, BF-Hamming 로 knnMatch ---① 9 | detector = cv2.ORB_create() 10 | kp1, desc1 = detector.detectAndCompute(gray1, None) 11 | kp2, desc2 = detector.detectAndCompute(gray2, None) 12 | matcher = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True) 13 | matches = matcher.match(desc1, desc2) 14 | 15 | # 매칭 결과를 거리기준 오름차순으로 정렬 ---③ 16 | matches = sorted(matches, key=lambda x:x.distance) 17 | # 모든 매칭점 그리기 ---④ 18 | res1 = cv2.drawMatches(img1, kp1, img2, kp2, matches, None, \ 19 | flags=cv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS) 20 | 21 | # 매칭점으로 원근 변환 및 영역 표시 ---⑤ 22 | src_pts = np.float32([ kp1[m.queryIdx].pt for m in matches ]) 23 | dst_pts = np.float32([ kp2[m.trainIdx].pt for m in matches ]) 24 | # RANSAC으로 변환 행렬 근사 계산 ---⑥ 25 | mtrx, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0) 26 | h,w = img1.shape[:2] 27 | pts = np.float32([ [[0,0]],[[0,h-1]],[[w-1,h-1]],[[w-1,0]] ]) 28 | dst = cv2.perspectiveTransform(pts,mtrx) 29 | img2 = cv2.polylines(img2,[np.int32(dst)],True,255,3, cv2.LINE_AA) 30 | 31 | # 정상치 매칭만 그리기 ---⑦ 32 | matchesMask = mask.ravel().tolist() 33 | res2 = cv2.drawMatches(img1, kp1, img2, kp2, matches, None, \ 34 | matchesMask = matchesMask, 35 | flags=cv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS) 36 | # 모든 매칭점과 정상치 비율 ---⑧ 37 | accuracy=float(mask.sum()) / mask.size 38 | print("accuracy: %d/%d(%.2f%%)"% (mask.sum(), mask.size, accuracy)) 39 | 40 | # 결과 출력 41 | cv2.imshow('Matching-All', res1) 42 | cv2.imshow('Matching-Inlier ', res2) 43 | cv2.waitKey() 44 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /07.segmentation/workshop_shape.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | # 이미지를 읽어서 그레이 스케일 및 스레시홀드 변환 5 | img = cv2.imread("../img/5shapes.jpg") 6 | img2 = img.copy() 7 | imgray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 8 | ret, th = cv2.threshold(imgray, 127, 255, cv2.THRESH_BINARY_INV) 9 | 10 | # 컨투어 찾기 11 | _, contours, _ = cv2.findContours(th, cv2.RETR_EXTERNAL, \ 12 | cv2.CHAIN_APPROX_SIMPLE) 13 | 14 | for contour in contours: 15 | # 각 컨투어에 근사 컨투어로 단순화 16 | approx = cv2.approxPolyDP(contour, 0.01*cv2.arcLength(contour, True), True) 17 | # 꼭지점의 갯수 18 | vertices = len(approx) 19 | print("vertices:", vertices) 20 | 21 | # 중심점 찾기 22 | mmt = cv2.moments(contour) 23 | cx,cy = int(mmt['m10']/mmt['m00']), int(mmt['m01']/mmt['m00']) 24 | 25 | name = "Unkown" 26 | if vertices == 3: # 꼭지점이 3개는 삼각형 27 | name = "Triangle" 28 | color = (0,255,0) 29 | elif vertices == 4: # 꼭지점 4개는 사각형 30 | x,y,w,h = cv2.boundingRect(contour) 31 | if abs(w-h) <= 3: # 폭과 높이의 차이가 3보다 작으면 정사각형 32 | name = 'Square' 33 | color = (0,125,255) 34 | else: # 폭과 높이 차이가 3보다 크면 직사각형 35 | name = 'Rectangle' 36 | color = (0,0,255) 37 | elif vertices == 10: # 꼭 지점 갯수 10개는 별 38 | name = 'Star' 39 | color = (255,255,0) 40 | elif vertices >= 15: # 꼭 지점 10개 이상이면 원 41 | name = 'Circle' 42 | color = (0,255,255) 43 | # 컨투어 그리기 44 | cv2.drawContours(img2, [contour], -1, color, -1) 45 | # 도형 이름 출력 46 | cv2.putText(img2, name, (cx-50, cy), cv2.FONT_HERSHEY_COMPLEX_SMALL,\ 47 | 1, (100,100,100), 1) 48 | 49 | cv2.imshow('Input Shapes', img) 50 | cv2.imshow('Recognizing Shapes', img2) 51 | cv2.waitKey(0) 52 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /07.segmentation/watershed.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | img = cv2.imread('../img/taekwonv1.jpg') 5 | rows, cols = img.shape[:2] 6 | img_draw = img.copy() 7 | 8 | # 마커 생성, 모든 요소는 0으로 초기화 ---① 9 | marker = np.zeros((rows, cols), np.int32) 10 | markerId = 1 # 마커 아이디는 1에서 시작 11 | colors = [] # 마커 선택한 영역 색상 저장할 공간 12 | isDragging = False # 드래그 여부 확인 변수 13 | 14 | # 마우스 이벤트 처리 함수 15 | def onMouse(event, x, y, flags, param): 16 | global img_draw, marker, markerId, isDragging 17 | if event == cv2.EVENT_LBUTTONDOWN: # 왼쪽 마우스 버튼 다운, 드래그 시작 18 | isDragging = True 19 | # 각 마커의 아이디와 현 위치의 색상 값을 쌍으로 매핑해서 저장 20 | colors.append((markerId, img[y,x])) 21 | elif event == cv2.EVENT_MOUSEMOVE: # 마우스 움직임 22 | if isDragging: # 드래그 진행 중 23 | # 마우스 좌표에 해당하는 마커의 좌표에 동일한 마커 아이디로 채워 넣기 ---② 24 | marker[y,x] = markerId 25 | # 마커 표시한 곳을 빨강색점으로 표시해서 출력 26 | cv2.circle(img_draw, (x,y), 3, (0,0,255), -1) 27 | cv2.imshow('watershed', img_draw) 28 | elif event == cv2.EVENT_LBUTTONUP: # 왼쪽 마우스 버튼 업 29 | if isDragging: 30 | isDragging = False # 드래그 중지 31 | # 다음 마커 선택을 위해 마커 아이디 증가 ---③ 32 | markerId +=1 33 | elif event == cv2.EVENT_RBUTTONDOWN: # 오른쪽 마우스 버튼 누름 34 | # 모아 놓은 마커를 이용해서 워터 쉐드 적용 ---④ 35 | cv2.watershed(img, marker) 36 | # 마커에 -1로 표시된 경계를 초록색으로 표시 ---⑤ 37 | img_draw[marker == -1] = (0,255,0) 38 | for mid, color in colors: # 선택한 마커 아이디 갯수 만큼 반복 39 | # 같은 마커 아이디 값을 갖는 영역을 마커 선택한 색상으로 채우기 ---⑥ 40 | img_draw[marker==mid] = color 41 | cv2.imshow('watershed', img_draw) # 표시한 결과 출력 42 | 43 | # 화면 출력 44 | cv2.imshow('watershed', img) 45 | cv2.setMouseCallback('watershed', onMouse) 46 | cv2.waitKey(0) 47 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /09.ml/lbp_face1_collect.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | import os 4 | 5 | # 변수 설정 ---① 6 | base_dir = './faces/' # 사진 저장할 디렉토리 경로 7 | target_cnt = 400 # 수집할 사진 갯수 8 | cnt = 0 # 사진 촬영 수 9 | 10 | # 얼굴 검출 분류기 생성 --- ② 11 | face_classifier = cv2.CascadeClassifier(\ 12 | '../data/haarcascade_frontalface_default.xml') 13 | 14 | # 사용자 이름과 번호를 입력 받아 디렉토리 생성 ---③ 15 | name = input("Insert User Name(Only Alphabet):") 16 | id = input("Insert User Id(Non-Duplicate number):") 17 | dir = os.path.join(base_dir, name+'_'+ id) 18 | if not os.path.exists(dir): 19 | os.mkdir(dir) 20 | 21 | # 카메라 캡쳐 22 | cap = cv2.VideoCapture(0) 23 | while cap.isOpened(): 24 | ret, frame = cap.read() 25 | if ret: 26 | img = frame.copy() 27 | gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) 28 | # 얼굴 검출 --- ④ 29 | faces = face_classifier.detectMultiScale(gray, 1.3, 5) 30 | if len(faces) == 1: 31 | (x,y,w,h) = faces[0] 32 | # 얼굴 영역 표시 및 파일 저장 ---⑤ 33 | cv2.rectangle(frame, (x,y), (x+w, y+h), (0,255,0), 1) 34 | face = gray[y:y+h, x:x+w] 35 | face = cv2.resize(face, (200, 200)) 36 | file_name_path = os.path.join(dir, str(cnt) + '.jpg') 37 | cv2.imwrite(file_name_path, face) 38 | cv2.putText(frame, str(cnt), (x, y), cv2.FONT_HERSHEY_COMPLEX, \ 39 | 1, (0,255,0), 2) 40 | cnt+=1 41 | else: 42 | # 얼굴 검출이 없거나 1이상 인 경우 오류 표시 ---⑥ 43 | if len(faces) == 0 : 44 | msg = "no face." 45 | elif len(faces) > 1: 46 | msg = "too many face." 47 | cv2.putText(frame, msg, (10, 50), cv2.FONT_HERSHEY_DUPLEX, \ 48 | 1, (0,0,255)) 49 | cv2.imshow('face record', frame) 50 | if cv2.waitKey(1) == 27 or cnt == target_cnt: 51 | break 52 | cap.release() 53 | cv2.destroyAllWindows() 54 | print("Collecting Samples Completed.") -------------------------------------------------------------------------------- /08.match_track/track_opticalLK.py: -------------------------------------------------------------------------------- 1 | import numpy as np, cv2 2 | 3 | cap = cv2.VideoCapture('../img/walking.avi') 4 | fps = cap.get(cv2.CAP_PROP_FPS) # 프레임 수 구하기 5 | delay = int(1000/fps) 6 | # 추적 경로를 그리기 위한 랜덤 색상 7 | color = np.random.randint(0,255,(200,3)) 8 | lines = None #추적 선을 그릴 이미지 저장 변수 9 | prevImg = None # 이전 프레임 저장 변수 10 | # calcOpticalFlowPyrLK 중지 요건 설정 11 | termcriteria = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03) 12 | 13 | while cap.isOpened(): 14 | ret,frame = cap.read() 15 | if not ret: 16 | break 17 | img_draw = frame.copy() 18 | gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) 19 | # 최초 프레임 경우 20 | if prevImg is None: 21 | prevImg = gray 22 | # 추적선 그릴 이미지를 프레임 크기에 맞게 생성 23 | lines = np.zeros_like(frame) 24 | # 추적 시작을 위한 코너 검출 ---① 25 | prevPt = cv2.goodFeaturesToTrack(prevImg, 200, 0.01, 10) 26 | else: 27 | nextImg = gray 28 | # 옵티컬 플로우로 다음 프레임의 코너점 찾기 ---② 29 | nextPt, status, err = cv2.calcOpticalFlowPyrLK(prevImg, nextImg, \ 30 | prevPt, None, criteria=termcriteria) 31 | # 대응점이 있는 코너, 움직인 코너 선별 ---③ 32 | prevMv = prevPt[status==1] 33 | nextMv = nextPt[status==1] 34 | for i,(p, n) in enumerate(zip(prevMv, nextMv)): 35 | px,py = p.ravel() 36 | nx,ny = n.ravel() 37 | # 이전 코너와 새로운 코너에 선그리기 ---④ 38 | cv2.line(lines, (px, py), (nx,ny), color[i].tolist(), 2) 39 | # 새로운 코너에 점 그리기 40 | cv2.circle(img_draw, (nx,ny), 2, color[i].tolist(), -1) 41 | # 누적된 추적 선을 출력 이미지에 합성 ---⑤ 42 | img_draw = cv2.add(img_draw, lines) 43 | # 다음 프레임을 위한 프레임과 코너점 이월 44 | prevImg = nextImg 45 | prevPt = nextMv.reshape(-1,1,2) 46 | 47 | cv2.imshow('OpticalFlow-LK', img_draw) 48 | key = cv2.waitKey(delay) 49 | if key == 27 : # Esc:종료 50 | break 51 | elif key == 8: # Backspace:추적 이력 지우기 52 | prevImg = None 53 | cv2.destroyAllWindows() 54 | cap.release() -------------------------------------------------------------------------------- /08.match_track/track_camsifht_cam.py: -------------------------------------------------------------------------------- 1 | import numpy as np, cv2 2 | 3 | roi_hist = None # 추적 객체 히스토그램 저장 변수 4 | win_name = 'Camshift Tracking' 5 | termination = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 1) 6 | 7 | cap = cv2.VideoCapture(0) 8 | cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640) 9 | cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480) 10 | while cap.isOpened(): 11 | ret, frame = cap.read() 12 | img_draw = frame.copy() 13 | 14 | if roi_hist is not None: # 추적 대상 객체 히스토그램 등록 됨 15 | # 전체 영상 hsv 컬로 변환 ---① 16 | hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) 17 | # 전체 영상 히스토그램과 roi 히스트그램 역투영 ---② 18 | dst = cv2.calcBackProject([hsv], [0], roi_hist, [0,180], 1) 19 | # 역 투영 결과와 초기 추적 위치로 평균 이동 추적 ---③ 20 | ret, (x,y,w,h) = cv2.CamShift(dst, (x,y,w,h), termination) 21 | # 새로운 위치에 사각형 표시 ---④ 22 | cv2.rectangle(img_draw, (x,y), (x+w, y+h), (0,255,0), 2) 23 | # 컬러 영상과 역투영 영상을 통합해서 출력 24 | result = np.hstack((img_draw, cv2.cvtColor(dst, cv2.COLOR_GRAY2BGR))) 25 | else: # 추적 대상 객체 히스토그램 등록 안됨 26 | cv2.putText(img_draw, "Hit the Space to set target to track", \ 27 | (10,30),cv2.FONT_HERSHEY_SIMPLEX, 1, (0,0,255), 1, cv2.LINE_AA) 28 | result = img_draw 29 | 30 | cv2.imshow(win_name, result) 31 | key = cv2.waitKey(1) & 0xff 32 | if key == 27: # Esc 33 | break 34 | elif key == ord(' '): # 스페이스-바, ROI 설정 35 | x,y,w,h = cv2.selectROI(win_name, frame, False) 36 | if w and h : # ROI가 제대로 설정됨 37 | # 초기 추적 대상 위치로 roi 설정 --- ⑤ 38 | roi = frame[y:y+h, x:x+w] 39 | # roi를 HSV 컬러로 변경 ---⑥ 40 | roi = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV) 41 | mask = None 42 | # roi에 대한 히스토그램 계산 ---⑦ 43 | roi_hist = cv2.calcHist([roi], [0], mask, [180], [0,180]) 44 | cv2.normalize(roi_hist, roi_hist, 0, 255, cv2.NORM_MINMAX) 45 | else: # ROI 설정 안됨 46 | roi_hist = None 47 | else: 48 | print('no camera!') 49 | cap.release() 50 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /08.match_track/track_meanshift_cam.py: -------------------------------------------------------------------------------- 1 | import numpy as np, cv2 2 | 3 | roi_hist = None # 추적 객체 히스토그램 저장 변수 4 | win_name = 'MeanShift Tracking' 5 | termination = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 1) 6 | 7 | cap = cv2.VideoCapture(0) 8 | cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640) 9 | cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480) 10 | while cap.isOpened(): 11 | ret, frame = cap.read() 12 | img_draw = frame.copy() 13 | 14 | if roi_hist is not None: # 추적 대상 객체 히스토그램 등록 됨 15 | # 전체 영상 hsv 컬로 변환 ---① 16 | hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) 17 | # 전체 영상 히스토그램과 roi 히스트그램 역투영 ---② 18 | dst = cv2.calcBackProject([hsv], [0], roi_hist, [0,180], 1) 19 | # 역 투영 결과와 초기 추적 위치로 평균 이동 추적 ---③ 20 | ret, (x,y,w,h) = cv2.meanShift(dst, (x,y,w,h), termination) 21 | # 새로운 위치에 사각형 표시 ---④ 22 | cv2.rectangle(img_draw, (x,y), (x+w, y+h), (0,255,0), 2) 23 | # 컬러 영상과 역투영 영상을 통합해서 출력 24 | result = np.hstack((img_draw, cv2.cvtColor(dst, cv2.COLOR_GRAY2BGR))) 25 | else: # 추적 대상 객체 히스토그램 등록 안됨 26 | cv2.putText(img_draw, "Hit the Space to set target to track", \ 27 | (10,30),cv2.FONT_HERSHEY_SIMPLEX, 1, (0,0,255), 1, cv2.LINE_AA) 28 | result = img_draw 29 | 30 | cv2.imshow(win_name, result) 31 | key = cv2.waitKey(1) & 0xff 32 | if key == 27: # Esc 33 | break 34 | elif key == ord(' '): # 스페이스-바, ROI 설정 35 | x,y,w,h = cv2.selectROI(win_name, frame, False) 36 | if w and h : # ROI가 제대로 설정됨 37 | # 초기 추적 대상 위치로 roi 설정 --- ⑤ 38 | roi = frame[y:y+h, x:x+w] 39 | # roi를 HSV 컬러로 변경 ---⑥ 40 | roi = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV) 41 | mask = None 42 | # roi에 대한 히스토그램 계산 ---⑦ 43 | roi_hist = cv2.calcHist([roi], [0], mask, [180], [0,180]) 44 | cv2.normalize(roi_hist, roi_hist, 0, 255, cv2.NORM_MINMAX) 45 | else: # ROI 설정 안됨 46 | roi_hist = None 47 | else: 48 | print('no camera!') 49 | cap.release() 50 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /04.img_processing/histo_backproject.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | import matplotlib.pyplot as plt 4 | 5 | win_name = 'back_projection' 6 | img = cv2.imread('../img/pump_horse.jpg') 7 | hsv_img = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) 8 | draw = img.copy() 9 | 10 | #--⑤ 역투영된 결과를 마스킹해서 결과를 출력하는 공통함수 11 | def masking(bp, win_name): 12 | disc = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5)) 13 | cv2.filter2D(bp,-1,disc,bp) 14 | _, mask = cv2.threshold(bp, 1, 255, cv2.THRESH_BINARY) 15 | result = cv2.bitwise_and(img, img, mask=mask) 16 | cv2.imshow(win_name, result) 17 | 18 | #--⑥ 직접 구현한 역투영 함수 19 | def backProject_manual(hist_roi): 20 | #--⑦ 전체 영상에 대한 H,S 히스토그램 계산 21 | hist_img = cv2.calcHist([hsv_img], [0,1], None,[180,256], [0,180,0,256]) 22 | #--⑧ 선택영역과 전체 영상에 대한 히스토그램 그램 비율계산 23 | hist_rate = hist_roi/ (hist_img + 1) 24 | #--⑨ 비율에 맞는 픽셀 값 매핑 25 | h,s,v = cv2.split(hsv_img) 26 | bp = hist_rate[h.ravel(), s.ravel()] 27 | # 비율은 1을 넘어서는 안되기 때문에 1을 넘는 수는 1을 갖게 함 28 | bp = np.minimum(bp, 1) 29 | # 1차원 배열을 원래의 shape로 변환 30 | bp = bp.reshape(hsv_img.shape[:2]) 31 | cv2.normalize(bp,bp, 0, 255, cv2.NORM_MINMAX) 32 | bp = bp.astype(np.uint8) 33 | #--⑩ 역 투영 결과로 마스킹해서 결과 출력 34 | masking(bp,'result_manual') 35 | 36 | # OpenCV API로 구현한 함수 ---⑪ 37 | def backProject_cv(hist_roi): 38 | # 역투영 함수 호출 ---⑫ 39 | bp = cv2.calcBackProject([hsv_img], [0, 1], hist_roi, [0, 180, 0, 256], 1) 40 | # 역 투영 결과로 마스킹해서 결과 출력 ---⑬ 41 | masking(bp,'result_cv') 42 | 43 | # ROI 선택 ---① 44 | (x,y,w,h) = cv2.selectROI(win_name, img, False) 45 | if w > 0 and h > 0: 46 | roi = draw[y:y+h, x:x+w] 47 | # 빨간 사각형으로 ROI 영역 표시 48 | cv2.rectangle(draw, (x, y), (x+w, y+h), (0,0,255), 2) 49 | #--② 선택한 ROI를 HSV 컬러 스페이스로 변경 50 | hsv_roi = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV) 51 | #--③ H,S 채널에 대한 히스토그램 계산 52 | hist_roi = cv2.calcHist([hsv_roi],[0, 1], None, [180, 256], [0, 180, 0, 256] ) 53 | #--④ ROI의 히스토그램을 매뉴얼 구현함수와 OpenCV 이용하는 함수에 각각 전달 54 | backProject_manual(hist_roi) 55 | backProject_cv(hist_roi) 56 | cv2.imshow(win_name, draw) 57 | cv2.waitKey() 58 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /04.img_processing/roi_crop_mouse.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | isDragging = False # 마우스 드래그 상태 저장 5 | x0, y0, w, h = -1,-1,-1,-1 # 영역 선택 좌표 저장 6 | blue, red = (255,0,0),(0,0,255) # 색상 값 7 | 8 | def onMouse(event,x,y,flags,param): # 마우스 이벤트 핸들 함수 ---① 9 | global isDragging, x0, y0, img # 전역변수 참조 10 | if event == cv2.EVENT_LBUTTONDOWN: # 왼쪽 마우스 버튼 다운, 드래그 시작 ---② 11 | isDragging = True 12 | x0 = x 13 | y0 = y 14 | elif event == cv2.EVENT_MOUSEMOVE: # 마우스 움직임 ---③ 15 | if isDragging: # 드래그 진행 중 16 | img_draw = img.copy() # 사각형 그림 표현을 위한 이미지 복제 17 | cv2.rectangle(img_draw, (x0, y0), (x, y), blue, 2) # 드래그 진행 영역 표시 18 | cv2.imshow('img', img_draw) # 사각형 표시된 그림 화면 출력 19 | elif event == cv2.EVENT_LBUTTONUP: # 왼쪽 마우스 버튼 업 ---④ 20 | if isDragging: # 드래그 중지 21 | isDragging = False 22 | w = x - x0 # 드래그 영역 폭 계산 23 | h = y - y0 # 드래그 영역 높이 계산 24 | print("x:%d, y:%d, w:%d, h:%d" % (x0, y0, w, h)) 25 | if w > 0 and h > 0: # 폭과 높이가 양수이면 드래그 방향이 옳음 ---⑤ 26 | img_draw = img.copy() # 선택 영역에 사각형 그림을 표시할 이미지 복제 27 | # 선택 영역에 빨간 사각형 표시 28 | cv2.rectangle(img_draw, (x0, y0), (x, y), red, 2) 29 | cv2.imshow('img', img_draw) # 빨간 사각형 그려진 이미지 화면 출력 30 | roi = img[y0:y0+h, x0:x0+w] # 원본 이미지에서 선택 영영만 ROI로 지정 ---⑥ 31 | cv2.imshow('cropped', roi) # ROI 지정 영역을 새창으로 표시 32 | cv2.moveWindow('cropped', 0, 0) # 새창을 화면 좌측 상단에 이동 33 | cv2.imwrite('./cropped.jpg', roi) # ROI 영역만 파일로 저장 ---⑦ 34 | print("croped.") 35 | else: 36 | cv2.imshow('img', img) # 드래그 방향이 잘못된 경우 사각형 그림ㅇㅣ 없는 원본 이미지 출력 37 | print("좌측 상단에서 우측 하단으로 영역을 드래그 하세요.") 38 | 39 | img = cv2.imread('../img/sunset.jpg') 40 | cv2.imshow('img', img) 41 | cv2.setMouseCallback('img', onMouse) # 마우스 이벤트 등록 ---⑧ 42 | cv2.waitKey() 43 | cv2.destroyAllWindows() 44 | -------------------------------------------------------------------------------- /09.ml/lbp_face3_recognize.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | import os, glob 4 | 5 | # 변수 설정 ---① 6 | base_dir = './faces' 7 | min_accuracy = 85 8 | 9 | # LBP 얼굴 인식기 및 케스케이드 얼굴 검출기 생성 및 훈련 모델 읽기 ---② 10 | face_classifier = cv2.CascadeClassifier(\ 11 | '../data/haarcascade_frontalface_default.xml') 12 | model = cv2.face.LBPHFaceRecognizer_create() 13 | model.read(os.path.join(base_dir, 'all_face.xml')) 14 | 15 | # 디렉토리 이름으로 사용자 이름과 아이디 매핑 정보 생성 ---③ 16 | dirs = [d for d in glob.glob(base_dir+"/*") if os.path.isdir(d)] 17 | names = dict([]) 18 | for dir in dirs: 19 | dir = os.path.basename(dir) 20 | name, id = dir.split('_') 21 | names[int(id)] = name 22 | 23 | # 카메라 캡처 장치 준비 24 | cap = cv2.VideoCapture(0) 25 | while cap.isOpened(): 26 | ret, frame = cap.read() 27 | if not ret: 28 | print("no frame") 29 | break 30 | gray = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY) 31 | # 얼굴 검출 ---④ 32 | faces = face_classifier.detectMultiScale(gray, 1.3, 5) 33 | for (x,y,w,h) in faces: 34 | # 얼굴 영역 표시하고 샘플과 같은 크기로 축소 ---⑤ 35 | cv2.rectangle(frame,(x,y),(x+w,y+h),(0,255,255),2) 36 | face = frame[y:y+h, x:x+w] 37 | face = cv2.resize(face, (200, 200)) 38 | face = cv2.cvtColor(face, cv2.COLOR_BGR2GRAY) 39 | # LBP 얼굴 인식기로 예측 ---⑥ 40 | label, confidence = model.predict(face) 41 | if confidence < 400: 42 | # 정확도 거리를 퍼센트로 변환 ---⑦ 43 | accuracy = int( 100 * (1 -confidence/400)) 44 | if accuracy >= min_accuracy: 45 | msg = '%s(%.0f%%)'%(names[label], accuracy) 46 | else: 47 | msg = 'Unknown' 48 | # 사용자 이름과 정확도 결과 출력 ---⑧ 49 | txt, base = cv2.getTextSize(msg, cv2.FONT_HERSHEY_PLAIN, 1, 3) 50 | cv2.rectangle(frame, (x,y-base-txt[1]), (x+txt[0], y+txt[1]), \ 51 | (0,255,255), -1) 52 | cv2.putText(frame, msg, (x, y), cv2.FONT_HERSHEY_PLAIN, 1, \ 53 | (200,200,200), 2,cv2.LINE_AA) 54 | cv2.imshow('Face Recognition', frame) 55 | if cv2.waitKey(1) == 27: #esc 56 | break 57 | cap.release() 58 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /09.ml/svm_mnist_hog_train.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | import mnist 4 | import time 5 | 6 | # 기울어진 숫자를 바로 세우기 위한 함수 ---① 7 | affine_flags = cv2.WARP_INVERSE_MAP|cv2.INTER_LINEAR 8 | def deskew(img): 9 | m = cv2.moments(img) 10 | if abs(m['mu02']) < 1e-2: 11 | return img.copy() 12 | skew = m['mu11']/m['mu02'] 13 | M = np.float32([[1, skew, -0.5*20*skew], [0, 1, 0]]) 14 | img = cv2.warpAffine(img,M,(20, 20),flags=affine_flags) 15 | return img 16 | 17 | # HOGDescriptor를 위한 파라미터 설정 및 생성---② 18 | winSize = (20,20) 19 | blockSize = (10,10) 20 | blockStride = (5,5) 21 | cellSize = (5,5) 22 | nbins = 9 23 | hogDesc = cv2.HOGDescriptor(winSize,blockSize,blockStride,cellSize,nbins) 24 | 25 | if __name__ =='__main__': 26 | # MNIST 이미지에서 학습용 이미지와 테스트용 이미지 가져오기 ---③ 27 | train_data, train_label = mnist.getTrain(reshape=False) 28 | test_data, test_label = mnist.getTest(reshape=False) 29 | # 학습 이미지 글씨 바로 세우기 ---④ 30 | deskewed = [list(map(deskew,row)) for row in train_data] 31 | # 학습 이미지 HOG 계산 ---⑤ 32 | hogdata = [list(map(hogDesc.compute,row)) for row in deskewed] 33 | train_data = np.float32(hogdata) 34 | print('SVM training started...train data:', train_data.shape) 35 | # 학습용 HOG 데이타 재배열 ---⑥ 36 | train_data = train_data.reshape(-1,train_data.shape[2]) 37 | # SVM 알고리즘 객체 생성 및 훈련 ---⑦ 38 | svm = cv2.ml.SVM_create() 39 | startT = time.time() 40 | svm.trainAuto(train_data, cv2.ml.ROW_SAMPLE, train_label) 41 | endT = time.time() - startT 42 | print('SVM training complete. %.2f Min'%(endT/60)) 43 | # 훈련된 결과 모델 저장 ---⑧ 44 | svm.save('svm_mnist.xml') 45 | 46 | # 테스트 이미지 글씨 바로 세우기 및 HOG 계산---⑨ 47 | deskewed = [list(map(deskew,row)) for row in test_data] 48 | hogdata = [list(map(hogDesc.compute,row)) for row in deskewed] 49 | test_data = np.float32(hogdata) 50 | # 테스트용 HOG 데이타 재배열 ---⑩ 51 | test_data = test_data.reshape(-1,test_data.shape[2]) 52 | # 테스트 데이타 결과 예측 ---⑪ 53 | ret, result = svm.predict(test_data) 54 | # 예측 결과와 테스트 레이블이 맞은 갯수 합산 및 정확도 출력---⑫ 55 | correct = (result==test_label).sum() 56 | print('Accuracy: %.2f%%'%(correct*100.0/result.size)) -------------------------------------------------------------------------------- /04.img_processing/workshop_cctv_motion_sensor.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | # 감도 설정(카메라 품질에 따라 조정 필요) 5 | thresh = 25 # 달라진 픽셀 값 기준치 설정 6 | max_diff = 5 # 달라진 픽셀 갯수 기준치 설정 7 | 8 | # 카메라 캡션 장치 준비 9 | a, b, c = None, None, None 10 | cap = cv2.VideoCapture(0) 11 | cap.set(cv2.CAP_PROP_FRAME_WIDTH, 480) # 프레임 폭을 480으로 설정 12 | cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 320) # 프레임 높이를 320으로 설정 13 | 14 | if cap.isOpened(): 15 | ret, a = cap.read() # a 프레임 읽기 16 | ret, b = cap.read() # b 프레임 읽기 17 | 18 | while ret: 19 | ret, c = cap.read() # c 프레임 읽기 20 | draw = c.copy() # 출력 영상에 사용할 복제본 21 | if not ret: 22 | break 23 | 24 | # 3개의 영상을 그레이 스케일로 변경 25 | a_gray = cv2.cvtColor(a, cv2.COLOR_BGR2GRAY) 26 | b_gray = cv2.cvtColor(b, cv2.COLOR_BGR2GRAY) 27 | c_gray = cv2.cvtColor(c, cv2.COLOR_BGR2GRAY) 28 | 29 | # a-b, b-c 절대 값 차 구하기 30 | diff1 = cv2.absdiff(a_gray, b_gray) 31 | diff2 = cv2.absdiff(b_gray, c_gray) 32 | 33 | # 스레시홀드로 기준치 이내의 차이는 무시 34 | ret, diff1_t = cv2.threshold(diff1, thresh, 255, cv2.THRESH_BINARY) 35 | ret, diff2_t = cv2.threshold(diff2, thresh, 255, cv2.THRESH_BINARY) 36 | 37 | # 두 차이에 대해서 AND 연산, 두 영상의 차이가 모두 발견된 경우 38 | diff = cv2.bitwise_and(diff1_t, diff2_t) 39 | 40 | # 열림 연산으로 노이즈 제거 ---① 41 | k = cv2.getStructuringElement(cv2.MORPH_CROSS, (3,3)) 42 | diff = cv2.morphologyEx(diff, cv2.MORPH_OPEN, k) 43 | 44 | # 차이가 발생한 픽셀이 갯수 판단 후 사각형 그리기 45 | diff_cnt = cv2.countNonZero(diff) 46 | if diff_cnt > max_diff: 47 | nzero = np.nonzero(diff) # 0이 아닌 픽셀의 좌표 얻기(y[...], x[...]) 48 | cv2.rectangle(draw, (min(nzero[1]), min(nzero[0])), \ 49 | (max(nzero[1]), max(nzero[0])), (0,255,0), 2) 50 | cv2.putText(draw, "Motion Detected", (10,30), \ 51 | cv2.FONT_HERSHEY_DUPLEX, 0.5, (0,0,255)) 52 | 53 | # 컬러 스케일 영상과 스레시홀드 영상을 통합해서 출력 54 | stacked = np.hstack((draw, cv2.cvtColor(diff, cv2.COLOR_GRAY2BGR))) 55 | cv2.imshow('motion sensor',stacked ) 56 | 57 | # 다음 비교를 위해 영상 순서 정리 58 | a = b 59 | b = c 60 | 61 | if cv2.waitKey(1) & 0xFF == 27: 62 | break -------------------------------------------------------------------------------- /05.geometric_transform/perspective_scan.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | win_name = "scanning" 5 | img = cv2.imread("../img/paper.jpg") 6 | rows, cols = img.shape[:2] 7 | draw = img.copy() 8 | pts_cnt = 0 9 | pts = np.zeros((4,2), dtype=np.float32) 10 | 11 | def onMouse(event, x, y, flags, param): #마우스 이벤트 콜백 함수 구현 ---① 12 | global pts_cnt # 마우스로 찍은 좌표의 갯수 저장 13 | if event == cv2.EVENT_LBUTTONDOWN: 14 | cv2.circle(draw, (x,y), 10, (0,255,0), -1) # 좌표에 초록색 동그라미 표시 15 | cv2.imshow(win_name, draw) 16 | 17 | pts[pts_cnt] = [x,y] # 마우스 좌표 저장 18 | pts_cnt+=1 19 | if pts_cnt == 4: # 좌표가 4개 수집됨 20 | # 좌표 4개 중 상하좌우 찾기 ---② 21 | sm = pts.sum(axis=1) # 4쌍의 좌표 각각 x+y 계산 22 | diff = np.diff(pts, axis = 1) # 4쌍의 좌표 각각 x-y 계산 23 | 24 | topLeft = pts[np.argmin(sm)] # x+y가 가장 값이 좌상단 좌표 25 | bottomRight = pts[np.argmax(sm)] # x+y가 가장 큰 값이 우하단 좌표 26 | topRight = pts[np.argmin(diff)] # x-y가 가장 작은 것이 우상단 좌표 27 | bottomLeft = pts[np.argmax(diff)] # x-y가 가장 큰 값이 좌하단 좌표 28 | 29 | # 변환 전 4개 좌표 30 | pts1 = np.float32([topLeft, topRight, bottomRight , bottomLeft]) 31 | 32 | # 변환 후 영상에 사용할 서류의 폭과 높이 계산 ---③ 33 | w1 = abs(bottomRight[0] - bottomLeft[0]) # 상단 좌우 좌표간의 거리 34 | w2 = abs(topRight[0] - topLeft[0]) # 하당 좌우 좌표간의 거리 35 | h1 = abs(topRight[1] - bottomRight[1]) # 우측 상하 좌표간의 거리 36 | h2 = abs(topLeft[1] - bottomLeft[1]) # 좌측 상하 좌표간의 거리 37 | width = max([w1, w2]) # 두 좌우 거리간의 최대값이 서류의 폭 38 | height = max([h1, h2]) # 두 상하 거리간의 최대값이 서류의 높이 39 | 40 | # 변환 후 4개 좌표 41 | pts2 = np.float32([[0,0], [width-1,0], 42 | [width-1,height-1], [0,height-1]]) 43 | 44 | # 변환 행렬 계산 45 | mtrx = cv2.getPerspectiveTransform(pts1, pts2) 46 | # 원근 변환 적용 47 | result = cv2.warpPerspective(img, mtrx, (width, height)) 48 | cv2.imshow('scanned', result) 49 | cv2.imshow(win_name, img) 50 | cv2.setMouseCallback(win_name, onMouse) # 마우스 콜백 함수를 GUI 윈도우에 등록 ---④ 51 | cv2.waitKey(0) 52 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /05.geometric_transform/workhop_distotion_camera.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | cap = cv2.VideoCapture(0) 5 | WIDTH = 500 6 | HEIGHT = 300 7 | cap.set(cv2.CAP_PROP_FRAME_WIDTH, WIDTH) 8 | cap.set(cv2.CAP_PROP_FRAME_HEIGHT, HEIGHT) 9 | rows, cols = HEIGHT, WIDTH 10 | map_y, map_x = np.indices((rows, cols), dtype=np.float32) 11 | 12 | # 거울 왜곡 효과 13 | map_mirrorh_x,map_mirrorh_y = map_x.copy(), map_y.copy() 14 | map_mirrorv_x,map_mirrorv_y = map_x.copy(), map_y.copy() 15 | ## 좌우 대칭 거울 좌표 연산 16 | map_mirrorh_x[: , cols//2:] = cols - map_mirrorh_x[:, cols//2:]-1 17 | ## 상하 대칭 거울 좌표 연산 18 | map_mirrorv_y[rows//2:, :] = rows - map_mirrorv_y[rows//2:, :]-1 19 | # 물결 효과 20 | map_wave_x, map_wave_y = map_x.copy(), map_y.copy() 21 | map_wave_x = map_wave_x + 15*np.sin(map_y/20) 22 | map_wave_y = map_wave_y + 15*np.sin(map_x/20) 23 | 24 | 25 | # 렌즈 효과 26 | ## 렌즈 효과, 중심점 이동 27 | map_lenz_x = 2*map_x/(cols-1)-1 28 | map_lenz_y = 2*map_y/(rows-1)-1 29 | ## 렌즈 효과, 극좌표 변환 30 | r, theta = cv2.cartToPolar(map_lenz_x, map_lenz_y) 31 | r_convex = r.copy() 32 | r_concave = r.copy() 33 | ## 볼록 렌즈 효과 매핑 좌표 연산 34 | r_convex[r< 1] = r_convex[r<1] **2 35 | print(r.shape, r_convex[r<1].shape) 36 | ## 오목 렌즈 효과 매핑 좌표 연산 37 | r_concave[r< 1] = r_concave[r<1] **0.5 38 | ## 렌즈 효과, 직교 좌표 복원 39 | map_convex_x, map_convex_y = cv2.polarToCart(r_convex, theta) 40 | map_concave_x, map_concave_y = cv2.polarToCart(r_concave, theta) 41 | ## 렌즈 효과, 좌상단 좌표 복원 42 | map_convex_x = ((map_convex_x + 1)*cols-1)/2 43 | map_convex_y = ((map_convex_y + 1)*rows-1)/2 44 | map_concave_x = ((map_concave_x + 1)*cols-1)/2 45 | map_concave_y = ((map_concave_y + 1)*rows-1)/2 46 | 47 | while True: 48 | ret, frame = cap.read() 49 | frame = frame[:HEIGHT, :WIDTH] 50 | # 준비한 매핑 좌표로 영상 효과 적용 51 | mirrorh=cv2.remap(frame,map_mirrorh_x,map_mirrorh_y,cv2.INTER_LINEAR) 52 | mirrorv=cv2.remap(frame,map_mirrorv_x,map_mirrorv_y,cv2.INTER_LINEAR) 53 | wave = cv2.remap(frame,map_wave_x,map_wave_y,cv2.INTER_LINEAR, \ 54 | None, cv2.BORDER_REPLICATE) 55 | convex = cv2.remap(frame,map_convex_x,map_convex_y,cv2.INTER_LINEAR) 56 | concave = cv2.remap(frame,map_concave_x,map_concave_y,cv2.INTER_LINEAR) 57 | # 영상 합치기 58 | r1 = np.hstack(( frame, mirrorh, mirrorv)) 59 | r2 = np.hstack(( wave, convex, concave)) 60 | merged = np.vstack((r1, r2)) 61 | 62 | cv2.imshow('distorted', merged) 63 | if cv2.waitKey(1) & 0xFF== 27: 64 | break 65 | cap.release 66 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /09.ml/mnist.py: -------------------------------------------------------------------------------- 1 | import numpy as np, cv2 2 | 3 | data = None # 이미지 데이타 셋 4 | k = list(range(10)) # [0,1,2,3,4,5,6,7,8,9] 레이블 셋 5 | 6 | # 이미지 데이타 읽어들이는 함수 ---① 7 | def load(): 8 | global data 9 | # 0~9 각각 500(5x100)개, 총5000(50x100)개, 한 숫자당 400(20x20)픽셀 10 | image = cv2.imread('../img/digits.png') 11 | gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY) 12 | # 숫자 한개(20x20)씩 구분하기 위해 행별(50)로 나누고 열별(100)로 나누기 13 | cells = [np.hsplit(row,100) for row in np.vsplit(gray,50)] 14 | # 리스트를 NumPy 배열로 변환 (50 x 100 x 20 x 20 ) 15 | data = np.array(cells) 16 | 17 | # 모든 숫자 데이타 반환 ---② 18 | def getData(reshape=True): 19 | if data is None: load() # 이미지 읽기 확인 20 | # 모든 데이타를 N x 400 형태로 변환 21 | if reshape: 22 | full = data.reshape(-1, 400).astype(np.float32) # 5000x400 23 | else: 24 | full = data 25 | labels = np.repeat(k,500).reshape(-1,1) # 각 숫자당 500번 반복(10x500) 26 | return (full, labels) 27 | 28 | # 훈련용 데이타 반환 ---③ 29 | def getTrain(reshape=True): 30 | if data is None: load() # 이미지 읽기 확인 31 | # 50x100 중에 90열만 훈련 데이타로 사용 32 | train = data[:,:90] 33 | if reshape: 34 | # 훈련 데이타를 N X 400으로 변환 35 | train = train.reshape(-1,400).astype(np.float32) # 4500x400 36 | # 레이블 생성 37 | train_labels = np.repeat(k,450).reshape(-1,1) # 각 숫자당 45번 반복(10x450) 38 | return (train, train_labels) 39 | 40 | # 테스트용 데이타 반환 ---④ 41 | def getTest(reshape=True): 42 | if data is None: load() 43 | # 50x100 중에 마지막 10열만 훈련 데이타로 사용 44 | test = data[:,90:100] 45 | # 테스트 데이타를 N x 400으로 변환 46 | if reshape: 47 | test = test.reshape(-1,400).astype(np.float32) # 500x400 48 | test_labels = np.repeat(k,50).reshape(-1,1) 49 | return (test, test_labels) 50 | 51 | 52 | # 손글씨 숫자 한 개를 20x20 로 변환후에 1x400 형태로 변환 ---⑤ 53 | def digit2data(src, reshape=True): 54 | h, w = src.shape[:2] 55 | square = src 56 | # 정사각형 형태로 만들기 57 | if h > w: 58 | pad = (h - w)//2 59 | square = np.zeros((h, h), dtype=np.uint8) 60 | square[:, pad:pad+w] = src 61 | elif w > h : 62 | pad = (w - h)//2 63 | square = np.zeros((w, w), dtype=np.uint8) 64 | square[pad:pad+h, :] = src 65 | # 0으로 채워진 20x20 이미지 생성 66 | px20 = np.zeros((20,20), np.uint8) 67 | # 원본을 16x16으로 축소해서 테두리 2픽셀 확보 68 | px20[2:18, 2:18] = cv2.resize(square, (16,16), interpolation=cv2.INTER_AREA) 69 | if reshape: 70 | # 1x400형태로 변환 71 | px20 = px20.reshape((1,400)).astype(np.float32) 72 | return px20 73 | -------------------------------------------------------------------------------- /08.match_track/track_trackingAPI.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | 3 | # 트랙커 객체 생성자 함수 리스트 ---① 4 | trackers = [cv2.TrackerBoosting_create, 5 | cv2.TrackerMIL_create, 6 | cv2.TrackerKCF_create, 7 | cv2.TrackerTLD_create, 8 | cv2.TrackerMedianFlow_create, 9 | cv2.TrackerGOTURN_create, #버그로 오류 발생 10 | cv2.TrackerCSRT_create, 11 | cv2.TrackerMOSSE_create] 12 | trackerIdx = 0 # 트랙커 생성자 함수 선택 인덱스 13 | tracker = None 14 | isFirst = True 15 | 16 | video_src = 0 # 비디오 파일과 카메라 선택 ---② 17 | video_src = "../img/highway.mp4" 18 | cap = cv2.VideoCapture(video_src) 19 | fps = cap.get(cv2.CAP_PROP_FPS) # 프레임 수 구하기 20 | delay = int(1000/fps) 21 | win_name = 'Tracking APIs' 22 | while cap.isOpened(): 23 | ret, frame = cap.read() 24 | if not ret: 25 | print('Cannot read video file') 26 | break 27 | img_draw = frame.copy() 28 | if tracker is None: # 트랙커 생성 안된 경우 29 | cv2.putText(img_draw, "Press the Space to set ROI!!", \ 30 | (100,80), cv2.FONT_HERSHEY_SIMPLEX, 0.75,(0,0,255),2,cv2.LINE_AA) 31 | else: 32 | ok, bbox = tracker.update(frame) # 새로운 프레임에서 추적 위치 찾기 ---③ 33 | (x,y,w,h) = bbox 34 | if ok: # 추적 성공 35 | cv2.rectangle(img_draw, (int(x), int(y)), (int(x + w), int(y + h)), \ 36 | (0,255,0), 2, 1) 37 | else : # 추적 실패 38 | cv2.putText(img_draw, "Tracking fail.", (100,80), \ 39 | cv2.FONT_HERSHEY_SIMPLEX, 0.75,(0,0,255),2,cv2.LINE_AA) 40 | trackerName = tracker.__class__.__name__ 41 | cv2.putText(img_draw, str(trackerIdx) + ":"+trackerName , (100,20), \ 42 | cv2.FONT_HERSHEY_SIMPLEX, 0.75, (0,255,0),2,cv2.LINE_AA) 43 | 44 | cv2.imshow(win_name, img_draw) 45 | key = cv2.waitKey(delay) & 0xff 46 | # 스페이스 바 또는 비디오 파일 최초 실행 ---④ 47 | if key == ord(' ') or (video_src != 0 and isFirst): 48 | isFirst = False 49 | roi = cv2.selectROI(win_name, frame, False) # 초기 객체 위치 설정 50 | if roi[2] and roi[3]: # 위치 설정 값 있는 경우 51 | tracker = trackers[trackerIdx]() #트랙커 객체 생성 ---⑤ 52 | isInit = tracker.init(frame, roi) 53 | elif key in range(48, 56): # 0~7 숫자 입력 ---⑥ 54 | trackerIdx = key-48 # 선택한 숫자로 트랙커 인덱스 수정 55 | if bbox is not None: 56 | tracker = trackers[trackerIdx]() # 선택한 숫자의 트랙커 객체 생성 ---⑦ 57 | isInit = tracker.init(frame, bbox) # 이전 추적 위치로 추적 위치 초기화 58 | elif key == 27 : 59 | break 60 | else: 61 | print( "Could not open video") 62 | cap.release() 63 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /07.segmentation/grabcut.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | img = cv2.imread('../img/taekwonv1.jpg') 5 | img_draw = img.copy() 6 | mask = np.zeros(img.shape[:2], dtype=np.uint8) # 마스크 생성 7 | rect = [0,0,0,0] # 사각형 영역 좌표 초기화 8 | mode = cv2.GC_EVAL # 그랩컷 초기 모드 9 | # 배경 및 전경 모델 버퍼 10 | bgdmodel = np.zeros((1,65),np.float64) 11 | fgdmodel = np.zeros((1,65),np.float64) 12 | 13 | # 마우스 이벤트 처리 함수 14 | def onMouse(event, x, y, flags, param): 15 | global mouse_mode, rect, mask, mode 16 | if event == cv2.EVENT_LBUTTONDOWN : # 왼쪽 마우스 누름 17 | if flags <= 1: # 아무 키도 안 눌렀으면 18 | mode = cv2.GC_INIT_WITH_RECT # 드래그 시작, 사각형 모드 ---① 19 | rect[:2] = x, y # 시작 좌표 저장 20 | # 마우스가 움직이고 왼쪽 버튼이 눌러진 상태 21 | elif event == cv2.EVENT_MOUSEMOVE and flags & cv2.EVENT_FLAG_LBUTTON : 22 | if mode == cv2.GC_INIT_WITH_RECT: # 드래그 진행 중 ---② 23 | img_temp = img.copy() 24 | # 드래그 사각형 화면에 표시 25 | cv2.rectangle(img_temp, (rect[0], rect[1]), (x, y), (0,255,0), 2) 26 | cv2.imshow('img', img_temp) 27 | elif flags > 1: # 키가 눌러진 상태 28 | mode = cv2.GC_INIT_WITH_MASK # 마스크 모드 ---③ 29 | if flags & cv2.EVENT_FLAG_CTRLKEY :# 컨트롤 키, 분명한 전경 30 | # 흰색 점 화면에 표시 31 | cv2.circle(img_draw,(x,y),3, (255,255,255),-1) 32 | # 마스크에 GC_FGD로 채우기 ---④ 33 | cv2.circle(mask,(x,y),3, cv2.GC_FGD,-1) 34 | if flags & cv2.EVENT_FLAG_SHIFTKEY : # 쉬프트키, 분명한 배경 35 | # 검정색 점 화면에 표시 36 | cv2.circle(img_draw,(x,y),3, (0,0,0),-1) 37 | # 마스크에 GC_BGD로 채우기 ---⑤ 38 | cv2.circle(mask,(x,y),3, cv2.GC_BGD,-1) 39 | cv2.imshow('img', img_draw) # 그려진 모습 화면에 출력 40 | elif event == cv2.EVENT_LBUTTONUP: # 마우스 왼쪽 버튼 뗀 상태 ---⑥ 41 | if mode == cv2.GC_INIT_WITH_RECT : # 사각형 그리기 종료 42 | rect[2:] =x, y # 사각형 마지막 좌표 수집 43 | # 사각형 그려서 화면에 출력 ---⑦ 44 | cv2.rectangle(img_draw, (rect[0], rect[1]), (x, y), (255,0,0), 2) 45 | cv2.imshow('img', img_draw) 46 | # 그랩컷 적용 ---⑧ 47 | cv2.grabCut(img, mask, tuple(rect), bgdmodel, fgdmodel, 1, mode) 48 | img2 = img.copy() 49 | # 마스크에 확실한 배경, 아마도 배경으로 표시된 영역을 0으로 채우기 50 | img2[(mask==cv2.GC_BGD) | (mask==cv2.GC_PR_BGD)] = 0 51 | cv2.imshow('grabcut', img2) # 최종 결과 출력 52 | mode = cv2.GC_EVAL # 그랩컷 모드 리셋 53 | # 초기 화면 출력 및 마우스 이벤트 등록 54 | cv2.imshow('img', img) 55 | cv2.setMouseCallback('img', onMouse) 56 | while True: 57 | if cv2.waitKey(0) & 0xFF == 27 : # esc 58 | break 59 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /07.segmentation/workshop_paper_scan.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | win_name = 'scan' 5 | # 이미지 읽기 6 | img = cv2.imread("../img/paper.jpg") 7 | cv2.imshow('original', img) 8 | cv2.waitKey(0) 9 | draw = img.copy() 10 | 11 | # 그레이스 스케일 변환 및 케니 엣지 12 | gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 13 | gray = cv2.GaussianBlur(gray, (3, 3), 0) # 가우시안 블러로 노이즈 제거 14 | edged = cv2.Canny(gray, 75, 200) # 케니 엣지로 경계 검출 15 | cv2.imshow(win_name, edged) 16 | cv2.waitKey(0) 17 | 18 | # 컨투어 찾기 19 | (_, cnts, _) = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL, \ 20 | cv2.CHAIN_APPROX_SIMPLE) 21 | # 모든 컨투어 그리기 22 | cv2.drawContours(draw, cnts, -1, (0,255,0)) 23 | cv2.imshow(win_name, draw) 24 | cv2.waitKey(0) 25 | 26 | # 컨투어들 중에 영역 크기 순으로 정렬 27 | cnts = sorted(cnts, key = cv2.contourArea, reverse = True)[:5] 28 | for c in cnts: 29 | # 영역이 가장 큰 컨투어 부터 근사 컨투어 단순화 30 | peri = cv2.arcLength(c, True) # 둘레 길이 31 | # 둘레 길이의 0.02 근사값으로 근사화 32 | vertices = cv2.approxPolyDP(c, 0.02 * peri, True) 33 | if len(vertices) == 4: # 근사한 꼭지점이 4개면 중지 34 | break 35 | pts = vertices.reshape(4, 2) # N x 1 x 2 배열을 4 x 2크기로 조정 36 | for x,y in pts: 37 | cv2.circle(draw, (x,y), 10, (0,255,0), -1) # 좌표에 초록색 동그라미 표시 38 | cv2.imshow(win_name, draw) 39 | cv2.waitKey(0) 40 | merged = np.hstack((img, draw)) 41 | 42 | #### 이하 [예제 5-8]과 동일 #### 43 | # 좌표 4개 중 상하좌우 찾기 ---② 44 | sm = pts.sum(axis=1) # 4쌍의 좌표 각각 x+y 계산 45 | diff = np.diff(pts, axis = 1) # 4쌍의 좌표 각각 x-y 계산 46 | 47 | topLeft = pts[np.argmin(sm)] # x+y가 가장 값이 좌상단 좌표 48 | bottomRight = pts[np.argmax(sm)] # x+y가 가장 큰 값이 좌상단 좌표 49 | topRight = pts[np.argmin(diff)] # x-y가 가장 작은 것이 우상단 좌표 50 | bottomLeft = pts[np.argmax(diff)] # x-y가 가장 큰 값이 좌하단 좌표 51 | 52 | # 변환 전 4개 좌표 53 | pts1 = np.float32([topLeft, topRight, bottomRight , bottomLeft]) 54 | 55 | # 변환 후 영상에 사용할 서류의 폭과 높이 계산 ---③ 56 | w1 = abs(bottomRight[0] - bottomLeft[0]) # 상단 좌우 좌표간의 거리 57 | w2 = abs(topRight[0] - topLeft[0]) # 하당 좌우 좌표간의 거리 58 | h1 = abs(topRight[1] - bottomRight[1]) # 우측 상하 좌표간의 거리 59 | h2 = abs(topLeft[1] - bottomLeft[1]) # 좌측 상하 좌표간의 거리 60 | width = max([w1, w2]) # 두 좌우 거리간의 최대값이 서류의 폭 61 | height = max([h1, h2]) # 두 상하 거리간의 최대값이 서류의 높이 62 | 63 | # 변환 후 4개 좌표 64 | pts2 = np.float32([[0,0], [width-1,0], 65 | [width-1,height-1], [0,height-1]]) 66 | 67 | # 변환 행렬 계산 68 | mtrx = cv2.getPerspectiveTransform(pts1, pts2) 69 | # 원근 변환 적용 70 | result = cv2.warpPerspective(img, mtrx, (width, height)) 71 | cv2.imshow(win_name, result) 72 | cv2.waitKey(0) 73 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 파이썬으로 만드는 OpenCV 프로젝트 2 | ========================== 3 | 4 | ## 스터디 개요 5 | 6 | - 스터디 목적은 캐글 컴퓨터 비전 대회에 참여하기 위함입니다. 7 | - '파이썬으로 만드는 OpenCV 프로젝트(이세우 저)' 교재를 활용하여 스터디를 했습니다. 8 | 9 | ## 스터디 일지 10 | 11 | - 2020.07.19 12 | 13 | - [파이썬으로 만드는 OpenCV 프로젝트](http://www.yes24.com/Product/Goods/71534451?OzSrank=1) 책 구매 14 | - 2020.07.20 15 | - 1장: 개요와 설치 (p.1~21) 16 | - 영상 처리와 컴퓨터 비전, OpenCV, Numpy설치, OpenCV-Python 설치, OpenCV 공식문서 17 | - 2020.07.21~07.23 18 | - 2장: 기본 입출력 (p.23-59) 19 | - 이미지와 비디오 입출력 20 | - 도형 그리기 (직선, 사각형, 다각형, 원, 타원, 글씨) 21 | - 창 관리 22 | - 이벤트 처리 (키보드 이벤트, 마우스 이벤트, 트랙바) 23 | - 2020.07.24~07.26 24 | - 3장: Numpy와 Matplotlib (p.61-104) 25 | - Numpy (이미지 처리와 관련된 각종 numpy 연산) 26 | - Matplotlib (plot, color, style, subplot, 이미지 표시) 27 | - 2020.07.27~08.03 28 | - 4장: 이미지 프로세싱 기초 (p.105-174) 29 | - 관심영역(ROI) 지정 30 | - 컬러 스페이스 (RGB, RGBA, HSV, YUV, 컬러 스페이스 변환) 31 | - 스레시홀딩 (전역 스레시홀딩, 오츠의 알고리즘, 적응형 스레시홀딩) 32 | - 이미지 연산 (알파 블렌딩, 비트와이즈 연산, 차영상, 이미지 합성과 마스킹) 33 | - 히스토그램 (히스토그램 표시, 정규화, 평탄화, CLAHE, 역투영) 34 | - 실전 워크숍 35 | - 2020.08.04~08.10 36 | - 5장: 기하학적 변환 (p.175-213) 37 | - 이동, 확대/축소, 회전 38 | - 뒤틀기 (어핀 변환, 원근 변환, 삼각현 어핀 변환) 39 | - 렌즈 왜곡 (리매핑, 오목/볼록 렌즈 왜곡, 방사 왜곡) 40 | - 실전 워크숍 41 | - 2020.08.11~08.16 42 | - 6장: 영상 필터 (p.215-250) 43 | - 컨볼루션과 블러링 (평균 블러링, 가우시안 블러링, 미디언 블러링, 바이레터럴 필터) 44 | - 경계 검출 (기본 미분 필터, 로버츠 교차 필터, 프리윗 필터, 소벨 필터, 샤르 필터, 라플라시안 필터, 캐니엣지) 45 | - 모폴로지 (침식 연산, 팽창 연산, 열림과 닫힘, 그밖의 모폴로지 연산) 46 | - 이미지 피라미드 (가우시안 피라미드, 라플라시안 피라미드) 47 | - 실전 워크숍 (모자이크 처리2, 스케치 효과 카메라) 48 | - 2020.08.27~08.30 49 | - 7장: 영상 분할 (p.251-300) 50 | - 컨투어 (이미지 모멘트와 컨투어 속성, 컨투어 단순화, 컨투어와 도형 매칭) 51 | - 허프 변환 (허프 선 변환, 확률적 허프 선 변환, 허프 원 변환) 52 | - 연속 영역 분할 (거리 변환, 연결 요소 레이블링, 색 채우기, 워터셰드, 그랩컷, 평균 이동 필터) 53 | - 실전 워크숍 (도형 알아맞히기, 문서 스캐너, 동전 개수 세기) 54 | - 2020.09.01~09.06 55 | - 8장: 영상 매칭과 추적 (p.301~376) 56 | - 비슷한 그림 찾기 (평균 해시 매칭, 템플릿 매칭) 57 | - 영상의 특징과 특징점 (코너 특징 검출, 특징점과 특징 검출기, GFTTDetector, FAST, SimpleBlobDetector) 58 | - 디스크립터 추출기 (특징 디스크립터와 추출기, SIFT, SURF, ORB) 59 | - 특징 매칭 (특징 매칭 인터페이스, BFMatcher, FLANN, 올바른 매칭점 찾기, 매칭 영역 원근 변환) 60 | - 객체 추적 (동영상 배경 제거, 광학 흐름, MeanShift 추적, CamShift 추적, Tracking API) 61 | - 실전 워크숍 (파노라마 사진 생성기, 책 표지 검색기) 62 | - 2020.09.07~09.11 63 | - 9장: 머신러닝 (p.377~p.446) 64 | - OpenCV와 머신러닝 65 | - k-means 클러스터 (k-means 알고리즘, mnist 군집화) 66 | - k-NN (k-NN 알고리즘, mnist 인식) 67 | - SVM과 HOG (SVM 알고리즘, HOG 디스크립터, 보행자 인식) 68 | - BOW (BOW 알고리즘과 객체 인식) 69 | - 캐스케이드 분류기 70 | - 실전 워크숍 71 | 72 | ## 이미지 파일 다운로드 73 | 74 | 이미지 파일은 [이곳](https://github.com/dltpdn/insightbook.opencv_project_python)에서 다운받으시면 됩니다. -------------------------------------------------------------------------------- /09.ml/workhop_face_distotion_camera.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | # 얼굴과 눈동자 검출기 생성 5 | face_cascade = cv2.CascadeClassifier('../data/haarcascade_frontalface_default.xml') 6 | eye_cascade = cv2.CascadeClassifier('../data/haarcascade_eye.xml') 7 | 8 | # 렌즈 왜곡 효과 함수 9 | def distortedMap(rows, cols, type=0): 10 | map_y, map_x = np.indices((rows, cols), dtype=np.float32) 11 | # 렌즈 효과 12 | ## 렌즈 효과, 중심점 이동 13 | map_lenz_x = (2*map_x - cols)/cols 14 | map_lenz_y = (2*map_y - rows)/rows 15 | ## 렌즈 효과, 극좌표 변환 16 | r, theta = cv2.cartToPolar(map_lenz_x, map_lenz_y) 17 | if type==0: 18 | ## 볼록 렌즈 효과 매핑 좌표 연산 19 | r[r< 1] = r[r<1] **3 20 | else: 21 | ## 오목 렌즈 효과 매핑 좌표 연산 22 | r[r< 1] = r[r<1] **0.5 23 | ## 렌즈 효과, 직교 좌표 복원 24 | mapx, mapy = cv2.polarToCart(r, theta) 25 | ## 렌즈 효과, 좌상단 좌표 복원 26 | mapx = ((mapx + 1)*cols)/2 27 | mapy = ((mapy + 1)*rows)/2 28 | return (mapx, mapy) 29 | 30 | # 얼굴 검출 함수 31 | def findFaces(img): 32 | gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 33 | faces = face_cascade.detectMultiScale(gray) 34 | face_coords = [] 35 | for (x,y,w,h) in faces: 36 | face_coords.append((x, y, w, h)) 37 | return face_coords 38 | # 눈 검출 함수 39 | def findEyes(img): 40 | gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 41 | faces = face_cascade.detectMultiScale(gray) 42 | eyes_coords = [] 43 | for (x,y,w,h) in faces: 44 | roi_gray = gray[y:y+h, x:x+w] 45 | eyes = eye_cascade.detectMultiScale(roi_gray ) 46 | for(ex,ey,ew,eh) in eyes: 47 | eyes_coords.append((ex+x,ey+y,ew,eh)) 48 | return eyes_coords 49 | 50 | 51 | cap = cv2.VideoCapture(0) 52 | cap.set(cv2.CAP_PROP_FRAME_WIDTH, 480) 53 | cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 320) 54 | 55 | while True: 56 | ret, frame = cap.read() 57 | img1 = frame.copy() 58 | img2 = frame.copy() 59 | # 얼굴 검출해서 오목/볼록 렌즈 효과로 왜곡 적용 60 | faces = findFaces(frame) 61 | for face in faces: 62 | x,y,w,h = face 63 | mapx, mapy = distortedMap(w,h, 1) 64 | roi = img1[y:y+h, x:x+w] 65 | convex = cv2.remap(roi,mapx,mapy,cv2.INTER_LINEAR) 66 | img1[y:y+h, x:x+w] = convex 67 | # 눈 영역 검출해서 볼록 렌즈 효과로 왜곡 적용 68 | eyes = findEyes(frame) 69 | for eye in eyes : 70 | x,y,w,h = eye 71 | mapx, mapy = distortedMap(w,h) 72 | roi = img2[y:y+h, x:x+w] 73 | convex = cv2.remap(roi,mapx,mapy,cv2.INTER_LINEAR) 74 | img2[y:y+h, x:x+w] = convex 75 | # 하나의 이미지로 병합해서 출력 76 | merged = np.hstack((frame, img1, img2)) 77 | cv2.imshow('Face Distortion', merged) 78 | if cv2.waitKey(1) == 27: 79 | break 80 | cv2.destroyAllWindows() 81 | 82 | -------------------------------------------------------------------------------- /05.geometric_transform/workshop_liquify_tool.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | win_title = 'Liquify' # 창 이름 5 | half = 50 # 관심 영역 절반 크기 6 | isDragging = False # 드래그 여부 플래그 7 | 8 | # 리퀴파이 함수 9 | def liquify(img, cx1,cy1, cx2,cy2) : 10 | # 대상 영역 좌표와 크기 설정 11 | x, y, w, h = cx1-half, cy1-half, half*2, half*2 12 | # 관심 영역 설정 13 | roi = img[y:y+h, x:x+w].copy() 14 | out = roi.copy() 15 | 16 | # 관심영역 기준으로 좌표 재 설정 17 | offset_cx1,offset_cy1 = cx1-x, cy1-y 18 | offset_cx2,offset_cy2 = cx2-x, cy2-y 19 | 20 | # 변환 이전 4개의 삼각형 좌표 21 | tri1 = [[ (0,0), (w, 0), (offset_cx1, offset_cy1)], # 상,top 22 | [ [0,0], [0, h], [offset_cx1, offset_cy1]], # 좌,left 23 | [ [w, 0], [offset_cx1, offset_cy1], [w, h]], # 우, right 24 | [ [0, h], [offset_cx1, offset_cy1], [w, h]]] # 하, bottom 25 | 26 | # 변환 이후 4개의 삼각형 좌표 27 | tri2 = [[ [0,0], [w,0], [offset_cx2, offset_cy2]], # 상, top 28 | [ [0,0], [0, h], [offset_cx2, offset_cy2]], # 좌, left 29 | [ [w,0], [offset_cx2, offset_cy2], [w, h]], # 우, right 30 | [ [0,h], [offset_cx2, offset_cy2], [w, h]]] # 하, bottom 31 | 32 | 33 | for i in range(4): 34 | # 각각의 삼각형 좌표에 대해 어핀 변환 적용 35 | matrix = cv2.getAffineTransform( np.float32(tri1[i]), \ 36 | np.float32(tri2[i])) 37 | warped = cv2.warpAffine( roi.copy(), matrix, (w, h), \ 38 | None, flags=cv2.INTER_LINEAR, borderMode=cv2.BORDER_REFLECT_101) 39 | # 삼각형 모양의 마스크 생성 40 | mask = np.zeros((h, w), dtype = np.uint8) 41 | cv2.fillConvexPoly(mask, np.int32(tri2[i]), (255,255,255)) 42 | 43 | # 마스킹 후 합성 44 | warped = cv2.bitwise_and(warped, warped, mask=mask) 45 | out = cv2.bitwise_and(out, out, mask=cv2.bitwise_not(mask)) 46 | out = out + warped 47 | 48 | # 관심 영역을 원본 영상에 합성 49 | img[y:y+h, x:x+w] = out 50 | return img 51 | 52 | # 마우스 이벤트 핸들 함수 53 | def onMouse(event,x,y,flags,param): 54 | global cx1, cy1, isDragging, img # 전역변수 참조 55 | # 마우스 중심 점을 기준으로 대상 영역 따라다니기 56 | if event == cv2.EVENT_MOUSEMOVE: 57 | if not isDragging : 58 | img_draw = img.copy() 59 | # 드래그 영역 표시 60 | cv2.rectangle(img_draw, (x-half, y-half), \ 61 | (x+half, y+half), (0,255,0)) 62 | cv2.imshow(win_title, img_draw) # 사각형 표시된 그림 화면 출력 63 | elif event == cv2.EVENT_LBUTTONDOWN : 64 | isDragging = True # 드래그 시작 65 | cx1, cy1 = x, y # 드래그 시작된 원래의 위치 좌표 저장 66 | elif event == cv2.EVENT_LBUTTONUP : 67 | if isDragging: 68 | isDragging = False # 드래그 끝 69 | # 드래그 시작 좌표와 끝난 좌표로 리퀴파이 적용 함수 호출 70 | liquify(img, cx1, cy1, x, y) 71 | cv2.imshow(win_title, img) 72 | 73 | if __name__ == '__main__' : 74 | img = cv2.imread("../img/taekwonv1.jpg") 75 | h, w = img.shape[:2] 76 | 77 | cv2.namedWindow(win_title) 78 | cv2.setMouseCallback(win_title, onMouse) 79 | cv2.imshow(win_title, img) 80 | while True: 81 | key = cv2.waitKey(1) 82 | if key & 0xFF == 27: 83 | break 84 | cv2.destroyAllWindows() 85 | -------------------------------------------------------------------------------- /08.match_track/match_camera.py: -------------------------------------------------------------------------------- 1 | import cv2, numpy as np 2 | 3 | img1 = None 4 | win_name = 'Camera Matching' 5 | MIN_MATCH = 10 6 | # ORB 검출기 생성 ---① 7 | detector = cv2.ORB_create(1000) 8 | # Flann 추출기 생성 ---② 9 | FLANN_INDEX_LSH = 6 10 | index_params= dict(algorithm = FLANN_INDEX_LSH, 11 | table_number = 6, 12 | key_size = 12, 13 | multi_probe_level = 1) 14 | search_params=dict(checks=32) 15 | matcher = cv2.FlannBasedMatcher(index_params, search_params) 16 | # 카메라 캡쳐 연결 및 프레임 크기 축소 ---③ 17 | cap = cv2.VideoCapture(0) 18 | cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640) 19 | cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480) 20 | 21 | while cap.isOpened(): 22 | ret, frame = cap.read() 23 | if img1 is None: # 등록된 이미지 없음, 카메라 바이패스 24 | res = frame 25 | else: # 등록된 이미지 있는 경우, 매칭 시작 26 | img2 = frame 27 | gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY) 28 | gray2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY) 29 | # 키포인트와 디스크립터 추출 30 | kp1, desc1 = detector.detectAndCompute(gray1, None) 31 | kp2, desc2 = detector.detectAndCompute(gray2, None) 32 | # k=2로 knnMatch 33 | matches = matcher.knnMatch(desc1, desc2, 2) 34 | # 이웃 거리의 75%로 좋은 매칭점 추출---② 35 | ratio = 0.75 36 | good_matches = [m[0] for m in matches \ 37 | if len(m) == 2 and m[0].distance < m[1].distance * ratio] 38 | print('good matches:%d/%d' %(len(good_matches),len(matches))) 39 | # 모든 매칭점 그리지 못하게 마스크를 0으로 채움 40 | matchesMask = np.zeros(len(good_matches)).tolist() 41 | # 좋은 매칭점 최소 갯수 이상 인 경우 42 | if len(good_matches) > MIN_MATCH: 43 | # 좋은 매칭점으로 원본과 대상 영상의 좌표 구하기 ---③ 44 | src_pts = np.float32([ kp1[m.queryIdx].pt for m in good_matches ]) 45 | dst_pts = np.float32([ kp2[m.trainIdx].pt for m in good_matches ]) 46 | # 원근 변환 행렬 구하기 ---⑤ 47 | mtrx, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0) 48 | accuracy=float(mask.sum()) / mask.size 49 | print("accuracy: %d/%d(%.2f%%)"% (mask.sum(), mask.size, accuracy)) 50 | if mask.sum() > MIN_MATCH: # 정상치 매칭점 최소 갯수 이상 인 경우 51 | # 이상점 매칭점만 그리게 마스크 설정 52 | matchesMask = mask.ravel().tolist() 53 | # 원본 영상 좌표로 원근 변환 후 영역 표시 ---⑦ 54 | h,w, = img1.shape[:2] 55 | pts = np.float32([ [[0,0]],[[0,h-1]],[[w-1,h-1]],[[w-1,0]] ]) 56 | dst = cv2.perspectiveTransform(pts,mtrx) 57 | img2 = cv2.polylines(img2,[np.int32(dst)],True,255,3, cv2.LINE_AA) 58 | # 마스크로 매칭점 그리기 ---⑨ 59 | res = cv2.drawMatches(img1, kp1, img2, kp2, good_matches, None, \ 60 | matchesMask=matchesMask, 61 | flags=cv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS) 62 | # 결과 출력 63 | cv2.imshow(win_name, res) 64 | key = cv2.waitKey(1) 65 | if key == 27: # Esc, 종료 66 | break 67 | elif key == ord(' '): # 스페이스바를 누르면 ROI로 img1 설정 68 | x,y,w,h = cv2.selectROI(win_name, frame, False) 69 | if w and h: 70 | img1 = frame[y:y+h, x:x+w] 71 | else: 72 | print("can't open camera.") 73 | cap.release() 74 | cv2.destroyAllWindows() 75 | -------------------------------------------------------------------------------- /08.match_track/workshop_booksearcher.py: -------------------------------------------------------------------------------- 1 | import cv2 , glob, numpy as np 2 | 3 | # 검색 설정 변수 ---① 4 | ratio = 0.7 5 | MIN_MATCH = 10 6 | # ORB 특징 검출기 생성 ---② 7 | detector = cv2.ORB_create() 8 | # Flann 매칭기 객체 생성 ---③ 9 | FLANN_INDEX_LSH = 6 10 | index_params= dict(algorithm = FLANN_INDEX_LSH, 11 | table_number = 6, 12 | key_size = 12, 13 | multi_probe_level = 1) 14 | search_params=dict(checks=32) 15 | matcher = cv2.FlannBasedMatcher(index_params, search_params) 16 | 17 | # 책 표지 검색 함수 ---④ 18 | def serch(img): 19 | gray1 = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 20 | kp1, desc1 = detector.detectAndCompute(gray1, None) 21 | 22 | results = {} 23 | # 책 커버 보관 디렉토리 경로 ---⑤ 24 | cover_paths = glob.glob('../img/books/*.*') 25 | for cover_path in cover_paths: 26 | cover = cv2.imread(cover_path) 27 | cv2.imshow('Searching...', cover) # 검색 중인 책 표지 표시 ---⑥ 28 | cv2.waitKey(5) 29 | gray2 = cv2.cvtColor(cover, cv2.COLOR_BGR2GRAY) 30 | kp2, desc2 = detector.detectAndCompute(gray2, None) # 특징점 검출 ---⑦ 31 | matches = matcher.knnMatch(desc1, desc2, 2) # 특징점 매칭 ---⑧ 32 | # 좋은 매칭 선별 ---⑨ 33 | good_matches = [m[0] for m in matches \ 34 | if len(m) == 2 and m[0].distance < m[1].distance * ratio] 35 | if len(good_matches) > MIN_MATCH: 36 | # 좋은 매칭점으로 원본과 대상 영상의 좌표 구하기 ---⑩ 37 | src_pts = np.float32([ kp1[m.queryIdx].pt for m in good_matches ]) 38 | dst_pts = np.float32([ kp2[m.trainIdx].pt for m in good_matches ]) 39 | # 원근 변환 행렬 구하기 ---⑪ 40 | mtrx, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0) 41 | # 원근 변환 결과에서 정상치 비율 계산 ---⑫ 42 | accuracy=float(mask.sum()) / mask.size 43 | results[cover_path] = accuracy 44 | cv2.destroyWindow('Searching...') 45 | if len(results) > 0: 46 | results = sorted([(v,k) for (k,v) in results.items() \ 47 | if v > 0], reverse=True) 48 | return results 49 | 50 | cap = cv2.VideoCapture(0) 51 | qImg = None 52 | while cap.isOpened(): 53 | ret, frame = cap.read() 54 | if not ret: 55 | print('No Frame!') 56 | break 57 | h, w = frame.shape[:2] 58 | # 화면에 책을 인식할 영역 표시 ---⑬ 59 | left = w // 3 60 | right = (w // 3) * 2 61 | top = (h // 2) - (h // 3) 62 | bottom = (h // 2) + (h // 3) 63 | cv2.rectangle(frame, (left,top), (right,bottom), (255,255,255), 3) 64 | 65 | # 거울 처럼 보기 좋게 화면 뒤집어 보이기 66 | flip = cv2.flip(frame,1) 67 | cv2.imshow('Book Searcher', flip) 68 | key = cv2.waitKey(10) 69 | if key == ord(' '): # 스페이스-바를 눌러서 사진 찍기 70 | qImg = frame[top:bottom , left:right] 71 | cv2.imshow('query', qImg) 72 | break 73 | elif key == 27 : #Esc 74 | break 75 | else: 76 | print('No Camera!!') 77 | cap.release() 78 | 79 | if qImg is not None: 80 | gray = cv2.cvtColor(qImg, cv2.COLOR_BGR2GRAY) 81 | results = serch(qImg) 82 | if len(results) == 0 : 83 | print("No matched book cover found.") 84 | else: 85 | for( i, (accuracy, cover_path)) in enumerate(results): 86 | print(i, cover_path, accuracy) 87 | if i==0: 88 | cover = cv2.imread(cover_path) 89 | cv2.putText(cover, ("Accuracy:%.2f%%"%(accuracy*100)), (10,100), \ 90 | cv2.FONT_HERSHEY_SIMPLEX, 1, (0,255,0), 2, cv2.LINE_AA) 91 | cv2.imshow('Result', cover) 92 | cv2.waitKey() 93 | cv2.destroyAllWindows() 94 | -------------------------------------------------------------------------------- /09.ml/bow_plane_bike_train.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | import os, glob, time 4 | 5 | # 각종 변수 선언---① 6 | startT = time.time() # 소요시간 측정을 위한 시간 저장 7 | categories = ['airplanes', 'Motorbikes' ] # 카테고리 이름 8 | dictionary_size = 50 # 사전 크기, 클러스터 갯수 9 | base_path = "../img/101_ObjectCategories/" # 학습 이미지 기본 경로 10 | dict_file = './plane_bike_dict.npy' # 사전 객체 저장할 파일 이름 11 | svm_model_file = './plane_bike_svm.xml' # SVM 모델 객체 저장할 파일 이름 12 | 13 | # 추출기와 BOW 객체 생 --- ② 14 | detector = cv2.xfeatures2d.SIFT_create() # 추출기로 SIFT 생성 15 | matcher = cv2.BFMatcher(cv2.NORM_L2) # 매칭기로 BF 생성 16 | bowTrainer = cv2.BOWKMeansTrainer(dictionary_size) # KMeans로 구현된 BWOTrainer 생성 17 | bowExtractor = cv2.BOWImgDescriptorExtractor(detector, matcher) # 히스토그램 계산할 BOW추출기 생성 18 | 19 | # 특징 디스크립터를 KMeansTrainer에 추가---③ 20 | train_paths = [] # 훈련에 사용할 모든 이미지 경로 21 | train_labels = [] # 학습 데이타 레이블 22 | print('Adding descriptor to BOWTrainer...') 23 | for idx, category in enumerate(categories): # 카테고리 순회 24 | dir_path = base_path + category 25 | img_paths = glob.glob(dir_path +'/*.jpg') 26 | img_len = len(img_paths) 27 | for i, img_path in enumerate(img_paths): # 카테고리 내의 모든 이미지 파일 순회 28 | train_paths.append(img_path) 29 | train_labels.append(idx) # 학습 데이타 레이블, 0 또는 1 30 | img = cv2.imread(img_path) 31 | gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 32 | # 특징점과 특징 디스크립터 추출 및 bowTrainer에 추가 ---④ 33 | kpt, desc= detector.detectAndCompute(gray, None) 34 | bowTrainer.add(desc) 35 | print('\t%s %d/%d(%.2f%%)' \ 36 | %(category,i+1, img_len, (i+1)/img_len*100), end='\r') 37 | print() 38 | print('Adding descriptor completed...') 39 | 40 | # KMeans 클러스터로 군집화하여 시각 사전 생성 및 저장---⑤ 41 | print('Starting Dictionary clustering(%d)... \ 42 | It will take several time...'%dictionary_size) 43 | dictionary = bowTrainer.cluster() # 군집화로 시각 사전 생성 44 | np.save(dict_file, dictionary) # 시각 사전 데이타(넘파일)를 파일로 저장 45 | print('Dictionary Clustering completed...dictionary shape:',dictionary.shape) 46 | 47 | # 시각 사전과 모든 이미지의 매칭점으로 히스토그램 계산---⑥ 48 | bowExtractor.setVocabulary(dictionary) # bowExtractor에 시각 사전 셋팅 49 | train_desc = [] # 학습 데이타 50 | for i, path in enumerate(train_paths): # 모든 학습 대상 이미지 순회 51 | img = cv2.imread(path) # 이미지 읽기 52 | gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 53 | # 매칭점에 대한 히스토그램 계산 --- ⑦ 54 | hist = bowExtractor.compute(gray, detector.detect(gray)) 55 | train_desc.extend(hist) 56 | print('Compute histogram training set...(%.2f%%)'\ 57 | %((i+1)/len(train_paths)*100),end='\r') 58 | print("\nsvm items", len(train_desc), len(train_desc[0])) 59 | 60 | # 히스토그램을 학습데이타로 SVM 훈련 및 모델 저장---⑧ 61 | print('svm training...') 62 | svm = cv2.ml.SVM_create() 63 | svm.trainAuto(np.array(train_desc), cv2.ml.ROW_SAMPLE, np.array(train_labels)) 64 | svm.save(svm_model_file) 65 | print('svm training completed.') 66 | print('Training Elapsed: %s'\ 67 | %time.strftime('%H:%M:%S', time.gmtime(time.time()-startT))) 68 | 69 | # 원래의 이미지로 테스트 --- ⑨ 70 | print("Accuracy(Self)") 71 | for label, dir_name in enumerate(categories): 72 | labels = [] 73 | results = [] 74 | img_paths = glob.glob(base_path + '/'+dir_name +'/*.*') 75 | for img_path in img_paths: 76 | labels.append(label) 77 | img = cv2.imread(img_path) 78 | gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 79 | feature = bowExtractor.compute(gray, detector.detect(gray)) 80 | ret, result = svm.predict(feature) 81 | resp = result[0][0] 82 | results.append(resp) 83 | 84 | labels = np.array(labels) 85 | results = np.array(results) 86 | err = (labels != results) 87 | err_mean = err.mean() 88 | print('\t%s: %.2f %%' % (dir_name, (1 - err_mean)*100)) 89 | -------------------------------------------------------------------------------- /07.segmentation/workshop_coin_count.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | # 이미지 읽기 5 | img = cv2.imread('../img/coins_connected.jpg') 6 | rows, cols = img.shape[:2] 7 | cv2.imshow('original', img) 8 | 9 | 10 | # 동전 표면을 흐릿하게 피라미드평균시프트 적용 11 | mean = cv2.pyrMeanShiftFiltering(img, 20, 50) 12 | cv2.imshow('mean', mean) 13 | # 바이너리 이미지 변환 14 | gray = cv2.cvtColor(mean, cv2.COLOR_BGR2GRAY) 15 | gray = cv2.GaussianBlur(gray, (3,3), 0) 16 | 17 | _, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU) 18 | cv2.imshow('thresh', thresh) 19 | # 거리 변환 20 | dst = cv2.distanceTransform(thresh, cv2.DIST_L2, 3) 21 | # 거리 값을 0 ~255로 변환 22 | dst = ( dst / (dst.max() - dst.min()) * 255 ).astype(np.uint8) 23 | cv2.imshow('dst', dst) 24 | 25 | # 거리 변환결과에서 로칼 최대 값 구하기 26 | ## 팽창 적용(동전 크기 정도의 구조화 요소 필요), 27 | localMx = cv2.dilate(dst, np.ones((50,50), np.uint8)) 28 | ## 로칼 최대 값 저장 할 배열 생성 29 | lm = np.zeros((rows, cols), np.uint8) 30 | ## 팽창 적용전 이미지와 같은 픽셀이 로컬 최대 값이므로 255로 설정 31 | lm[(localMx==dst) & (dst != 0)] = 255 32 | cv2.imshow('localMx', lm) 33 | 34 | # 로컬 최대값으로 색 채우기 35 | ## 로컬 최대 값이 있는 좌표 구하기 36 | seeds = np.where(lm ==255) 37 | seed = np.stack( (seeds[1], seeds[0]), axis=-1) 38 | ## 색 채우기를 위한 채우기 마스크 생성 39 | fill_mask = np.zeros((rows+2, cols+2), np.uint8) 40 | for x,y in seed: 41 | ## 로칼 최대값을 시드로해서 평균 시프트 영상에 색채우기 42 | ret = cv2.floodFill(mean, fill_mask, (x,y), (255,255,255), \ 43 | (10,10,10), (10,10,10)) 44 | cv2.imshow('floodFill', mean) 45 | 46 | # 색 채우기 적용한 영상에 다시 거리 변환 적용 47 | gray = cv2.cvtColor(mean, cv2.COLOR_BGR2GRAY) 48 | gray = cv2.GaussianBlur(gray, (5,5), 0) 49 | 50 | ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU) 51 | dst = cv2.distanceTransform(thresh, cv2.DIST_L2, 5) 52 | dst = ( (dst / (dst.max() - dst.min())) * 255 ).astype(np.uint8) 53 | cv2.imshow('dst2', dst) 54 | 55 | # 거리 변환 결과값의 절반 이상을 차지한 영역은 확실한 전경으로 설정 56 | ret, sure_fg = cv2.threshold(dst, 0.5*dst.max(), 255,0) 57 | cv2.imshow('sure_fg', sure_fg) 58 | 59 | # 거리 변환 결과를 반전해서 확실한 배경 찾기 60 | _, bg_th = cv2.threshold(dst, 0.3*dst.max(), 255, cv2.THRESH_BINARY_INV) 61 | bg_dst = cv2.distanceTransform(bg_th, cv2.DIST_L2, 5) 62 | bg_dst = ( (bg_dst / (bg_dst.max() - bg_dst.min())) * 255 ).astype(np.uint8) 63 | ret, sure_bg = cv2.threshold(bg_dst, 0.3*bg_dst.max(), 255,cv2.THRESH_BINARY) 64 | cv2.imshow('sure_bg', sure_bg) 65 | 66 | 67 | # 불확실한 영역 설정 : 확실한 배경을 반전해서 확실한 전경을 빼기 68 | ret, inv_sure_bg = cv2.threshold(sure_bg, 127, 255,cv2.THRESH_BINARY_INV) 69 | unkown = cv2.subtract(inv_sure_bg, sure_fg) 70 | cv2.imshow('unkown', unkown) 71 | 72 | # 연결된 요소 레이블링 73 | _, markers = cv2.connectedComponents(sure_fg) 74 | 75 | # 레이블링을 1씩 증가 시키고 0번 레이블 알 수 없는 영역을 0번 레이블로 설정 76 | markers = markers+1 77 | markers[unkown ==255] = 0 78 | print("워터쉐드 전:", np.unique(markers)) 79 | colors = [] 80 | marker_show = np.zeros_like(img) 81 | for mid in np.unique(markers): # 선택한 마커 아이디 갯수 만큼 반복 82 | color = [int(j) for j in np.random.randint(0,255, 3)] 83 | colors.append((mid, color)) 84 | marker_show[markers==mid] = color 85 | coords = np.where(markers==mid) 86 | x, y = coords[1][0], coords[0][0] 87 | cv2.putText(marker_show, str(mid), (x+20, y+20), cv2.FONT_HERSHEY_PLAIN, \ 88 | 2, (255,255,255)) 89 | cv2.imshow('before', marker_show) 90 | 91 | # 레이블링이 완성된 마커로 워터 쉐드 적용 92 | markers = cv2.watershed(img, markers) 93 | print("워터쉐드 후:", np.unique(markers)) 94 | 95 | for mid, color in colors: # 선택한 마커 아이디 갯수 만큼 반복 96 | marker_show[markers==mid] = color 97 | coords = np.where(markers==mid) 98 | if coords[0].size <= 0 : 99 | continue 100 | x, y = coords[1][0], coords[0][0] 101 | cv2.putText(marker_show, str(mid), (x+20, y+20), cv2.FONT_HERSHEY_PLAIN, \ 102 | 2, (255,255,255)) 103 | marker_show[markers==-1] = (0,255,0) 104 | cv2.imshow('watershed marker', marker_show) 105 | 106 | img[markers==-1] = (0,255,0) 107 | cv2.imshow('watershed', img) 108 | 109 | # 동전 추출을 위한 마스킹 생성 110 | mask = np.zeros((rows, cols), np.uint8) 111 | # 배경 마스크 생성 112 | mask[markers!=1] = 255 113 | # 배경 지우기 114 | nobg = cv2.bitwise_and(img, img, mask=mask) 115 | # 동전만 있는 라벨 생성 (배경(1), 경계(-1) 없는) 116 | coin_label = [l for l in np.unique(markers) if (l != 1 and l !=-1)] 117 | # 동전 라벨 순회 하면서 동전 영역만 추출 118 | for i, label in enumerate(coin_label): 119 | mask[:,:] = 0 120 | # 해당 동전 추출 마스크 생성 121 | mask[markers ==label] = 255 122 | # 동전 영역만 마스크로 추출 123 | coins = cv2.bitwise_and(img, img, mask=mask) 124 | # 동전 하나만 있는 곳에서 최외곽 컨투어 추출 125 | _, contour, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL,\ 126 | cv2.CHAIN_APPROX_NONE) 127 | # 동전을 감싸는 사각형 좌표 128 | x,y,w,h = cv2.boundingRect(contour[0]) 129 | # 동전 영역만 추출해서 출력 130 | coin = coins[y:y+h, x:x+w] 131 | cv2.imshow('coin%d'%(i+1), coin) 132 | cv2.imwrite('../img/coin_test/coin%d.jpg'%(i+1), coin) 133 | cv2.waitKey() 134 | cv2.destroyAllWindows() --------------------------------------------------------------------------------