一、信用卡卡号识别

一、思路分析

大体思路:首先拿到一张银行卡,我们得有银行卡号数字的0-9样式的模板,然后再通过不同数字的轮廓的外接矩形来进行匹配,最终识别出银行卡号所对应的数字。
银行卡数字模板:
在这里插入图片描述
银行卡信息:
在这里插入图片描述

拿到银行卡的时候,因为银行卡上面不仅仅只是银行卡号,还会存在一些干扰项,这时候需要对这些干扰项进行过滤,这些干扰项和数字所在的外接轮廓大小是不相同的,故可以以此进行过滤筛选。当然,一下次不会将单个数字给定位到,拿到的也不是单个数字,绝大多数的银行卡号都是四个为一组,接下来再对每一组中的四个数字进行拆分。

二、导包以及相关函数

from imutils import contours
import numpy as np
import argparse
import cv2
# 绘图展示
def cv_show(name,img):cv2.imshow(name, img)cv2.waitKey(0)cv2.destroyAllWindows()
#因为银行卡分为四个大轮廓,每个大轮廓中又包括四个数字,这里需要定义一个函数用于将识别出的四个大轮廓依次排序存放
def sort_contours(cnts, method="left-to-right"):reverse = Falsei = 0if method == "right-to-left" or method == "bottom-to-top":reverse = Trueif method == "top-to-bottom" or method == "bottom-to-top":i = 1boundingBoxes = [cv2.boundingRect(c) for c in cnts] #用一个最小的矩形,把找到的形状包起来x,y,h,w(cnts, boundingBoxes) = zip(*sorted(zip(cnts, boundingBoxes),key=lambda b: b[1][i], reverse=reverse))#对模板上的轮廓进行排序,也就是将模板上的数字给贴个标签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 imageif 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

三、获取模板上的数字信息

指定测试图像以及模板图像位置

# 设置参数
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True,help="path to input image")#指定输入图像
ap.add_argument("-t", "--template", required=True,help="path to template OCR-A image")#指定模板图像
args = vars(ap.parse_args())

设置银行卡类型参数

# 指定信用卡类型
FIRST_NUMBER = {"3": "American Express","4": "Visa","5": "MasterCard","6": "Discover Card"
}

首先处理模板图像,模板图像存放这0-9数字,读取模板图像,灰度图、二值化

# 读取一个模板图像
img = cv2.imread(args["template"])
cv_show('img',img)
# 灰度图
ref = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv_show('ref',ref)
# 二值图像
ref = cv2.threshold(ref, 10, 255, cv2.THRESH_BINARY_INV)[1]
cv_show('ref',ref)

对二值化之后的模板图像获取轮廓

# 计算轮廓
#cv2.findContours()函数接受的参数为二值图,即黑白的(不是灰度图),cv2.RETR_EXTERNAL只检测外轮廓,cv2.CHAIN_APPROX_SIMPLE只保留终点坐标
#返回的list中每个元素都是图像中的一个轮廓
ref_, refCnts, hierarchy = cv2.findContours(ref.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)

用红色线进行绘制模板轮廓,定义一个空字典digits,用于存储后续得到模板图像轮廓信息

cv2.drawContours(img,refCnts,-1,(0,0,255),3) #用红色线画轮廓
cv_show('img',img)
print (np.array(refCnts).shape)#出现10个轮廓,0-9数字所对应的图像信息
refCnts = sort_contours(refCnts, method="left-to-right")[0] #排序,从左到右,从上到下  得到模板排序完之后的轮廓
digits = {}#指定一个空字典

对模板图像中0-9个轮廓依次去遍历,得到信息存储到digits字典中

# 遍历每一个轮廓
for (i, c) in enumerate(refCnts):#在模板轮廓中不断的去遍历,i为轮廓的索引,c为轮廓# 计算外接矩形并且resize成合适大小(x, y, w, h) = cv2.boundingRect(c)#得到第i个轮廓的外接矩形信息roi = ref[y:y + h, x:x + w]#用外接矩形对模板图像相同位置抠出来roi = cv2.resize(roi, (57, 88))#抠出来的模板图像的大小可能会较小,把图像给resize成一个差不多大小的图像# 每一个数字对应每一个模板digits[i] = roi#把从模板中抠出来的数字存入到字典中,模板为value,索引为key
#循环结束之后,digits字典中就存放有了0-9数字的模板图像信息

