项目二:opencv实战之‘信用卡数字识别’

  • 知识点杂记
	1,出现于myutils.py中的函数
	def resize(image, width=None, height=None, inter=cv2.INTER_AREA)
	
	interplolation为缩放时候的差值方式,主要有以下几种:
	
		cv2.INTER_AREA #利用像素关系重采样。当图像缩小时,可以避免波 纹;当图像放大的时候,类似于cv2.INTER_NN。
		
			cv2.INTER_CUBIC  # 立方插值
			cv2.INTER_LINEAR  # 双线形插值 
			cv2.INTER_NN      # 最近邻插值

	2,argparse包,argparse 是python自带的命令行参数解析包,可以用来方便地读取命令行参数,当你的代码需要频繁地修改参数的时候,使用这个工具可以将参数和代码分离开来,让你的代码更简洁,适用范围更广。

	   parser = argparse.ArgumentParser(description = 'This is a test')
	  parser.add_argument("-p","--port",help='increase output port') 
	  #定义了可选参数-p和--port,赋值后,其值保存在args.port中(其值		    都是保存在最后一个定义的参数中)


	3,灰度是指黑白图像中的颜色深度,范围一般0-255,白色为255,黑色为0,故黑白图片也称为灰度图像。

若是彩色图像的灰度其实是在转化为黑白图像后的像素值。

如果一个二值灰度图像,它的像素值只能为01,我们说它的灰度级为2
	4,np.absolute(a): 计算数组a的绝对值。
	
	5,retval,dst = cv2.threshold(ref, 10, 255, cv2.THRESH_BINARY_INV)

	因为cv2.threshold()会返回两个值,一个是返回值retval,一个是图像目标dst。
	
所以用的时候常常:
dst = cv2.threshold(ref, 10, 255, cv2.THRESH_BINARY_INV)[1]
只取第二个返回值


6zip() 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。
如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同,利用 * 号操作符,可以将元组解压为列表。
>>>a = [1,2,3]

>>> b = [4,5,6]

>>> c = [4,5,6,7,8]

>>> zipped = zip(a,b)     # 打包为元组的列表
[(1, 4), (2, 5), (3, 6)]

>>> zip(a,c)              # 元素个数与最短的列表一致
[(1, 4), (2, 5), (3, 6)]

>>> zip(*zipped)   # 与 zip 相反,*zipped 可理解为解压,返回二维矩阵式
[(1, 2, 3), (4, 5, 6)]



7,排序函数sorted()
sorted(iterable, cmp=None, key=None, reverse=False)

iterable -- 可迭代对象。

cmp -- 比较的函数,这个具有两个参数,参数的值都是从可迭代对象中取出,此函数必须遵守的规则为,大于则返回1,小于则返回-1,等于则返回0。

key -- 主要是用来进行比较的元素,只有一个参数,具体的函数的参数就是取自于可迭代对象中,指定可迭代对象中的一个元素来进行排序。

reverse -- 排序规则,reverse = True 降序 , reverse = False 升序(默认)。


8,
items() 字典函数以列表返回可遍历的(,) 元组数组。

dict = {'Hunan': 'Changsha', 'Hubei': 'Wuhan', 'Sichuan': 'Chengdu'}

print(dict.items())
#输出的字典值 : [('Hunan', 'Changsha'), ('Hubei', 'Wuhan'), ('Sichuan', 'Chengdu')]

for (key,values) in  dict.items():
print key,values

以上实例输出结果为:

Hunan Changsha
Hubei Wuhan
Sichuan Chengdu


9,    
cv2.putText(img, str(i), (123,456)), font, 2, (0,255,0), 3)
这个函数是opencv里面向图像上添加文本内容的函数.

各参数依次是:图片,添加的文字,左上角坐标,字体,字体大小,颜色,字体粗细


10,
extend() 函数用于在列表末尾一次性追加另一个序列中的多个值(用新列表扩展原来的列表)

参数
seq -- 元素列表

