├── 动手实践01_钱币检测 ├── CircleDetection │ ├── __init__.py │ ├── main.py │ ├── my_canny.py │ ├── my_hough.py │ └── picture_source │ │ └── picture.jpg ├── __init__.py ├── readme.txt ├── 参考实现 │ ├── __init__.py │ ├── main.py │ ├── my_canny.py │ ├── my_hough.py │ ├── picture_result │ │ ├── canny_result.jpg │ │ └── hough_result.jpg │ └── picture_source │ │ └── picture.jpg └── 钱币检测任务说明.pdf └── 动手实践02_词袋模型图片分类 ├── MyBoW ├── ClassifierKernel.py ├── DataProcess.py ├── ImageInfo.py ├── Vocabulary.py ├── __init__.py └── main.py ├── __init__.py ├── all_npy ├── Bow.npy ├── test_label.npy └── train_label.npy ├── 参考实现 ├── ClassifierKernel.py ├── DataProcess.py ├── ImageInfo.py ├── Vocabulary.py ├── __init__.py ├── confusion_matrix.png ├── main.py └── mytest.log └── 图片分类任务说明.pdf /动手实践01_钱币检测/CircleDetection/__init__.py: -------------------------------------------------------------------------------- 1 | # author:nannan 2 | # contact: zhaozhaoran@bupt.edu.cn 3 | # datetime:2020/8/18 2:57 下午 4 | # software: PyCharm -------------------------------------------------------------------------------- /动手实践01_钱币检测/CircleDetection/main.py: -------------------------------------------------------------------------------- 1 | 2 | import cv2 3 | import math 4 | from my_hough import Hough_transform 5 | from my_canny import Canny 6 | 7 | # np.set_printoptions(threshold=np.inf) 8 | Path = "picture_source/picture.jpg" 9 | Save_Path = "picture_result/" 10 | Reduced_ratio = 2 11 | Guassian_kernal_size = 3 12 | HT_high_threshold = 45 13 | HT_low_threshold = 25 14 | Hough_transform_step = 6 15 | Hough_transform_threshold = 110 16 | 17 | if __name__ == '__main__': 18 | img_gray = cv2.imread(Path, cv2.IMREAD_GRAYSCALE) 19 | img_RGB = cv2.imread(Path) 20 | y, x = img_gray.shape[0:2] 21 | img_gray = cv2.resize(img_gray, (int(x / Reduced_ratio), int(y / Reduced_ratio))) 22 | img_RGB = cv2.resize(img_RGB, (int(x / Reduced_ratio), int(y / Reduced_ratio))) 23 | # canny takes about 40 seconds 24 | print ('Canny ...') 25 | canny = Canny(Guassian_kernal_size, img_gray, HT_high_threshold, HT_low_threshold) 26 | canny.canny_algorithm() 27 | cv2.imwrite(Save_Path + "canny_result.jpg", canny.img) 28 | 29 | # hough takes about 30 seconds 30 | print ('Hough ...') 31 | Hough = Hough_transform(canny.img, canny.angle, Hough_transform_step, Hough_transform_threshold) 32 | circles = Hough.Calculate() 33 | for circle in circles: 34 | cv2.circle(img_RGB, (math.ceil(circle[0]), math.ceil(circle[1])), math.ceil(circle[2]), (132, 135, 239), 2) 35 | cv2.imwrite(Save_Path + "hough_result.jpg", img_RGB) 36 | print ('Finished!') 37 | -------------------------------------------------------------------------------- /动手实践01_钱币检测/CircleDetection/my_canny.py: -------------------------------------------------------------------------------- 1 | ''' 2 | 3 | ''' 4 | import cv2 5 | import numpy as np 6 | 7 | 8 | class Canny: 9 | 10 | def __init__(self, Guassian_kernal_size, img, HT_high_threshold, HT_low_threshold): 11 | ''' 12 | :param Guassian_kernal_size: 高斯滤波器尺寸 13 | :param img: 输入的图片,在算法过程中改变 14 | :param HT_high_threshold: 滞后阈值法中的高阈值 15 | :param HT_low_threshold: 滞后阈值法中的低阈值 16 | ''' 17 | self.Guassian_kernal_size = Guassian_kernal_size 18 | self.img = img 19 | self.y, self.x = img.shape[0:2] 20 | self.angle = np.zeros([self.y, self.x]) 21 | self.img_origin = None 22 | self.x_kernal = np.array([[-1, 1]]) 23 | self.y_kernal = np.array([[-1], [1]]) 24 | self.HT_high_threshold = HT_high_threshold 25 | self.HT_low_threshold = HT_low_threshold 26 | 27 | def Get_gradient_img(self): 28 | ''' 29 | 计算梯度图和梯度方向矩阵。 30 | :return: 生成的梯度图 31 | ''' 32 | print ('Get_gradient_img') 33 | # ------------- write your code bellow ---------------- 34 | 35 | 36 | 37 | # ------------- write your code above ---------------- 38 | return self.img 39 | 40 | def Non_maximum_suppression (self): 41 | ''' 42 | 对生成的梯度图进行非极大化抑制,将tan值的大小与正负结合,确定离散中梯度的方向。 43 | :return: 生成的非极大化抑制结果图 44 | ''' 45 | print ('Non_maximum_suppression') 46 | # ------------- write your code bellow ---------------- 47 | 48 | 49 | 50 | # ------------- write your code above ---------------- 51 | return self.img 52 | 53 | def Hysteresis_thresholding(self): 54 | ''' 55 | 对生成的非极大化抑制结果图进行滞后阈值法,用强边延伸弱边,这里的延伸方向为梯度的垂直方向, 56 | 将比低阈值大比高阈值小的点置为高阈值大小,方向在离散点上的确定与非极大化抑制相似。 57 | :return: 滞后阈值法结果图 58 | ''' 59 | print ('Hysteresis_thresholding') 60 | # ------------- write your code bellow ---------------- 61 | 62 | 63 | 64 | # ------------- write your code above ---------------- 65 | return self.img 66 | 67 | def canny_algorithm(self): 68 | ''' 69 | 按照顺序和步骤调用以上所有成员函数。 70 | :return: Canny 算法的结果 71 | ''' 72 | self.img = cv2.GaussianBlur(self.img, (self.Guassian_kernal_size, self.Guassian_kernal_size), 0) 73 | self.Get_gradient_img() 74 | self.img_origin = self.img.copy() 75 | self.Non_maximum_suppression() 76 | self.Hysteresis_thresholding() 77 | return self.img -------------------------------------------------------------------------------- /动手实践01_钱币检测/CircleDetection/my_hough.py: -------------------------------------------------------------------------------- 1 | ''' 2 | 3 | ''' 4 | 5 | import numpy as np 6 | import math 7 | 8 | class Hough_transform: 9 | def __init__(self, img, angle, step=5, threshold=135): 10 | ''' 11 | 12 | :param img: 输入的图像 13 | :param angle: 输入的梯度方向矩阵 14 | :param step: Hough 变换步长大小 15 | :param threshold: 筛选单元的阈值 16 | ''' 17 | self.img = img 18 | self.angle = angle 19 | self.y, self.x = img.shape[0:2] 20 | self.radius = math.ceil(math.sqrt(self.y**2 + self.x**2)) 21 | self.step = step 22 | self.vote_matrix = np.zeros([math.ceil(self.y / self.step), math.ceil(self.x / self.step), math.ceil(self.radius / self.step)]) 23 | self.threshold = threshold 24 | self.circles = [] 25 | 26 | def Hough_transform_algorithm(self): 27 | ''' 28 | 按照 x,y,radius 建立三维空间,根据图片中边上的点沿梯度方向对空间中的所有单 29 | 元进行投票。每个点投出来结果为一折线。 30 | :return: 投票矩阵 31 | ''' 32 | print ('Hough_transform_algorithm') 33 | # ------------- write your code bellow ---------------- 34 | 35 | 36 | 37 | # ------------- write your code above ---------------- 38 | return self.vote_matrix 39 | 40 | 41 | def Select_Circle(self): 42 | ''' 43 | 按照阈值从投票矩阵中筛选出合适的圆,并作极大化抑制。 44 | :return: None 45 | ''' 46 | print ('Select_Circle') 47 | # ------------- write your code bellow ---------------- 48 | 49 | 50 | 51 | # ------------- write your code above ---------------- 52 | 53 | 54 | def Calculate(self): 55 | ''' 56 | 按照算法顺序调用以上成员函数 57 | :return: 圆形拟合结果图,圆的坐标及半径集合 58 | ''' 59 | self.Hough_transform_algorithm() 60 | self.Select_Circle() 61 | return self.circles -------------------------------------------------------------------------------- /动手实践01_钱币检测/CircleDetection/picture_source/picture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CV-xueba/A01_cvclass_basic_exercise/f940f39a856916e78077b7073fdd56659ad979cb/动手实践01_钱币检测/CircleDetection/picture_source/picture.jpg -------------------------------------------------------------------------------- /动手实践01_钱币检测/__init__.py: -------------------------------------------------------------------------------- 1 | # author:nannan 2 | # contact: zhaozhaoran@bupt.edu.cn 3 | # datetime:2020/8/18 2:57 下午 4 | # software: PyCharm -------------------------------------------------------------------------------- /动手实践01_钱币检测/readme.txt: -------------------------------------------------------------------------------- 1 | 关于第一次作业素材使用说明: 2 | 1.第一次作业.pdf介绍了本次作业的目标、算法的大体流程以及运行结果展示 3 | 2.CircleDetection文件夹包含了算法的基本框架,同学们需要填写核心代码来完成整个系统 4 | 3.为了便于大家学习,我们提供了样例代码(参考实现文件夹中)。 -------------------------------------------------------------------------------- /动手实践01_钱币检测/参考实现/__init__.py: -------------------------------------------------------------------------------- 1 | # author:nannan 2 | # contact: zhaozhaoran@bupt.edu.cn 3 | # datetime:2020/8/18 2:57 下午 4 | # software: PyCharm -------------------------------------------------------------------------------- /动手实践01_钱币检测/参考实现/main.py: -------------------------------------------------------------------------------- 1 | # Author: Ji Qiu (BUPT) 2 | # cv_xueba@163.com 3 | 4 | import cv2 5 | import math 6 | from my_hough import Hough_transform 7 | from my_canny import Canny 8 | 9 | # np.set_printoptions(threshold=np.inf) 10 | Path = "picture_source/picture.jpg" 11 | Save_Path = "picture_result/" 12 | Reduced_ratio = 2 13 | Guassian_kernal_size = 3 14 | HT_high_threshold = 45 15 | HT_low_threshold = 25 16 | Hough_transform_step = 6 17 | Hough_transform_threshold = 110 18 | 19 | if __name__ == '__main__': 20 | img_gray = cv2.imread(Path, cv2.IMREAD_GRAYSCALE) 21 | img_RGB = cv2.imread(Path) 22 | y, x = img_gray.shape[0:2] 23 | img_gray = cv2.resize(img_gray, (int(x / Reduced_ratio), int(y / Reduced_ratio))) 24 | img_RGB = cv2.resize(img_RGB, (int(x / Reduced_ratio), int(y / Reduced_ratio))) 25 | # canny takes about 40 seconds 26 | print ('Canny ...') 27 | canny = Canny(Guassian_kernal_size, img_gray, HT_high_threshold, HT_low_threshold) 28 | canny.canny_algorithm() 29 | cv2.imwrite(Save_Path + "canny_result.jpg", canny.img) 30 | 31 | # hough takes about 30 seconds 32 | print ('Hough ...') 33 | Hough = Hough_transform(canny.img, canny.angle, Hough_transform_step, Hough_transform_threshold) 34 | circles = Hough.Calculate() 35 | for circle in circles: 36 | cv2.circle(img_RGB, (math.ceil(circle[0]), math.ceil(circle[1])), math.ceil(circle[2]), (132, 135, 239), 2) 37 | cv2.imwrite(Save_Path + "hough_result.jpg", img_RGB) 38 | print ('Finished!') 39 | -------------------------------------------------------------------------------- /动手实践01_钱币检测/参考实现/my_canny.py: -------------------------------------------------------------------------------- 1 | # Author: Ji Qiu (BUPT) 2 | # cv_xueba@163.com 3 | 4 | import cv2 5 | import numpy as np 6 | 7 | 8 | class Canny: 9 | 10 | def __init__(self, Guassian_kernal_size, img, HT_high_threshold, HT_low_threshold): 11 | ''' 12 | :param Guassian_kernal_size: 高斯滤波器尺寸 13 | :param img: 输入的图片,在算法过程中改变 14 | :param HT_high_threshold: 滞后阈值法中的高阈值 15 | :param HT_low_threshold: 滞后阈值法中的低阈值 16 | ''' 17 | self.Guassian_kernal_size = Guassian_kernal_size 18 | self.img = img 19 | self.y, self.x = img.shape[0:2] 20 | self.angle = np.zeros([self.y, self.x]) 21 | self.img_origin = None 22 | self.x_kernal = np.array([[-1, 1]]) 23 | self.y_kernal = np.array([[-1], [1]]) 24 | self.HT_high_threshold = HT_high_threshold 25 | self.HT_low_threshold = HT_low_threshold 26 | 27 | def Get_gradient_img(self): 28 | ''' 29 | 计算梯度图和梯度方向矩阵。 30 | :return: 生成的梯度图 31 | ''' 32 | print ('Get_gradient_img') 33 | 34 | new_img_x = np.zeros([self.y, self.x], dtype=np.float) 35 | new_img_y = np.zeros([self.y, self.x], dtype=np.float) 36 | for i in range(0, self.x): 37 | for j in range(0, self.y): 38 | if j == 0: 39 | new_img_y[j][i] = 1 40 | else: 41 | new_img_y[j][i] = np.sum(np.array([[self.img[j - 1][i]], [self.img[j][i]]]) * self.y_kernal) 42 | if i == 0: 43 | new_img_x[j][i] = 1 44 | else: 45 | new_img_x[j][i] = np.sum(np.array([self.img[j][i - 1], self.img[j][i]]) * self.x_kernal) 46 | 47 | gradient_img, self.angle = cv2.cartToPolar(new_img_x, new_img_y) 48 | self.angle = np.tan(self.angle) 49 | self.img = gradient_img.astype(np.uint8) 50 | return self.img 51 | 52 | def Non_maximum_suppression (self): 53 | ''' 54 | 对生成的梯度图进行非极大化抑制,将tan值的大小与正负结合,确定离散中梯度的方向。 55 | :return: 生成的非极大化抑制结果图 56 | ''' 57 | print ('Non_maximum_suppression') 58 | 59 | result = np.zeros([self.y, self.x]) 60 | for i in range(1, self.y - 1): 61 | for j in range(1, self.x - 1): 62 | if abs(self.img[i][j]) <= 4: 63 | result[i][j] = 0 64 | continue 65 | elif abs(self.angle[i][j]) > 1: 66 | gradient2 = self.img[i - 1][j] 67 | gradient4 = self.img[i + 1][j] 68 | # g1 g2 69 | # C 70 | # g4 g3 71 | if self.angle[i][j] > 0: 72 | gradient1 = self.img[i - 1][j - 1] 73 | gradient3 = self.img[i + 1][j + 1] 74 | # g2 g1 75 | # C 76 | # g3 g4 77 | else: 78 | gradient1 = self.img[i - 1][j + 1] 79 | gradient3 = self.img[i + 1][j - 1] 80 | else: 81 | gradient2 = self.img[i][j - 1] 82 | gradient4 = self.img[i][j + 1] 83 | # g1 84 | # g2 C g4 85 | # g3 86 | if self.angle[i][j] > 0: 87 | gradient1 = self.img[i - 1][j - 1] 88 | gradient3 = self.img[i + 1][j + 1] 89 | # g3 90 | # g2 C g4 91 | # g1 92 | else: 93 | gradient3 = self.img[i - 1][j + 1] 94 | gradient1 = self.img[i + 1][j - 1] 95 | 96 | temp1 = abs(self.angle[i][j]) * gradient1 + (1 - abs(self.angle[i][j])) * gradient2 97 | temp2 = abs(self.angle[i][j]) * gradient3 + (1 - abs(self.angle[i][j])) * gradient4 98 | if self.img[i][j] >= temp1 and self.img[i][j] >= temp2: 99 | result[i][j] = self.img[i][j] 100 | else: 101 | result[i][j] = 0 102 | self.img = result 103 | return self.img 104 | 105 | def Hysteresis_thresholding(self): 106 | ''' 107 | 对生成的非极大化抑制结果图进行滞后阈值法,用强边延伸弱边,这里的延伸方向为梯度的垂直方向, 108 | 将比低阈值大比高阈值小的点置为高阈值大小,方向在离散点上的确定与非极大化抑制相似。 109 | :return: 滞后阈值法结果图 110 | ''' 111 | print ('Hysteresis_thresholding') 112 | 113 | for i in range(1, self.y - 1): 114 | for j in range(1, self.x - 1): 115 | if self.img[i][j] >= self.HT_high_threshold: 116 | if abs(self.angle[i][j]) < 1: 117 | if self.img_origin[i - 1][j] > self.HT_low_threshold: 118 | self.img[i - 1][j] = self.HT_high_threshold 119 | if self.img_origin[i + 1][j] > self.HT_low_threshold: 120 | self.img[i + 1][j] = self.HT_high_threshold 121 | # g1 g2 122 | # C 123 | # g4 g3 124 | if self.angle[i][j] < 0: 125 | if self.img_origin[i - 1][j - 1] > self.HT_low_threshold: 126 | self.img[i - 1][j - 1] = self.HT_high_threshold 127 | if self.img_origin[i + 1][j + 1] > self.HT_low_threshold: 128 | self.img[i + 1][j + 1] = self.HT_high_threshold 129 | # g2 g1 130 | # C 131 | # g3 g4 132 | else: 133 | if self.img_origin[i - 1][j + 1] > self.HT_low_threshold: 134 | self.img[i - 1][j + 1] = self.HT_high_threshold 135 | if self.img_origin[i + 1][j - 1] > self.HT_low_threshold: 136 | self.img[i + 1][j - 1] = self.HT_high_threshold 137 | else: 138 | if self.img_origin[i][j - 1] > self.HT_low_threshold: 139 | self.img[i][j - 1] = self.HT_high_threshold 140 | if self.img_origin[i][j + 1] > self.HT_low_threshold: 141 | self.img[i][j + 1] = self.HT_high_threshold 142 | # g1 143 | # g2 C g4 144 | # g3 145 | if self.angle[i][j] < 0: 146 | if self.img_origin[i - 1][j - 1] > self.HT_low_threshold: 147 | self.img[i - 1][j - 1] = self.HT_high_threshold 148 | if self.img_origin[i + 1][j + 1] > self.HT_low_threshold: 149 | self.img[i + 1][j + 1] = self.HT_high_threshold 150 | # g3 151 | # g2 C g4 152 | # g1 153 | else: 154 | if self.img_origin[i - 1][j + 1] > self.HT_low_threshold: 155 | self.img[i + 1][j - 1] = self.HT_high_threshold 156 | if self.img_origin[i + 1][j - 1] > self.HT_low_threshold: 157 | self.img[i + 1][j - 1] = self.HT_high_threshold 158 | return self.img 159 | 160 | def canny_algorithm(self): 161 | ''' 162 | 按照顺序和步骤调用以上所有成员函数。 163 | :return: Canny 算法的结果 164 | ''' 165 | self.img = cv2.GaussianBlur(self.img, (self.Guassian_kernal_size, self.Guassian_kernal_size), 0) 166 | self.Get_gradient_img() 167 | self.img_origin = self.img.copy() 168 | self.Non_maximum_suppression() 169 | self.Hysteresis_thresholding() 170 | return self.img 171 | -------------------------------------------------------------------------------- /动手实践01_钱币检测/参考实现/my_hough.py: -------------------------------------------------------------------------------- 1 | # Author: Ji Qiu (BUPT) 2 | # cv_xueba@163.com 3 | 4 | 5 | import numpy as np 6 | import math 7 | 8 | class Hough_transform: 9 | def __init__(self, img, angle, step=5, threshold=135): 10 | ''' 11 | 12 | :param img: 输入的图像 13 | :param angle: 输入的梯度方向矩阵 14 | :param step: Hough 变换步长大小 15 | :param threshold: 筛选单元的阈值 16 | ''' 17 | self.img = img 18 | self.angle = angle 19 | self.y, self.x = img.shape[0:2] 20 | self.radius = math.ceil(math.sqrt(self.y**2 + self.x**2)) 21 | self.step = step 22 | self.vote_matrix = np.zeros([math.ceil(self.y / self.step), math.ceil(self.x / self.step), math.ceil(self.radius / self.step)]) 23 | self.threshold = threshold 24 | self.circles = [] 25 | 26 | def Hough_transform_algorithm(self): 27 | ''' 28 | 按照 x,y,radius 建立三维空间,根据图片中边上的点沿梯度方向对空间中的所有单 29 | 元进行投票。每个点投出来结果为一折线。 30 | :return: 投票矩阵 31 | ''' 32 | print ('Hough_transform_algorithm') 33 | 34 | for i in range(1, self.y - 1): 35 | for j in range(1, self.x - 1): 36 | if self.img[i][j] > 0: 37 | y = i 38 | x = j 39 | r = 0 40 | while y < self.y and x < self.x and y >= 0 and x >= 0: 41 | self.vote_matrix[math.floor(y / self.step)][math.floor(x / self.step)][math.floor(r / self.step)] += 1 42 | y = y + self.step * self.angle[i][j] 43 | x = x + self.step 44 | r = r + math.sqrt((self.step * self.angle[i][j])**2 + self.step**2) 45 | y = i - self.step * self.angle[i][j] 46 | x = j - self.step 47 | r = math.sqrt((self.step * self.angle[i][j])**2 + self.step**2) 48 | while y < self.y and x < self.x and y >= 0 and x >= 0: 49 | self.vote_matrix[math.floor(y / self.step)][math.floor(x / self.step)][math.floor(r / self.step)] += 1 50 | y = y - self.step * self.angle[i][j] 51 | x = x - self.step 52 | r = r + math.sqrt((self.step * self.angle[i][j])**2 + self.step**2) 53 | 54 | return self.vote_matrix 55 | 56 | 57 | def Select_Circle(self): 58 | ''' 59 | 按照阈值从投票矩阵中筛选出合适的圆,并作极大化抑制,这里的非极大化抑制我采 60 | 用的是邻近点结果取平均值的方法,而非单纯的取极大值。 61 | :return: None 62 | ''' 63 | print ('Select_Circle') 64 | 65 | houxuanyuan = [] 66 | for i in range(0, math.ceil(self.y / self.step)): 67 | for j in range(0, math.ceil(self.x / self.step)): 68 | for r in range(0, math.ceil(self.radius / self.step)): 69 | if self.vote_matrix[i][j][r] >= self.threshold: 70 | y = i * self.step + self.step / 2 71 | x = j * self.step + self.step / 2 72 | r = r * self.step + self.step / 2 73 | houxuanyuan.append((math.ceil(x), math.ceil(y), math.ceil(r))) 74 | if len(houxuanyuan) == 0: 75 | print("No Circle in this threshold.") 76 | return 77 | x, y, r = houxuanyuan[0] 78 | possible = [] 79 | middle = [] 80 | for circle in houxuanyuan: 81 | if abs(x - circle[0]) <= 20 and abs(y - circle[1]) <= 20: 82 | possible.append([circle[0], circle[1], circle[2]]) 83 | else: 84 | result = np.array(possible).mean(axis=0) 85 | middle.append((result[0], result[1], result[2])) 86 | possible.clear() 87 | x, y, r = circle 88 | possible.append([x, y, r]) 89 | result = np.array(possible).mean(axis=0) 90 | middle.append((result[0], result[1], result[2])) 91 | 92 | def takeFirst(elem): 93 | return elem[0] 94 | 95 | middle.sort(key=takeFirst) 96 | x, y, r = middle[0] 97 | possible = [] 98 | for circle in middle: 99 | if abs(x - circle[0]) <= 20 and abs(y - circle[1]) <= 20: 100 | possible.append([circle[0], circle[1], circle[2]]) 101 | else: 102 | result = np.array(possible).mean(axis=0) 103 | print("Circle core: (%f, %f) Radius: %f" % (result[0], result[1], result[2])) 104 | self.circles.append((result[0], result[1], result[2])) 105 | possible.clear() 106 | x, y, r = circle 107 | possible.append([x, y, r]) 108 | result = np.array(possible).mean(axis=0) 109 | print("Circle core: (%f, %f) Radius: %f" % (result[0], result[1], result[2])) 110 | self.circles.append((result[0], result[1], result[2])) 111 | 112 | 113 | def Calculate(self): 114 | ''' 115 | 按照算法顺序调用以上成员函数 116 | :return: 圆形拟合结果图,圆的坐标及半径集合 117 | ''' 118 | self.Hough_transform_algorithm() 119 | self.Select_Circle() 120 | return self.circles 121 | -------------------------------------------------------------------------------- /动手实践01_钱币检测/参考实现/picture_result/canny_result.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CV-xueba/A01_cvclass_basic_exercise/f940f39a856916e78077b7073fdd56659ad979cb/动手实践01_钱币检测/参考实现/picture_result/canny_result.jpg -------------------------------------------------------------------------------- /动手实践01_钱币检测/参考实现/picture_result/hough_result.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CV-xueba/A01_cvclass_basic_exercise/f940f39a856916e78077b7073fdd56659ad979cb/动手实践01_钱币检测/参考实现/picture_result/hough_result.jpg -------------------------------------------------------------------------------- /动手实践01_钱币检测/参考实现/picture_source/picture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CV-xueba/A01_cvclass_basic_exercise/f940f39a856916e78077b7073fdd56659ad979cb/动手实践01_钱币检测/参考实现/picture_source/picture.jpg -------------------------------------------------------------------------------- /动手实践01_钱币检测/钱币检测任务说明.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CV-xueba/A01_cvclass_basic_exercise/f940f39a856916e78077b7073fdd56659ad979cb/动手实践01_钱币检测/钱币检测任务说明.pdf -------------------------------------------------------------------------------- /动手实践02_词袋模型图片分类/MyBoW/ClassifierKernel.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | import DataProcess 4 | from sklearn import svm 5 | from sklearn.metrics import confusion_matrix 6 | from sklearn import metrics 7 | import main 8 | 9 | def trainSVM(data, labels): 10 | """ 11 | 训练 SVM 数据集。 12 | :param data: 输入图片投票向量 13 | :param labels: 图片数据集的标签 14 | :return: svm 模型 15 | """ 16 | data = np.array(data, dtype='float32') 17 | labels = np.int64(labels) 18 | #----------------------write your code bellow---------------------- 19 | 20 | # ----------------------write your code above---------------------- 21 | return rbf_svc 22 | 23 | def predict(data, model): 24 | """ 25 | 根据 svm 模型和数据集预测结果 26 | :param classes: 测试集数据集 27 | :param model: 输入 svm 模型 28 | :return: 数据集预测结果 29 | 30 | """ 31 | data = np.array(data, dtype='float32') 32 | prediction = model.predict(data) 33 | 34 | return prediction 35 | 36 | def evaluate(prediction, labels): 37 | ''' 38 | 评估模型预测结果 39 | :param prediction: 数据集预测结果 40 | :param labels: 数据集标签 41 | :return: 分类结果,混淆矩阵 42 | 43 | ''' 44 | report = metrics.classification_report(labels, prediction, target_names=main.targetName) 45 | confuse_matrix = confusion_matrix(labels, prediction) 46 | return report, confuse_matrix -------------------------------------------------------------------------------- /动手实践02_词袋模型图片分类/MyBoW/DataProcess.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | import os 4 | import matplotlib.pyplot as plt 5 | import ImageInfo 6 | from matplotlib.ticker import MultipleLocator 7 | 8 | def plotCM(classes, matrix, savename): 9 | ''' 10 | 绘制混淆矩阵 11 | :param classes: 图片标签名称 12 | :param matrix: 混淆矩阵 13 | :param savename: 混淆矩阵保存路径 14 | :return: None 15 | ''' 16 | 17 | matrix = matrix.astype(np.float) 18 | linesum = matrix.sum(1) 19 | linesum = np.dot(linesum.reshape(-1, 1), np.ones((1, matrix.shape[1]))) 20 | matrix /= linesum 21 | plt.switch_backend('agg') 22 | fig = plt.figure() 23 | ax = fig.add_subplot(111) 24 | cax = ax.matshow(matrix) 25 | fig.colorbar(cax) 26 | ax.xaxis.set_major_locator(MultipleLocator(1)) 27 | ax.yaxis.set_major_locator(MultipleLocator(1)) 28 | for i in range(matrix.shape[0]): 29 | ax.text(i, i, str('%.2f' % (matrix[i, i] * 100)), va='center', ha='center', fontsize=6) 30 | ax.set_xticklabels([''] + classes, rotation=90) 31 | ax.set_yticklabels([''] + classes) 32 | plt.savefig(savename) 33 | 34 | def getDatasetFromFile(path): 35 | 36 | ''' 37 | 读取数据库中图片,生成训练集和测试集特征点向量 38 | :param path: 数据库路径 39 | :return: 训练集特征点向量,测试集特征点向量 40 | 41 | ''' 42 | dirs = os.listdir(path) 43 | 44 | imgTrainSet = [] 45 | imgTestSet = [] 46 | 47 | label = 0 48 | feature_set = np.float32([]).reshape(0, 128) 49 | for dir in dirs: 50 | files = os.listdir(path + "/" + dir) 51 | #files.remove("Thumbs.db") 52 | 53 | for i in range(150): 54 | # ----------------------write your code bellow---------------------- 55 | 56 | # ----------------------write your code above---------------------- 57 | 58 | for i in range(150, len(files)): 59 | # ----------------------write your code bellow---------------------- 60 | 61 | # ----------------------write your code above---------------------- 62 | label += 1 63 | 64 | np.save("feature_set.npy", feature_set) 65 | return imgTrainSet, imgTestSet 66 | 67 | -------------------------------------------------------------------------------- /动手实践02_词袋模型图片分类/MyBoW/ImageInfo.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | class ImageInfo: 5 | def __init__(self, image, label): 6 | self.image = image 7 | self.height, self.width = image.shape[0:2] 8 | self.label = label 9 | self.descriptors = None 10 | self.keypoints = None 11 | 12 | def getImgFeature(self): 13 | ''' 14 | 提取图片 img 的 SIFT 特征点 15 | :param self.img: 输入图片的矩阵 16 | :return: img 的特征点向量,img 的 keypoints 列表 17 | ''' 18 | # ----------------------write your code bellow---------------------- 19 | 20 | # ----------------------write your code above---------------------- 21 | self.descriptors = descriptors 22 | self.keypoints = keypoints 23 | return descriptors, keypoints 24 | 25 | def normalizeSIFT(self): 26 | ''' 27 | 归一化图片的 SIFT 28 | :param self.descriptors: 图片的特征点向量 29 | :return: None 30 | ''' 31 | for i in range(len(self.descriptors)): 32 | # ----------------------write your code bellow---------------------- 33 | 34 | # ----------------------write your code above---------------------- -------------------------------------------------------------------------------- /动手实践02_词袋模型图片分类/MyBoW/Vocabulary.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | from sklearn.cluster import MiniBatchKMeans 4 | import math 5 | 6 | class Vocabulary: 7 | def __init__(self, k): 8 | self.k = k 9 | self.vocabulary = None 10 | 11 | def generateBoW(self, path, random_state): 12 | """ 13 | 14 | 通过聚类算法,生成词袋模型 15 | 16 | :param path:词袋模型存储路径 17 | 18 | :param self.k: 词袋模型中视觉词汇的个数 19 | 20 | :param random_state: 随机数种子 21 | 22 | :return: 词袋模型视觉词汇矩阵 23 | 24 | """ 25 | featureSet = np.load(path) 26 | # ----------------------write your code bellow---------------------- 27 | 28 | # ----------------------write your code above---------------------- 29 | return centers 30 | 31 | def getBow(self, path): 32 | """ 33 | 34 | 读取词袋模型文件 35 | 36 | :param path: 词袋模型文件路径 37 | 38 | :return: 词袋模型矩阵 39 | 40 | """ 41 | centers = np.load(path) 42 | self.vocabulary = centers 43 | return centers 44 | 45 | def calSPMFeature(self, features, keypoints, center, img_x, img_y, numberOfBag): 46 | ''' 47 | 使用 SPM 算法,生成不同尺度下图片对视觉词汇的投票结果向量 48 | :param features:图片的特征点向量 49 | :param keypoints: 图片的特征点列表 50 | :param center: 词袋中的视觉词汇的向量 51 | :param img_x: 图片的宽度 52 | :param img_y: 图片的长度 53 | :param self.k: 词袋中视觉词汇的个数 54 | :return: 基于 SPM 思想生成的图片视觉词汇投票结果向量 55 | 56 | ''' 57 | size = len(features) 58 | # ----------------------write your code bellow---------------------- 59 | # The following is a reference 60 | 61 | # widthStep = math.ceil(img_x / 4) 62 | # heightStep = math.ceil(img_y / 4) 63 | # histogramOfLevelTwo = np.zeros((16, numberOfBag)) 64 | # histogramOfLevelOne = np.zeros((4, numberOfBag)) 65 | # histogramOfLevelZero = np.zeros((1, numberOfBag)) 66 | # for i in range(size): 67 | # feature = features[i] 68 | # keypoint = keypoints[i] 69 | # x, y = keypoint.pt 70 | # boundaryIndex = math.floor(x / widthStep) + math.floor(y / heightStep) * 4 71 | # diff = np.tile(feature, (numberOfBag, 1)) - center 72 | # SquareSum = np.sum(np.square(diff), axis=1) 73 | # index = np.argmin(SquareSum) 74 | # histogramOfLevelTwo[boundaryIndex][index] += 1 75 | # 76 | # for i in range(4): 77 | # for j in range(4): 78 | # histogramOfLevelOne[i] += histogramOfLevelTwo[j * 4 + i] 79 | # 80 | # for i in range(4): 81 | # histogramOfLevelZero[0] += histogramOfLevelOne[i] 82 | # 83 | # result = np.float32([]).reshape(0, numberOfBag) 84 | # result = np.append(result, histogramOfLevelZero * 0.25, axis=0) 85 | # result = np.append(result, histogramOfLevelOne * 0.25, axis=0) 86 | # result = np.append(result, histogramOfLevelTwo * 0.5, axis=0) 87 | 88 | # ----------------------write your code above---------------------- 89 | return result 90 | 91 | def Imginfo2SVMdata(self, data): 92 | """ 93 | 94 | 将图片特征点数据转化为 SVM 训练的投票向量 95 | 96 | :param self.vocabulary: 词袋模型 97 | 98 | :param datas: 图片特征点数据 99 | 100 | :param self.k: 101 | 102 | 词袋模型中视觉词汇的数量 103 | 104 | :return: 投票向量矩阵,图片标签 105 | 106 | """ 107 | dataset = np.float32([]).reshape(0, self.k * 21) 108 | labels = [] 109 | # ----------------------write your code bellow---------------------- 110 | # for simple in data: 111 | # votes = self.calSPMFeature(simple.descriptors, simple.keypoints, self.vocabulary, simple.width, simple.height, self.k) 112 | # votes = votes.ravel().reshape(1, self.k * 21) 113 | # dataset = np.append(dataset, votes, axis=0) 114 | # labels.append(simple.label) 115 | # ----------------------write your code above---------------------- 116 | labels = np.array(labels) 117 | 118 | return dataset, labels 119 | 120 | -------------------------------------------------------------------------------- /动手实践02_词袋模型图片分类/MyBoW/__init__.py: -------------------------------------------------------------------------------- 1 | # author:nannan 2 | # contact: zhaozhaoran@bupt.edu.cn 3 | # datetime:2020/8/18 3:23 下午 4 | # software: PyCharm -------------------------------------------------------------------------------- /动手实践02_词袋模型图片分类/MyBoW/main.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import DataProcess 3 | import os 4 | import numpy as np 5 | import random 6 | import Vocabulary 7 | import ClassifierKernel 8 | 9 | Path = "dataset" 10 | targetName = os.listdir(Path) 11 | random_state = 3 12 | random.seed(random_state) 13 | numOfBag = 200 14 | num_feature = 200 15 | 16 | def main(): 17 | if not os.path.exists("train_set.npy"): 18 | # 提取数据集中的样本,并划分训练集和测试集 19 | trainData, testData = DataProcess.getDatasetFromFile(Path) 20 | #特征提取与词典生成 21 | vocabulary = Vocabulary.Vocabulary(numOfBag) 22 | vocabulary.generateBoW("feature_set.npy", random_state) 23 | # vocabulary.getBow("Bow.npy") 24 | # 图片表示,使用SPM方法生成图片特征向量 25 | trainSet, trainlabels = vocabulary.Imginfo2SVMdata(trainData) 26 | testSet, testlabels = vocabulary.Imginfo2SVMdata(testData) 27 | np.save("train_set.npy", trainSet) 28 | np.save("train_label.npy", trainlabels) 29 | np.save("test_set.npy", testSet) 30 | np.save("test_label.npy", testlabels) 31 | else: 32 | trainSet = np.load("train_set.npy") 33 | trainlabels = np.load("train_label.npy") 34 | testSet = np.load("test_set.npy") 35 | testlabels = np.load("test_label.npy") 36 | 37 | # 执行分类,使用支持向量机模型对测试集图片的类别进行预测 38 | svm = ClassifierKernel.trainSVM(trainSet, trainlabels) 39 | result = ClassifierKernel.predict(trainSet, svm) 40 | testResult = ClassifierKernel.predict(testSet, svm) 41 | 42 | # 评估预测结果,并生成分类报告和输出混淆矩阵 43 | trainReport, _ = ClassifierKernel.evaluate(result, trainlabels) 44 | testReport, cm = ClassifierKernel.evaluate(testResult, testlabels) 45 | 46 | DataProcess.plotCM(targetName, cm, "confusion_matrix.png") 47 | print("训练集混淆矩阵:") 48 | print(trainReport) 49 | print("测试集混淆矩阵:") 50 | print(testReport) 51 | 52 | if __name__ == '__main__': 53 | main() -------------------------------------------------------------------------------- /动手实践02_词袋模型图片分类/__init__.py: -------------------------------------------------------------------------------- 1 | # author:nannan 2 | # contact: zhaozhaoran@bupt.edu.cn 3 | # datetime:2020/8/18 3:23 下午 4 | # software: PyCharm -------------------------------------------------------------------------------- /动手实践02_词袋模型图片分类/all_npy/Bow.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CV-xueba/A01_cvclass_basic_exercise/f940f39a856916e78077b7073fdd56659ad979cb/动手实践02_词袋模型图片分类/all_npy/Bow.npy -------------------------------------------------------------------------------- /动手实践02_词袋模型图片分类/all_npy/test_label.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CV-xueba/A01_cvclass_basic_exercise/f940f39a856916e78077b7073fdd56659ad979cb/动手实践02_词袋模型图片分类/all_npy/test_label.npy -------------------------------------------------------------------------------- /动手实践02_词袋模型图片分类/all_npy/train_label.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CV-xueba/A01_cvclass_basic_exercise/f940f39a856916e78077b7073fdd56659ad979cb/动手实践02_词袋模型图片分类/all_npy/train_label.npy -------------------------------------------------------------------------------- /动手实践02_词袋模型图片分类/参考实现/ClassifierKernel.py: -------------------------------------------------------------------------------- 1 | # Author: Ji Qiu (BUPT) 2 | # cv_xueba@163.com 3 | 4 | import cv2 5 | import numpy as np 6 | import DataProcess 7 | from sklearn import svm 8 | from sklearn.metrics import confusion_matrix 9 | from sklearn import metrics 10 | import main 11 | 12 | def trainSVM(data, labels): 13 | """ 14 | 训练 SVM 数据集。 15 | :param data: 输入图片投票向量 16 | :param labels: 图片数据集的标签 17 | :return: svm 模型 18 | """ 19 | data = np.array(data, dtype='float32') 20 | labels = np.int64(labels) 21 | rbf_svc = svm.SVC(kernel='rbf', C=1000, decision_function_shape='ovo') 22 | # rbf_svc = svm.NuSVC(kernel='rbf', nu=0.1) 23 | rbf_svc.fit(data, labels) 24 | 25 | return rbf_svc 26 | 27 | def predict(data, model): 28 | """ 29 | 根据 svm 模型和数据集预测结果 30 | :param classes: 测试集数据集 31 | :param model: 输入 svm 模型 32 | :return: 数据集预测结果 33 | 34 | """ 35 | data = np.array(data, dtype='float32') 36 | prediction = model.predict(data) 37 | 38 | return prediction 39 | 40 | def evaluate(prediction, labels): 41 | ''' 42 | 评估模型预测结果 43 | :param prediction: 数据集预测结果 44 | :param labels: 数据集标签 45 | :return: 分类结果,混淆矩阵 46 | 47 | ''' 48 | report = metrics.classification_report(labels, prediction, target_names=main.targetName) 49 | confuse_matrix = confusion_matrix(labels, prediction) 50 | return report, confuse_matrix -------------------------------------------------------------------------------- /动手实践02_词袋模型图片分类/参考实现/DataProcess.py: -------------------------------------------------------------------------------- 1 | # Author: Ji Qiu (BUPT) 2 | # cv_xueba@163.com 3 | 4 | import cv2 5 | import numpy as np 6 | import os 7 | import matplotlib.pyplot as plt 8 | import ImageInfo 9 | from matplotlib.ticker import MultipleLocator 10 | 11 | def plotCM(classes, matrix, savename): 12 | ''' 13 | 绘制混淆矩阵 14 | :param classes: 图片标签名称 15 | :param matrix: 混淆矩阵 16 | :param savename: 混淆矩阵保存路径 17 | :return: None 18 | ''' 19 | matrix = matrix.astype(np.float) 20 | linesum = matrix.sum(1) 21 | linesum = np.dot(linesum.reshape(-1, 1), np.ones((1, matrix.shape[1]))) 22 | matrix /= linesum 23 | plt.switch_backend('agg') 24 | fig = plt.figure() 25 | ax = fig.add_subplot(111) 26 | cax = ax.matshow(matrix) 27 | fig.colorbar(cax) 28 | ax.xaxis.set_major_locator(MultipleLocator(1)) 29 | ax.yaxis.set_major_locator(MultipleLocator(1)) 30 | for i in range(matrix.shape[0]): 31 | ax.text(i, i, str('%.2f' % (matrix[i, i] * 100)), va='center', ha='center', fontsize=6) 32 | ax.set_xticklabels([''] + classes, rotation=90) 33 | ax.set_yticklabels([''] + classes) 34 | plt.savefig(savename) 35 | 36 | def getDatasetFromFile(path): 37 | 38 | 39 | ''' 40 | 读取数据库中图片,生成训练集和测试集特征点向量 41 | :param path: 数据库路径 42 | :return: 训练集特征点向量,测试集特征点向量 43 | 44 | ''' 45 | dirs = os.listdir(path) 46 | 47 | imgTrainSet = [] 48 | imgTestSet = [] 49 | 50 | label = 0 51 | feature_set = np.float32([]).reshape(0, 128) 52 | for dir in dirs: 53 | files = os.listdir(path + "/" + dir) 54 | #files.remove("Thumbs.db") 55 | 56 | for i in range(150): 57 | img = cv2.imread(path + "/" + dir + "/" + files[i]) 58 | img_info = ImageInfo.ImageInfo(img, label) 59 | img_info.getImgFeature() 60 | img_info.normalizeSIFT() 61 | imgTrainSet.append(img_info) 62 | feature_set = np.append(feature_set, img_info.descriptors, axis=0) 63 | 64 | for i in range(150, len(files)): 65 | img = cv2.imread(path + "/" + dir + "/" + files[i]) 66 | img_info = ImageInfo.ImageInfo(img, label) 67 | img_info.getImgFeature() 68 | img_info.normalizeSIFT() 69 | imgTestSet.append(img_info) 70 | 71 | label += 1 72 | 73 | np.save("feature_set.npy", feature_set) 74 | return imgTrainSet, imgTestSet 75 | 76 | -------------------------------------------------------------------------------- /动手实践02_词袋模型图片分类/参考实现/ImageInfo.py: -------------------------------------------------------------------------------- 1 | # Author: Ji Qiu (BUPT) 2 | # cv_xueba@163.com 3 | 4 | import cv2 5 | import numpy as np 6 | 7 | class ImageInfo: 8 | def __init__(self, image, label): 9 | self.image = image 10 | self.height, self.width = image.shape[0:2] 11 | self.label = label 12 | self.descriptors = None 13 | self.keypoints = None 14 | 15 | def getImgFeature(self): 16 | ''' 17 | 提取图片 img 的 SIFT 特征点 18 | :param self.img: 输入图片的矩阵 19 | :ret 20 | ''' 21 | gray = cv2.cvtColor(self.image, cv2.COLOR_BGR2GRAY) 22 | sift = cv2.xfeatures2d.SIFT_create() 23 | keypoints, descriptors = sift.detectAndCompute(gray, None) 24 | self.descriptors = descriptors 25 | self.keypoints = keypoints 26 | return descriptors, keypoints 27 | 28 | def normalizeSIFT(self): 29 | ''' 30 | 归一化图片的 SIFT 31 | :param self.descriptors: 图片的特征点向量 32 | :return: None 33 | ''' 34 | for i in range(len(self.descriptors)): 35 | norm = np.linalg.norm(self.descriptors[i]) 36 | if norm > 1: 37 | self.descriptors[i] /= float(norm) 38 | -------------------------------------------------------------------------------- /动手实践02_词袋模型图片分类/参考实现/Vocabulary.py: -------------------------------------------------------------------------------- 1 | # Author: Ji Qiu (BUPT) 2 | # cv_xueba@163.com 3 | 4 | import cv2 5 | import numpy as np 6 | from sklearn.cluster import MiniBatchKMeans 7 | import math 8 | 9 | class Vocabulary: 10 | def __init__(self, k): 11 | self.k = k 12 | self.vocabulary = None 13 | 14 | def generateBoW(self, path, random_state): 15 | """ 16 | 17 | 通过聚类算法,生成词袋模型 18 | 19 | :param path:词袋模型存储路径 20 | 21 | :param self.k: 词袋模型中视觉词汇的个数 22 | 23 | :param random_state: 随机数种子 24 | 25 | :return: 词袋模型视觉词汇矩阵 26 | 27 | """ 28 | featureSet = np.load(path) 29 | np.random.shuffle(featureSet) 30 | kmeans = MiniBatchKMeans(n_clusters=self.k, random_state=random_state, batch_size=200).fit(featureSet) 31 | centers = kmeans.cluster_centers_ 32 | self.vocabulary = centers 33 | np.save("Bow.npy", centers) 34 | return centers 35 | 36 | def getBow(self, path): 37 | """ 38 | 39 | 读取词袋模型文件 40 | 41 | :param path: 词袋模型文件路径 42 | 43 | :return: 词袋模型矩阵 44 | 45 | """ 46 | centers = np.load(path) 47 | self.vocabulary = centers 48 | return centers 49 | 50 | def calSPMFeature(self, features, keypoints, center, img_x, img_y, numberOfBag): 51 | ''' 52 | 使用 SPM 算法,生成不同尺度下图片对视觉词汇的投票结果向量 53 | :param features:图片的特征点向量 54 | :param keypoints: 图片的特征点列表 55 | :param center: 词袋中的视觉词汇的向量 56 | :param img_x: 图片的宽度 57 | :param img_y: 图片的长度 58 | :param self.k: 词袋中视觉词汇的个数 59 | :return: 基于 SPM 思想生成的图片视觉词汇投票结果向量 60 | 61 | ''' 62 | size = len(features) 63 | widthStep = math.ceil(img_x / 4) 64 | heightStep = math.ceil(img_y / 4) 65 | histogramOfLevelTwo = np.zeros((16, numberOfBag)) 66 | histogramOfLevelOne = np.zeros((4, numberOfBag)) 67 | histogramOfLevelZero = np.zeros((1, numberOfBag)) 68 | for i in range(size): 69 | feature = features[i] 70 | keypoint = keypoints[i] 71 | x, y = keypoint.pt 72 | boundaryIndex = math.floor(x / widthStep) + math.floor(y / heightStep) * 4 73 | diff = np.tile(feature, (numberOfBag, 1)) - center 74 | SquareSum = np.sum(np.square(diff), axis=1) 75 | index = np.argmin(SquareSum) 76 | histogramOfLevelTwo[boundaryIndex][index] += 1 77 | 78 | for i in range(4): 79 | for j in range(4): 80 | histogramOfLevelOne[i] += histogramOfLevelTwo[j * 4 + i] 81 | 82 | for i in range(4): 83 | histogramOfLevelZero[0] += histogramOfLevelOne[i] 84 | 85 | result = np.float32([]).reshape(0, numberOfBag) 86 | result = np.append(result, histogramOfLevelZero * 0.25, axis=0) 87 | result = np.append(result, histogramOfLevelOne * 0.25, axis=0) 88 | result = np.append(result, histogramOfLevelTwo * 0.5, axis=0) 89 | return result 90 | 91 | def Imginfo2SVMdata(self, data): 92 | """ 93 | 94 | 将图片特征点数据转化为 SVM 训练的投票向量 95 | 96 | :param self.vocabulary: 词袋模型 97 | 98 | :param datas: 图片特征点数据 99 | 100 | :param self.k: 101 | 102 | 词袋模型中视觉词汇的数量 103 | 104 | :return: 投票向量矩阵,图片标签 105 | 106 | """ 107 | dataset = np.float32([]).reshape(0, self.k * 21) 108 | labels = [] 109 | for simple in data: 110 | votes = self.calSPMFeature(simple.descriptors, simple.keypoints, self.vocabulary, simple.width, simple.height, self.k) 111 | votes = votes.ravel().reshape(1, self.k * 21) 112 | dataset = np.append(dataset, votes, axis=0) 113 | labels.append(simple.label) 114 | labels = np.array(labels) 115 | 116 | return dataset, labels 117 | 118 | -------------------------------------------------------------------------------- /动手实践02_词袋模型图片分类/参考实现/__init__.py: -------------------------------------------------------------------------------- 1 | # author:nannan 2 | # contact: zhaozhaoran@bupt.edu.cn 3 | # datetime:2020/8/18 3:23 下午 4 | # software: PyCharm -------------------------------------------------------------------------------- /动手实践02_词袋模型图片分类/参考实现/confusion_matrix.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CV-xueba/A01_cvclass_basic_exercise/f940f39a856916e78077b7073fdd56659ad979cb/动手实践02_词袋模型图片分类/参考实现/confusion_matrix.png -------------------------------------------------------------------------------- /动手实践02_词袋模型图片分类/参考实现/main.py: -------------------------------------------------------------------------------- 1 | # Author: Ji Qiu (BUPT) 2 | # cv_xueba@163.com 3 | 4 | import cv2 5 | import DataProcess 6 | import os 7 | import numpy as np 8 | import random 9 | import Vocabulary 10 | import ClassifierKernel 11 | 12 | Path = "dataset" 13 | targetName = os.listdir(Path) 14 | random_state = 3 15 | random.seed(random_state) 16 | numOfBag = 200 17 | num_feature = 200 18 | 19 | def main(): 20 | if not os.path.exists("train_set.npy"): 21 | # 提取数据集中的样本,并划分训练集和测试集 22 | trainData, testData = DataProcess.getDatasetFromFile(Path) 23 | #特征提取与词典生成 24 | vocabulary = Vocabulary.Vocabulary(numOfBag) 25 | vocabulary.generateBoW("feature_set.npy", random_state) 26 | # vocabulary.getBow("Bow.npy") 27 | # 图片表示,使用SPM方法生成图片特征向量 28 | trainSet, trainlabels = vocabulary.Imginfo2SVMdata(trainData) 29 | testSet, testlabels = vocabulary.Imginfo2SVMdata(testData) 30 | np.save("train_set.npy", trainSet) 31 | np.save("train_label.npy", trainlabels) 32 | np.save("test_set.npy", testSet) 33 | np.save("test_label.npy", testlabels) 34 | else: 35 | trainSet = np.load("train_set.npy") 36 | trainlabels = np.load("train_label.npy") 37 | testSet = np.load("test_set.npy") 38 | testlabels = np.load("test_label.npy") 39 | 40 | # 执行分类,使用支持向量机模型对测试集图片的类别进行预测 41 | svm = ClassifierKernel.trainSVM(trainSet, trainlabels) 42 | result = ClassifierKernel.predict(trainSet, svm) 43 | testResult = ClassifierKernel.predict(testSet, svm) 44 | 45 | # 评估预测结果,并生成分类报告和输出混淆矩阵 46 | trainReport, _ = ClassifierKernel.evaluate(result, trainlabels) 47 | testReport, cm = ClassifierKernel.evaluate(testResult, testlabels) 48 | 49 | DataProcess.plotCM(targetName, cm, "confusion_matrix.png") 50 | print("训练集混淆矩阵:") 51 | print(trainReport) 52 | print("测试集混淆矩阵:") 53 | print(testReport) 54 | 55 | if __name__ == '__main__': 56 | main() -------------------------------------------------------------------------------- /动手实践02_词袋模型图片分类/参考实现/mytest.log: -------------------------------------------------------------------------------- 1 | 训练集混淆矩阵: 2 | precision recall f1-score support 3 | 4 | bedroom 1.00 1.00 1.00 150 5 | MITcoast 1.00 1.00 1.00 150 6 | MITopencountry 1.00 1.00 1.00 150 7 | MIThighway 1.00 1.00 1.00 150 8 | MITstreet 1.00 1.00 1.00 150 9 | MITinsidecity 1.00 1.00 1.00 150 10 | industrial 1.00 1.00 1.00 150 11 | PARoffice 1.00 1.00 1.00 150 12 | MITmountain 1.00 1.00 1.00 150 13 | livingroom 1.00 1.00 1.00 150 14 | kitchen 1.00 1.00 1.00 150 15 | CALsuburb 1.00 1.00 1.00 150 16 | MITtallbuilding 1.00 1.00 1.00 150 17 | MITforest 1.00 1.00 1.00 150 18 | store 1.00 1.00 1.00 150 19 | 20 | accuracy 1.00 2250 21 | macro avg 1.00 1.00 1.00 2250 22 | weighted avg 1.00 1.00 1.00 2250 23 | 24 | 测试集混淆矩阵: 25 | precision recall f1-score support 26 | 27 | bedroom 0.30 0.47 0.36 66 28 | MITcoast 0.62 0.80 0.70 210 29 | MITopencountry 0.71 0.49 0.58 260 30 | MIThighway 0.61 0.83 0.71 110 31 | MITstreet 0.70 0.74 0.72 142 32 | MITinsidecity 0.63 0.54 0.59 158 33 | industrial 0.52 0.35 0.42 161 34 | PARoffice 0.62 0.63 0.63 65 35 | MITmountain 0.69 0.66 0.67 224 36 | livingroom 0.54 0.49 0.51 139 37 | kitchen 0.39 0.52 0.45 60 38 | CALsuburb 0.81 0.91 0.86 91 39 | MITtallbuilding 0.73 0.64 0.68 206 40 | MITforest 0.84 0.92 0.88 178 41 | store 0.62 0.63 0.62 165 42 | 43 | accuracy 0.64 2235 44 | macro avg 0.62 0.64 0.62 2235 45 | weighted avg 0.65 0.64 0.64 2235 46 | 47 | -------------------------------------------------------------------------------- /动手实践02_词袋模型图片分类/图片分类任务说明.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CV-xueba/A01_cvclass_basic_exercise/f940f39a856916e78077b7073fdd56659ad979cb/动手实践02_词袋模型图片分类/图片分类任务说明.pdf --------------------------------------------------------------------------------