三、对测试图像进行形态学操作,消除其他的干扰因素

根据不同情景选取合适的卷积核

# 初始化卷积核 这里主要是根据具体情况具体分析  卷积核的定义需要看具体情况而定
rectKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 3))
sqKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))

对测试图像进行预处理操作

#读取输入图像,预处理
image = cv2.imread(args["image"])#读取测试图片
cv_show('image',image)#显示一下测试图像
image = resize(image, width=300)#重新resize一下图像大小
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)#因为传入的测试图像是彩色图,需要转换为灰度图
cv_show('gray',gray)#显示一下灰度图

将得到的灰度图图像通过礼帽操作,使得数字特征信息更加明显

#礼帽操作,突出更明亮的区域
tophat = cv2.morphologyEx(gray, cv2.MORPH_TOPHAT, rectKernel) 
cv_show('tophat',tophat) 
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")print (np.array(gradX).shape)
cv_show('gradX',gradX)

将数字部分进行融合到一块,分成四个大轮廓

#通过闭操作(先膨胀,再腐蚀)将数字连在一起
gradX = cv2.morphologyEx(gradX, cv2.MORPH_CLOSE, rectKernel) 
cv_show('gradX',gradX)
#THRESH_OTSU会自动寻找合适的阈值,适合双峰,需把阈值参数设置为0
thresh = cv2.threshold(gradX, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1] 
cv_show('thresh',thresh)#因为实际效果并不好,没有完全融合到一块,故再来一个闭操作
thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, sqKernel) #再来一个闭操作
cv_show('thresh',thresh)

绘制测试图像中的轮廓信息

# 计算轮廓
thresh_, threshCnts, hierarchy = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,	cv2.CHAIN_APPROX_SIMPLE)cnts = threshCnts
cur_img = image.copy()
cv2.drawContours(cur_img,cnts,-1,(0,0,255),3) #将处理之后的图像轮廓绘制到原始图像中去
cv_show('img',cur_img)
locs = []#因为对测试图像轮廓检测会得到很多个轮廓,其中只有数字部分轮廓是我们需要的,这里定义一个列表,用于存储我们需要的数字轮廓

四、开始将测试图像与模板图像数字轮廓依次进行比较

因为测试图像中的轮廓会有好多,我们只需要数字轮廓部分,故图像轮廓的宽高比进行筛选

# 遍历轮廓
for (i, c) in enumerate(cnts):# 计算矩形(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))#将符合我们所设定的轮廓进行存储,这些都是四个数字为一组,一共有四组轮廓信息

将筛选之后得出的轮廓进行排序存放

# 将符合的轮廓从左到右排序
locs = sorted(locs, key=lambda x:x[0])#对获取的大轮廓从左到右排序
output = []

遍历每个轮廓中的数字信息与模板中的数字信息比较评分

# 遍历每一个轮廓中的数字
for (i, (gX, gY, gW, gH)) in enumerate(locs):# initialize the list of group digitsgroupOutput = []# 根据坐标提取每一个组group = gray[gY - 5:gY + gH + 5, gX - 5:gX + gW + 5]#为了使得效果处理较好,将拿到的大轮廓数据往上往下往左往右都扩大点cv_show('group',group)#显示第i个大轮廓# 预处理group = cv2.threshold(group, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]#对第i个大轮廓二值化,为了找大轮廓中的四个数字轮廓cv_show('group',group)# 计算每一组的轮廓group_,digitCnts,hierarchy = cv2.findContours(group.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)#对第i个大轮廓依次进行轮廓检测digitCnts = contours.sort_contours(digitCnts,method="left-to-right")[0]#对检测出来的小轮廓从左到右排序# 计算每一组中的每一个数值for c in digitCnts:#每个大轮廓都有四个数字,对每一个大轮廓中的每一个小数字分别进行计算,此时c有4个值,因为测试图像中有每个大轮廓有四个数字# 找到当前数值的轮廓,resize成合适的的大小(x, y, w, h) = cv2.boundingRect(c)#对大轮廓找取外接轮廓roi = group[y:y + h, x:x + w]#找到每个数字的轮廓信息roi = cv2.resize(roi, (57, 88))#这个resize的参数要与上列的模板设定的大小一致,到时候需要做模板匹配大小应该一致cv_show('roi',roi)#依次展示第i个大轮廓中的四个数字# 计算匹配得分scores = []#得到数字轮廓信息,要对模板进行比较,存储得分信息# 在模板中计算每一个得分for (digit, digitROI) in digits.items():#将这个数字模板依次与标准模板中的十个数进行匹配# 模板匹配result = cv2.matchTemplate(roi, digitROI, cv2.TM_CCOEFF)(_, score, _, _) = cv2.minMaxLoc(result)scores.append(score)#依次将得分信息存入# 得到最合适的数字groupOutput.append(str(np.argmax(scores)))#选出得分最高的那个数即可# 画出来cv2.rectangle(image, (gX - 5, gY - 5), (gX + gW + 5, gY + gH + 5), (0, 0, 255), 1)cv2.putText(image, "".join(groupOutput), (gX, gY - 15), cv2.FONT_HERSHEY_SIMPLEX, 0.65, (0, 0, 255), 2)# 得到结果output.extend(groupOutput)#得到第c组大轮廓的四个数

五、输出展示

# 打印结果
print("Credit Card Type: {}".format(FIRST_NUMBER[output[0]]))
print("Credit Card #: {}".format("".join(output)))
cv2.imshow("Image", image)
cv2.waitKey(0)

六、Pycharm参数设定方法

在这里插入图片描述
找到Edit Configurations
在这里插入图片描述
--image images/credit_card_04.png --template ocr_a_reference.png
其中:images/credit_card_04.png为测试图片的位置、ocr_a_reference.png为银行卡数字模板图片的位置

七、项目完整代码

# 导入工具包
from imutils import contours
import numpy as np
import argparse
import cv2
#import myutils# 设置参数
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True,help="path to input image")#指定输入图像
ap.add_argument("-t", "--template", required=True,help="path to template OCR-A image")#指定模板图像
args = vars(ap.parse_args())# 指定信用卡类型
FIRST_NUMBER = {"3": "American Express","4": "Visa","5": "MasterCard","6": "Discover Card"
}
# 绘图展示
def cv_show(name,img):cv2.imshow(name, img)cv2.waitKey(0)cv2.destroyAllWindows()def sort_contours(cnts, method="left-to-right"):reverse = Falsei = 0if method == "right-to-left" or method == "bottom-to-top":reverse = Trueif method == "top-to-bottom" or method == "bottom-to-top":i = 1boundingBoxes = [cv2.boundingRect(c) for c in cnts] #用一个最小的矩形,把找到的形状包起来x,y,h,w(cnts, boundingBoxes) = zip(*sorted(zip(cnts, boundingBoxes),key=lambda b: b[1][i], reverse=reverse))#对模板上的轮廓进行排序,也就是将模板上的数字给贴个标签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 imageif 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# 读取一个模板图像
img = cv2.imread(args["template"])
cv_show('img',img)
# 灰度图
ref = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv_show('ref',ref)
# 二值图像
ref = cv2.threshold(ref, 10, 255, cv2.THRESH_BINARY_INV)[1]
cv_show('ref',ref)# 计算轮廓
#cv2.findContours()函数接受的参数为二值图,即黑白的(不是灰度图),cv2.RETR_EXTERNAL只检测外轮廓,cv2.CHAIN_APPROX_SIMPLE只保留终点坐标
#返回的list中每个元素都是图像中的一个轮廓
ref_, refCnts, hierarchy = cv2.findContours(ref.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)cv2.drawContours(img,refCnts,-1,(0,0,255),3) #用红色线画轮廓
cv_show('img',img)
print (np.array(refCnts).shape)#出现十个轮廓
refCnts = sort_contours(refCnts, method="left-to-right")[0] #排序,从左到右,从上到下  得到模板排序完之后的轮廓
digits = {}#指定一个空字典# 遍历每一个轮廓
for (i, c) in enumerate(refCnts):#在模板轮廓中不断的去遍历,i为轮廓的索引,c为轮廓# 计算外接矩形并且resize成合适大小(x, y, w, h) = cv2.boundingRect(c)#得到第i个轮廓的外接矩形信息roi = ref[y:y + h, x:x + w]#用外接矩形对模板图像相同位置抠出来roi = cv2.resize(roi, (57, 88))#抠出来的模板图像的大小可能会较小,把图像给resize成一个差不多大小的图像# 每一个数字对应每一个模板digits[i] = roi#把从模板中抠出来的数字存入到字典中,模板为value,索引为key
#循环结束之后,digits字典中就存放有了0-9数字的模板图像信息# 初始化卷积核
rectKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9, 3))
sqKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))#读取输入图像,预处理
image = cv2.imread(args["image"])#读取测试图片
cv_show('image',image)#显示一下测试图像
image = resize(image, width=300)#重新resize一下图像大小
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)#因为传入的测试图像是彩色图,需要转换为灰度图
cv_show('gray',gray)#显示一下灰度图#礼帽操作,突出更明亮的区域
tophat = cv2.morphologyEx(gray, cv2.MORPH_TOPHAT, rectKernel) 
cv_show('tophat',tophat) 
# 
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")print (np.array(gradX).shape)
cv_show('gradX',gradX)#通过闭操作(先膨胀,再腐蚀)将数字连在一起
gradX = cv2.morphologyEx(gradX, cv2.MORPH_CLOSE, rectKernel) 
cv_show('gradX',gradX)
#THRESH_OTSU会自动寻找合适的阈值,适合双峰,需把阈值参数设置为0
thresh = cv2.threshold(gradX, 0, 255,cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1] 
cv_show('thresh',thresh)#再来一个闭操作
thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, sqKernel) #再来一个闭操作
cv_show('thresh',thresh)# 计算轮廓
thresh_, threshCnts, hierarchy = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,	cv2.CHAIN_APPROX_SIMPLE)cnts = threshCnts
cur_img = image.copy()
cv2.drawContours(cur_img,cnts,-1,(0,0,255),3) #将处理之后的图像轮廓绘制到原始图像中去
cv_show('img',cur_img)
locs = []#因为对测试图像轮廓检测会得到很多个轮廓,其中只有数字部分轮廓是我们需要的,这里定义一个列表,用于存储我们需要的数字轮廓# 遍历轮廓
for (i, c) in enumerate(cnts):# 计算矩形(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))#将符合我们所设定的轮廓进行存储,这些都是四个数字为一组,一共有四组轮廓信息# 将符合的轮廓从左到右排序
locs = sorted(locs, key=lambda x:x[0])#对获取的大轮廓从左到右排序
output = []# 遍历每一个轮廓中的数字
for (i, (gX, gY, gW, gH)) in enumerate(locs):# initialize the list of group digitsgroupOutput = []# 根据坐标提取每一个组group = gray[gY - 5:gY + gH + 5, gX - 5:gX + gW + 5]#为了使得效果处理较好,将拿到的大轮廓数据往上往下往左往右都扩大点cv_show('group',group)#显示第i个大轮廓# 预处理group = cv2.threshold(group, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]#对第i个大轮廓二值化,为了找大轮廓中的四个数字轮廓cv_show('group',group)# 计算每一组的轮廓group_,digitCnts,hierarchy = cv2.findContours(group.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)#对第i个大轮廓依次进行轮廓检测digitCnts = contours.sort_contours(digitCnts,method="left-to-right")[0]#对检测出来的小轮廓从左到右排序# 计算每一组中的每一个数值for c in digitCnts:#每个大轮廓都有四个数字,对每一个大轮廓中的每一个小数字分别进行计算,此时c有4个值,因为测试图像中有每个大轮廓有四个数字# 找到当前数值的轮廓,resize成合适的的大小(x, y, w, h) = cv2.boundingRect(c)#对大轮廓找取外接轮廓roi = group[y:y + h, x:x + w]#找到每个数字的轮廓信息roi = cv2.resize(roi, (57, 88))#这个resize的参数要与上列的模板设定的大小一致,到时候需要做模板匹配大小应该一致cv_show('roi',roi)#依次展示第i个大轮廓中的四个数字# 计算匹配得分scores = []#得到数字轮廓信息,要对模板进行比较,存储得分信息# 在模板中计算每一个得分for (digit, digitROI) in digits.items():#将这个数字模板依次与标准模板中的十个数进行匹配# 模板匹配result = cv2.matchTemplate(roi, digitROI, cv2.TM_CCOEFF)(_, score, _, _) = cv2.minMaxLoc(result)scores.append(score)#依次将得分信息存入# 得到最合适的数字groupOutput.append(str(np.argmax(scores)))#选出得分最高的那个数即可# 画出来cv2.rectangle(image, (gX - 5, gY - 5), (gX + gW + 5, gY + gH + 5), (0, 0, 255), 1)cv2.putText(image, "".join(groupOutput), (gX, gY - 15), cv2.FONT_HERSHEY_SIMPLEX, 0.65, (0, 0, 255), 2)# 得到结果output.extend(groupOutput)#得到第c组大轮廓的四个数# 打印结果
print("Credit Card Type: {}".format(FIRST_NUMBER[output[0]]))
print("Credit Card #: {}".format("".join(output)))
cv2.imshow("Image", image)
cv2.waitKey(0)

