├── README_images ├── system.png └── histogram.png ├── data ├── 600 │ ├── 1 │ │ └── 600-3-1-1.bmp │ └── 2 │ │ └── 600-3-1-1.bmp └── roi_600_2_all_320240 │ └── 600-3-3-1.bmp ├── README.md └── vein_main.py /README_images/system.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Qingcsai/Finger-Vein-Recognition/HEAD/README_images/system.png -------------------------------------------------------------------------------- /data/600/1/600-3-1-1.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Qingcsai/Finger-Vein-Recognition/HEAD/data/600/1/600-3-1-1.bmp -------------------------------------------------------------------------------- /data/600/2/600-3-1-1.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Qingcsai/Finger-Vein-Recognition/HEAD/data/600/2/600-3-1-1.bmp -------------------------------------------------------------------------------- /README_images/histogram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Qingcsai/Finger-Vein-Recognition/HEAD/README_images/histogram.png -------------------------------------------------------------------------------- /data/roi_600_2_all_320240/600-3-3-1.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Qingcsai/Finger-Vein-Recognition/HEAD/data/roi_600_2_all_320240/600-3-3-1.bmp -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Finger-Vein-Recognition 2 | 3 | ## Background 4 | 5 | My personal project for the final assignment of Class *Machine Vision Application* in SCUT. 6 | 7 | ## Requirements 8 | 9 | * opencv-python 10 | * opencv-contrib-python <= 3.4.0.10 (for SIFT & SURF algorithem can be used.) 11 | * numpy 12 | * matplotlib 13 | 14 | ## Descriptions 15 | 16 | Here is the structure of the whole system: 17 | 18 | ![系统结构图](https://github.com/Qingcsai/Finger-Vein-Recognition/blob/master/README_images/system.png) 19 | 20 | We use the traditional ways to process the images, rather than the deep-learning methods. 21 | 22 | After your running ```vein_main.py```, you should see the histogram of the scores between inter-class and in-class. 23 | 24 | ![特征匹配得分直方图](https://github.com/Qingcsai/Finger-Vein-Recognition/blob/master/README_images/histogram.png) 25 | 26 | So we can set the threshold value to 60 for classification. 27 | 28 | ## Usage 29 | 30 | ``` python 31 | python vein_main.py 32 | ``` 33 | 34 | Besides, you should dive into the file ```vein_main.py```, and adjust the comments for many other usages. 35 | 36 | ## Data preparation 37 | 38 | I didn' t upload all of my own vein data for individual privacy. 39 | You should place your own vein data in the ```./data/600/2``` folder and name it like the format below. 40 | 41 | ``` 42 | ├──data 43 | │ ├── 600 // A Person's vein image 44 | │ │ ├── 1 // the first machine 45 | │ │ ├── 2 // the second machine 46 | │ │ │ ├── 600-1-1-1.bmp 47 | │ │ │ ├── 600-1-2-1.bmp 48 | │ │ │ ├── 600-1-3-1.bmp 49 | │ │ │ ├── ... 50 | │ │ │ ├── 600-2-1-1.bmp 51 | │ │ │ ├── 600-2-2-1.bmp 52 | │ │ │ ├── 600-2-3-1.bmp 53 | │ │ │ ├── ... 54 | │ ├── roi_600_2_all_320240 //saved ROI 55 | │ │ ├── 600-1-1-1.bmp 56 | │ │ ├── 600-1-2-1.bmp 57 | │ │ ├── 600-1-3-1.bmp 58 | │ │ ├── ... 59 | ``` 60 | 61 | ## License 62 | 63 | The MIT License ([MIT](https://mit-license.org/)) 64 | Copyright © 2020 65 | -------------------------------------------------------------------------------- /vein_main.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import cv2 3 | import numpy as np 4 | import matplotlib.pyplot as plt 5 | import math 6 | import numpy 7 | import os 8 | 9 | def first_filter(img): 10 | #均值滤波 11 | img_Blur=cv2.blur(img,(5,5)) 12 | ''' 13 | #高斯滤波 14 | img_GaussianBlur=cv2.GaussianBlur(img,(7,7),0) 15 | #高斯双边滤波 16 | img_bilateralFilter=cv2.bilateralFilter(img,40,75,75) 17 | ''' 18 | return img, img_Blur 19 | 20 | ######################## 21 | #边缘检测 22 | def edge_detection(img): 23 | #img = cv2.imread(file, 0) 24 | #img = cv2.imread("01.jpg", 0) 25 | x = cv2.Sobel(img,cv2.CV_16S,1,0) 26 | y = cv2.Sobel(img,cv2.CV_16S,0,1) 27 | absX = cv2.convertScaleAbs(x)# 转回uint8 28 | absY = cv2.convertScaleAbs(y) 29 | img_edge = cv2.addWeighted(absX,0.5,absY,0.5,0) 30 | ''' 31 | #cv2.imshow("absX", absX) 32 | #cv2.imshow("absY", absY) 33 | #cv2.imshow("Result", img_edge) 34 | #cv2.waitKey(0) 35 | #cv2.destroyAllWindows() 36 | fig = plt.figure(figsize = (30, 30)) 37 | ax1 = fig.add_subplot(1, 2, 1) 38 | ax2 = fig.add_subplot(1, 2, 2) 39 | #ax3 = fig.add_subplot(1, 3, 3) 40 | ax1.imshow(img, cmap = plt.cm.gray) 41 | ax2.imshow(img_edge, cmap = plt.cm.gray) 42 | plt.show() 43 | ''' 44 | return img, img_edge 45 | 46 | ############################################ 47 | #像素二值化 48 | def pixel_polarization(img_edge, img, threshold): # threshold 像素两极化的阈值 49 | for i in range(len(img_edge)): 50 | for j in range(len(img_edge[i,:])): 51 | if img_edge[i][j] > threshold: 52 | img_edge[i][j] = 255 53 | else: 54 | img_edge[i][j] = 0 55 | ''' 56 | fig = plt.figure(figsize = (16, 16)) 57 | ax1 = fig.add_subplot(1, 2, 1) 58 | ax2 = fig.add_subplot(1, 2, 2) 59 | ax1.imshow(img, cmap = plt.cm.gray) 60 | ax2.imshow(img_edge, cmap = plt.cm.gray) 61 | plt.show() 62 | ''' 63 | img_edge_polar = img_edge 64 | return img_edge_polar 65 | 66 | 67 | def positioning_middle_point(img, dst, point_pixel): 68 | h, w = img.shape 69 | w1 = w // 5 # 作为左边竖线的x坐标 70 | w2 = (w // 5) * 4 # 作为右边竖线的x坐标 71 | ''' 72 | print("roi width: ",h, w1, w2) 73 | ''' 74 | low_l = False 75 | high_l = False 76 | while (not low_l or not high_l) and w1 < (w // 2): 77 | for i, pix in enumerate(dst[:, w1]): 78 | if i+1 < (h // 2) and not low_l: 79 | if pix == 255: 80 | low_l = True 81 | lower_left = i 82 | elif i+1 > (h // 2) and not high_l: 83 | h_h = int(h * (3/2) - (i+1)) # 除法会带来小数,因此用int(), h/2开始对称位置找亮点 84 | ''' 85 | print(h_h) 86 | ''' 87 | if dst[h_h, w1] == 255: 88 | high_l = True 89 | higher_left = h_h 90 | if not low_l or not high_l: 91 | w1 = w1 + 2 92 | middle_left = (lower_left + higher_left) // 2 93 | 94 | low_r = False 95 | high_r = False 96 | while (not low_r or not high_r) and w2 > (w // 2): 97 | for i, pix in enumerate(dst[:, w2]): 98 | if i+1 < (h // 2) and not low_r: 99 | if pix == 255: 100 | low_r = True 101 | lower_right = i 102 | elif i+1 > (h // 2) and not high_r: 103 | h_h = int(h * (3/2) - (i+1)) 104 | if dst[h_h, w2] == 255: 105 | high_r = True 106 | higher_right = h_h 107 | if not low_r or not high_r: 108 | w2 = w2 - 2 109 | middle_right = (lower_right + higher_right) // 2 110 | ''' 111 | dst[middle_left, w1] = point_pixel 112 | dst[middle_left+1, w1] = point_pixel 113 | dst[middle_left-1, w1] = point_pixel 114 | dst[middle_left, w1 + 1] = point_pixel 115 | dst[middle_left, w1 - 1] = point_pixel 116 | dst[middle_right, w2] = point_pixel 117 | dst[middle_right+1, w2] = point_pixel 118 | dst[middle_right-1, w2] = point_pixel 119 | dst[middle_right, w2 + 1] = point_pixel 120 | dst[middle_right, w2 - 1] = point_pixel 121 | 122 | fig = plt.figure(figsize = (16, 16)) 123 | ax1 = fig.add_subplot(1, 2, 1) 124 | ax2 = fig.add_subplot(1, 2, 2) 125 | ax1.imshow(img, cmap = plt.cm.gray) 126 | ax2.imshow(dst, cmap = plt.cm.gray) 127 | plt.show() 128 | ''' 129 | return dst, middle_left, middle_right, w1, w2 130 | 131 | ################################# 132 | #旋转矫正 133 | def rotation_correction(img, dst, middle_right, middle_left, w1, w2): 134 | tangent_value = float(middle_right - middle_left) / float(w2 - w1) 135 | rotation_angle = np.arctan(tangent_value)/math.pi*180 136 | (h,w) = img.shape 137 | center = (w // 2,h // 2) 138 | M = cv2.getRotationMatrix2D(center,rotation_angle,1)#旋转缩放矩阵:(旋转中心,旋转角度,缩放因子) 139 | rotated_dst = cv2.warpAffine(dst,M,(w,h)) 140 | rotated_img = cv2.warpAffine(img,M,(w,h)) 141 | ''' 142 | fig = plt.figure(figsize = (16, 16)) 143 | ax1 = fig.add_subplot(1, 3, 1) 144 | ax2 = fig.add_subplot(1, 3, 2) 145 | ax3 = fig.add_subplot(1, 3, 3) 146 | ax1.imshow(img, cmap = plt.cm.gray) 147 | ax2.imshow(rotated_dst, cmap = plt.cm.gray) 148 | ax3.imshow(rotated_img, cmap = plt.cm.gray) 149 | plt.show() 150 | ''' 151 | return rotated_dst, rotated_img 152 | 153 | 154 | def roi(rotated_img, rotated_edge, w1, w2, url): 155 | h, w = rotated_edge.shape 156 | r = range(0, h) 157 | r1 = range(0, h // 2) 158 | r2 = range(h // 2, h - 1) 159 | c = range(0, w) 160 | c1 = range(0, w // 2) 161 | c2 = range(w // 2, w-1) 162 | 163 | highest_edge = (rotated_edge[r1][:,c].sum(axis=1).argmax()) 164 | lowest_edge = (rotated_edge[r2][:,c].sum(axis=1).argmax() + (h // 2)) 165 | ''' 166 | leftest_edge = (rotated_edge[r][:,c1].sum(axis=0).argmax()) 167 | rightest_edge = (rotated_edge[r][:,c2].sum(axis=0).argmax() + (w // 2)) 168 | ''' 169 | leftest_edge = w1 170 | rightest_edge = w2 171 | ''' 172 | _, img_w = rotated_edge.shape 173 | half = int(img_w/2) 174 | max_right_sum = 0 175 | max_right_i = 0 176 | sum_img = numpy.sum(rotated_img,axis=0) 177 | for i in range(half,img_w-50): 178 | s = sum(sum_img[i:i+50]) 179 | if s > max_right_sum: 180 | max_right_sum = s 181 | max_right_i = i 182 | ''' 183 | 184 | #print(highest_edge, lowest_edge, leftest_edge, rightest_edge) 185 | #print max_right_i 186 | #rightest_edge = max_right_i + 200 187 | #leftest_edge = 0 188 | ''' 189 | rotated_edge[highest_edge, : ] = 200 190 | rotated_edge[lowest_edge, : ] = 200 #150 191 | rotated_edge[: , leftest_edge] = 200 #200 192 | rotated_edge[: , rightest_edge] = 200 #250 193 | rotated_croped = rotated_edge[highest_edge : lowest_edge, leftest_edge : rightest_edge] 194 | ''' 195 | rotated_croped_img = rotated_img[highest_edge : lowest_edge, leftest_edge : rightest_edge] 196 | ''' 197 | fig = plt.figure(figsize = (30, 30)) 198 | ax1 = fig.add_subplot(2, 2, 1) 199 | ax2 = fig.add_subplot(2, 2, 2) 200 | ax3 = fig.add_subplot(2, 2, 3) 201 | ax4 = fig.add_subplot(2, 2, 4) 202 | ax1.imshow(rotated_edge, cmap = plt.cm.gray) 203 | ax2.imshow(rotated_croped, cmap = plt.cm.gray) 204 | ax3.imshow(rotated_img, cmap = plt.cm.gray) 205 | ax4.imshow(rotated_croped_img, cmap = plt.cm.gray) 206 | plt.show() 207 | ''' 208 | #print("rotated_croped_img type: ", rotated_croped_img) 209 | #cv2.imwrite(url, rotated_croped_img) 210 | 211 | #im = Image.fromarray(rotated_croped_img) 212 | #im.save(url) 213 | return rotated_croped_img 214 | 215 | def img_resized_enhance(img, url): 216 | #尺度归一化 217 | #resized_img = cv2.resize(img, (136, 100), cv2.INTER_NEAREST) #最近邻插值 218 | resized_img = cv2.resize(img, (320, 240), cv2.INTER_LINEAR) #双线性插值 219 | #resized_img = cv2.resize(img, (136, 100), cv2.INTER_NEAREST) #最近邻插值 220 | ''' 221 | fig = plt.figure(figsize = (30, 20)) 222 | ax1 = fig.add_subplot(1, 2, 1) 223 | ax2 = fig.add_subplot(1, 2, 2) 224 | ax1.imshow(img, cmap = plt.cm.gray) 225 | ax2.imshow(resized_img, cmap = plt.cm.gray) 226 | plt.show() 227 | ''' 228 | norm_resized_img = resized_img 229 | # 灰度归一化 230 | norm_resized_img = cv2.normalize(resized_img, norm_resized_img, 0, 255, cv2.NORM_MINMAX) 231 | # 直方图均衡化 232 | #equ_resized_img = cv2.equalizeHist(resized_img) 233 | 234 | # create a CLAHE object (Arguments are optional). 235 | clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8)) 236 | clahe_resized_img = clahe.apply(norm_resized_img) 237 | ''' 238 | plt.figure(figsize = (30, 30)) 239 | plt.subplot(2, 2, 1), plt.title('image') 240 | plt.imshow(img, cmap = plt.cm.gray) 241 | plt.subplot(2, 2, 2), plt.title('resized_img') 242 | plt.imshow(resized_img, cmap = plt.cm.gray) 243 | plt.subplot(2, 2, 3), plt.title('norm_resized_img') 244 | plt.imshow(norm_resized_img, cmap = plt.cm.gray) 245 | plt.subplot(2, 2, 4), plt.title('CLAHE') 246 | plt.imshow(clahe_resized_img, cmap = plt.cm.gray) 247 | plt.show() 248 | ''' 249 | print('saving...') 250 | #保存前一定要创建文件夹 251 | cv2.imwrite(url, clahe_resized_img) 252 | print('done') 253 | return clahe_resized_img 254 | 255 | def get_imgs_roi(img_file): 256 | images = os.listdir(img_file) 257 | for i, image in enumerate(images): 258 | print(i) 259 | print(image) 260 | img_raw = cv2.imread(os.path.join(img_file, image), 0) 261 | print(img_raw.shape) 262 | ''' 263 | (h,w) = img.shape 264 | center = (w / 2,h / 2) 265 | M = cv2.getRotationMatrix2D(center,90,1)#旋转缩放矩阵:(旋转中心,旋转角度,缩放因子) 266 | img_raw = cv2.warpAffine(img,M,(w,h)) 267 | ''' 268 | #img_raw, img_edge = edge_detection(img_raw) 269 | img_raw, img_Blur = first_filter(img_raw) 270 | img_raw, img_Blur_edge = edge_detection(img_Blur) 271 | ''' 272 | fig = plt.figure(figsize = (50, 15)) 273 | ax1 = fig.add_subplot(1, 3, 1) 274 | ax2 = fig.add_subplot(1, 3, 2) 275 | ax3 = fig.add_subplot(1, 3, 3) 276 | ax1.imshow(img_raw, cmap = plt.cm.gray) 277 | ax2.imshow(img_edge, cmap = plt.cm.gray) 278 | ax3.imshow(img_Blur_edge, cmap = plt.cm.gray) 279 | plt.show() 280 | ''' 281 | img_Blur_edge_polar = pixel_polarization(img_Blur_edge, img_raw, 25) #二值化 282 | img_Blur_edge_polar_midd, middle_left, middle_right, w1, w2= positioning_middle_point(img_raw, img_Blur_edge_polar, 100) 283 | img_Blur_edge_polar_midd_rotated, rotated_img = rotation_correction(img_raw, img_Blur_edge_polar_midd, middle_right, middle_left, w1, w2) 284 | # roi图像保存路径 285 | new_file = './roi_600_2_all_320240' 286 | save_root = os.path.join(new_file,image) 287 | roi_img = roi(rotated_img, img_Blur_edge_polar_midd_rotated, w1, w2, save_root) 288 | resized_roi_img = img_resized_enhance(roi_img, save_root) 289 | 290 | 291 | def build_filters(): 292 | """ returns a list of kernels in several orientations 293 | """ 294 | filters = [] 295 | ksize = 31 296 | for theta in np.arange(0, np.pi, np.pi / 4): 297 | params = {'ksize':(ksize, ksize), 'sigma':3.3, 'theta':theta, 'lambd':18.3, 298 | 'gamma':4.5, 'psi':0.89, 'ktype':cv2.CV_32F} 299 | kern = cv2.getGaborKernel(**params) 300 | kern /= 1.5*kern.sum() 301 | filters.append((kern,params)) 302 | return filters 303 | 304 | def getGabor(img, filters): 305 | """ returns the img filtered by the filter list 306 | """ 307 | accum = np.zeros_like(img) 308 | for kern,params in filters: 309 | fimg = cv2.filter2D(img, cv2.CV_8UC3, kern) 310 | np.maximum(accum, fimg, accum) 311 | return accum 312 | 313 | 314 | ################################################################ 315 | #二值纹理特征提取 316 | def bin_features_extract(roi_file): 317 | ''' 318 | images_roi = os.listdir(roi_file) 319 | for i, image_roi in enumerate(images_roi): 320 | print(i) 321 | print(image_roi) 322 | img_roi_raw = cv2.imread(os.path.join(roi_file, image_roi), 0) 323 | ''' 324 | img_roi_raw = cv2.imread(roi_file, 0) 325 | # Gabor滤波器 326 | filters = build_filters() 327 | img_roi_raw_gabor = getGabor(img_roi_raw, filters) 328 | #print(img_roi_raw_gabor) 329 | #灰度归一化 330 | #norm_resized_img = cv2.normalize(img_roi_raw_gabor, norm_resized_img, 0, 255, cv2.NORM_MINMAX) 331 | #二值化 332 | #img_roi_raw_gabor_polar60 = img_roi_raw_gabor.copy() 333 | #img_roi_raw_gabor_polar60 = pixel_polarization(img_roi_raw_gabor_polar60, img_roi_raw, 60) 334 | img_roi_raw_gabor_polar70 = img_roi_raw_gabor.copy() 335 | img_roi_raw_gabor_polar70 = pixel_polarization(img_roi_raw_gabor_polar70, img_roi_raw, 70) 336 | ''' 337 | plt.figure(figsize = (30, 30)) 338 | plt.subplot(2, 2, 1), plt.title('img_roi_raw') 339 | plt.imshow(img_roi_raw, cmap = plt.cm.gray) 340 | plt.subplot(2, 2, 2), plt.title('img_roi_raw_gabor') 341 | plt.imshow(img_roi_raw_gabor, cmap = plt.cm.gray) 342 | plt.subplot(2, 2, 3), plt.title('img_roi_raw_gabor_polar60') 343 | plt.imshow(img_roi_raw_gabor_polar60, cmap = plt.cm.gray) 344 | plt.subplot(2, 2, 4), plt.title('img_roi_raw_gabor_polar70') 345 | plt.imshow(img_roi_raw_gabor_polar70, cmap = plt.cm.gray) 346 | plt.show() 347 | ''' 348 | 349 | return img_roi_raw_gabor_polar70 350 | 351 | def bin_match(img1_path, img2_path): 352 | img1 = bin_features_extract(img1_path) 353 | img2 = bin_features_extract(img2_path) 354 | height, width = img1.shape 355 | size = height * width 356 | score = 0 357 | for i in range(len(img1)): 358 | for j in range(len(img1[i,:])): 359 | if img1[i][j] == img2[i][j]: 360 | score += 1 361 | scores = 100 * round((score / size), 4) 362 | #print(img1_path, img2_path, scores) 363 | return scores 364 | 365 | 366 | ########################################################### 367 | #图片分成m*n块 368 | def cut_image(image, m, n): 369 | height, width = image.shape 370 | item_width = int(width // m) 371 | item_height = int(height // n) 372 | #box_list = [] 373 | cropped_list = [] 374 | # (left, upper, right, lower) 375 | for i in range(0,n):#两重循环,生成m*n张图片基于原图的位置 376 | for j in range(0,m): 377 | #print((i*item_width,j*item_width,(i+1)*item_width,(j+1)*item_width)) 378 | #box = (j*item_width,i*item_height,(j+1)*item_width,(i+1)*item_height) 379 | #box_list.append(box) 380 | cropped = image[i*item_height:(i+1)*item_height, j*item_width:(j+1)*item_width] 381 | cropped_list.append(cropped) 382 | 383 | print(len(cropped_list)) 384 | #image_list = [image.crop(box) for box in box_list] 385 | return cropped_list 386 | 387 | #LBP特征提取 388 | from skimage.feature import local_binary_pattern 389 | 390 | def LBP_feature_extrector(roi_file): 391 | images_roi = os.listdir(roi_file) 392 | # settings for LBP 393 | radius = 3 394 | n_points = 8 * radius 395 | METHOD = 'uniform' 396 | for i, image_roi in enumerate(images_roi): 397 | print(i) 398 | print(image_roi) 399 | img_roi_raw = cv2.imread(os.path.join(roi_file, image_roi), 0) 400 | img_roi_raw_lbp = local_binary_pattern(img_roi_raw, n_points, radius, METHOD) 401 | #print(img_roi_raw_lbp.shape()) 402 | #img_roi_raw_lbp_cut = cut_image(img_roi_raw_lbp, 4, 4) #分成4*4 403 | #分块显示 404 | #plt.figure(figsize = (30, 30)) 405 | #print(img_roi_raw_lbp_cut.shape()) 406 | ''' 407 | score = cv2.compareHist(lbp_hist, lbp_hist, cv2.HISTCMP_BHATTACHARYYA) 408 | #score = kullback_leibler_divergence(lbp_hist, lbp_hist) 409 | print(score) 410 | ''' 411 | ''' 412 | #绘制直方图 413 | #lbp_hist = plt.hist(img_roi_raw_lbp.ravel(),256,[0,256]) 414 | n_bins = int(img_roi_raw_lbp.max() + 1) 415 | lbp_hist = plt.hist(img_roi_raw_lbp.ravel(), density=True, bins=n_bins, range=(0, n_bins), facecolor='0.5') 416 | 417 | plt.figure(figsize = (30, 30)) 418 | plt.subplot(1, 2, 1), plt.title('img_roi_raw') 419 | plt.imshow(img_roi_raw, cmap = plt.cm.gray) 420 | plt.subplot(1, 2, 2), plt.title('img_roi_raw_lbp') 421 | plt.imshow(img_roi_raw_lbp, cmap = plt.cm.gray) 422 | # plt.subplot(1, 3, 3), plt.title('lbp_hist') 423 | # plt.imshow(lbp_hist) 424 | plt.show() 425 | ''' 426 | 427 | ########################################## 428 | #SIFT特征提取与匹配 429 | def SIFT_detector(gray_path): 430 | images_sift = os.listdir(gray_path) 431 | for i, image_sift in enumerate(images_sift): 432 | print(i) 433 | print(image_sift) 434 | img = cv2.imread(os.path.join(gray_path, image_sift), 0) 435 | ''' 436 | #sift检测 437 | sift = cv2.xfeatures2d.SIFT_create() 438 | kp = sift.detect(img,None) 439 | img_sift=cv2.drawKeypoints(img,kp,img,flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS) 440 | ''' 441 | ''' 442 | #SURF检测 443 | surf = cv2.xfeatures2d.SURF_create() 444 | kp = surf.detect(img,None) 445 | img_surf=cv2.drawKeypoints(img,kp,img,flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS) 446 | ''' 447 | ''' 448 | #ORB检测,几乎没有 449 | orb = cv2.ORB_create() 450 | kp = orb.detect(img,None) 451 | img_orb=cv2.drawKeypoints(img,kp,img,flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS) 452 | ''' 453 | 454 | #KAZE检测 455 | kaze = cv2.KAZE_create() 456 | kp = kaze.detect(img,None) 457 | img_kaze=cv2.drawKeypoints(img,kp,img,flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS) 458 | 459 | #cv2.imwrite('sift_keypoints.jpg',img) 460 | 461 | plt.figure(figsize = (30, 30)) 462 | plt.subplot(1, 2, 1), plt.title('img') 463 | plt.imshow(img, cmap = plt.cm.gray) 464 | plt.subplot(1, 2, 2), plt.title('img_kaze') 465 | plt.imshow(img_kaze, cmap = plt.cm.gray) 466 | # plt.subplot(1, 3, 3), plt.title('lbp_hist') 467 | # plt.imshow(lbp_hist) 468 | plt.show() 469 | 470 | def SIFT_match(img1_path, img2_path): 471 | 472 | img1 = cv2.imread(img1_path,0) # queryImage 473 | img2 = cv2.imread(img2_path,0) # trainImage 474 | 475 | # Initiate SIFT detector 476 | sift = cv2.xfeatures2d.SIFT_create() 477 | 478 | # find the keypoints and descriptors with SIFT 479 | kp1, des1 = sift.detectAndCompute(img1,None) 480 | kp2, des2 = sift.detectAndCompute(img2,None) 481 | 482 | # BFMatcher with default params 483 | bf = cv2.BFMatcher() 484 | matches = bf.knnMatch(des1,des2, k=2) 485 | 486 | # Apply ratio test 487 | good = [] 488 | for m,n in matches: 489 | if m.distance < 0.75*n.distance: 490 | good.append([m]) 491 | 492 | # cv2.drawMatchesKnn expects list of lists as matches. 493 | img3 = cv2.drawMatchesKnn(img1,kp1,img2,kp2,good,None,flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS) 494 | plt.imshow(img3),plt.show() 495 | 496 | def FLANN_based_Matcher(img1_path, img2_path): 497 | img1 = cv2.imread(img1_path, 0) # queryImage 498 | img2 = cv2.imread(img2_path, 0) # trainImage 499 | ''' 500 | # Initiate SURF detector 501 | surf = cv2.xfeatures2d.SURF_create() 502 | # find the keypoints and descriptors with SIFT 503 | kp1, des1 = surf.detectAndCompute(img1,None) 504 | kp2, des2 = surf.detectAndCompute(img2,None) 505 | ''' 506 | ''' 507 | kaze = cv2.KAZE_create() 508 | kp1, des1 = kaze.detectAndCompute(img1, None) 509 | kp2, des2 = kaze.detectAndCompute(img2, None) 510 | 511 | # Initiate ORB detector 512 | orb = cv2.ORB_create() 513 | # find the keypoints and descriptors with ORB 514 | kp1, des1 = orb.detectAndCompute(img1,None) 515 | kp2, des2 = orb.detectAndCompute(img2,None) 516 | ''' 517 | # Initiate SIFT detector 518 | sift = cv2.xfeatures2d.SIFT_create() 519 | # find the keypoints and descriptors with SIFT 520 | kp1, des1 = sift.detectAndCompute(img1,None) 521 | kp2, des2 = sift.detectAndCompute(img2,None) 522 | 523 | # FLANN parameters 524 | FLANN_INDEX_KDTREE = 1 525 | index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5) 526 | search_params = dict(checks=50) # or pass empty dictionary 527 | flann = cv2.FlannBasedMatcher(index_params,search_params) 528 | matches = flann.knnMatch(des1,des2,k=2) 529 | # Need to draw only good matches, so create a mask 530 | matchesMask = [[0,0] for i in range(len(matches))] 531 | #matchesMask = [] 532 | # ratio test as per Lowe's paper 533 | match_keypoints_count = 0 534 | for i,(m,n) in enumerate(matches): 535 | if m.distance < 0.8*n.distance: 536 | matchesMask[i]=[1,0] 537 | #matchesMask.append(m) 538 | match_keypoints_count += 1 539 | draw_params = dict(matchColor = (0,255,0), 540 | singlePointColor = (255,0,0), 541 | matchesMask = matchesMask, 542 | flags = cv2.DrawMatchesFlags_DEFAULT) 543 | #计算匹配得分,保留小数点后两位 544 | score = 100 * round(match_keypoints_count / len(matchesMask), 4) 545 | #print('score = ', score) 546 | ''' 547 | img3 = cv2.drawMatchesKnn(img1,kp1,img2,kp2,matches,None,**draw_params) 548 | #img3 = cv2.drawMatchesKnn(img1,kp1,img2,kp2,matches,None,flags=2) 549 | plt.imshow(img3),plt.show() 550 | ''' 551 | return score 552 | 553 | #绘制第几组样本的类内类间距离直方图 554 | def cal_scores(method='FLANN', flag=1): 555 | scores_list_diff = [] 556 | scores_list_same = [] 557 | #类间比较 558 | for k in range(1,5): 559 | if k is not flag: 560 | for i in range(1,11): 561 | for j in range(1,11): 562 | #print('%s', ) 563 | strs1 = './data/roi_600_2_all_320240/600-{}-{}-1.bmp'.format(flag,i) 564 | strs2 = './data/roi_600_2_all_320240/600-{}-{}-1.bmp'.format(k,j) 565 | if method == 'FLANN': 566 | scores = FLANN_based_Matcher(strs1, strs2) 567 | scores_list_diff.append(scores) 568 | if method == 'BIN': 569 | scores = bin_match(strs1, strs2) 570 | scores_list_diff.append(scores) 571 | print(strs1,strs2, scores) 572 | 573 | 574 | #类内比较 575 | for i in range(1,11): 576 | for j in range(1,11): 577 | #print('%s', ) 578 | strs1 = './data/roi_600_2_all_320240/600-{}-{}-1.bmp'.format(flag,i) 579 | strs2 = './data/roi_600_2_all_320240/600-{}-{}-1.bmp'.format(flag,j) 580 | 581 | if method == 'FLANN': 582 | scores = FLANN_based_Matcher(strs1, strs2) 583 | scores_list_same.append(scores) 584 | if method == 'BIN': 585 | scores = bin_match(strs1, strs2) 586 | scores_list_same.append(scores) 587 | print(strs1,strs2, scores) 588 | 589 | plt.hist(scores_list_diff, 60, range=(0,100), density=True, histtype="bar", facecolor='g', label='Inter-class', alpha=0.5) 590 | plt.hist(scores_list_same, 60, range=(0,100), density=True, histtype="bar", facecolor='r', label='In-class', alpha=0.5) 591 | plt.xlabel('Matched Features Ratio(MFR)(%)', fontsize=25) 592 | plt.ylabel('MFR Histogram', fontsize=25) 593 | plt.title('Distribution of matching ratio between in-class samples and inter-class samples', fontsize=30) 594 | #plt.text(60, .025, r'$\mu=100,\ \sigma=15$') 595 | #plt.axis([0, 1, 0, 0.03]) 596 | plt.grid(True) 597 | plt.show() 598 | 599 | #print(scores_list) 600 | 601 | #get_imgs_roi('./data/600/2') 602 | #bin_features_extract('./data/roi_320240') 603 | #bin_match('./data/roi_600_2_all_320240/600-3-7-1.bmp', './data/roi_600_2_all_320240/600-3-8-1.bmp') 604 | #LBP_feature_extrector('./data/roi_320240') 605 | #SIFT_detector('./data/roi_320240/') 606 | #SIFT_match('./data/roi_320240/600-3-7-1.bmp', './data/roi_320240/600-3-8-1.bmp') 607 | #2号样本计算分布直方图 608 | #cal_scores('FLANN', 2) 609 | #4号样本计算直方图 610 | #cal_scores('BIN', 4) 611 | --------------------------------------------------------------------------------