├── .gitignore ├── 02.interface ├── blank_img.py ├── draw_circle.py ├── draw_line.py ├── draw_poly.py ├── draw_rect.py ├── draw_text.py ├── event_key.py ├── event_mouse_circle.py ├── event_mouse_circle_flag.py ├── event_trackbar.py ├── img_show.py ├── img_show_gray.py ├── img_write.py ├── video_cam.py ├── video_cam_rec.py ├── video_cam_resize.py ├── video_cam_take_pic.py ├── video_play.py ├── video_play_fps.py └── win.py ├── 03.numpy_matplotlib ├── np_bgr.py ├── np_broadcat.py ├── np_create_arange.py ├── np_create_array.py ├── np_create_like.py ├── np_create_size.py ├── np_dtype.py ├── np_gray.py ├── np_img.py ├── np_index.py ├── np_reshape.py ├── np_scalar_operation.py ├── plt_color.py ├── plt_imgshow_rgb.py ├── plt_imshow.py ├── plt_imshow_subplot.py ├── plt_plot.py ├── plt_simple.py ├── plt_style.py └── plt_subplot.py ├── 04.img_processing ├── addition_rgba_mask.py ├── arithmatic.py ├── arithmatic_mask.py ├── bgr2gray.py ├── bgr2hsv.py ├── bgr2yuv.py ├── bitwise.py ├── bitwise_masking.py ├── bitwise_masking2.py ├── blending_alpha.py ├── blending_alpha_trackbar.py ├── blending_simple.py ├── chromakey.py ├── cropped.jpg ├── cropped2.jpg ├── diff_absolute.py ├── histo_2d.py ├── histo_backproject.py ├── histo_clahe.py ├── histo_compare.py ├── histo_equalize.py ├── histo_equalize_yuv.py ├── histo_gray.py ├── histo_normalize.py ├── histo_rgb.py ├── hsv_color_mask.py ├── rgba.py ├── roi.py ├── roi_copy.py ├── roi_crop_mouse.py ├── roi_select_img.py ├── seamlessclone.py ├── threshold.py ├── threshold_adpted.py ├── threshold_flag.py ├── threshold_flag_cvshow.py ├── threshold_otsu.py ├── thresholds.py ├── workshop_cctv_motion_sensor.py └── workshop_two_face.py ├── 05.geometric_transform ├── getAffine.py ├── perspective.py ├── perspective_scan.py ├── remap_barrel.py ├── remap_flip.py ├── remap_lens.py ├── remap_sin_cos.py ├── rotate_getmatrix.py ├── rotate_matrix.py ├── scale_matrix.py ├── scale_resize.py ├── translate.py ├── triangle_affine.py ├── undistort_barrel.py ├── workhop_distotion_camera.py ├── workshop_liquify_tool.py └── workshop_mosaic.py ├── 06.filter ├── blur_avg_api.py ├── blur_avg_kernel.py ├── blur_bilateral.py ├── blur_gaussian.py ├── blur_median.py ├── edge_canny.py ├── edge_differential.py ├── edge_laplacian.py ├── edge_prewitt.py ├── edge_roberts.py ├── edge_scharr.py ├── edge_sobel.py ├── morph_dilate.py ├── morph_erode.py ├── morph_gradient.py ├── morph_hat.py ├── morph_open_close.py ├── pyramid_gaussian.py ├── pyramid_laplacian.py ├── workshop_mosic2.py └── workshop_painting_cam.py ├── 07.segmentation ├── cntr_approximate.py ├── cntr_bound_fit.py ├── cntr_convexhull.py ├── cntr_find.py ├── cntr_hierarchy.py ├── cntr_matchShape.py ├── cntr_moment.py ├── connected_label.py ├── distanceTrans.py ├── flood_fill.py ├── grabcut.py ├── hough_circle.py ├── hough_line.py ├── hough_lineP.py ├── mean_shift.py ├── watershed.py ├── workshop_coin_count.py ├── workshop_paper_scan.py └── workshop_shape.py ├── 08.match_track ├── avg_hash.py ├── avg_hash_matching.py ├── corner_goodFeature.py ├── corner_harris.py ├── desc_orb.py ├── desc_sift.py ├── desc_surf.py ├── kpt_blob.py ├── kpt_blob_param.py ├── kpt_fast.py ├── kpt_gftt.py ├── match_bf_orb.py ├── match_bf_sift.py ├── match_bf_surf.py ├── match_camera.py ├── match_flann_orb.py ├── match_flann_sift.py ├── match_flann_surf.py ├── match_good.py ├── match_good_knn.py ├── match_homography.py ├── match_homography_accuracy.py ├── template_matching.py ├── track_bgsub_mog.py ├── track_bgsub_mog2.py ├── track_camsifht_cam.py ├── track_meanshift_cam.py ├── track_opticalLK.py ├── track_optical_farneback.py ├── track_trackingAPI.py ├── workshop_booksearcher.py └── workshop_panorama.py ├── 09.ml ├── bow_plane_bike_test.py ├── bow_plane_bike_train.py ├── data │ ├── haarcascade_eye.xml │ ├── haarcascade_frontalface_alt.xml │ └── haarcascade_frontalface_default.xml ├── haar_face.py ├── haar_face_cam.py ├── k-means_color.py ├── k-means_handwritten.py ├── k-means_random.py ├── kNN_handwritten.py ├── kNN_mnist.py ├── kNN_movie.py ├── kNN_random.py ├── lbp_face1_collect.py ├── lbp_face2_train.py ├── lbp_face3_recognize.py ├── mnist.py ├── plane_bike_dict.npy ├── plane_bike_dict_4000.npy ├── plane_bike_svm.xml ├── plane_bike_svm_4000.xml ├── svm_handwritten.py ├── svm_hog_pedestrian.py ├── svm_mnist.xml ├── svm_mnist_hog_train.py ├── svm_random.py ├── svm_random.xml ├── workhop_face_distotion_camera.py ├── workshop_face_mosaic.py └── workshop_hannibal_mask.py ├── 10.apdx ├── face_delauney_triangle.py ├── face_landmark.py ├── face_landmark_cam.py └── face_swap.py ├── README.md └── img ├── 4027.png ├── 4star.jpg ├── 5shapes.jpg ├── abnormal.jpg ├── actor.jpg ├── aircraft.jpg ├── bad_rect.png ├── big_buck.avi ├── blank_500.jpg ├── books ├── book0.jpg ├── book1.jpg ├── book10.jpg ├── book11.jpg ├── book12.jpg ├── book13.jpg ├── book14.jpg ├── book15.jpg ├── book16.jpg ├── book17.jpg ├── book18.jpg ├── book19.jpg ├── book2.jpg ├── book20.jpg ├── book21.jpg ├── book22.jpg ├── book23.jpg ├── book24.jpg ├── book25.jpg ├── book26.jpg ├── book27.jpg ├── book28.jpg ├── book29.jpg ├── book3.jpg ├── book30.jpg ├── book31.jpg ├── book32.jpg ├── book33.jpg ├── book34.jpg ├── book35.jpg ├── book36.jpg ├── book37.jpg ├── book38.jpg ├── book39.jpg ├── book4.jpg ├── book40.jpg ├── book41.jpg ├── book42.jpg ├── book43.jpg ├── book44.jpg ├── book45.jpg ├── book46.jpg ├── book47.jpg ├── book48.jpg ├── book49.jpg ├── book5.jpg ├── book50.jpg ├── book51.jpg ├── book52.jpg ├── book53.jpg ├── book54.jpg ├── book55.jpg ├── book56.jpg ├── book57.jpg ├── book58.jpg ├── book59.jpg ├── book6.jpg ├── book60.jpg ├── book61.jpg ├── book62.jpg ├── book63.jpg ├── book64.jpg ├── book65.jpg ├── book66.jpg ├── book67.jpg ├── book68.jpg ├── book69.jpg ├── book7.jpg ├── book70.jpg ├── book71.jpg ├── book72.jpg ├── book8.jpg └── book9.jpg ├── boy_face.jpg ├── bright.jpg ├── bright_abnormal.jpg ├── children.jpg ├── coin_test ├── coin1.jpg ├── coin10.jpg ├── coin11.jpg ├── coin12.jpg ├── coin13.jpg ├── coin2.jpg ├── coin3.jpg ├── coin4.jpg ├── coin5.jpg ├── coin6.jpg ├── coin7.jpg ├── coin8.jpg └── coin9.jpg ├── coins_connected.jpg ├── coins_spread1.jpg ├── cube.jpg ├── digits.png ├── dr_ochanomizu.jpg ├── drawing.jpg ├── figures.jpg ├── figures2.jpg ├── figures3.jpg ├── figures4.jpg ├── figures4.png ├── figures5.jpg ├── fish.jpg ├── flower_wall.jpg ├── full_body.jpg ├── gaussian_noise.jpg ├── girl.jpg ├── girl_face.jpg ├── girl_gray.jpg ├── gray_gradient.jpg ├── hand.jpg ├── highway.mp4 ├── house.jpg ├── jetstar.jpg ├── lightning.png ├── lion_face.jpg ├── man_chromakey.jpg ├── man_face.jpg ├── mask_hannibal.png ├── model.jpg ├── model2.jpg ├── model3.jpg ├── moon_gray.jpg ├── morph_dot.png ├── morph_hole.png ├── morphological.png ├── motorbike.jpg ├── motorcycle.jpg ├── mountain.jpg ├── my_hand.jpg ├── opencv_logo.png ├── paper.jpg ├── pistol.jpg ├── pump_horse.jpg ├── restaurant1.jpg ├── restaurant2.jpg ├── robot_arm1.jpg ├── robot_arm2.jpg ├── salt_pepper_noise.jpg ├── scaned_paper.jpg ├── shapes.png ├── shapes_donut.png ├── shapestomatch.jpg ├── skull.jpg ├── street.jpg ├── sudoku.jpg ├── sudoku.png ├── sunset.jpg ├── taekwon_v.jpg ├── taekwonv1.jpg ├── taekwonv2.jpg ├── taekwonv3.jpg ├── walking.avi ├── wing_wall.jpg └── yate.jpg /02.interface/blank_img.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | img = np.full((500,500,3), 255, dtype=np.uint8) 5 | cv2.imwrite('./img/blank_500.jpg', img) 6 | -------------------------------------------------------------------------------- /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() -------------------------------------------------------------------------------- /02.interface/draw_line.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | 3 | img = cv2.imread('../img/blank_500.jpg') 4 | 5 | cv2.line(img, (50, 50), (150, 50), (255,0,0)) # 파란색 1픽셀 선 6 | cv2.line(img, (200, 50), (300, 50), (0,255,0)) # 초록색 1픽셀 선 7 | cv2.line(img, (350, 50), (450, 50), (0,0,255)) # 빨간색 1픽셀 선 8 | 9 | # 하늘색(파랑+초록) 10픽셀 선 10 | cv2.line(img, (100, 100), (400, 100), (255,255,0), 10) 11 | # 분홍(파랑+빨강) 10픽셀 선 12 | cv2.line(img, (100, 150), (400, 150), (255,0,255), 10) 13 | # 노랑(초록+빨강) 10픽셀 선 14 | cv2.line(img, (100, 200), (400, 200), (0,255,255), 10) 15 | # 회색(파랑+초록+빨강) 10픽셀 선 16 | cv2.line(img, (100, 250), (400, 250), (200,200,200), 10) 17 | # 검정 10픽셀 선 18 | cv2.line(img, (100, 300), (400, 300), (0,0,0), 10) 19 | 20 | # 4연결 선 21 | cv2.line(img, (100, 350), (400, 400), (0,0,255), 20, cv2.LINE_4) 22 | # 8연결 선 23 | cv2.line(img, (100, 400), (400, 450), (0,0,255), 20, cv2.LINE_8) 24 | # 안티에일리어싱 선 25 | cv2.line(img, (100, 450), (400, 500), (0,0,255), 20, cv2.LINE_AA) 26 | # 이미지 전체에 대각선 27 | cv2.line(img, (0,0), (500,500), (0,0,255)) 28 | 29 | cv2.imshow('lines', img) 30 | cv2.waitKey(0) 31 | 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() -------------------------------------------------------------------------------- /02.interface/draw_rect.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | 3 | img = cv2.imread('../img/blank_500.jpg') 4 | 5 | # 좌상, 우하 좌표로 사각형 그리기 6 | cv2.rectangle(img, (50, 50), (150, 150), (255,0,0) ) 7 | # 우하, 좌상 좌표로 사각형 그리기 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() -------------------------------------------------------------------------------- /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() -------------------------------------------------------------------------------- /02.interface/event_key.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | 3 | img_file = "../img/girl.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 | cv2.moveWindow(title, x, y) 11 | key = cv2.waitKey(0) & 0xFF # 키보드 입력을 무한 대기, 8비트 마스크처리 12 | print(key, chr(key)) # 키보드 입력 값, 문자 값 출력 13 | if key == ord('h'): # 'h' 키 이면 좌로 이동 14 | x -= 10 15 | elif key == ord('j'): # 'j' 키 이면 아래로 이동 16 | y += 10 17 | elif key == ord('k'): # 'k' 키 이면 위로 이동 18 | y -= 10 19 | elif key == ord('l'): # 'l' 키 이면 오른쪽으로 이동 20 | x += 10 21 | elif key == ord('q') or key == 27: # 'q' 이거나 'esc' 이면 종료 22 | break 23 | cv2.destroyAllWindows() 24 | cv2.moveWindow(title, x, y ) # 새로운 좌표로 창 이동 25 | -------------------------------------------------------------------------------- /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() -------------------------------------------------------------------------------- /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() -------------------------------------------------------------------------------- /02.interface/event_trackbar.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | win_name = 'Trackbar' # 창 이름 5 | 6 | img = cv2.imread('../img/blank_500.jpg') 7 | cv2.imshow(win_name,img) # 초기 이미지를 창에 표시 8 | 9 | # 트랙바 이벤트 처리 함수 선언 ---① 10 | def onChange(x): 11 | print(x) # 트랙바 새로운 위치 값 --- ② 12 | # 'R', 'G', 'B' 각 트랙바 위치 값 --- ③ 13 | r = cv2.getTrackbarPos('R',win_name) 14 | g = cv2.getTrackbarPos('G',win_name) 15 | b = cv2.getTrackbarPos('B',win_name) 16 | print(r, g, b) 17 | img[:] = [b,g,r] # 기존 이미지에 새로운 픽셀 값 적용 --- ④ 18 | cv2.imshow(win_name, img) # 새 이미지 창에 표시 19 | 20 | # 트랙바 생성 --- ⑤ 21 | cv2.createTrackbar('R', win_name, 255, 255, onChange) 22 | cv2.createTrackbar('G', win_name, 255, 255, onChange) 23 | cv2.createTrackbar('B', win_name, 255, 255, onChange) 24 | 25 | while True: 26 | if cv2.waitKey(1) & 0xFF == 27: 27 | break 28 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /02.interface/img_show.py: -------------------------------------------------------------------------------- 1 | ''' 2 | This code is provided for the book published by Insight book Inc. 3 | This code is released under the MIT license, and is available on GitHub site below 4 | 5 | 이 코드는 인사이트출판사에서 출판된 책 <파이썬으로 만드는 OpenCV 프로젝트>를 위해 제공합니다. 6 | 이 코드는 MIT 라이센스를 따르고 아래의 GitHub 주소에서도 받을 수 있습니다. 7 | 8 | GitHub : https://github.com/dltpdn/book_opencv_prject_using_python 9 | Author : Lee Sewoo(이세우, dltpdn@gmail.com) 10 | ''' 11 | import cv2 12 | 13 | img_file = "../img/girl.jpg" # 표시할 이미지 경로 ---① 14 | img = cv2.imread(img_file) # 이미지를 읽어서 img 변수에 할당 ---② 15 | 16 | if img is not None: 17 | cv2.imshow('IMG', img) # 읽은 이미지를 화면에 표시 --- ③ 18 | cv2.waitKey() # 키가 입력될 때 까지 대기 --- ④ 19 | cv2.destroyAllWindows() # 창 모두 닫기 --- ⑤ 20 | else: 21 | print('No image file.') 22 | -------------------------------------------------------------------------------- /02.interface/img_show_gray.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | 3 | img_file = "../img/girl.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 | -------------------------------------------------------------------------------- /02.interface/img_write.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | 3 | img_file = '../img/girl.jpg' 4 | save_file = '../img/girl_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 | -------------------------------------------------------------------------------- /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() -------------------------------------------------------------------------------- /02.interface/video_cam_rec.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | 3 | cap = cv2.VideoCapture(0) # 0번 카메라 연결 4 | if cap.isOpened: 5 | file_path = './record.avi' # 저장할 파일 경로 이름 ---① 6 | fps = 30.0 # FPS, 초당 프레임 수 7 | fourcc = cv2.VideoWriter_fourcc(*'DIVX') # 인코딩 포맷 문자 8 | width = cap.get(cv2.CAP_PROP_FRAME_WIDTH) 9 | height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT) 10 | size = (int(width), int(height)) # 프레임 크기 11 | out = cv2.VideoWriter(file_path, fourcc, fps, size) # VideoWriter 객체 생성 12 | while True: 13 | ret, frame = cap.read() 14 | if ret: 15 | cv2.imshow('camera-recording',frame) 16 | out.write(frame) # 파일 저장 17 | if cv2.waitKey(int(1000/fps)) != -1: 18 | break 19 | else: 20 | print("no frame!") 21 | break 22 | out.release() # 파일 닫기 23 | else: 24 | print("can't open camera!") 25 | cap.release() 26 | 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() -------------------------------------------------------------------------------- /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() -------------------------------------------------------------------------------- /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/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() -------------------------------------------------------------------------------- /02.interface/win.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | 3 | file_path = '../img/girl.jpg' 4 | img = cv2.imread(file_path) # 이미지를 기본 값으로 읽기 5 | img_gray = cv2.imread(file_path, cv2.IMREAD_GRAYSCALE) # 이미지를 그레이 스케일로 읽기 6 | 7 | cv2.namedWindow('origin') # origin 이름으로 창 생성 8 | cv2.namedWindow('gray', cv2.WINDOW_NORMAL) # gray 이름으로 창 생성 9 | cv2.imshow('origin', img) # origin 창에 이미지 표시 10 | cv2.imshow('gray', img_gray) # gray 창에 이미지 표시 11 | 12 | cv2.moveWindow('origin', 0, 0) # 창 위치 변경 13 | cv2.moveWindow('gray', 100, 100) # 창 위치 변경 14 | 15 | cv2.waitKey(0) # 아무키나 누르면 16 | cv2.resizeWindow('origin', 200, 200) # 창 크기 변경 (변경 안됨) 17 | cv2.resizeWindow('gray', 100, 100) # 창 크기 변경 (변경 됨)) 18 | 19 | cv2.waitKey(0) # 아무키나 누르면 20 | cv2.destroyWindow("gray") # gray 창 닫기 21 | 22 | cv2.waitKey(0) # 아무키나 누르면 23 | cv2.destroyAllWindows() # 모든 창 닫기 -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/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_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_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) -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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/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_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 | -------------------------------------------------------------------------------- /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_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_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() -------------------------------------------------------------------------------- /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/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() -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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/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() -------------------------------------------------------------------------------- /04.img_processing/addition_rgba_mask.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | #--① 합성에 사용할 영상 읽기, 전경 영상은 4채널 png 파일 5 | img_fg = cv2.imread('../img/opencv_logo.png', cv2.IMREAD_UNCHANGED) 6 | img_bg = cv2.imread('../img/girl.jpg') 7 | 8 | #--② 알파채널을 이용해서 마스크와 역마스크 생성 9 | _, mask = cv2.threshold(img_fg[:,:,3], 1, 255, cv2.THRESH_BINARY) 10 | mask_inv = cv2.bitwise_not(mask) 11 | 12 | #--③ 전경 영상 크기로 배경 영상에서 ROI 잘라내기 13 | img_fg = cv2.cvtColor(img_fg, cv2.COLOR_BGRA2BGR) 14 | h, w = img_fg.shape[:2] 15 | roi = img_bg[10:10+h, 10:10+w ] 16 | 17 | #--④ 마스크 이용해서 오려내기 18 | masked_fg = cv2.bitwise_and(img_fg, img_fg, mask=mask) 19 | masked_bg = cv2.bitwise_and(roi, roi, mask=mask_inv) 20 | 21 | #--⑥ 이미지 합성 22 | added = masked_fg + masked_bg 23 | img_bg[10:10+h, 10:10+w] = added 24 | 25 | cv2.imshow('mask', mask) 26 | cv2.imshow('mask_inv', mask_inv) 27 | cv2.imshow('masked_fg', masked_fg) 28 | cv2.imshow('masked_bg', masked_bg) 29 | cv2.imshow('added', added) 30 | cv2.imshow('result', img_bg) 31 | cv2.waitKey() 32 | 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/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 | -------------------------------------------------------------------------------- /04.img_processing/bgr2gray.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | img = cv2.imread('../img/girl.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/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 | -------------------------------------------------------------------------------- /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/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/bitwise_masking.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_like(img) 9 | cv2.circle(mask, (150,140), 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() -------------------------------------------------------------------------------- /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() -------------------------------------------------------------------------------- /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_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() -------------------------------------------------------------------------------- /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() -------------------------------------------------------------------------------- /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() -------------------------------------------------------------------------------- /04.img_processing/cropped.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/04.img_processing/cropped.jpg -------------------------------------------------------------------------------- /04.img_processing/cropped2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/04.img_processing/cropped2.jpg -------------------------------------------------------------------------------- /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() -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | 28 | bp = np.minimum(bp, 1) 29 | bp = bp.reshape(hsv_img.shape[:2]) 30 | cv2.normalize(bp,bp, 0, 255, cv2.NORM_MINMAX) 31 | bp = bp.astype(np.uint8) 32 | #--⑩ 역 투영 결과로 마스킹해서 결과 출력 33 | masking(bp,'result_manual') 34 | 35 | # OpenCV API로 구현한 함수 ---⑪ 36 | def backProject_cv(hist_roi): 37 | # 역투영 함수 호출 ---⑫ 38 | bp = cv2.calcBackProject([hsv_img], [0, 1], hist_roi, [0, 180, 0, 256], 1) 39 | # 역 투영 결과로 마스킹해서 결과 출력 ---⑬ 40 | masking(bp,'result_cv') 41 | 42 | # ROI 선택 ---① 43 | (x,y,w,h) = cv2.selectROI(win_name, img, False) 44 | if w > 0 and h > 0: 45 | #roi = draw[y:y+h, x:x+w] 46 | roi = img[y:y+h, x:x+w] 47 | cv2.rectangle(draw, (x, y), (x+w, y+h), (0,0,255), 2) 48 | #--② 선택한 ROI를 HSV 컬러 스페이스로 변경 49 | hsv_roi = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV) 50 | #--③ H,S 채널에 대한 히스토그램 계산 51 | hist_roi = cv2.calcHist([hsv_roi],[0, 1], None, [180, 256], [0, 180, 0, 256] ) 52 | #--④ ROI의 히스토그램을 매뉴얼 구현함수와 OpenCV 이용하는 함수에 각각 전달 53 | backProject_manual(hist_roi) 54 | backProject_cv(hist_roi) 55 | cv2.imshow(win_name, draw) 56 | cv2.waitKey() 57 | 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() -------------------------------------------------------------------------------- /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() -------------------------------------------------------------------------------- /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/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 | 8 | #--② YUV 컬러 스케일의 첫번째 채널에 대해서 이퀄라이즈 적용 9 | img_yuv[:,:,0] = cv2.equalizeHist(img_yuv[:,:,0]) 10 | 11 | #--③ 컬러 스케일을 YUV에서 BGR로 변경 12 | img2 = cv2.cvtColor(img_yuv, cv2.COLOR_YUV2BGR) 13 | 14 | cv2.imshow('Before', img) 15 | cv2.imshow('After', img2) 16 | cv2.waitKey() 17 | 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,255]) 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 | -------------------------------------------------------------------------------- /04.img_processing/histo_normalize.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | import matplotlib.pylab as plt 4 | 5 | #--① 그레이 스케일로 영상 읽기 6 | img = cv2.imread('../img/abnormal.jpg', cv2.IMREAD_GRAYSCALE) 7 | 8 | #--② 직접 연산한 정규화 9 | img_f = img.astype(np.float32) 10 | img_norm = ((img_f - img_f.min()) * (255) / (img_f.max() - img_f.min())) 11 | img_norm = img_norm.astype(np.uint8) 12 | 13 | #--③ OpenCV API를 이용한 정규화 14 | img_norm2 = cv2.normalize(img, None, 0, 255, cv2.NORM_MINMAX) 15 | 16 | #--④ 히스토그램 계산 17 | hist = cv2.calcHist([img], [0], None, [256], [0, 255]) 18 | hist_norm = cv2.calcHist([img_norm], [0], None, [256], [0, 255]) 19 | hist_norm2 = cv2.calcHist([img_norm2], [0], None, [256], [0, 255]) 20 | 21 | cv2.imshow('Before', img) 22 | cv2.imshow('Manual', img_norm) 23 | cv2.imshow('cv2.normalize()', img_norm2) 24 | 25 | hists = {'Before' : hist, 'Manual':hist_norm, 'cv2.normalize()':hist_norm2} 26 | for i, (k, v) in enumerate(hists.items()): 27 | plt.subplot(1,3,i+1) 28 | plt.title(k) 29 | plt.plot(v) 30 | plt.show() 31 | 32 | -------------------------------------------------------------------------------- /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, 255]) 14 | plt.plot(hist, color = color) 15 | plt.show() 16 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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() -------------------------------------------------------------------------------- /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/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() -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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.imshow('img', img) 13 | cv2.waitKey(0) 14 | cv2.destroyAllWindows() 15 | -------------------------------------------------------------------------------- /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() -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /04.img_processing/threshold_adpted.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | import matplotlib.pyplot as plt 4 | 5 | blk_size = 9 # 블럭 사이즈 6 | C = 5 # 차감 상수 7 | img = cv2.imread('../img/sudoku.png', cv2.IMREAD_GRAYSCALE) # 그레이 스케일로 읽기 8 | 9 | # ---① 오츠의 알고리즘으로 단일 경계 값을 전체 이미지에 적용 10 | ret, th1 = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU) 11 | 12 | # ---② 어뎁티드 쓰레시홀드를 평균과 가우시안 분포로 각각 적용 13 | th2 = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_MEAN_C,\ 14 | cv2.THRESH_BINARY, blk_size, C) 15 | th3 = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, \ 16 | cv2.THRESH_BINARY, blk_size, C) 17 | 18 | # ---③ 결과를 Matplot으로 출력 19 | imgs = {'Original': img, 'Global-Otsu:%d'%ret:th1, \ 20 | 'Adapted-Mean':th2, 'Adapted-Gaussian': th3} 21 | for i, (k, v) in enumerate(imgs.items()): 22 | plt.subplot(2,2,i+1) 23 | plt.title(k) 24 | plt.imshow(v,'gray') 25 | plt.xticks([]),plt.yticks([]) 26 | 27 | plt.show() 28 | -------------------------------------------------------------------------------- /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 | 16 | for i, (key, value) in enumerate(imgs.items()): 17 | plt.subplot(2,3, i+1) 18 | plt.title(key) 19 | plt.imshow(value, cmap='gray') 20 | plt.xticks([]); plt.yticks([]) 21 | 22 | plt.show() 23 | -------------------------------------------------------------------------------- /04.img_processing/threshold_flag_cvshow.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 | 16 | for i, (key, value) in enumerate(imgs.items()): 17 | cv2.imshow(key, value) 18 | if i==3: 19 | print(value[-1, -1]) 20 | 21 | cv2.waitKey() 22 | cv2.destroyAllWindows() 23 | -------------------------------------------------------------------------------- /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() -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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() -------------------------------------------------------------------------------- /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('affin', dst) 26 | cv2.waitKey(0) 27 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /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() -------------------------------------------------------------------------------- /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/girl.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() -------------------------------------------------------------------------------- /05.geometric_transform/remap_flip.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | import time 4 | 5 | img = cv2.imread('../img/girl.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_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 = 2 # 볼록, 오목 지수 (오목 : 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 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() -------------------------------------------------------------------------------- /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.5, fy=0.5, \ 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 | -------------------------------------------------------------------------------- /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 | contours, hierachy = cv2.findContours(th, cv2.RETR_EXTERNAL, \ 13 | cv2.CHAIN_APPROX_SIMPLE)[-2:] 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 | -------------------------------------------------------------------------------- /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 | contours, hr = cv2.findContours(th, cv2.RETR_EXTERNAL, \ 11 | cv2.CHAIN_APPROX_SIMPLE)[-2:] 12 | contr = contours[0] 13 | print(type(contr), contr.shape, contr.dtype) 14 | 15 | # 감싸는 사각형 표시(검정색) 16 | x,y,w,h = cv2.boundingRect(contr) 17 | cv2.rectangle(img, (x,y), (x+w, y+h), (0,0,0), 3) 18 | 19 | # 최소한의 사각형 표시(초록색) 20 | rect = cv2.minAreaRect(contr) 21 | box = cv2.boxPoints(rect) # 중심점과 각도를 4개의 꼭지점 좌표로 변환 22 | box = np.int0(box) # 정수로 변환 23 | cv2.drawContours(img, [box], -1, (0,255,0), 3) 24 | 25 | # 최소한의 원 표시(파랑색) 26 | (x,y), radius = cv2.minEnclosingCircle(contr) 27 | cv2.circle(img, (int(x), int(y)), int(radius), (255,0,0), 2) 28 | 29 | # 최소한의 삼각형 표시(분홍색) 30 | ret, tri = cv2.minEnclosingTriangle(np.float32(contr)) 31 | cv2.polylines(img, [np.int32(tri)], True, (255,0,255), 2) 32 | 33 | # 최소한의 타원 표시(노랑색) 34 | ellipse = cv2.fitEllipse(contr) 35 | cv2.ellipse(img, ellipse, (0,255,255), 3) 36 | 37 | # 중심점 통과하는 직선 표시(빨강색) 38 | vx,vy,x,y = cv2.fitLine(contr, cv2.DIST_L2,0,0.01,0.01) 39 | cols,rows = img.shape[:2] 40 | cv2.line(img, (0, int(0-x*(vy/vx) + y)), (cols-1, int((cols-x)*(vy/vx) + y)), \ 41 | (0,0,255),2) 42 | 43 | # 결과 출력 44 | cv2.imshow('Bound Fit shapes', img) 45 | cv2.waitKey(0) 46 | 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 | contours, heiarchy = cv2.findContours(th, cv2.RETR_EXTERNAL, \ 12 | cv2.CHAIN_APPROX_SIMPLE)[-2:] 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_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 | contour, hierarchy = cv2.findContours(imthres, cv2.RETR_EXTERNAL, \ 14 | cv2.CHAIN_APPROX_NONE)[-2:] 15 | # 가장 바깥쪽 컨투어에 대해 꼭지점 좌표만 반환 ---④ 16 | contour2, hierarchy = cv2.findContours(imthres, cv2.RETR_EXTERNAL, \ 17 | cv2.CHAIN_APPROX_SIMPLE)[-2:] 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('CHAIN_APPROX_NONE', img) 38 | cv2.imshow('CHAIN_APPROX_SIMPLE', img2) 39 | cv2.waitKey(0) 40 | 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 | contour, hierarchy = cv2.findContours(imthres, cv2.RETR_EXTERNAL, \ 13 | cv2.CHAIN_APPROX_NONE)[-2:] 14 | # 컨투어 갯수와 계층 트리 출력 --- ② 15 | print(len(contour), hierarchy) 16 | 17 | # 모든 컨투어를 트리 계층 으로 수집 ---③ 18 | contour2, hierarchy = cv2.findContours(imthres, cv2.RETR_TREE, \ 19 | cv2.CHAIN_APPROX_SIMPLE)[-2:] 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() -------------------------------------------------------------------------------- /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)[-2:] 16 | cntrs_shapes, _ = cv2.findContours(shapesTh, cv2.RETR_EXTERNAL, \ 17 | cv2.CHAIN_APPROX_SIMPLE)[-2:] 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 | -------------------------------------------------------------------------------- /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 | contours, hierachy = cv2.findContours(th, cv2.RETR_EXTERNAL, \ 11 | cv2.CHAIN_APPROX_SIMPLE)[-2:] 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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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() -------------------------------------------------------------------------------- /07.segmentation/hough_circle.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | img = cv2.imread('../img/coins_spread1.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.5, 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 | -------------------------------------------------------------------------------- /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] # 거리와 각도wh 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, (int(abs(x0)), int(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() -------------------------------------------------------------------------------- /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() -------------------------------------------------------------------------------- /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() -------------------------------------------------------------------------------- /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() -------------------------------------------------------------------------------- /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)[-2:] 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() -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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() -------------------------------------------------------------------------------- /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 | coord = np.stack((coord[1], coord[0]), axis=-1) 12 | 13 | # 코너 좌표에 동그리미 그리기 ---③ 14 | for x, y in coord: 15 | cv2.circle(img, (x,y), 5, (0,0,255), 1, cv2.LINE_AA) 16 | 17 | # 변화량을 영상으로 표현하기 위해서 0~255로 정규화 ---④ 18 | corner_norm = cv2.normalize(corner, None, 0, 255, cv2.NORM_MINMAX, cv2.CV_8U) 19 | # 화면에 출력 20 | corner_norm = cv2.cvtColor(corner_norm, cv2.COLOR_GRAY2BGR) 21 | merged = np.hstack((corner_norm, img)) 22 | cv2.imshow('Harris Corner', merged) 23 | cv2.waitKey() 24 | 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() -------------------------------------------------------------------------------- /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() -------------------------------------------------------------------------------- /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, extended=True, upright=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() -------------------------------------------------------------------------------- /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) -------------------------------------------------------------------------------- /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) -------------------------------------------------------------------------------- /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() -------------------------------------------------------------------------------- /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() -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /08.match_track/match_flann_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 | # ORB 추출기 생성 9 | detector = cv2.ORB_create() 10 | # 키 포인트와 서술자 추출 11 | kp1, desc1 = detector.detectAndCompute(gray1, None) 12 | kp2, desc2 = detector.detectAndCompute(gray2, None) 13 | 14 | # 인덱스 파라미터 설정 ---① 15 | FLANN_INDEX_LSH = 6 16 | index_params= dict(algorithm = FLANN_INDEX_LSH, 17 | table_number = 6, 18 | key_size = 12, 19 | multi_probe_level = 1) 20 | # 검색 파라미터 설정 ---② 21 | search_params=dict(checks=32) 22 | # Flann 매처 생성 ---③ 23 | matcher = cv2.FlannBasedMatcher(index_params, search_params) 24 | # 매칭 계산 ---④ 25 | matches = matcher.match(desc1, desc2) 26 | # 매칭 그리기 27 | res = cv2.drawMatches(img1, kp1, img2, kp2, matches, None, \ 28 | flags=cv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS) 29 | # 결과 출력 30 | cv2.imshow('Flann + ORB', res) 31 | cv2.waitKey() 32 | 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() -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /08.match_track/match_good_knn.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_HAMMING2) 14 | # knnMatch, k=2 ---③ 15 | matches = matcher.knnMatch(desc1, desc2, 2) 16 | 17 | # 첫번재 이웃의 거리가 두 번째 이웃 거리의 75% 이내인 것만 추출---⑤ 18 | ratio = 0.75 19 | good_matches = [first for first,second in matches \ 20 | if first.distance < second.distance * ratio] 21 | print('matches:%d/%d' %(len(good_matches),len(matches))) 22 | 23 | # 좋은 매칭만 그리기 24 | res = cv2.drawMatches(img1, kp1, img2, kp2, good_matches, None, \ 25 | flags=cv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS) 26 | # 결과 출력 27 | cv2.imshow('Matching', res) 28 | cv2.waitKey() 29 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /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 | 21 | # 좋은 매칭점의 queryIdx로 원본 영상의 좌표 구하기 ---③ 22 | src_pts = np.float32([ kp1[m.queryIdx].pt for m in good_matches ]) 23 | # 좋은 매칭점의 trainIdx로 대상 영상의 좌표 구하기 ---④ 24 | dst_pts = np.float32([ kp2[m.trainIdx].pt for m in good_matches ]) 25 | # 원근 변환 행렬 구하기 ---⑤ 26 | mtrx, mask = cv2.findHomography(src_pts, dst_pts) 27 | # 원본 영상 크기로 변환 영역 좌표 생성 ---⑥ 28 | h,w, = img1.shape[:2] 29 | pts = np.float32([ [[0,0]],[[0,h-1]],[[w-1,h-1]],[[w-1,0]] ]) 30 | # 원본 영상 좌표를 원근 변환 ---⑦ 31 | dst = cv2.perspectiveTransform(pts,mtrx) 32 | # 변환 좌표 영역을 대상 영상에 그리기 ---⑧ 33 | img2 = cv2.polylines(img2,[np.int32(dst)],True,255,3, cv2.LINE_AA) 34 | 35 | # 좋은 매칭 그려서 출력 ---⑨ 36 | res = cv2.drawMatches(img1, kp1, img2, kp2, good_matches, None, \ 37 | flags=cv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS) 38 | cv2.imshow('Matching Homography', res) 39 | cv2.waitKey() 40 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /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() -------------------------------------------------------------------------------- /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() -------------------------------------------------------------------------------- /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() -------------------------------------------------------------------------------- /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() -------------------------------------------------------------------------------- /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() -------------------------------------------------------------------------------- /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().astype(np.int32) 36 | nx,ny = n.ravel().astype(np.int32) 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_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() -------------------------------------------------------------------------------- /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() -------------------------------------------------------------------------------- /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() -------------------------------------------------------------------------------- /09.ml/haar_face_cam.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | 3 | # 얼굴과 검출을 위한 케스케이드 분류기 생성 4 | face_cascade = cv2.CascadeClassifier('./data/haarcascade_frontalface_default.xml') 5 | eye_cascade = cv2.CascadeClassifier('./data/haarcascade_eye.xml') 6 | 7 | # 카메라 캡쳐 활성화 8 | cap = cv2.VideoCapture(0) 9 | while cap.isOpened(): 10 | ret, img = cap.read() # 프레임 읽기 11 | if ret: 12 | gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 13 | # 얼굴 검출 14 | faces = face_cascade.detectMultiScale(gray, scaleFactor=1.3, \ 15 | minNeighbors=5, minSize=(80,80)) 16 | for(x,y,w,h) in faces: 17 | cv2.rectangle(img, (x,y), (x+w, y+h), (0, 255,0),2) 18 | roi = gray[y:y+h, x:x+w] 19 | # 눈 검출 20 | eyes = eye_cascade.detectMultiScale(roi) 21 | for i, (ex, ey, ew, eh) in enumerate(eyes): 22 | if i >= 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 | -------------------------------------------------------------------------------- /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 | # 원본 영상의 형태로 변환 ---⑦ 18 | res = res.reshape((img.shape)) 19 | # 결과 출력 ---⑧ 20 | merged = np.hstack((img, res)) 21 | cv2.imshow('KMeans Color',merged) 22 | cv2.waitKey(0) 23 | 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() -------------------------------------------------------------------------------- /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() -------------------------------------------------------------------------------- /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 | contours, _ = cv2.findContours(gray, cv2.RETR_EXTERNAL, \ 21 | cv2.CHAIN_APPROX_SIMPLE)[-2:] 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() -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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_random.py: -------------------------------------------------------------------------------- 1 | import cv2, numpy as np, matplotlib.pyplot as plt 2 | 3 | # 0~200 사이의 무작위 수 50x2개 데이타 생성 ---① 4 | red = np.random.randint(0, 110, (25,2)).astype(np.float32) 5 | blue = np.random.randint(90, 200, (25, 2)).astype(np.float32) 6 | trainData = np.vstack((red, blue)) 7 | 8 | # 50x1개 레이블 생성 ---② 9 | labels = np.zeros((50,1), dtype=np.float32) # 0:빨강색 삼각형 10 | labels[25:] = 1 # 1:파랑색 사각형 11 | 12 | # 레이블 값 0과 같은 자리는 red, 1과 같은 자리는 blue로 분류해서 표시 13 | plt.scatter(red[:,0], red[:,1], 80, 'r', '^') # 빨강색 삼각형 14 | plt.scatter(blue[:,0], blue[:,1], 80, 'b', 's')# 파랑색 사각형 15 | 16 | # 0 ~ 200 사이의 1개의 새로운 무작위 수 생성 ---③ 17 | newcomer = np.random.randint(0,200,(1,2)).astype(np.float32) 18 | plt.scatter(newcomer[:,0],newcomer[:,1],80,'g','o') # 초록색 원 19 | 20 | # KNearest 알고리즘 객체 생성 ---④ 21 | knn = cv2.ml.KNearest_create() 22 | # train, 행 단위 샘플 ---⑤ 23 | knn.train(trainData, cv2.ml.ROW_SAMPLE, labels) 24 | # 예측 ---⑥ 25 | #ret, results = knn.predict(newcomer) 26 | ret, results, neighbours ,dist = knn.findNearest(newcomer, 3)#K=3 27 | # 결과 출력 28 | print('ret:%s, result:%s, negibours:%s, distance:%s' \ 29 | %(ret,results, neighbours, dist)) 30 | plt.annotate('red' if ret==0.0 else 'blue', xy=newcomer[0], \ 31 | xytext=(newcomer[0]+1)) 32 | plt.show() -------------------------------------------------------------------------------- /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.") -------------------------------------------------------------------------------- /09.ml/lbp_face2_train.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | import os, glob 4 | 5 | # 변수 설정 --- ① 6 | base_dir = './faces' 7 | train_data, train_labels = [], [] 8 | 9 | 10 | dirs = [d for d in glob.glob(base_dir+"/*") if os.path.isdir(d)] 11 | print('Collecting train data set:') 12 | for dir in dirs: 13 | # name_id 형식에서 id를 분리 ---② 14 | id = dir.split('_')[1] 15 | files = glob.glob(dir+'/*.jpg') 16 | print('\t path:%s, %dfiles'%(dir, len(files))) 17 | for file in files: 18 | img = cv2.imread(file, cv2.IMREAD_GRAYSCALE) 19 | # 이미지는 train_data, 아이디는 train_lables에 저장 ---③ 20 | train_data.append(np.asarray(img, dtype=np.uint8)) 21 | train_labels.append(int(id)) 22 | 23 | # NumPy 배열로 변환 ---④ 24 | train_data = np.asarray(train_data) 25 | train_labels = np.int32(train_labels) 26 | 27 | # LBP 얼굴인식기 생성 및 훈련 ---⑤ 28 | print('Starting LBP Model training...') 29 | model = cv2.face.LBPHFaceRecognizer_create() 30 | model.train(train_data, train_labels) 31 | model.write('./faces/all_face.xml') 32 | print("Model trained successfully!") 33 | -------------------------------------------------------------------------------- /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/plane_bike_dict.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/09.ml/plane_bike_dict.npy -------------------------------------------------------------------------------- /09.ml/plane_bike_dict_4000.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/09.ml/plane_bike_dict_4000.npy -------------------------------------------------------------------------------- /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 | contours, _ = cv2.findContours(gray, cv2.RETR_EXTERNAL, \ 21 | cv2.CHAIN_APPROX_SIMPLE)[-2:] 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() -------------------------------------------------------------------------------- /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() -------------------------------------------------------------------------------- /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() -------------------------------------------------------------------------------- /09.ml/workshop_face_mosaic.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | 3 | rate = 15 # 모자이크에 사용할 축소 비율 (1/rate) 4 | #하르 케스케이드 검출기 생성 --- 5 | face_cascade = cv2.CascadeClassifier('./data/haarcascade_frontalface_default.xml') 6 | 7 | cap = cv2.VideoCapture(0) 8 | while cap.isOpened(): 9 | ret, frame = cap.read() 10 | gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) 11 | faces = face_cascade.detectMultiScale(gray,scaleFactor=1.3, minNeighbors=5, \ 12 | minSize=(80,80)) 13 | for (x,y,w,h) in faces: 14 | x = x - 5 15 | y = y - 15 16 | w = w + 10 17 | h = h + 30 18 | roi = frame[y:y+h, x:x+w] # 관심영역 지정 19 | roi = cv2.resize(roi, (w//rate, h//rate)) # 1/rate 비율로 축소 20 | # 원래 크기로 확대 21 | roi = cv2.resize(roi, (w,h), interpolation=cv2.INTER_AREA) 22 | frame[y:y+h, x:x+w] = roi # 원본 이미지에 적용 23 | cv2.imshow('mosaic', frame) 24 | if cv2.waitKey(1) == 27: 25 | break 26 | cap.release() 27 | cv2.destroyAllWindows() -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /10.apdx/face_delauney_triangle.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | import dlib 4 | 5 | # 얼굴 검출기와 랜드마크 검출기 생성 --- ① 6 | detector = dlib.get_frontal_face_detector() 7 | predictor = dlib.shape_predictor('./shape_predictor_68_face_landmarks.dat') 8 | 9 | img = cv2.imread("../img/man_face.jpg") 10 | h, w = img.shape[:2] 11 | gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 12 | # 얼굴 영역 검출 --- ② 13 | rects = faces = detector(gray) 14 | 15 | points = [] 16 | for rect in rects: 17 | # 랜드마크 검출 --- ③ 18 | shape = predictor(gray, rect) 19 | for i in range(68): 20 | part = shape.part(i) 21 | points.append((part.x, part.y)) 22 | 23 | 24 | # 들로네 삼각 분할 객체 생성 --- ④ 25 | x,y,w,h = cv2.boundingRect(np.float32(points)) 26 | subdiv = cv2.Subdiv2D((x,y,x+w,y+h)) 27 | # 랜드마크 좌표 추가 --- ⑤ 28 | subdiv.insert(points) 29 | # 들로네 삼각형 좌표 계산 --- ⑥ 30 | triangleList = subdiv.getTriangleList() 31 | # 들로네 삼각형 그리기 --- ⑦ 32 | h, w = img.shape[:2] 33 | cnt = 0 34 | for t in triangleList : 35 | pts = t.reshape(-1,2).astype(np.int32) 36 | # 좌표 중에 이미지 영역을 벗어나는 것을 제외(음수 등) ---⑧ 37 | if (pts < 0).sum() or (pts[:, 0] > w).sum() or (pts[:, 1] > h).sum(): 38 | print(pts) 39 | continue 40 | cv2.polylines(img, [pts], True, (255, 255,255), 1, cv2.LINE_AA) 41 | cnt+=1 42 | print(cnt) 43 | 44 | 45 | cv2.imshow("Delaunay",img) 46 | cv2.waitKey(0) -------------------------------------------------------------------------------- /10.apdx/face_landmark.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import dlib 3 | 4 | # 얼굴 검출기와 랜드마크 검출기 생성 --- ① 5 | detector = dlib.get_frontal_face_detector() 6 | predictor = dlib.shape_predictor('./shape_predictor_68_face_landmarks.dat') 7 | 8 | img = cv2.imread("../img/man_face.jpg") 9 | gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 10 | # 얼굴 영역 검출 --- ② 11 | faces = detector(gray) 12 | for rect in faces: 13 | # 얼굴 영역을 좌표로 변환 후 사각형 표시 --- ③ 14 | x,y = rect.left(), rect.top() 15 | w,h = rect.right()-x, rect.bottom()-y 16 | cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 1) 17 | 18 | # 얼굴 랜드마크 검출 --- ④ 19 | shape = predictor(gray, rect) 20 | for i in range(68): 21 | # 부위별 좌표 추출 및 표시 --- ⑤ 22 | part = shape.part(i) 23 | cv2.circle(img, (part.x, part.y), 2, (0, 0, 255), -1) 24 | cv2.putText(img, str(i), (part.x, part.y), cv2.FONT_HERSHEY_PLAIN, \ 25 | 0.5,(255,255,255), 1, cv2.LINE_AA) 26 | 27 | cv2.imshow("face landmark", img) 28 | cv2.waitKey(0) -------------------------------------------------------------------------------- /10.apdx/face_landmark_cam.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import dlib 3 | 4 | # 얼굴 검출기와 랜드마크 검출기 생성 --- ① 5 | detector = dlib.get_frontal_face_detector() 6 | predictor = dlib.shape_predictor('./shape_predictor_68_face_landmarks.dat') 7 | 8 | cap = cv2.VideoCapture(0) 9 | #cap.set(cv2.cv2.CAP_PROP_FRAME_WIDTH, 480) 10 | #cap.set(cv2.cv2.CAP_PROP_FRAME_HEIGHT, 320) 11 | 12 | while cap.isOpened(): 13 | ret, img = cap.read() 14 | if not ret: 15 | print('no frame.');break 16 | gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 17 | # 얼굴 영역 검출 --- ② 18 | faces = detector(gray) 19 | for rect in faces: 20 | # 얼굴 영역을 좌표로 변환 후 사각형 표시 --- ③ 21 | x,y = rect.left(), rect.top() 22 | w,h = rect.right()-x, rect.bottom()-y 23 | cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 1) 24 | 25 | # 얼굴 랜드마크 검출 --- ④ 26 | shape = predictor(gray, rect) 27 | for i in range(68): 28 | # 부위별 좌표 추출 및 표시 --- ⑤ 29 | part = shape.part(i) 30 | cv2.circle(img, (part.x, part.y), 2, (0, 0, 255), -1) 31 | # cv2.putText(img, str(i), (part.x, part.y), cv2.FONT_HERSHEY_PLAIN, 0.5,(255,255,255), 1, cv2.LINE_AA) 32 | 33 | cv2.imshow("face landmark", img) 34 | if cv2.waitKey(1)== 27: 35 | break 36 | cap.release() 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 파이썬으로 만드는 OpenCV 프로젝트 2 | **(간단한 영상 입출력부터 머신러닝까지)** 3 | 4 | 이 저장소는 2019년 인사이트출판사에서 출간된 책 **"파이썬으로 만드는 OpenCV 프로젝트"**에 포함된 예제 코드를 담고 있습니다. 5 | 6 | 7 | 8 | 9 | 10 | * 책 구매 11 | * http://www.yes24.com/Product/Goods/71534451 12 | * https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=187390704 13 | * http://www.kyobobook.co.kr/product/detailViewKor.laf?ejkGb=KOR&mallGb=KOR&barcode=9788966262410&orderClick=LEa&Kc= 14 | -------------------------------------------------------------------------------- /img/4027.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/4027.png -------------------------------------------------------------------------------- /img/4star.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/4star.jpg -------------------------------------------------------------------------------- /img/5shapes.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/5shapes.jpg -------------------------------------------------------------------------------- /img/abnormal.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/abnormal.jpg -------------------------------------------------------------------------------- /img/actor.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/actor.jpg -------------------------------------------------------------------------------- /img/aircraft.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/aircraft.jpg -------------------------------------------------------------------------------- /img/bad_rect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/bad_rect.png -------------------------------------------------------------------------------- /img/big_buck.avi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/big_buck.avi -------------------------------------------------------------------------------- /img/blank_500.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/blank_500.jpg -------------------------------------------------------------------------------- /img/books/book0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book0.jpg -------------------------------------------------------------------------------- /img/books/book1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book1.jpg -------------------------------------------------------------------------------- /img/books/book10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book10.jpg -------------------------------------------------------------------------------- /img/books/book11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book11.jpg -------------------------------------------------------------------------------- /img/books/book12.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book12.jpg -------------------------------------------------------------------------------- /img/books/book13.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book13.jpg -------------------------------------------------------------------------------- /img/books/book14.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book14.jpg -------------------------------------------------------------------------------- /img/books/book15.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book15.jpg -------------------------------------------------------------------------------- /img/books/book16.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book16.jpg -------------------------------------------------------------------------------- /img/books/book17.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book17.jpg -------------------------------------------------------------------------------- /img/books/book18.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book18.jpg -------------------------------------------------------------------------------- /img/books/book19.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book19.jpg -------------------------------------------------------------------------------- /img/books/book2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book2.jpg -------------------------------------------------------------------------------- /img/books/book20.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book20.jpg -------------------------------------------------------------------------------- /img/books/book21.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book21.jpg -------------------------------------------------------------------------------- /img/books/book22.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book22.jpg -------------------------------------------------------------------------------- /img/books/book23.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book23.jpg -------------------------------------------------------------------------------- /img/books/book24.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book24.jpg -------------------------------------------------------------------------------- /img/books/book25.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book25.jpg -------------------------------------------------------------------------------- /img/books/book26.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book26.jpg -------------------------------------------------------------------------------- /img/books/book27.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book27.jpg -------------------------------------------------------------------------------- /img/books/book28.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book28.jpg -------------------------------------------------------------------------------- /img/books/book29.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book29.jpg -------------------------------------------------------------------------------- /img/books/book3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book3.jpg -------------------------------------------------------------------------------- /img/books/book30.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book30.jpg -------------------------------------------------------------------------------- /img/books/book31.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book31.jpg -------------------------------------------------------------------------------- /img/books/book32.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book32.jpg -------------------------------------------------------------------------------- /img/books/book33.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book33.jpg -------------------------------------------------------------------------------- /img/books/book34.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book34.jpg -------------------------------------------------------------------------------- /img/books/book35.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book35.jpg -------------------------------------------------------------------------------- /img/books/book36.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book36.jpg -------------------------------------------------------------------------------- /img/books/book37.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book37.jpg -------------------------------------------------------------------------------- /img/books/book38.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book38.jpg -------------------------------------------------------------------------------- /img/books/book39.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book39.jpg -------------------------------------------------------------------------------- /img/books/book4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book4.jpg -------------------------------------------------------------------------------- /img/books/book40.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book40.jpg -------------------------------------------------------------------------------- /img/books/book41.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book41.jpg -------------------------------------------------------------------------------- /img/books/book42.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book42.jpg -------------------------------------------------------------------------------- /img/books/book43.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book43.jpg -------------------------------------------------------------------------------- /img/books/book44.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book44.jpg -------------------------------------------------------------------------------- /img/books/book45.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book45.jpg -------------------------------------------------------------------------------- /img/books/book46.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book46.jpg -------------------------------------------------------------------------------- /img/books/book47.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book47.jpg -------------------------------------------------------------------------------- /img/books/book48.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book48.jpg -------------------------------------------------------------------------------- /img/books/book49.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book49.jpg -------------------------------------------------------------------------------- /img/books/book5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book5.jpg -------------------------------------------------------------------------------- /img/books/book50.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book50.jpg -------------------------------------------------------------------------------- /img/books/book51.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book51.jpg -------------------------------------------------------------------------------- /img/books/book52.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book52.jpg -------------------------------------------------------------------------------- /img/books/book53.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book53.jpg -------------------------------------------------------------------------------- /img/books/book54.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book54.jpg -------------------------------------------------------------------------------- /img/books/book55.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book55.jpg -------------------------------------------------------------------------------- /img/books/book56.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book56.jpg -------------------------------------------------------------------------------- /img/books/book57.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book57.jpg -------------------------------------------------------------------------------- /img/books/book58.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book58.jpg -------------------------------------------------------------------------------- /img/books/book59.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book59.jpg -------------------------------------------------------------------------------- /img/books/book6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book6.jpg -------------------------------------------------------------------------------- /img/books/book60.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book60.jpg -------------------------------------------------------------------------------- /img/books/book61.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book61.jpg -------------------------------------------------------------------------------- /img/books/book62.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book62.jpg -------------------------------------------------------------------------------- /img/books/book63.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book63.jpg -------------------------------------------------------------------------------- /img/books/book64.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book64.jpg -------------------------------------------------------------------------------- /img/books/book65.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book65.jpg -------------------------------------------------------------------------------- /img/books/book66.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book66.jpg -------------------------------------------------------------------------------- /img/books/book67.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book67.jpg -------------------------------------------------------------------------------- /img/books/book68.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book68.jpg -------------------------------------------------------------------------------- /img/books/book69.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book69.jpg -------------------------------------------------------------------------------- /img/books/book7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book7.jpg -------------------------------------------------------------------------------- /img/books/book70.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book70.jpg -------------------------------------------------------------------------------- /img/books/book71.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book71.jpg -------------------------------------------------------------------------------- /img/books/book72.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book72.jpg -------------------------------------------------------------------------------- /img/books/book8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book8.jpg -------------------------------------------------------------------------------- /img/books/book9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/books/book9.jpg -------------------------------------------------------------------------------- /img/boy_face.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/boy_face.jpg -------------------------------------------------------------------------------- /img/bright.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/bright.jpg -------------------------------------------------------------------------------- /img/bright_abnormal.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/bright_abnormal.jpg -------------------------------------------------------------------------------- /img/children.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/children.jpg -------------------------------------------------------------------------------- /img/coin_test/coin1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/coin_test/coin1.jpg -------------------------------------------------------------------------------- /img/coin_test/coin10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/coin_test/coin10.jpg -------------------------------------------------------------------------------- /img/coin_test/coin11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/coin_test/coin11.jpg -------------------------------------------------------------------------------- /img/coin_test/coin12.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/coin_test/coin12.jpg -------------------------------------------------------------------------------- /img/coin_test/coin13.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/coin_test/coin13.jpg -------------------------------------------------------------------------------- /img/coin_test/coin2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/coin_test/coin2.jpg -------------------------------------------------------------------------------- /img/coin_test/coin3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/coin_test/coin3.jpg -------------------------------------------------------------------------------- /img/coin_test/coin4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/coin_test/coin4.jpg -------------------------------------------------------------------------------- /img/coin_test/coin5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/coin_test/coin5.jpg -------------------------------------------------------------------------------- /img/coin_test/coin6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/coin_test/coin6.jpg -------------------------------------------------------------------------------- /img/coin_test/coin7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/coin_test/coin7.jpg -------------------------------------------------------------------------------- /img/coin_test/coin8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/coin_test/coin8.jpg -------------------------------------------------------------------------------- /img/coin_test/coin9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/coin_test/coin9.jpg -------------------------------------------------------------------------------- /img/coins_connected.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/coins_connected.jpg -------------------------------------------------------------------------------- /img/coins_spread1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/coins_spread1.jpg -------------------------------------------------------------------------------- /img/cube.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/cube.jpg -------------------------------------------------------------------------------- /img/digits.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/digits.png -------------------------------------------------------------------------------- /img/dr_ochanomizu.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/dr_ochanomizu.jpg -------------------------------------------------------------------------------- /img/drawing.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/drawing.jpg -------------------------------------------------------------------------------- /img/figures.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/figures.jpg -------------------------------------------------------------------------------- /img/figures2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/figures2.jpg -------------------------------------------------------------------------------- /img/figures3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/figures3.jpg -------------------------------------------------------------------------------- /img/figures4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/figures4.jpg -------------------------------------------------------------------------------- /img/figures4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/figures4.png -------------------------------------------------------------------------------- /img/figures5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/figures5.jpg -------------------------------------------------------------------------------- /img/fish.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/fish.jpg -------------------------------------------------------------------------------- /img/flower_wall.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/flower_wall.jpg -------------------------------------------------------------------------------- /img/full_body.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/full_body.jpg -------------------------------------------------------------------------------- /img/gaussian_noise.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/gaussian_noise.jpg -------------------------------------------------------------------------------- /img/girl.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/girl.jpg -------------------------------------------------------------------------------- /img/girl_face.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/girl_face.jpg -------------------------------------------------------------------------------- /img/girl_gray.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/girl_gray.jpg -------------------------------------------------------------------------------- /img/gray_gradient.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/gray_gradient.jpg -------------------------------------------------------------------------------- /img/hand.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/hand.jpg -------------------------------------------------------------------------------- /img/highway.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/highway.mp4 -------------------------------------------------------------------------------- /img/house.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/house.jpg -------------------------------------------------------------------------------- /img/jetstar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/jetstar.jpg -------------------------------------------------------------------------------- /img/lightning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/lightning.png -------------------------------------------------------------------------------- /img/lion_face.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/lion_face.jpg -------------------------------------------------------------------------------- /img/man_chromakey.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/man_chromakey.jpg -------------------------------------------------------------------------------- /img/man_face.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/man_face.jpg -------------------------------------------------------------------------------- /img/mask_hannibal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/mask_hannibal.png -------------------------------------------------------------------------------- /img/model.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/model.jpg -------------------------------------------------------------------------------- /img/model2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/model2.jpg -------------------------------------------------------------------------------- /img/model3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/model3.jpg -------------------------------------------------------------------------------- /img/moon_gray.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/moon_gray.jpg -------------------------------------------------------------------------------- /img/morph_dot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/morph_dot.png -------------------------------------------------------------------------------- /img/morph_hole.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/morph_hole.png -------------------------------------------------------------------------------- /img/morphological.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/morphological.png -------------------------------------------------------------------------------- /img/motorbike.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/motorbike.jpg -------------------------------------------------------------------------------- /img/motorcycle.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/motorcycle.jpg -------------------------------------------------------------------------------- /img/mountain.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/mountain.jpg -------------------------------------------------------------------------------- /img/my_hand.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/my_hand.jpg -------------------------------------------------------------------------------- /img/opencv_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/opencv_logo.png -------------------------------------------------------------------------------- /img/paper.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/paper.jpg -------------------------------------------------------------------------------- /img/pistol.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/pistol.jpg -------------------------------------------------------------------------------- /img/pump_horse.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/pump_horse.jpg -------------------------------------------------------------------------------- /img/restaurant1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/restaurant1.jpg -------------------------------------------------------------------------------- /img/restaurant2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/restaurant2.jpg -------------------------------------------------------------------------------- /img/robot_arm1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/robot_arm1.jpg -------------------------------------------------------------------------------- /img/robot_arm2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/robot_arm2.jpg -------------------------------------------------------------------------------- /img/salt_pepper_noise.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/salt_pepper_noise.jpg -------------------------------------------------------------------------------- /img/scaned_paper.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/scaned_paper.jpg -------------------------------------------------------------------------------- /img/shapes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/shapes.png -------------------------------------------------------------------------------- /img/shapes_donut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/shapes_donut.png -------------------------------------------------------------------------------- /img/shapestomatch.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/shapestomatch.jpg -------------------------------------------------------------------------------- /img/skull.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/skull.jpg -------------------------------------------------------------------------------- /img/street.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/street.jpg -------------------------------------------------------------------------------- /img/sudoku.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/sudoku.jpg -------------------------------------------------------------------------------- /img/sudoku.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/sudoku.png -------------------------------------------------------------------------------- /img/sunset.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/sunset.jpg -------------------------------------------------------------------------------- /img/taekwon_v.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/taekwon_v.jpg -------------------------------------------------------------------------------- /img/taekwonv1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/taekwonv1.jpg -------------------------------------------------------------------------------- /img/taekwonv2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/taekwonv2.jpg -------------------------------------------------------------------------------- /img/taekwonv3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/taekwonv3.jpg -------------------------------------------------------------------------------- /img/walking.avi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/walking.avi -------------------------------------------------------------------------------- /img/wing_wall.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/wing_wall.jpg -------------------------------------------------------------------------------- /img/yate.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dltpdn/insightbook.opencv_project_python/4f62bc4d084acf575c9f6bfa6d429772072a09bc/img/yate.jpg --------------------------------------------------------------------------------