八、测试图片和模板图片

模板图像:
模板图片
测试图像:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

九、运行效果展示

在这里插入图片描述
在这里插入图片描述在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述

在这里插入图片描述
在这里插入图片描述在这里插入图片描述
在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述
在这里插入图片描述在这里插入图片描述
在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述
在这里插入图片描述在这里插入图片描述
在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述
在这里插入图片描述在这里插入图片描述
在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/377884.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

bootstrap网格系统_如何使用Bootstrap网格系统?

bootstrap网格系统In the last article, we learned how to create a simple page of Bootstrap? Now, we will learn what is "Grid System" in Bootstrap and how we can use or implement it in our bootstrap page? As you know bootstrap is a mobile-friendl…

回溯法初步

本文为参考公众号所做的笔记。 代码随想录原文 回溯法本质是穷举&#xff0c;穷举所有可能&#xff0c;然后选出我们想要的答案&#xff0c;所以它并不是一个高效的算法。但是由于有些问题本身能用暴力搜出来就不错了&#xff0c;所以回溯法也有很多的应用。 回溯法解决的问题…

二、文档扫描OCR

一、思路分析 首先&#xff0c;拿到一张文档&#xff0c;我们需要对文档进行预处理操作&#xff0c;再进行轮廓检测&#xff0c;因为就算拿到文档轮廓&#xff0c;但是这些轮廓也有可能是歪歪扭扭的&#xff0c;这时候需要通过一系列的透视变换操作&#xff0c;将文档摆正。通…

