基于KNN的数码管数字识别----树莓派上实现

     树莓派是一个非常好用的工具,在上面可以跑Ubuntu mate系统。这个项目主要是对一个固定设备进行拍照、识别数码管数字,实现对设备的实时数据监测。使用了python+opencv从免驱摄像头获得图像进行分割,识别实现功能。这里要吐槽一下设备商,数据接口不开放真的很烦人。在这个系统里要做以下几件事情:

    1、对树莓派刷Ubuntu mate系统
    2、安装并配置python+opencv
    3、安装fswebcam,在Ubuntu下实现拍照功能
    4、制作训练集
    5、写程序......程序比较简单
    具体的思路:
    第一步:python调用系统函数,执行fswebcam命令,利用fswebcam软件获得免驱摄像头图片。
    第二步:opencv读入照片,将图像变成灰度图,再进行二值化(二值化可以选择自适应,应对不同的光照强度)。
    第三步:二值化之后,圈出感兴趣区域,即数字区域,进行图像分割(此部分全由手动设置参数完成,比较简单,但是很笨)
    第四步:数字分割完成后,将图片映射成32x32大小,再KNN识别数字。具体的算法后面给出。
刷系统:
    制作SD卡系统卡(具体方法,网上太多,不再赘述),将树莓派接上显示屏,插上SD卡,将树莓派上电,按照提示操作即可
安装python+opencv:
    python内建于系统不用再安装(python3),需要下载opencv并make源码。
先更新仓库:
sudo apt-get update && sudo apt-get upgrade 
安装必要的python插件及一些环境
sudo apt-get install python3-setuptools python3-dev -y  
安装pip
sudo easy_install3 pip
安装numpy包
pip install numpy
安装build-essential
sudo apt-get install build-essential -y
在这里没有安装libavcodec-dev libavformat-dev libswscale-dev包,因为后两个包在make opencv源码时报错。只需要安装gtk的相关包即可,否则无法创建窗口显示图像。
安装opencv:ubuntu/树莓派通用
1、首先,找一个合适的地方存放opencv的安装包,我选择的路径是~/Download/opencv
2、进入安装路径,并下载安装包
cd /Download/opencv
wget https://github.com/Itseez/opencv/archive/3.0.0.zip
3、下载完成后,需要创建编译后文件存放的路径:
 
unzip 3.0.0.zip && cd opencv-3.0.0
mkdir build && cd build
4、接下来一步,要小心小心按照本地路径来配置,在build目录下执行如下命令:
cmake -D CMAKE_BUILD_TYPE=Release -D CMAKE_INSTALL_PREFIX=/usr/local
PYTHON3_EXECUTABLE=/usr/bin/python3
PYTHON_INCLUDE_DIR=/usr/include/python3.4
PYTHON_LIBRARY=/usr/lib/x86_64-linux-gnu/libpython3.4m.so
PYTHON3_NUMPY_INCLUDE_DIRS=/usr/local/lib/python3.4/dist-packages/numpy/core/include ..
5、最后执行安装命令: 
make && sudo make install
此步骤是在build目录下执行,安装时间较长,注意是否报错。如果上述过程安步骤顺利进行,应该是一步到位。
6、如果你之前的步骤都完成了,那么恭喜你,开始验证吧
import cv2
>>> print(cv2.__version__)
... opencv-3.0.0 
安装完opencv后,我们的前期工作就完成了。
安装fswebcam:
sudo apt-get install fswebcam
使用fswebcam拍照实验:
sudo fswebcam -d /dev/video0 --no-banner -r 320x240 /root/Desktop/image.jpg
在终端中进入/dev  文件夹下查看摄像头编号,一般为video0/1
cd /dev && ls
成功打开摄像头之后,我们就可以开始编写程序了:
直接给出代码如下:
#!/usr/bin/python 
# -*- coding: utf-8 -*-
import cv2
from urllib import request
import numpy as np
import sys
from numpy import *
import operator
import time
from os import listdir
def classify(inputPoint,dataSet,labels,k):
    dataSetSize = dataSet.shape[0]  #已知分类的数据集(训练集)的行数
    #先tile函数将输入点拓展成与训练集相同维数的矩阵,再计算欧氏距离
    diffMat = tile(inputPoint,(dataSetSize,1))-dataSet  #样本与训练集的差值矩阵
    sqDiffMat = diffMat ** 2     #差值矩阵平方
    sqDistances = sqDiffMat.sum(axis=1)   #计算每一行上元素的和
    distances = sqDistances ** 0.5     #开方得到欧拉距离矩阵
    sortedDistIndicies = distances.argsort() #按distances中元素进行升序排序后得到的对应下标的列表
    #选择距离最小的k个点
    classCount = {}
    for i in range(k):
        voteIlabel = labels[ sortedDistIndicies[i] ]
        classCount[voteIlabel] = classCount.get(voteIlabel,0)+1
    #按classCount字典的第2个元素(即类别出现的次数)从大到小排序
    sortedClassCount = sorted(classCount.items(), key = operator.itemgetter(1), reverse = True)
    return sortedClassCount[0][0]
