目录
使用Python的OpenCV库进行图像处理和数字识别的例子。通过下面的步骤对摄像头的黑色数字进行识别(由于我电脑没有摄像头,实际使用需要替换获取图像部分的代码)。这里的代码只能用于识别照片里面最大的单个数字的简单识别算法,需要更多样化的识别就需要自己在这基础上扩展咯!!!(注意:识别的是黑色数字)
具体步骤如下:
首先,它读取一个名为“digits.png”的图像文件,这个文件应该包含了一些手写数字。然后,它将这个图像从彩色模式转化为灰度模式,这样做可以减少数据的维度,使得处理更加简单。通过使用numpy数组,图像数据被分割成10行,每行90个像素,这样的块被称为“cells”。
接下来,这些cells被组合成一个大数组,然后调整其形状为(-1, 400),这是k-NN算法需要的输入格式。这个调整形状的操作通过numpy的reshape函数实现。
然后,这个调整后的数组被用作训练数据,训练一个k-最近邻(k-NN)分类器。这个分类器用于识别和分类图像中的数字。k-NN是一种常见的机器学习算法,它假设样本在特征空间中的邻近情况可以反映其类别。
在主循环中,代码读取另一个名为“6.png”的图像文件,并对其进行一系列操作:先将其从BGR颜色空间转化为HSV颜色空间,然后通过取反操作将颜色值反转,这可以使图像中的白色区域变为黑色,黑色区域变为白色。
然后,使用OpenCV的findContours函数找出图像中的轮廓。一般来说,数字的轮廓会被找出,然后可以使用boundingRect函数得到这个轮廓的边界矩形。这个边界矩形可以确定数字的大致位置。
接下来,通过裁剪和重新调整大小,将数字图像处理为26x26像素大小。这样做可以使得处理简单化,因为所有的数字图像都有相同的大小。最后,使用k-NN分类器对处理后的数字图像进行分类。
这段代码的主要目的是对一个包含手写数字的图像进行识别。用户可以在屏幕上看到识别结果。如果用户按下“q”键,代码会结束运行并关闭所有打开的窗口。
- import numpy as np
- import cv2 as cv
-
-
- img = cv.imread('digits.png') # 读取名为'digits.png'的图像
- gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY) # 将图像转换为灰度图像
-
- # 现在我们将图像分割为900个单元格,每个单元格为20x20
- cells = [np.hsplit(row,90) for row in np.vsplit(gray,10)] # 将图像分割成10行90列的单元格,每个单元格为20x20像素
-
- # 使其成为一个Numpy数组。它的大小将是(10,90,20,20)
- x = np.array(cells) # 将分割后的图像转换为一个Numpy数组
-
- # 现在我们准备train_data和test_data。
- train = x[:,:90].reshape(-1,400).astype(np.float32) # 取数组作为训练数据,并将其形状转换为(450,400)的浮点数类型
-
- # 为训练和测试数据创建标签
- k = np.arange(10) # 创建一个包含数字0到10的一维数组
- train_labels = np.repeat(k,90)[:,np.newaxis] # 将数组重复90次,得到一个(900,1)的二维数组,作为训练数据的标签
-
-
- # 初始化kNN,训练数据,然后使用k = 1的测试数据对其进行测试
- knn = cv.ml.KNearest_create() # 创建一个kNN分类器对象
- knn.train(train, cv.ml.ROW_SAMPLE, train_labels) # 使用训练数据和标签训练分类器
-
-
- while True:
-
- img = cv.imread('6.png')
-
- # 转换颜色空间 BGR 到 HSV
- hsv = cv.cvtColor(img, cv.COLOR_BGR2HSV)
- # 定义HSV中黑色的范围
- lower_blue = np.array([0,0,0])
- upper_blue = np.array([0,0,50])
- # 设置HSV的阈值使得只取黑色
- mask = cv.inRange(hsv, lower_blue, upper_blue)
-
- # 查找图像轮廓
- contours,hierarchy = cv.findContours(mask, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
-
- # 判断是否检测到轮廓
- if contours:
-
- # 取最大的轮廓
- cnt = contours[0]
-
- # 计算轮廓的边界矩形
- x, y, w, h = cv.boundingRect(cnt)
-
- # 复制选中的图像为新变量
- buf = mask[y:y+h, x:x+w]
-
- # 显示结果帧
- cv.imshow('buf', buf)
-
- # 获取缩小的比例
- num_x = 1/(w/20)
- num_y = 1/((h)/20)
-
- # 对图像进行缩放
- res = cv.resize(buf,None,fx=num_x, fy=num_y, interpolation = cv.INTER_CUBIC)
-
- # 创建一个新的图像,大小是26x26,三个通道,数据类型为8位无符号整数(即像素值范围从0到255)
- new_img = np.zeros((28, 28), dtype=np.uint8)
-
- # 将扩展后的 res 赋值给 new_img
- new_img[4:20+4, 4:20+4] = res
-
- # 获取缩小的比例
- new_num = 1/(28/20)
-
- # 对图像进行缩放
- res = cv.resize(new_img,None,fx=new_num, fy=new_num, interpolation = cv.INTER_CUBIC)
-
- # 将图像颜色值取反
- res = cv.bitwise_not(res)
-
- # 显示结果帧
- cv.imshow('res', res)
-
- # 将图像转换为一个Numpy数组
- gray1_array = np.array(res)
-
- # 取数组作为测试数据,并将其形状转换为(450,400)的浮点数类型
- test = gray1_array[:,:].reshape(-1,400).astype(np.float32)
-
- # 使用测试数据和k=1的参数调用分类器的findNearest方法,得到返回值、预测结果、最近邻样本和距离
- ret,result,neighbours,dist = knn.findNearest(test,k=1)
-
- print( "result:\n{}\n".format(result) )
-
-
- if cv.waitKey(1) == ord('q'):
- # 完成所有操作后,释放捕获器
- cv.destroyAllWindows()
- break
- # 完成所有操作后,释放捕获器
- cv.destroyAllWindows()
-
-
-