leetcode 77. 组合 思考分析

目录1、题目2、回溯法思路3、参考其他思路&#xff0c;更深入了解这个问题4、剪枝优化可能需要回顾到的知识文章&#xff1a;1、常用算法总结(穷举法、贪心算法、递归与分治算法、回溯算法、数值概率算法)2、回溯法初步删除vector容器中的对象元素的三种方法:pop_back, erase与…

三、全景拼接

一、项目所涉及到的一些知识点 Ⅰ&#xff0c;BF(Brute-Force)暴力匹配&#xff1a;把两张图像的特征点全部给算出来&#xff0c;然后使用归一化的欧氏距离比较这两张图像上特征点之间的大小关系&#xff0c;越小越相似。 SIFT算法 import cv2 import numpy as np import ma…

leetcode 216. 组合总和 III 思考分析

可能需要回顾的文章; leetcode 77. 组合 思考分析 1、题目 找出所有相加之和为 n 的 k 个数的组合。组合中只允许含有 1 - 9 的正整数&#xff0c;并且每种组合中不存在重复的数字。 说明&#xff1a; 所有数字都是正整数。 解集不能包含重复的组合。 2、递归 这一题和之前…

约束执行区域(CER)

受约束的执行区域 (CER) 是创作可靠托管代码的机制的一部分。CER 定义一个区域&#xff0c;在该区域中公共语言运行库 (CLR) 会受到约束&#xff0c;不能引发可使区域中的代码无法完全执行的带外异常。在该区域中&#xff0c;用户代码受到约束&#xff0c;不能执行会导致引发带…

四、模拟英语四六级答题卡识别阅卷评分

一、思路分析 首先拿到答题卡照片的时候&#xff0c;需要对照片进行一系列预处理操作&#xff0c;通过透视变换将图像摆正方便后续的操作。每一道题五个选项&#xff0c;有五道题&#xff0c;通过字典存放准确答案。没有依次对答题卡进行轮廓检测&#xff0c;这里采用的是正方…

leetcode 17. 电话号码的字母组合 思考分析

题目 给定一个仅包含数字 2-9 的字符串&#xff0c;返回所有它能表示的字母组合。 给出数字到字母的映射如下&#xff08;与电话按键相同&#xff09;。注意 1 不对应任何字母。 思考与递归程序 解空间树的宽度是输入数字对应的字符的个数&#xff0c;深度是输入的数字的个数…

BHMS的完整形式是什么?

BHMS&#xff1a;顺势疗法医学和外科学士 (BHMS: Bachelor of Homeopathic Medicine and Surgery) BHMS is an abbreviation of Bachelor of Homeopathic Medicine and Surgery. It is a medical degree program for under graduation in Homeopathy; an alternative move towa…

WordPress Event Easy Calendar插件多个跨站请求伪造漏洞

漏洞名称&#xff1a;WordPress Event Easy Calendar插件多个跨站请求伪造漏洞CNNVD编号&#xff1a;CNNVD-201309-083发布时间&#xff1a;2013-09-11更新时间&#xff1a;2013-09-11危害等级&#xff1a; 漏洞类型&#xff1a;跨站请求伪造威胁类型&#xff1a;远程CVE编号&…

XML转txt格式脚本

一、东北大学老师收集的钢材缺陷数据集是XML格式的&#xff0c;但是YOLOv5只允许使用txt文件标签 例如其中一种缺陷图片所对应的标签&#xff1a;crazing_1.xml <annotation><folder>cr</folder><filename>crazing_1.jpg</filename><source&…

python程序生成exe_使用Python程序生成QR代码的Python程序

python程序生成exeQR code is a short form of the quick response code. It is a type of matrix barcode that contains some information like some specific link, important message, email-id, etc. In Python, the qrcode module is used to generate the QR code of so…

leetcode 242. 有效的字母异位词 思考分析

题目 给定两个字符串 s 和 t &#xff0c;编写一个函数来判断 t 是否是 s 的字母异位词。 我们先考虑低阶版本&#xff0c;认为字符只有26种可能&#xff0c;然后将a ~ z的字符映射到数组的索引0 ~ 25&#xff0c;数组中存放的则是该索引出现的频次。 记录下s的频次和t的频次…

js \n直接显示字符串_显示N个字符的最短时间

js \n直接显示字符串Problem statement: 问题陈述&#xff1a; You need to display N similar characters on a screen. You are allowed to do three types of operation each time. 您需要在屏幕上显示N个相似的字符。 每次允许您执行三种类型的操作。 You can insert a c…

三、标签准备

所有操作均在anaconda中的自己配置的环境下进行 一、安装labelimg 因为YOLO模型所需要的样本标签必须是txt类型&#xff0c;本人使用labelimg软件进行对图像进行打标签操作。 pip install pycocotools-windows pip install pyqt5 pip install labelimg 通过labelimg命令打…

leetcode 39. 组合总和 思考分析

目录1、题目2、思考分析3、未经优化代码4、剪枝优化1、题目 给定一个无重复元素的数组 candidates 和一个目标数 target &#xff0c;找出 candidates 中所有可以使数字和为 target 的组合。 candidates 中的数字可以无限制重复被选取。 2、思考分析 解空间树宽度部分即数…

一、机器学习概念

一、何为机器学习(Mechine Learning)&#xff1f; 答&#xff1a;利用已有数据(经验)&#xff0c;来训练某种模型&#xff0c;利用此模型来预测未来。机器学习是人工智能的核心Mechine Learning。 例如&#xff1a;你和狗蛋儿7点在老槐树下集合&#xff0c;如何一块约去开黑&a…

Java线程新特征——Java并发库

一、线程池 Sun在Java5中&#xff0c;对Java线程的类库做了大量的扩展&#xff0c;其中线程池就是Java5的新特征之一&#xff0c;除了线程池之外&#xff0c;还有很多多线程相关的内容&#xff0c;为多线程的编程带来了极大便利。为了编写高效稳定可靠的多线程程序&#xff0c;…

leetcode 40. 组合总和 II 思考分析

题目 给定一个数组 candidates 和一个目标数 target &#xff0c;找出 candidates 中所有可以使数字和为 target 的组合。 candidates 中的每个数字在每个组合中只能使用一次。 思考以及代码 如果我们直接套用39题的思路&#xff0c;那么就会出现重复的组合。 重复组合的…