def img2vector(filename):
    returnVect = []
    fr = open(filename)
    for i in range(32):
        lineStr = fr.readline()
        for j in range(32):
            returnVect.append(int(lineStr[j]))
    return returnVect
def classnumCut(fileName):
    fileStr = fileName.split('.')[0]
    classNumStr = int(fileStr.split('_')[0])
    return classNumStr
#构建训练集数据向量,及对应分类标签向量
def trainingDataSet():
    hwLabels = []
    trainingFileList = listdir('E:/VS2013Project/picsolve/trainingDigits')     #获取目录内容
    m = len(trainingFileList)
    trainingMat = zeros((m,1024))        #m维向量的训练集
    for i in range(m):
        fileNameStr = trainingFileList[i]
        hwLabels.append(classnumCut(fileNameStr))
        trainingMat[i,:] = img2vector('E:/VS2013Project/picsolve/trainingDigits/%s' % fileNameStr)
        #print type(trainingMat)
    return hwLabels,trainingMat
img = cv2.imread('5.jpg')
#显示原图
cv2.namedWindow("image",cv2.WINDOW_NORMAL)
cv2.imshow("image",img)
cv2.waitKey(0)
#sp[0] rows sp[1] cols sp[2] pixels
sp=img.shape
#转化为灰度图
grayimg = cv2.cvtColor(img,cv2.COLOR_RGB2GRAY)
#转化为二值图
retval,dstimg = cv2.threshold(grayimg,120,255,cv2.THRESH_BINARY)
dst_sp=dstimg.shape
print(dst_sp[0])
print(dst_sp[1])
#圈出数字区域
roi_img = dstimg[850:890,620:750]
roi_sp = roi_img.shape
cv2.namedWindow("roi",cv2.WINDOW_NORMAL)
cv2.imshow("roi",roi_img)
cv2.waitKey(0)
#切分图片        
roi_img = roi_img[2:35,7:130]
cv2.namedWindow("roi1",cv2.WINDOW_NORMAL)
cv2.imshow("roi1",roi_img)
cv2.waitKey(0)
dst_sp2=roi_img.shape
print(dst_sp2[0])
print(dst_sp2[1])
index=[0,0,0,0,0]
k=0
for i in range(6):
    if i == 2:
       continue
    elif i == 0:
       roi_img1 = roi_img[1:180,i*20:i*20+20]
    else :
       roi_img1 = roi_img[1:180,i*20:i*20+20]   
    cv2.namedWindow("roi2",cv2.WINDOW_NORMAL)
    cv2.imshow("roi2",roi_img1)
    cv2.waitKey(0)
#归一化 32X32
    res=cv2.resize(roi_img1,(32,32),interpolation=cv2.INTER_CUBIC)
#0/1矩阵
#    fid=open(str(i)+'.txt','w')
    pic=[]
    for i in range(32):
        for j in range(32):
            if res[i][j]<=200:
                res[i][j]=0
            else:
                res[i][j]=1
            pic.append(int(res[i][j]))
 #           fid.write(str(res[i][j]))
 #       fid.write("\n")
 #   fid.close()
    hwLabels,trainingMat = trainingDataSet()
    classifierResult = classify(pic, trainingMat, hwLabels, 3)
    index[k]=classifierResult
    k=k+1
    print (classifierResult)
print(index)
num1 = index[0]*10+index[1]
num2 = index[2]*100+index[3]*10+index[4]
print(num1)
print(num2)
cv2.destroyAllWindows()
本文参考了如下博客,谨向作者表达谢意!

猜你喜欢

转载自blog.csdn.net/qq_22272261/article/details/80950924