输入:
aList = [123, 'xyz', 'zara', 'abc', 123];
bList = [2009, 'manni'];
aList.extend(bList)

print "Extended List : ", aList ;

输出结果如下:
Extended List :  [123, 'xyz', 'zara', 'abc', 123, 2009, 'manni']


11,
imutils包
是在opencv基础上对一些方法进行了再次加工,使这些方法更加简单易用,包括 translation, rotation, resizing, skeletonization, and displaying Matplotlib images 等。


12,图像梯度对意义:

当用均值滤波器降低图像噪声的时候,会带来图像模糊的副作用。我们当然希望看到的是清晰图像。那么,清晰图像和模糊图像之间的差别在哪里呢?从逻辑上考虑,图像模糊是因为图像中物体的轮廓不明显,轮廓边缘灰度变化不强烈,层次感不强造成的,那么反过来考虑,轮廓边缘灰度变化明显些,层次感强些是不是图像就更清晰些呢。

那么,这种灰度变化明显不明显怎样去定义呢。我们学过微积分,知道微分就是求函数的变化率,即导数(梯度),那么对于图像来说,可以用微分来表示图像灰度的变化率。

那么,这个梯度(或者说灰度值的变化率)如何增强图像的清晰度呢?
如果我们把梯度值与对应的像素相加,那么灰度值没有变化的,像素值不变,而有梯度值的,灰度值变大了。

def This_is_a_white: def
####################################
####################################

13,   
join()用法
join()方法——用于将序列中的元素以指定的字符连接生成一个新的字符串。
join()方法语法:str.join(sequence),sequence为要连接的元素序列。
str = "-"
seq = ("a", "b", "c") # 字符串序列
# c = [1, 2, 3] 数字不行,变成# c = ["1", "2", "3"]
print(str.join(seq))  # 输出结果为a-b-c
# print("-".join(seq))  直接这样写也行
# print(“”.join(seq))  输出结果为abc


  • 代码
"""
myutils.py

"""
import cv2

def sort_contours(cnts, method='left_to_right'):
    boundingBoxes = [cv2.boundingRect(c) for c in cnts]

    (cnts, boundingBoxes) = zip(*sorted(zip(cnts, boundingBoxes),
                                        key=lambda x:x[1][0], reverse=False))

    return cnts, boundingBoxes

def resize(image, width=None, height=None, inter=cv2.INTER_AREA):
    dim = None
    (h, w) = image.shape[:2]
    if width is None and height is None:
        return image
    if width is None:
        r = height / float(h)
        dim = (int(w * r), height)
    else:
        r = width / float(w)
        dim = (width, int(h * r))
    resized = cv2.resize(image, dim, interpolation=inter)
    return resized

"""

template_match.py

"""
# 主函数
from imutils import contours
import numpy as np
import cv2
import myutils


# 绘画函数
def cv_show(name, img):
    cv2.imshow(name, img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()


# 导入模版
temp = cv2.imread('images/ocr_a_reference.png')
cv_show('temp', temp)

# 预处理
temp_gray = cv2.cvtColor(temp, cv2.COLOR_BGR2GRAY)
cv_show('temp_gray', temp_gray)

temp_binaryzation = cv2.threshold(temp_gray, 10, 255, cv2.THRESH_BINARY_INV)[1]
cv_show('temp_binaryzation', temp_binaryzation)

# 找到模版的轮廓
a_, tempConts, c_ = cv2.findContours(temp_binaryzation, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

# 绘制模版轮廓
cv2.drawContours(temp, tempConts, -1, (0, 0, 255), 2)
cv_show('tempConts', temp)

# 给模版轮廓排序
tempConts = contours.sort_contours(tempConts, method='left-to-right')[0]

digits = {}
# 遍历模版轮廓
for (i, c) in enumerate(tempConts):
    (x, y, w, h) = cv2.boundingRect(c)

    roi = temp_binaryzation[y:y + h, x:x + w]
    roi = cv2.resize(roi, (57, 88))

    # 把0-9这十个模版存入字典digits
    digits[i] = roi

# 读入信用卡图片
img = cv2.imread('images/credit_card_03.png')
cv_show('img', img)

img = myutils.resize(img, width=300)

# 灰度化
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv_show('gray', gray)

#  二值化
binary = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
cv_show('binary', binary)

# 导入卷积核
rectKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 3))
sqKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))

