一、使用KNN算法识别数字
1、明确目的:
有一张图片,其中有一份数据,其中共有0-9的不同写法的数字,共5000条,现在想要对这张图片中的数据进行训练,以完成当输入一张图片,图片内为手写的数字,能自动识别其数字的值为多少,从而完成训练。
2、获取数据
首先看下面一张图:
它的像素点为1000 x 2000,其中长有100个数据。宽有50个数据,共5000个数据
可能你看不清楚什么样的,那么不妨方法一下,其竖直方向排布如下:
3、明确操作流程
首先导入这张图片,将这张图片转换成灰度图(3.1解析灰度图),然后将这张图片中的每个数字提取出来,这张图片中的每个数字都是由20x20=400个像素点组成,将这每一个单独的数字存放的列表中,然后将列表使用np.reshape()函数转换成二维数组的形式,以便于后面的切分操作。
对存放所有数据的二维数组进行切分,前一半当做训练集,后一半当做测试集,这张图中0-9对应的每个数字都为5行100列,成上下排布,我们只对列作切半处理,不对行进行切分,由此来得到训练集和测试集的数据,但是这个数据还不能直接拿来训练,还需要将每单个数字中的20x20的像素点转变成一行,此时可以使用np.reshape()将其转变成1x400像素值的状态,以便于对其进行训练和测试。
接下来有了训练集和测试集,但是却没有标签集,此时可以生成一个0-9的数组,然后因为训练集中每个单个数据都有250个,即一共2500个,那么就要设置2500个标签用来对应这2500个数字,即可以使用np.repeat()来将0-9每个数字都复制250遍,然后再使用np.newaxis将这个一维数组生高成二维数组,以满足和训练集同样的维度。
最后就是开始训练数据了,这里使用OpenCV中的包cv2.ml的方法KNearest_Create() 来创建一个knn算法的分类器对象,并对其进行初始化,然后导入训练集以及训练标签,并使用cv2.ml.ROW_SAMPLE表示对每一行数据进行训练,接下来就是导入数据进行测试,使用knn.finNearest()导入数据并指定邻居个数,返回四个值ret、result、neighbours、dist,其解释在下列3.2。此时即完成全流程的解说。
3.1 什么是灰度图
灰度图是一种图像的表示方式,相比于彩色图像,灰度图仅包含一个灰度通道,即每个像素只有一个灰度级。灰度级通常用一个8位整数表示,范围从0(黑色)到255(白色),表示不同的亮度值。
在灰度图中,每个像素表示图像中某一点的亮度级别。亮度级别越高,该点在图像中就越亮;亮度级别越低,该点在图像中就越暗。因此,灰度图能够表示图像的明暗程度。
灰度图常用于图像处理领域和计算机视觉任务中。通过对灰度图进行处理,可以实现诸如图像增强、边缘检测、目标检测、人脸识别等功能。例如,对于目标检测任务,可以将灰度图作为输入,通过检测明暗程度变化或者轮廓来识别目标物体。
为了生成灰度图,可以将彩色图像转换为灰度图。一种常见的方法是使用加权平均法,根据红色、绿色和蓝色通道的亮度对应比例,计算出每个像素的灰度值。另外,还可以使用其他方法,如取最大值、取最小值等来生成灰度图。例如可以使用OpenCV中的方法:
import cv2
# 读取彩色图像
image = cv2.imread('color_image.jpg')
# 转换为灰度图
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 显示灰度图
cv2.imshow('Gray Image', gray_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
在以上代码中,首先使用cv2.imread()函数读取彩色图像,将图像保存在image变量中。然后,使用cv2.cvtColor()函数将彩色图像转换为灰度图,将灰度图保存在gray_image变量中。最后,使用cv2.imshow()函数显示灰度图窗口,并通过cv2.waitKey()和cv2.destroyAllWindows()函数等待关闭窗口。
注意,cv2.COLOR_BGR2GRAY参数表示将BGR格式的图像转换为灰度图。如果你的图像不是BGR格式,你可能需要根据实际情况选择不同的颜色空间转换函数。
3.2 ret、result、neighbours、dist 解析
ret
: 返回值,表示操作是否成功(通常是 0 表示成功)。result
: 每个测试样本的预测标签。是对test_new
中每一行数据的预测结果。neighbours
: 最近邻的标签的矩阵,表示每个测试样本的最近 K 个邻居的标签。dist
: 最近邻的距离矩阵,表示每个测试样本到其最近 K 个邻居的距离。
4、代码实现
4.1 导包
#后面等于号为指定版本号,防止和有些包使用发生冲突
pip install opencv_python==3.4.17.61
4.2 完整代码如下:
import numpy as np
import cv2
# 导入图片
img = cv2.imread('digits.png')
# 将图片转化成灰度图
grey = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# 将这个图片中的每一个数字分隔出来然后插入列表
cells = []
for row in np.vsplit(grey,50):
cells.append(np.hsplit(row,100))
# 将列表数据转化成矩阵类型
x = np.array(cells)
# 取前一半数据当做训练集,后一半数据当做测试集
# 取出矩阵x的行列,行为所有的行,列为0到50列,但是不包含第50列,当做训练集
train = x[:,:50]
# 即所有的行,以及后50列
test = x[:,50:100]
# 将每一个数字数据的像素点由20x20像素的转换成1*400像素的,即转换成一行像素点数据
# -1为自动判断样本数
train_new = train.reshape(-1,400).astype(np.float32)
test_new = test.reshape(-1,400).astype(np.float32)
# 定义标签列,便签值为0~9,将其生成一个0-9的数组
y = np.arange(10)
# 将0-9的一维数组中的每个元素复制250次得到一个新的一维数组,其内有10x250个数据
labels = np.repeat(y,250)
# 将上述充满0-9数字的2500条数据的一维数组,增加其维度到二维数组,即每单个值为一个一维数组
train_label = labels[:,np.newaxis]
test_label = np.repeat(y,250)[:,np.newaxis]
# 使用OpenCV中的包cv2.ml的用法KNearest_create创建一个knn分类器对象,用于初始化模型
knn = cv2.ml.KNearest_create()
# cv2.ml.ROW_SAMPLE表示每一行的数据,即导入train_new的每一行数据用来训练,同时插入标签列train_label
knn.train(train_new,cv2.ml.ROW_SAMPLE,train_label)
# 导入测试数据进行测试,并指定最近邻的个数为5,其返回值为ret:表示测试的正确性,正确返回1,错误返回0,result返回测试结果,
# neighbors 表示最近邻的标签的矩阵,表示每个测试样本的最近k个邻居的标签
# dist 表示每个测试样本到其最近k个令居的距离
ret,result,neighbours,dist = knn.findNearest(test_new,k=5)
print(result)
# 判断语句,判断测试结果是否与测试数据的标签相等,返回true或false
maches = result==test_label
# 统计非空数据的和,表示判断为1的个数
count = np.count_nonzero(maches)
# 计算正确率,即为1的个数除以测试结果的总条数
person = count*100/len(result)
print(person)
二、手写数字进行识别
1、在画图板中手绘数字
如下图所示流程:
2、实操代码
import numpy as np
import cv2
img = cv2.imread('digits.png') # 导入图片数据
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) # 转变为灰度图
cells = [np.hsplit(row,100) for row in np.vsplit(gray,50)] #将 每个数字都存放到列表中
x = np.array(cells) # 将数据转换成矩阵类型
train = x[:,:] #将整个图片的数据当做训练集
train_new = train.reshape(-1,400).astype(np.float32) # 将每单个数据对应的像素点转变成一行的状态
k = np.arange(10)
labels = np.repeat(k,500)
train_labels = labels[:,np.newaxis]
knn = cv2.ml.KNearest_create() # 创建一个knn分类器,并初始化模型
knn.train(train_new,cv2.ml.ROW_SAMPLE,train_labels) # 导入数据进行训练
testt = cv2.imread('4.png') # 导入刚刚保存的图片
gray2 = cv2.cvtColor(testt,cv2.COLOR_BGR2GRAY) # 将图片转变成灰度图
x1 = np.array(gray2) # 将数据转变成矩阵类型
test_new1 = x1.reshape(-1,400).astype(np.float32) # 将每个数据转变成单独的一行
ret,result,neighbours,dist = knn.findNearest(test_new1,k=3) # 将数据输入进行测试
print(result)
测试结果为: