基于模板匹配的数字电表数字识别(python)

模板匹配可以说是比较传统的数学方法去做图像识别,以往的模板匹配往往只是让原图像与模板图像做减运算,最后选出最小误差的那张,但在实际识别中,这一方法识别的效果并不是很有效,特别对于两张数字类型并不是很相似的时候,因此在此基础上改经这一普通的减运算,对原图像与模板图像进行距离计算,此处采用欧式距离,计算欧式距离的函数代码如下:

def getTempMinDis(i,j,temp):
    minDis = float('inf')
    h = temp.shape[0] #图像的高
    w = temp.shape[1] #图像的宽
    for i1 in range(h):
        for i2 in range(w):
            if(temp[i1][i2]==255):
                continue
            dis = math.pow(math.pow(i-i1,2)+math.pow(j-i2,2),0.5) #欧式距离
            minDis = min(minDis,dis)
    return minDis

def getRawMinDis(raw,temp):
    dis = 0
    h = raw.shape[0]
    w = raw.shape[1]
    for i in range(h):
        for j in range(w):
            if(raw[i][j] == 255):
                continue
            x = getTempMinDis(i,j,temp)
            dis += x
    return dis

对文件中的模板与原图像依次做欧式距离计算,选取最小的为识别出的数字。
铺垫这么多,看一下一个简单的数字电表的识别实例,电表原图像如下:
数字电表示例
实例中,为了降低识别的繁琐,通过ROI的方式将核心的区域裁剪出来,并做了二值化操作,对切割出来的图像又通过垂直投影的方式切割出单一数字。效果如下:
step1:ROI裁剪
裁剪+二值化
step2:垂直投影分割
像素统计
切割图片
step3:模板匹配识别
识别结果输出
整套代码如下:

import cv2
import numpy as np
import tkinter as tk
from tkinter import filedialog
import os
import math
def get_vvList(list_data):
    #取出list中像素存在的区间
    vv_list=list()
    v_list=list()
    for index,i in enumerate(list_data):
        # print(i)
        if i>4:
            v_list.append(index)
        else:
            if v_list:
                vv_list.append(v_list)
                #list的clear与[]有区别
                v_list=[]
    return vv_list

def cut(img):
    rows, cols = img.shape
    ver_list = [0] * cols
    for j in range(cols):
        for i in range(rows):
            if img.item(i, j) == 0:
                ver_list[j] = ver_list[j] + 1
    '''
    对ver_list中的元素进行筛选,可以去除一些噪点
    '''
    ver_arr = np.array(ver_list)
    ver_arr[np.where(ver_arr < 1)] = 0
    ver_list = ver_arr.tolist()

    # 绘制垂直投影
    img_white = np.ones(shape=(rows, cols), dtype=np.uint8) * 255
    for j in range(cols):
        pt1 = (j, rows - 1)
        pt2 = (j, rows - 1 - ver_list[j])
        cv2.line(img_white, pt1, pt2, (0,), 1)
    cv2.imshow('vect', img_white)
    cv2.waitKey(0)

    # 切割单一字符
    vv_list = get_vvList(ver_list)
    j = 0
    img_list = list()
    for i in vv_list:
        img_ver = img[:, i[0]:i[-1]]
        # cv2.imshow('per char', img_ver)
        cv2.imwrite(r"./rawChar/"+str(j)+".png",img_ver)
        j+=1
        img_list.append(img_ver)
    return img_list

def getTempMinDis(i,j,temp):
    minDis = float('inf')
    h = temp.shape[0]
    w = temp.shape[1]
    for i1 in range(h):
        for i2 in range(w):
            if(temp[i1][i2]==255):
                continue
            dis = math.pow(math.pow(i-i1,2)+math.pow(j-i2,2),0.5)
            minDis = min(minDis,dis)
    return minDis

def getRawMinDis(raw,temp):
    dis = 0
    h = raw.shape[0]
    w = raw.shape[1]
    for i in range(h):
        for j in range(w):
            if(raw[i][j] == 255):
                continue
            x = getTempMinDis(i,j,temp)
            dis += x
    return dis

def chooseFile():
    default_dir = r"D:\pycharm_project\electricity_project\fnn44p4mj8-1\RAW IMAGES\RAW IMAGES\1)Day Light"
    return filedialog.askopenfilename(title=u'选择文件', initialdir=(os.path.expanduser(default_dir)))

root = tk.Tk()
root.withdraw()
file_path = chooseFile()
img = cv2.imread(file_path)  # 获取BGR图像,第二个参数默认值为1,可不填
height = img.shape[0] //4 # 将tuple中的元素取出,赋值给height,width,channels
width = img.shape[1] //4
img = cv2.resize(img,(width,height),cv2.INTER_CUBIC)
rect = cv2.selectROI("roi", img, showCrosshair = False, fromCenter = False)
(x,y,w,h) = rect
imgcrop = img[int(y) : int(y+h), int(x):int(x+w)]
cv2.imshow("img_crop",imgcrop)
gray = cv2.cvtColor(imgcrop,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(gray,0,255,cv2.THRESH_OTSU+cv2.THRESH_BINARY)
cv2.imshow("thresh",thresh)
cv2.waitKey(0)
cv2.destroyAllWindows()
charcut = cut(thresh)
cv2.waitKey(0)
temp_path = "./template/"
file = os.listdir("./template/")
file.sort(key=lambda x: int(x[:-4]))
code = list()
# thresh = 50
for k in range(len(charcut)):
    error = list()
    raw_char = cv2.resize(charcut[k],(16,32),cv2.INTER_CUBIC)
    # gray = cv2.cvtColor(raw_char,cv2.COLOR_BGR2GRAY)
    # ret, raw_char = cv2.threshold(gray, 0, 255, cv2.THRESH_OTSU + cv2.THRESH_BINARY)
    for c in range(len(file)):
        file_path = temp_path + file[c]
        nfile = cv2.imread(file_path)
        temp_char = cv2.resize(nfile, (16, 32), cv2.INTER_CUBIC)
        gray = cv2.cvtColor(temp_char, cv2.COLOR_BGR2GRAY)
        ret, temp_char = cv2.threshold(gray, 0, 255, cv2.THRESH_OTSU + cv2.THRESH_BINARY)
        dis = getRawMinDis(raw_char,temp_char)
        error.append(dis)
    mindis = min(error)
    findc = error.index(mindis)
    findc = str(findc)
    code.append(findc)
l = len(code)
code[l-2] = '.'
res = ''.join(code)
print("识别结果为:",res)

欢迎入门者学习参考。

评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值