# 顶帽操作突出明亮部分
tophat = cv2.morphologyEx(binary, cv2.MORPH_TOPHAT, rectKernel)
cv_show('tophat', tophat)

# Sobel求图像梯度,使得轮廓更加清晰
gradX = cv2.Sobel(tophat, ddepth=cv2.CV_32F, dx=1, dy=0, ksize=-1)  # ksize=-1默认为(3,3)的核

gradX = np.absolute(gradX)
(minval, maxval) = (np.min(gradX), np.max(gradX))

gradX = (255 * (gradX - minval) / (maxval - minval))  # 归一化
gradX = gradX.astype('uint8')
cv_show('gradX', gradX)



# 闭操作,先膨胀后腐蚀,连接区域
close1 = cv2.morphologyEx(gradX, cv2.MORPH_CLOSE, rectKernel)
cv_show('close1', close1)

# 再次闭操作,填充洞
close2 = cv2.morphologyEx(close1, cv2.MORPH_CLOSE, sqKernel)
cv_show('close2', close2)

#  计算图像的轮廓
(_, imgConts, _) = cv2.findContours(close2, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

img_copy = img.copy()
cv2.drawContours(img_copy, imgConts, -1, (0, 0, 255), 2)
cv_show('imgConts', img_copy)

locs = []
# 遍历轮廓,根据长宽比找到合适位置的轮廓并保存到locs
for (i, c) in enumerate(imgConts):
    (x, y, w, h) = cv2.boundingRect(c)
    ar = w / float(h)

    # 选择合适的区域
    if ar > 2.5 and ar < 4.0:
        if (w > 40 and w < 55) and (h > 10 and h < 20):
            locs.append((x, y, w, h))

# 把找到的合适轮廓按照x取值,从左到右从大到小排序
locs = sorted(locs, key=lambda x: x[0])

output = []
# 遍历找到的四组
for (i, (gX, gY, gW, gH)) in enumerate(locs):
    groupOut = []
    # 根据坐标求每一组
    group = gray[gY:gY + gH, gX:gX + gW]

    group = cv2.threshold(group, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
    cv_show('group', group)

    #  计算一组中的轮廓
    (_, cnts, _) = cv2.findContours(group, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

    # 给这四个小数字轮廓排序
    cnts = contours.sort_contours(cnts, method='left-to-right')[0]

    # 计算每组中的数字
    for (i, c) in enumerate(cnts):
        (x, y, w, h) = cv2.boundingRect(c)
        roi = group[y:y + h, x:x + w]
        roi = cv2.resize(roi, (57, 88))
        #cv_show('digit', roi)

        # 计算得分
        scores = []

        # 模版匹配
        for (digit, digitROI) in digits.items():
            res = cv2.matchTemplate(roi, digitROI, cv2.TM_CCOEFF)

            (_, score, _, _) = cv2.minMaxLoc(res)
            scores.append(score)

        groupOut.append(str(np.argmax(scores))) # 这里要记得转换为str,不然join()会出错

    # 画出来
    cv2.rectangle(img, (gX - 5, gY - 5), (gX + gW + 5, gY + gH + 5),
                  (0, 0, 255), 1)
    cv2.putText(img, ''.join(groupOut), (gX, gY - 15), cv2.FONT_HERSHEY_SIMPLEX, 0.65, (0, 255, 0), 2)
    output.extend(groupOut)

print('This result is {}'.format(''.join(output)))
cv_show('result', img)




发布了4 篇原创文章 · 获赞 3 · 访问量 123

猜你喜欢

转载自blog.csdn.net/asd2390181722/article/details/104640810
今日推荐