runosd手表(runosd手表 斯诺威登官网)
文章目录
Opencv项目实战:01文字检测OCR(1)(2)
Opencv项目实战:02角度探测器
Opencv项目实战:03扫描二维码&条形码
Opencv项目实战:04全景图片拼接
Opencv项目实战:05物体检测
Opencv项目实战:06文档扫描仪
Opencv项目实战:07人脸识别和考勤系统
Opencv项目实战:08Yolov3更高精度的检测物体
Opencv项目实战:09物体尺寸测量
01文字检测OCR(1)
由图我们可知,对图片进行了数字和字母的识别。
(1)下载Tesseract
点击此网址:https://sourceforge.net/projects/tesseract-ocr-alt/files/
我下载的是第四个版本,下载后是zip包的形式,压缩后可安装,选择路径可更改,否则会在默认的C:\\\\ProgramFiles里面,没有什么大的影响。
(2)下载pytesseract
默认大家都已经下载好了opencv,方式相同,打开pycharm,进入此设置页面。
点击加号,收索软件包,选择蓝色条框进行下载,即可。
(3)pytesseract的函数讲解
#flake8:noqa:F401from.pytesseractimportALTONotSupportedfrom.pytesseractimportget_languagesfrom.pytesseractimportget_tesseract_versionfrom.pytesseractimportimage_to_alto_xmlfrom.pytesseractimportimage_to_boxesfrom.pytesseractimportimage_to_datafrom.pytesseractimportimage_to_osdfrom.pytesseractimportimage_to_pdf_or_hocrfrom.pytesseractimportimage_to_stringfrom.pytesseractimportOutputfrom.pytesseractimportrun_and_get_outputfrom.pytesseractimportTesseractErrorfrom.pytesseractimportTesseractNotFoundErrorfrom.pytesseractimportTSVNotSupported__version__='0.3.9'
我们着重讲解该项目所需的三个函数:
#1,pytesseract.image_to_string(img)#2,pytesseract.image_to_boxes(img)#3,pytesseract.image_to_data(img,confg=cong)
传入的参数都为img,只有用到第三个函数才会单独进行配置。
那么它们所包含的意思是什么呢?
由上至下
ReturnstheresultofaTesseractOCRrunontheprovidedimagetostring
将在提供的图像上运行TesseractOCR的结果返回到字符串
Returnsstringcontainingrecognizedcharactersandtheirboxboundaries
返回包含可识别字符及其框边界的字符串
Returnsstringcontainingboxboundaries,confidences,andotherinformation.
返回包含框边界、置信度和其他信息的字符串。
importcv2importpytesseractimportnumpyasnpfromPILimportImageGrabimporttimepytesseract.pytesseract.tesseract_cmd='E:\\pythonProject\\Github\\Tesseract-OCR\\\\tesseract.exe'img=cv2.imread('1.png')img=cv2.cvtColor(img,cv2.COLOR_BGR2RGB)#####################################DetectingCharacters#######################################print(pytesseract.image_to_string(img))hImg,wImg,_=img.shapeboxes=pytesseract.image_to_boxes(img)forbinboxes.splitlines():print(b)b=b.split('')print(b)x,y,w,h=int(b[1]),int(b[2]),int(b[3]),int(b[4])cv2.rectangle(img,(x,hImg-y),(w,hImg-h),(50,50,255),2)cv2.putText(img,b[0],(x,hImg-y+25),cv2.FONT_HERSHEY_SIMPLEX,1,(50,50,255),2)cv2.imshow('img',img)cv2.waitKey(0)
我先给大家讲解一下代码的思路,对于新入门的同学是极其重要的(本人同样也是)。
首先,通过pytesseract.pytesseract.tesseract_cmd录入我们刚刚下载Tesseract的路径,最好不要包含中文路径。
第二步,读入我们的图像,并将其转换为RGB格式,我们知道在opencv当中颜色是BGR格式,但我们的Tesseract读取的是RGB格式,故此多了一步转换。
第三步,打印pytesseract.image_to_string(img),识别内容会出现在运行台中,可以用来检测是否将数字和字母识别正确或者识别完。注释掉无影响。
第四步,将图片的长,宽,通道数录入。用boxes接收pytesseract.image_to_boxes(img)它的参数。如下:
16852476544021325231455430319752420954404260523275543053295223415430
所获取的信息为(从左到右):识别内容;x;y;宽;高;0(不用此参数)
第五步,根据获得的信息,对boxes做行的录入,形成列表,同时是按空格将信息分开。如下:
['1','68','524','76','544','0']['2','132','523','145','543','0']['3','197','524','209','544','0']['4','260','523','275','543','0']
第六步,将x,y,宽,高录进参数当中,用cv2.rectangle()函数,画出相应的矩形框,这时候大家或许会有疑问,就是为什么不是下面这样的呢?
cv2.rectangle(img,(x,y),(x+w,y+h),(50,50,255),2)
而是如下所示:
cv2.rectangle(img,(x,hImg-y),(w,hImg-h),(50,50,255),2)
我们先看看上面代码带来的效果:
矩形框对准的部位非常糟糕,那么不要怕,我们分析下。
由图,我们可知,在x的方向上的信息是正确的,问题出在了y的坐标上,用pytesseract.image_to_boxes(img)获得的信息可能是按下图的坐标轴:
而我们知道在opencv当中的坐标轴是按照如下所示:
所以大家能理解这个地方了吗?
最后一步就是,对图像添加文本,放在合适的位置,并进行窗口展示。
一些其他的内容我将在《Opencv项目实战:01文字检测OCR(2)》中介绍,包括了,文字,字母的单独检测,pytesseract.image_to_data(img,confg=cong)的配置问题,Tesseract的效果评估,以及此项目的总结。
图片素材,需用自取。
01文字检测OCR(2)
image_to_data()的输出结果是表格形式,输出变量的类型依旧是字符串。
你会得到一个这样的列表['level','page_num','block_num','par_num','line_num','word_num','left','top','width','height','conf','text'],我们逐个解释下:
level,当前项的层级;
page_num,当前项所属页,一般情况下,单张图片的内容均会被分在同一个页;
block_num,当前项所属块,Tesseract会将图像分割为多个不同的block,block会出现1,2,3……等等值;
par_num,当前图像中文字的段落分类;
line_num,当前项所属行;
word_num,为同一行中当前项所属的单词序号;
left\\top\\width\\height,分别为当前项所在矩形区域的左上角坐标、宽度和高度;
conf,当前检测字符的置信度,表示项无文字,值为-1,若Tesseract认为当前区域有文字,则其值得范围为0~100;
text,即为当前项的文本,若无文字此项为空。
那么关于enumerate()函数,大家可以看看此文。
(1)DetectingWords
importcv2importpytesseractimportnumpyasnpfromPILimportImageGrabimporttimepytesseract.pytesseract.tesseract_cmd='E:\\pythonProject\\Github\\Tesseract-OCR\\\\tesseract.exe'img=cv2.imread('1.png')img=cv2.cvtColor(img,cv2.COLOR_BGR2RGB)###################################################DetectingWords#####################################################[01234567891011]#['level','page_num','block_num','par_num','line_num','word_num','left','top','width','height','conf','text']boxes=pytesseract.image_to_data(img)fora,binenumerate(boxes.splitlines()):print(b)ifa!=0:b=b.split()iflen(b)==12:x,y,w,h=int(b[6]),int(b[7]),int(b[8]),int(b[9])cv2.putText(img,b[11],(x,y-5),cv2.FONT_HERSHEY_SIMPLEX,1,(50,50,255),2)cv2.rectangle(img,(x,y),(x+w,y+h),(50,50,255),2)cv2.imshow('img',img)cv2.waitKey(0)
(2)DetectingONLYDigits
importcv2importpytesseractimportnumpyasnpfromPILimportImageGrabimporttimepytesseract.pytesseract.tesseract_cmd='E:\\pythonProject\\Github\\Tesseract-OCR\\\\tesseract.exe'img=cv2.imread('1.png')img=cv2.cvtColor(img,cv2.COLOR_BGR2RGB)###################################################DetectingONLYDigits####################################################hImg,wImg,_=img.shapeconf=r'--oem3--psm6outputbasedigits'boxes=pytesseract.image_to_boxes(img,config=conf)forbinboxes.splitlines():print(b)b=b.split('')print(b)x,y,w,h=int(b[1]),int(b[2]),int(b[3]),int(b[4])cv2.rectangle(img,(x,hImg-y),(w,hImg-h),(50,50,255),2)cv2.putText(img,b[0],(x,hImg-y+25),cv2.FONT_HERSHEY_SIMPLEX,1,(50,50,255),2)cv2.imshow('img',img)cv2.waitKey(0)
首先,我遇到的问题有
(1)无效的TeserAct版本:“TeserAct3.02”
可能是此版本太低了,但我找了找新的版本,在此更新一下路径:
点击此网址https://github.com/UB-Mannheim/tesseract/wiki
自行选择合适的就可以了。
(2)识别效果差
可以看到,将本来不是数字的字母也强行识别出来了,这简直说不过去了。
最后我们看看更改后的效果:
cool,非常的棒,快去试试吧!
对于数字又强差人意了,所以说它这个本身还是存在一点的问题。我觉得影响不大,你觉得不舒服,可以换张图试试。
oem讲解
OEM_TESSERACТ_ONLY只以最快的速度运行Tesseract
OEM_CUBE_ONLY仅运行多维数据集-精度更高,但速度更慢
OEM_TESSERACT_CUBE_cOMBINED同时运行并组合结果-最佳精度
OEM_DEFAULT在调用init_*0时指定此模式,以指示应根据特定于语言的配置中的变量自动推断上述任何模式。命令行配置,或者如果没有在上面任何一项中指定,则应设置为默认的OEM_TESSERACT_ONLY。
psm讲解
PSM_OSD_ONLY仅用于方向和脚本检测。
PSM_AUTO_OSD带有方向和脚本检测的自动页面分割。(OSD)PSM_AUTO_ONLY自动页面分割,但没有OSD或OCR。PSM_AUTO完全自动页面分割,但没有OSD。PSM_SINGLE_COLUMN假设一列大小可变的文本。PSM_SINGLE_BLOCK_VERT_TEXT假设一个统一的垂直对齐文本块。PSM_SINGLE_BLOCK假设一个统一的文本块(默认值)PSM_SINGLE_LINE将图像视为单个文本行。PSM_SINGLE_WORD将图像视为单个单词。PSM_CIRCLE_WORD将图像视为圆圈中的单个单词。PSM_SINGLE_CHAR将图像视为单个字符。PSM_SPARSE_TEXT在没有特定顺序的情况下尽可能多地查找文本。PSM_SPARSE_TEXT_OSD具有方向和脚本检测的稀疏文本。
PSM_RAW_LINE将图像视为单个文本行,绕过特定于Tesseract的黑客攻击。
importcv2importpytesseractimportnumpyasnpfromPILimportImageGrabimporttimepytesseract.pytesseract.tesseract_cmd='E:\\pythonProject\\Github\\Tesseract-OCR\\\\tesseract.exe'img=cv2.imread('1.png')img=cv2.cvtColor(img,cv2.COLOR_BGR2RGB)cap=cv2.VideoCapture(0)cap.set(3,640)cap.set(4,480)defcaptureScreen(bbox=(300,300,1500,1000)):capScr=np.array(ImageGrab.grab(bbox))capScr=cv2.cvtColor(capScr,cv2.COLOR_RGB2BGR)returncapScrwhileTrue:timer=cv2.getTickCount()_,img=cap.read()#img=captureScreen()#DETECTINGCHARACTEREShImg,wImg,_=img.shapeboxes=pytesseract.image_to_boxes(img)forbinboxes.splitlines():#print(b)b=b.split('')#print(b)x,y,w,h=int(b[1]),int(b[2]),int(b[3]),int(b[4])cv2.rectangle(img,(x,hImg-y),(w,hImg-h),(50,50,255),2)cv2.putText(img,b[0],(x,hImg-y+25),cv2.FONT_HERSHEY_SIMPLEX,1,(50,50,255),2)fps=cv2.getTickFrequency()/(cv2.getTickCount()-timer);#cv2.putText(img,str(int(fps)),(75,40),cv2.FONT_HERSHEY_SIMPLEX,0.7,(20,230,20),2);cv2.imshow("Result",img)cv2.waitKey(1)cv2.imshow('img',img)cv2.waitKey(0)
进行网络摄像头的实时文字测试。
我是首次使用Tesseract,体验感很不好,这是我在b站的评论中看到的:
说实话,我还没有学到用算法的地步,学学了解一下就好了,反正我是准备项目实战的中后期去学习深度学习,以及其他的算法学习,这方面我不好说,但它的精度的确是不达标,你们也看到了,居然把文字也识别成了数字。而且开启摄像头识别的也不是很好,识别不完全or识别错误。
02角度探测器
本次项目很简单,即是根据鼠标的点击,检测角度值,如上图,存在一些人为误差,效果也是相当不错的,接下来我们正式开始。
(1)鼠标点击事件
cv2.setMouseCallback(windowName,onMouse)cv2.EVENT_LBUTTONDOWN
第一个函数是指在鼠标点击后得到的响应,'windowName'参数是指鼠标点击的窗口名,'onMouse',可以作为在得到响应后,需要进一步操作的函数。
第二个函数是指敲击了鼠标左键。想了解更多可以看下面这篇博客。
(2)两线间角度
有三个点的坐标,分别求出三条直线的斜率,k1,k2,k3两条斜率分别为k1,k2的直线,他们的夹角公式为:L1与L2的夹角为θ,则tanθ=∣(k2-k1)/(1+k1*k2)∣importcv2importmathpath='test.png'img=cv2.imread(path)pointsList=[]defmousePoints(event,x,y,flags,params):ifevent==cv2.EVENT_LBUTTONDOWN:size=len(pointsList)ifsize!=0andsize%3!=0:cv2.line(img,tuple(pointsList[round((size-1)/3)*3]),(x,y),(0,0,255),2)cv2.circle(img,(x,y),5,(0,0,255),cv2.FILLED)pointsList.append([x,y])defgradient(pt1,pt2):return(pt2[1]-pt1[1])/(pt2[0]-pt1[0])defgetAngle(pointsList):pt1,pt2,pt3=pointsList[-3:]m1=gradient(pt1,pt2)m2=gradient(pt1,pt3)angR=math.atan((m2-m1)/(1+(m2*m1)))#弧度制angD=round(math.degrees(angR))#度数cv2.putText(img,str(angD),(pt1[0]-40,pt1[1]-20),cv2.FONT_HERSHEY_COMPLEX,1.5,(0,0,255),2)whileTrue:iflen(pointsList)%3==0andlen(pointsList)!=0:getAngle(pointsList)img=cv2.resize(img,(1044,614))cv2.imshow('Image',img)cv2.setMouseCallback('Image',mousePoints)ifcv2.waitKey(1)&0xFF==ord('q'):pointsList=[]img=cv2.imread(path)elifcv2.waitKey(1)&0xFF==ord('w'):break
由我来讲解一下此代码,可以先看我的分析,再去看着代码,敲一遍就好了。
首先,读入我们的图像,并建立一个空列表用来接收每次鼠标点击之后返回的坐标值。其次,(1)在mousePoints函数里面,用pointsList收集鼠标点击的坐标,并在点击处画点,而在连线处有个问题,那就是cv2.line是输入两点的坐标后画线,第二个点就保持鼠标点击得到的坐标,对于第一个点,那就是保持第一次点击的坐标,即pst1的坐标;(2)在gradient函数里面,作用就很简单了,即是求pst1与pst2,pst1与pst3之间的斜率;(3)在getAngle函数里面,则是根据公式求出角度值,并将其打印在合适的位置;最后,whileTrue循环当中,就是对函数的调用,并且用点击键盘的'q',刷新图片和清空存储在pointsList的坐标,点击键盘的'w',退出循环。
本次项目较为简单,没有太过困难的地方,在结尾处我会附加上图片素材,需用自取,但我不知道在上传后,图片大小是否会改变,原图片的大小为1392*818,在本次项目中我采用了其大小的75%,拿到图片后,先看图片的属性,再在此位置进行修改
img=cv2.resize(img,(1044,614))
从使用体验上,我觉得新鲜感不够,但用于新入门的来说,就还不错吧。
希望你在本项目中,玩的开心!!
03扫描二维码&条形码
声明:二维码会让图片违规,我处理了一下,大家看看效果
我们扫描出来的结果会有数字,网址链接,英文等。
使用pip下载,打开控制面板,输入:
pipinstallpyzbar
打开DataFile.text,输入以下内容:
111111111112111113111114111115
或则输入其他内容,包括英文和数字,注意不要用中文。
二维码生成网站:
在线二维码生成器~二维工坊(2weima.com)
https://www.2weima.com/
按照你写的DataFile.text里面的内容来生成二维码,可以准备几个其他内容的二维码,因为我们是在项目拓展中才会使用,亦或者使用生活中的二维码,比如,书籍,牛奶盒,微信收款码等等。
条形码生成网站:
免费在线条形码生成器(t-x-m.com)
http://t-x-m.com/
条形码无所谓多少。建议大家将准备好的二维码和条形码打印到一张纸上,方便扫描,我昨天打印的不见了,所以效果展示我就用手机拍下来扫描的。
importcv2importnumpyasnpfrompyzbar.pyzbarimportdecodecap=cv2.VideoCapture(0)cap.set(3,640)cap.set(4,480)whileTrue:success,img=cap.read()forbarcodeindecode(img):myData=barcode.data.decode('utf-8')print(myData)pts=np.array([barcode.polygon],np.int32)pts=pts.reshape((-1,1,2))cv2.polylines(img,[pts],True,(255,0,255),5)pts2=barcode.rectcv2.putText(img,myData,(pts2[0],pts2[1]),cv2.FONT_HERSHEY_SIMPLEX,0.9,(255,0,255),2)cv2.imshow('Result',img)k=cv2.waitKey(1)&0xFFifk==27:break
本次项目没什么难点,我们直接讲解一下,此项目实现的思路。先看我的分析,再去跟着敲一遍代码。
首先,在本项目中不管是读取图像,还是读取摄像头都能实现,那么我们在这里是实现摄像头的实时扫描。读取网络摄像头(在效果展示中,我采用的外用摄像头),在cap.set()函数里面,用‘3’代表的是宽,用‘4’代表的是高的设置,使其窗口大小合适。其次是在whileTrue中,success接受的是布尔值,检测是否读取成功,用img读取每一帧的图像。采取pyzbar包中的decode函数,对img进行解码,并将解码后的内容打印在控制台中,大家也可以尝试将解码的内容打印出来,看看有些什么东西。(包括barcode.rect和barcode.data)除此之外,在Opencv中绘制包围住二维码的方法有很多,比如绘制矩形、绘制多边形;如果是选择矩形框框,识别时二维码存在的倾斜角度会导致添加的框框不能跟着倾斜,而这不是我们想要的效果,因此我们需要选用绘制多边形。具体如下:第一行使用numpy库中array函数,得到一个四点数据矩阵。其中barcode.polygon作用是从轮廓中提取polygon点,作为顶点(请看下方图一);np.int32则是对于数据的类型约束。第二行的reshape((-1,1,2))函数,-1表示行有先,主要功能是将原有的数据形状转换为opencv中常用的形状:(x,1,y),便于使用(请看下方图二)。如将(4,2)转换为(4,1,2)。第三行就是绘画多边形的过程,使用cv.ploylines函数,绘制了一个闭合、紫色、宽度为五的四边形。注意此次的布尔值指的是是否为闭合图型。
图一:
图二:
紧接着,是放置文本框,那么我们当然不需要它移动,我们希望的是它可以固定在某一点。那么在此处我们采取了rect的方法,得到如下图所表示:最后,就是展示窗口,在此处如果想关闭窗口,点击Esc键即可,27即是Esc键的Ascll码。项目拓展描述:
公司的员工使用工作牌扫描二维码开门的想法的实现,根据我们之前准备好的DataFile.text,以及生成的二维码,如果扫描的是DataFile.text里的内容就用绿色框和文本表示已经授权;否则,用红色框和文本表示未授权。
我们来看看它的效果是怎么样的。如下
项目实现的效果非常好,下面的代码我也不再多做讲解了,快去做起来吧!
importcv2importnumpyasnpfrompyzbar.pyzbarimportdecodecap=cv2.VideoCapture(1)cap.set(3,640)cap.set(4,480)withopen('DataFile.text')asf:myDataList=f.read().splitlines()whileTrue:success,img=cap.read()forbarcodeindecode(img):myData=barcode.data.decode('utf-8')print(myData)ifmyDatainmyDataList:myOutput='Authorized'myColor=(0,255,0)else:myOutput='Un-Authorized'myColor=(0,0,255)pts=np.array([barcode.polygon],np.int32)pts=pts.reshape((-1,1,2))cv2.polylines(img,[pts],True,myColor,5)pts2=barcode.rectcv2.putText(img,myOutput,(pts2[0],pts2[1]),cv2.FONT_HERSHEY_SIMPLEX,0.9,myColor,2)cv2.imshow('Result',img)k=cv2.waitKey(1)&0xFFifk==27:break
本次项目中,由于我也不是很很了解reshape函数,还是查了资料才了解,对于二维码的扫描都是相当不错的,但对于条形码的扫描,在生活中的条形码没能成功,可能与摄像头有关吧。
希望你在本项目中玩的开心!!!
可惜,二维码图片可能会违规,大家就自己在网站制作吧,需用自取
barcode:
04全景图片拼接
首先,需要拍摄像这种的图片(当然,大家用我这的就可以了,我实在是太了解大家了)。
接下来,我们来看看拼接的效果图:
效果非常的棒,那我们再来看看,不同大小的图片的拼接效果
除了缺失的角,其他的都还好说,本来也在我的意料之中,如果还能实现自动补齐,那我肯定会大呼一声:“厉害!!”
在pycharm项目中,请向我一样按照如图下所示创建。
我们只需要一个放置不同图片的文件夹和一个.py文件,注意照片一定不能放乱了,在结尾处我会附上素材。
(2)熟悉一下os
当然,此项目我们只需要一个函数,学久必有忘。
\tos.listdir(path)#返回path指定的文件夹包含的文件或文件夹的名字的列表。
importcv2importosmainFolder='Images'myFolders=os.listdir(mainFolder)#读取主文件print(myFolders)forfolderinmyFolders:path=mainFolder+'/'+folderimages=[]myList=os.listdir(path)print(f'Totalnumberofimagesdetected{len(myList)}')forimgNinmyList:curImg=cv2.imread(f'{path}/{imgN}')curImg=cv2.resize(curImg,(0,0),None,0.2,0.2)images.append(curImg)stitcher=cv2.Stitcher.create()(status,result)=stitcher.stitch(images)if(status==cv2.STITCHER_OK):print('PanoramaGenerated')cv2.imshow(folder,result)cv2.waitKey(1)else:print('PanoramaGenerationUnsuccessful')cv2.waitKey(0)
老规矩,还是看我分析讲解代码,再去看代码敲一遍。
首先,我们将图片是放在了Image文件,那么它就是我们的主文件夹,使用os.listdir(path)函数,他会返回一个包含了此路径下的列表如下所示:其次,我们已经知道在Images文件夹下有两个文件,此时需要对其进行遍历,读取我们的图片,还是用os.listdir(path)函数,但此时我们的路径需要更改了,path=Images/1,Images/2,成功读取后,将图片放入列表当中,并通过打印查看是否将所有的图片读取完。除此之外,我们需要用到的是Opencv当中的Stitcher类,在这个类下有一个create函数,它的作用是简短创建在其中一种缝合模式下配置的缝合器,参数不用调配,它会提供一个默认值,它的使用方式:cv2.Stitcher.create(),接下来,我们还需要用Stitcher类下的stitch函数,它的作用是,返回状态代码和拼接结果。最后如果返回的状态码正确,即status==cv2.STITCHER_OK,当然我们将代码改成if(status==0):
也没有任何问题,因为STITCHER_OK=0。
如果你想创建一个应用程序,实现拼接功能,再了解特征检测的内部运行,将其结合在一起,这将是一个很棒思考的方向,因为我们的图片都是同一时间的场景,对比度,饱和度等是看不出变化的。

最初的效果展示中,我们可以看到在边角处还是存在着一些黑色瑕疵,那么两张尺寸不同的图,也可以进行拼接,只是有所缺角。
Images/1/1.jpg
Images/1/2.jpg
Images/1/3.jpg
Images/2/1.jpg
Images/2/2.jpg
希望大家可以开心的完成本项目,如果你觉得有用,请收藏和点赞。
05物体检测
为此,我专门还去查了查,怎么将视频转化为gif图,不知不觉中,我又多学会了一项技能。
OK!cool,效果很不错,今天需要搭配一些文件,都是可以从官网里找到的,那么我为了方便,专门去学习怎么在GitHub上托管项目,还下载了VScode和Git,我太难受了,如果不是要写博客,我绝对懒得去找教程。谢谢自己!
那么在此gif图像中,我检测了水瓶(截图时间不够了),鼠标,剪刀,书,手机,牙刷,键盘,电脑等。
我会在结尾处,提供相关的资源,我们先在项目下新建一个目录,其中包含的文件,如图所示:
importcv2thres=0.45#Thresholdtodetectobjectcap=cv2.VideoCapture(1)cap.set(3,640)cap.set(4,480)cap.set(10,70)classNames=[]classFile='coco.names'withopen(classFile,'rt')asf:classNames=f.read().rstrip('\\n').split('\\n')#restrip返回删除尾随空白的字符串副本。如果给定了字符而不是无,则删除字符中的字符。configPath='ssd_mobilenet_v3_large_coco_2020_01_14.pbtxt'weightsPath='frozen_inference_graph.pb'net=cv2.dnn_DetectionModel(weightsPath,configPath)net.setInputSize(320,320)net.setInputScale(1.0/127.5)net.setInputMean((127.5,127.5,127.5))net.setInputSwapRB(True)whileTrue:success,img=cap.read()classIds,confs,bbox=net.detect(img,confThreshold=thres)print(classIds,bbox)iflen(classIds)!=0:forclassId,confidence,boxinzip(classIds.flatten(),confs.flatten(),bbox):cv2.rectangle(img,box,color=(0,255,0),thickness=2)cv2.putText(img,classNames[classId-1].upper(),(box[0]+10,box[1]+30),cv2.FONT_HERSHEY_COMPLEX,1,(0,255,0),2)cv2.putText(img,str(round(confidence*100,2)),(box[0]+200,box[1]+30),cv2.FONT_HERSHEY_COMPLEX,1,(0,255,0),2)cv2.imshow("Output",img)ifcv2.waitKey(1)&0xFF==27:break#对于物体的检测
今天的重点在于讲解代码的思路。
首先,打开我们的外部摄像头,并且设置窗口的宽,长,亮度,注意不要将窗口的大小超出我们外部摄像头的大小,不然你得到的图像可能就是黑屏。其次,在我们的coco.names文件当中,它是每个名词单独一行,所以通过文件操作,将其内容放入一个空列表当中,我们用到了read(),rstrip(),split()函数,不清楚的地方,可以去W3school上查询。接着,我们看看在包含了net的代码,它用到了DNN算法,其余的函数都可以在dnn.py文件里面查找到。(1)setInputSize(weight,height)weight新输入宽度,height新输入宽度。(2)setInputScale(1.0/127.5)设置帧的缩放因子值,帧值的比例乘数。(3)setInputMean((127.5,127.5,127.5))简要设置帧的平均值。(4)setInputSwapRB(True)将帧的标志设置为True。然后,又要用到一个detect()函数,它是属于classDetectionModel(Model)下的函数,在这里confThreshold用于根据置信度筛选框的阈值,我们将其阈值放在了较前面的位置,方便更改,它会返回ClassID结果检测中的类索引,一组对应的置信度,一组边界框。除此之外,我们用len(classIds)!=0来代表检测到了物体,然而我们有三个需要遍历的变量或信息,所以我们用到了zip函数,避免了写三个循环,而flatten()函数可以将其中的信息展开,再然后画框,放置文本,在这里需要提两句,在coco.name文件里面,每个名词是从1开始的,而classNames列表是从0开始的,故要在索引处-1,使用round()函数是因为confidence是小数,会与之前的classNmaes的东西叠加在一起,故此将其看作是百分数,并保留了两位小数。最后就是,imshow的展示窗口,以及点击Esc键推出。
我已经将注释写在了代码当中,如有不清楚的地方,可以将其打印出来,进行观察。
其优化效果——有效的优化了之前检测框闪烁和重叠的现象。
importcv2importnumpyasnpthres=0.45#Thresholdtodetectobject#使用nms,不会像先前那样检测框有重叠和闪烁nms_threshold=0.2#0.2已经是较大的抑制效果#若设置成1,将没有效果cap=cv2.VideoCapture(1)cap.set(3,1280)cap.set(4,720)cap.set(10,150)classNames=[]classFile='coco.names'withopen(classFile,'rt')asf:classNames=f.read().rstrip('\\n').split('\\n')#print(classNames)configPath='ssd_mobilenet_v3_large_coco_2020_01_14.pbtxt'weightsPath='frozen_inference_graph.pb'net=cv2.dnn_DetectionModel(weightsPath,configPath)net.setInputSize(320,320)net.setInputScale(1.0/127.5)net.setInputMean((127.5,127.5,127.5))net.setInputSwapRB(True)whileTrue:success,img=cap.read()classIds,confs,bbox=net.detect(img,confThreshold=thres)bbox=list(bbox)#bbox本身得到的是numpy的数组,将其改为listconfs=list(np.array(confs).reshape(1,-1)[0])#将其内容转化为只有一个列表,使用np.array()是因为元组是不能reshapeconfs=list(map(float,confs))#原本的confs是float32的形式,使用map()函数将float映射在confs上#print(type(confs[0]))#print(confs)indices=cv2.dnn.NMSBoxes(bbox,confs,thres,nms_threshold)#print(indices)foriinindices:i=i[0]#打印(indices)的内容是[[0]]box=bbox[i]x,y,w,h=box[0],box[1],box[2],box[3]cv2.rectangle(img,(x,y),(x+w,h+y),color=(0,255,0),thickness=2)cv2.putText(img,classNames[classIds[i][0]-1].upper(),(box[0]+10,box[1]+30),cv2.FONT_HERSHEY_COMPLEX,1,(0,255,0),2)#此处需要一个classIds的特殊索引,它就是i,而且已经有了一个[],所以是[i][0]cv2.imshow("Output",img)cv2.waitKey(1)
GitHub:
Auorui/Opencv-project-training:AccordingtotheprojectmadebylearningmurtazaHassan'svideoseveryday,thanktheupMasterofstationB:agraduatestudentwhoknowsalittleabouteverything.Itismainlyusedtolearnopencvbymyself.OnmyCSDNblog,Ihaveadetailedpictureandtextintroductionofeachproject.Iwillcontinuetostudyhard.WelcometomyCSDNblog,whereIstoremycodeandsomeinformation.CSDNlink:https://blog.csdn.net/m0_62919535?type=blog。Youcancheckitinmycolumn-opencvprojectpractice.(github.com)
https://github.com/Auorui/Opencv-project-training
免费转化为Gif图网站:
踢踢零工具-tt0.top
https://tt0.top/
其中的很多算法我也不是很明白,只是使用的思路学会到了,后面将会有人脸检测的项目,应该会用到YOYO算法。希望有人能在这个项目中玩的开心,感谢您的关注与支持!!!
06文档扫描仪
网络摄像头扫描:
图片扫描:
最终扫描保存的图片:
(视频)
(图片)
今天的项目文件只需要两个.py文件,其中一个.py文件是已经写好的函数,你将直接使用它,我不会在此多做讲解,因为我们将会在主要的.py文件import导入它,如果想了解其中函数是如何写的,请自行学习。
utlis.py,需要添加的.py文件
importcv2importnumpyasnp#TOSTACKALLTHEIMAGESINONEWINDOWdefstackImages(imgArray,scale,lables=[]):rows=len(imgArray)cols=len(imgArray[0])rowsAvailable=isinstance(imgArray[0],list)width=imgArray[0][0].shape[1]height=imgArray[0][0].shape[0]ifrowsAvailable:forxinrange(0,rows):foryinrange(0,cols):imgArray[x][y]=cv2.resize(imgArray[x][y],(0,0),None,scale,scale)iflen(imgArray[x][y].shape)==2:imgArray[x][y]=cv2.cvtColor(imgArray[x][y],cv2.COLOR_GRAY2BGR)imageBlank=np.zeros((height,width,3),np.uint8)hor=[imageBlank]*rowshor_con=[imageBlank]*rowsforxinrange(0,rows):hor[x]=np.hstack(imgArray[x])hor_con[x]=np.concatenate(imgArray[x])ver=np.vstack(hor)ver_con=np.concatenate(hor)else:forxinrange(0,rows):imgArray[x]=cv2.resize(imgArray[x],(0,0),None,scale,scale)iflen(imgArray[x].shape)==2:imgArray[x]=cv2.cvtColor(imgArray[x],cv2.COLOR_GRAY2BGR)hor=np.hstack(imgArray)hor_con=np.concatenate(imgArray)ver=horiflen(lables)!=0:eachImgWidth=int(ver.shape[1]/cols)eachImgHeight=int(ver.shape[0]/rows)print(eachImgHeight)fordinrange(0,rows):forcinrange(0,cols):cv2.rectangle(ver,(c*eachImgWidth,eachImgHeight*d),(c*eachImgWidth+len(lables[d][c])*13+27,30+eachImgHeight*d),(255,255,255),cv2.FILLED)cv2.putText(ver,lables[d][c],(eachImgWidth*c+10,eachImgHeight*d+20),cv2.FONT_HERSHEY_COMPLEX,0.7,(255,0,255),2)returnverdefreorder(myPoints):myPoints=myPoints.reshape((4,2))myPointsNew=np.zeros((4,1,2),dtype=np.int32)add=myPoints.sum(1)myPointsNew[0]=myPoints[np.argmin(add)]myPointsNew[3]=myPoints[np.argmax(add)]diff=np.diff(myPoints,axis=1)myPointsNew[1]=myPoints[np.argmin(diff)]myPointsNew[2]=myPoints[np.argmax(diff)]returnmyPointsNewdefbiggestContour(contours):biggest=np.array([])max_area=0foriincontours:area=cv2.contourArea(i)ifarea>5000:peri=cv2.arcLength(i,True)approx=cv2.approxPolyDP(i,0.02*peri,True)ifarea>max_areaandlen(approx)==4:biggest=approxmax_area=areareturnbiggest,max_areadefdrawRectangle(img,biggest,thickness):cv2.line(img,(biggest[0][0][0],biggest[0][0][1]),(biggest[1][0][0],biggest[1][0][1]),(0,255,0),thickness)cv2.line(img,(biggest[0][0][0],biggest[0][0][1]),(biggest[2][0][0],biggest[2][0][1]),(0,255,0),thickness)cv2.line(img,(biggest[3][0][0],biggest[3][0][1]),(biggest[2][0][0],biggest[2][0][1]),(0,255,0),thickness)cv2.line(img,(biggest[3][0][0],biggest[3][0][1]),(biggest[1][0][0],biggest[1][0][1]),(0,255,0),thickness)returnimgdefnothing(x):passdefinitializeTrackbars(intialTracbarVals=0):cv2.namedWindow("Trackbars")cv2.resizeWindow("Trackbars",360,240)cv2.createTrackbar("Threshold1","Trackbars",200,255,nothing)cv2.createTrackbar("Threshold2","Trackbars",200,255,nothing)defvalTrackbars():Threshold1=cv2.getTrackbarPos("Threshold1","Trackbars")Threshold2=cv2.getTrackbarPos("Threshold2","Trackbars")src=Threshold1,Threshold2returnsrc
importcv2importnumpyasnpimportutlis########################################################################webCamFeed=True#pathImage="1.jpg"#cap=cv2.VideoCapture(1)#cap.set(10,160)#heightImg=640#widthImg=480#########################################################################utlis.initializeTrackbars()count=0whileTrue:ifwebCamFeed:ret,img=cap.read()else:img=cv2.imread(pathImage)img=cv2.resize(img,(widthImg,heightImg))imgBlank=np.zeros((heightImg,widthImg,3),np.uint8)imgGray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)imgBlur=cv2.GaussianBlur(imgGray,(5,5),1)#添加高斯模糊thres=utlis.valTrackbars()#获取阈值的轨迹栏值imgThreshold=cv2.Canny(imgBlur,thres[0],thres[1])#应用CANNY模糊kernel=np.ones((5,5))imgDial=cv2.dilate(imgThreshold,kernel,iterations=2)imgThreshold=cv2.erode(imgDial,kernel,iterations=1)#查找所有轮廓imgContours=img.copy()imgBigContour=img.copy()contours,hierarchy=cv2.findContours(imgThreshold,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)#FINDALLCONTOURScv2.drawContours(imgContours,contours,-1,(0,255,0),10)#绘制所有检测到的轮廓#找到最大的轮廓biggest,maxArea=utlis.biggestContour(contours)#找到最大的轮廓ifbiggest.size!=0:biggest=utlis.reorder(biggest)cv2.drawContours(imgBigContour,biggest,-1,(0,255,0),20)#画最大的轮廓imgBigContour=utlis.drawRectangle(imgBigContour,biggest,2)pts1=np.float32(biggest)#为扭曲准备点pts2=np.float32([[0,0],[widthImg,0],[0,heightImg],[widthImg,heightImg]])#为扭曲准备点matrix=cv2.getPerspectiveTransform(pts1,pts2)imgWarpColored=cv2.warpPerspective(img,matrix,(widthImg,heightImg))#从每侧移除20个像素imgWarpColored=imgWarpColored[20:imgWarpColored.shape[0]-20,20:imgWarpColored.shape[1]-20]imgWarpColored=cv2.resize(imgWarpColored,(widthImg,heightImg))#应用自适应阈值imgWarpGray=cv2.cvtColor(imgWarpColored,cv2.COLOR_BGR2GRAY)imgAdaptiveThre=cv2.adaptiveThreshold(imgWarpGray,255,1,1,7,2)imgAdaptiveThre=cv2.bitwise_not(imgAdaptiveThre)imgAdaptiveThre=cv2.medianBlur(imgAdaptiveThre,3)#用于显示的图像阵列imageArray=([img,imgGray,imgThreshold,imgContours],[imgBigContour,imgWarpColored,imgWarpGray,imgAdaptiveThre])else:imageArray=([img,imgGray,imgThreshold,imgContours],[imgBlank,imgBlank,imgBlank,imgBlank])#显示标签lables=[["Original","Gray","Threshold","Contours"],["BiggestContour","WarpPrespective","WarpGray","AdaptiveThreshold"]]stackedImage=utlis.stackImages(imageArray,0.75,lables)cv2.imshow("Result",stackedImage)#按下“s”键时保存图像ifcv2.waitKey(1)&0xFF==ord('s'):cv2.imwrite("Scanned/myImage"+str(count)+".jpg",imgWarpColored)cv2.rectangle(stackedImage,((int(stackedImage.shape[1]/2)-230),int(stackedImage.shape[0]/2)+50),(1100,350),(0,255,0),cv2.FILLED)cv2.putText(stackedImage,"ScanSaved",(int(stackedImage.shape[1]/2)-200,int(stackedImage.shape[0]/2)),cv2.FONT_HERSHEY_DUPLEX,3,(0,0,255),5,cv2.LINE_AA)cv2.imshow('Result',stackedImage)cv2.waitKey(300)count+=1elifcv2.waitKey(1)&0xFF==27:break
今天需要要讲解的还是主函数Main.py,由我来讲解,其实我也有点压力,因为这个项目它涉及了Opencv核心知识点,有的地方我也需要去查找,因为学久必会忘,更何况我也是刚刚起步的阶段,所以我会尽我所能的去讲清楚。
注意:我是以网络摄像头为例,读取图片的方式,同理可得。
首先,请看#号框内,我们将从这里开始起,设立变量webCamFeed,用其表示是否打开摄像头,接着亮度,宽,高的赋值。utlis.initializeTrackbars()是utlis.py文件当中的轨迹栏初始化函数。然后,我们依次对图像进行大小调整、灰度图像、高斯模糊、Canny边缘检测、扩张、侵蚀。之后,找出图像可以检测的所有轮廓,并找到最大的轮廓并且画出来,同时要为扫描到的文档找到四个顶点,也就是扭曲点,用cv2.getPerspectiveTransform()函数找到点的坐标,用cv2.warpPerspective()函数输出图像,如果到了这一步,我们去运行一下会发现有边角是桌子的颜色但并没有很多,所以我们需要从每侧移除20个像素,应用自适应阈值让图像变得较为清晰——黑色的文字更加的明显。接着,配置utlis.stackImages()需要的参数——图像(列表的形式),规模,标签(列表的形式,可以不用标签,程序一样可以正确运行),展示窗口。最后,如果你觉得比较满意,按下s键,即可保存,并在图中央出现有"ScanSaved"的矩形框。点击Esc键即可退出程序。
GitHUb:Opencv-project-training/Opencvprojecttraining/06DocumentScanneratmain·Auorui/Opencv-project-training·GitHub
它是一个很好的项目,要知道我们要实现这种效果,即修正文档,还得清晰,要么有VIP,兑换积分,看广告等。如果你发现扫描的文档不清晰,请修改合适的分辨率。
07人脸识别和考勤系统
人脸识别:
考勤效果:
接下来,我们将学习如何以高精度执行面部识别,首先简要介绍理论并学习基本实现。然后我们将创建一个考勤项目,该项目将使用网络摄像头检测人脸并在Excel表中实时记录考勤情况。
在此之前,你应该看过此篇,完成了对项目包的搭建(37条消息)Python3.7最简便的方式解决下载dlib和face_recognition的问题_夏天是冰红茶的博客-CSDN博客
此外,我们还需要安装一个包,按照步骤来就好了:
pipinstallface_recognition_models
按照图示配置,Attendance.csv文件当中的内容只有(Name,Time),在Attendance_images文件当中,你可以添加你想添加的图片,最好是单个人物的图片,且以他们的英文名命名图片。
importcv2importface_recognitionimgElon=face_recognition.load_image_file('ImagesBasic/ElonMusk.png')imgElon=cv2.cvtColor(imgElon,cv2.COLOR_BGR2RGB)imgTest=face_recognition.load_image_file('ImagesBasic/Elontest.png')imgTest=cv2.cvtColor(imgTest,cv2.COLOR_BGR2RGB)faceLoc=face_recognition.face_locations(imgElon)[0]encodeElon=face_recognition.face_encodings(imgElon)[0]cv2.rectangle(imgElon,(faceLoc[3],faceLoc[0]),(faceLoc[1],faceLoc[2]),(255,0,255),2)faceLocTest=face_recognition.face_locations(imgTest)[0]encodeTest=face_recognition.face_encodings(imgTest)[0]cv2.rectangle(imgTest,(faceLocTest[3],faceLocTest[0]),(faceLocTest[1],faceLocTest[2]),(255,0,255),2)results=face_recognition.compare_faces([encodeElon],encodeTest)faceDis=face_recognition.face_distance([encodeElon],encodeTest)print(results,faceDis)cv2.putText(imgTest,f'{results}{round(faceDis[0],2)}',(50,50),cv2.FONT_HERSHEY_COMPLEX,1,(0,0,255),2)cv2.imshow('ElonMusk',imgElon)cv2.imshow('ElonTest',imgTest)cv2.waitKey(0)
我们将会以马斯克先生的图片,作为标准测试,即'ElonMusk.png'。另外两张图片分别是比尔盖茨先生和马斯克先生。
今天的讲解会分为两部分,这是基础部分的讲解。
首先,导入这两张代码中的图片,我们用的是face_recognition中的load_image_file函数,它会将图像文件(.jpg、.png等)加载到numpy数组中,且默认的mode='RGB'格式,故在此有一步转化。其次,faceLoc接受face_locations()函数返回的图像中人脸的边界框数组,请看注1,取第一个数,则会等到一个元组,我们要以按css(上、右、下、左)顺序找到的面位置的元组列表。encodeElon()函数是返回128维人脸编码列表(图像中每个人脸一个),为什么是128维?请看注2。在这之后,又是画框操作,我相信如果看过我前期的文章的人肯定是太熟悉了,按照注3,将坐标输入。之后,compare_faces()将面部编码列表与候选编码进行比较,以查看它们是否匹配,记住,只有第一个是列表,其将会返回真/假值列表;face_distance()需要给定人脸编码列表,将其与已知人脸编码进行比较,并获得每个比较人脸的欧几里德距离。距离会告诉您这些面有多相似。再说一次,只有第一个是列表。前看注4。最后,放置图框的信息在合适的位置,展示图片。
注1:[(44,306,152,199)]
注2:机器学习很有趣!第4部分:现代人脸识别与深度学习-金融科技排名(fintechranking.com),作者是AdamGeitgey。
注3:坐标图
注4:[True][0.4559636]
修改此处代码,我们初步实现了人脸识别。
imgTest=face_recognition.load_image_file('ImagesBasic/BillGates.png')imgTest=cv2.cvtColor(imgTest,cv2.COLOR_BGR2RGB)
importcv2importnumpyasnpimportface_recognitionimportosfromdatetimeimportdatetime#fromPILimportImageGrabpath='Attendance_images'images=[]classNames=[]myList=os.listdir(path)print(myList)forclinmyList:curImg=cv2.imread(f'{path}/{cl}')images.append(curImg)classNames.append(os.path.splitext(cl)[0])print(classNames)deffindEncodings(images):encodeList=[]forimginimages:img=cv2.cvtColor(img,cv2.COLOR_BGR2RGB)encode=face_recognition.face_encodings(img)[0]encodeList.append(encode)returnencodeListdefmarkAttendance(name):withopen('Attendance_lists.csv','r+')asf:myDataList=f.readlines()nameList=[]forlineinmyDataList:entry=line.split(',')nameList.append(entry[0])ifnamenotinnameList:now=datetime.now()dtString=now.strftime('%H:%M:%S')f.writelines(f'\\n{name},{dtString}')####FORCAPTURINGSCREENRATHERTHANWEBCAM#defcaptureScreen(bbox=(300,300,690+300,530+300)):#capScr=np.array(ImageGrab.grab(bbox))#capScr=cv2.cvtColor(capScr,cv2.COLOR_RGB2BGR)#returncapScrencodeListKnown=findEncodings(images)print('EncodingComplete')cap=cv2.VideoCapture(1)whileTrue:success,img=cap.read()#img=captureScreen()imgS=cv2.resize(img,(0,0),None,0.25,0.25)imgS=cv2.cvtColor(imgS,cv2.COLOR_BGR2RGB)facesCurFrame=face_recognition.face_locations(imgS)encodesCurFrame=face_recognition.face_encodings(imgS,facesCurFrame)forencodeFace,faceLocinzip(encodesCurFrame,facesCurFrame):matches=face_recognition.compare_faces(encodeListKnown,encodeFace)faceDis=face_recognition.face_distance(encodeListKnown,encodeFace)#print(faceDis)matchIndex=np.argmin(faceDis)ifmatches[matchIndex]:name=classNames[matchIndex].upper()#print(name)y1,x2,y2,x1=faceLocy1,x2,y2,x1=y1*4,x2*4,y2*4,x1*4cv2.rectangle(img,(x1,y1),(x2,y2),(0,255,0),2)cv2.rectangle(img,(x1,y2-35),(x2,y2),(0,255,0),cv2.FILLED)cv2.putText(img,name,(x1+6,y2-6),cv2.FONT_HERSHEY_COMPLEX,1,(255,255,255),2)markAttendance(name)cv2.imshow('Webcam',img)cv2.waitKey(1)
这里面的一些操作,在我之前的博客中有讲过,且前面也讲的很清楚了,所以我会略讲。
首先,读取Attendance_images文件当中图片的名字,注意它是带有.png,而我们的命名并不需要它,所以取了一个[0]。其次,编写findEncodings()用于储存标准图像的编码,按照列表的形式。markAttendance()函数用于读取Attendance_lists.csv的文件信息,并写入Excel,其中还可写入时间。然后,剩余的一些,我相信参照上面的讲解应该没什么问题了。再说一下y1,x2,y2,x1=y1*4,x2*4,y2*4,x1*4,为什么要乘以4,还记得上面的resize吗,它并没有要求像素的改变,而是缩小的比例,正是0.25。
Github:Opencv-project-training/Opencvprojecttraining/07FaceRecognitionandAttendanceSystematmain·Auorui/Opencv-project-training·GitHub
今天的项目比起之前的物体检测还有一定的难度,对于我来说现在的效率实在不是很高,昨天的dlib和face_recognition包的下载实在没有弄好,临时换了个项目,今天也是弄了好久。
08Yolov3更高精度的检测物体
本次物体检测,将采用新的方法,相比于上一次,它的检测效果更好,具体在下面的项目介绍当中,本次检测的物品有手机、牙刷、剪刀、杯子、运动球、书等。检测的这些物品是方便展示的,本来还有水果的,但昨天都吃完了,只有核桃了,大家做好后,可以自己去试试
在本项目中,我们将用新的方法对物体的检测,采用了Yolov3,当然它又有检测范围,只能鉴定我们给予的文件当中的物体,但它相较于我们之前的物体检测又有更高的精度,没有出现边界框闪烁,重叠的问题。
如图所示,其中有些文件是我从官网上下载的,那么为了说清楚它的来源,我还是写下来,以免读者看了云里雾里。
输入此网址:YOLO:实时对象检测(pjreddie.com)
下载两种是为了比较一下它们的一些优缺点,320指的是分辨率320*320,它的检测能力属于中间吧,不过它的帧速率比起tiny要小很多,但又要比tiny的精度较高。
而coco.names是我从之前的《Opencv项目实战:05物体检测》的一个文件,ctrl+cv过来的,不知道的可以看看此篇。(16条消息)Opencv项目实战:05物体检测_夏天是冰红茶的博客-CSDN博客,或许你先看这篇后,更容易理解此篇。
再提一句,下载cfg是在Github里面,如果网速较慢的,可以给我评论,我考虑一下抽点时间,将Github的一些加速的方法总结一篇。
如有不知道的地方再回头来看,现在看一遍,加一点表面印象,不要求理解。
架构图:
我们可以看到这个网络,有很多层,中间的部分有很多的卷积层,而我们需要的就是末尾的那三层。
打印outputs[0][0]:
[3.8534008e-026.2166303e-024.4057447e-011.9734769e-015.1320876e-090.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+00]
85的含义:
85含有中心x,y,宽,高,物体的置信度,其余的是每个类别的预测概率,也就是valuenumber
x,y=int((det[0]*wT)-w/2),int((det[1]*hT)-h/2)手绘图版本:
真的随手画,哈哈。大家可以理解到就成。
关于coco.names文件:
与项目5当中的文件有所区别,大家按照项目介绍当中的图对其中的内容进行删改即可。
importcv2ascvimportnumpyasnpcap=cv.VideoCapture(0)whT=320confThreshold=0.5nmsThreshold=0.2#theloweritisthemoreaggressiveitwillbeprint(f"以下是你可以检测的{80}种物品:")####LOADMODEL#########################################导入coco.names文件当中的内容classesFile="coco.names"#classNames=[]#withopen(classesFile,'rt')asf:#classNames=f.read().rstrip('\\n').split('\\n')#print(classNames)###########################################################ModelFiles#####################################################引进我们的模块modelConfiguration="yolov3-320.cfg"#modelWeights="yolov3-320.weights"#net=cv.dnn.readNetFromDarknet(modelConfiguration,modelWeights)#net.setPreferableBackend(cv.dnn.DNN_BACKEND_OPENCV)#net.setPreferableTarget(cv.dnn.DNN_TARGET_CPU)####################################################################deffindObjects(outputs,img):hT,wT,cT=img.shapebbox=[]classIds=[]confs=[]foroutputinoutputs:fordetinoutput:scores=det[5:]#我们需要寻找某一个类中,判别最高的classId=np.argmax(scores)confidence=scores[classId]ifconfidence>confThreshold:w,h=int(det[2]*wT),int(det[3]*hT)#值是百分比,乘以图像的大小才是正确的像素值x,y=int((det[0]*wT)-w/2),int((det[1]*hT)-h/2)bbox.append([x,y,w,h])classIds.append(classId)confs.append(float(confidence))indices=cv.dnn.NMSBoxes(bbox,confs,confThreshold,nmsThreshold)#置信度阈值以及nms的阈值#print(indices)foriinindices:box=bbox[i]x,y,w,h=box[0],box[1],box[2],box[3]#print(x,y,w,h)cv.rectangle(img,(x,y),(x+w,y+h),(255,0,255),2)cv.putText(img,f'{classNames[classIds[i]].upper()}{int(confs[i]*100)}%',(x,y-10),cv.FONT_HERSHEY_SIMPLEX,0.6,(255,0,255),2)whileTrue:success,img=cap.read()blob=cv.dnn.blobFromImage(img,1/255,(whT,whT),[0,0,0],1,crop=False)net.setInput(blob)layersNames=net.getLayerNames()#print(layersNames)#print(net.getUnconnectedOutLayers())outputNames=[(layersNames[i-1])foriinnet.getUnconnectedOutLayers()]#print(outputNames)outputs=net.forward(outputNames)#print(len(outputs))#检测是否取到我们需要的那三层,输出为3,Trueoutputs=list(outputs)#输出之前是元组#print(type(outputs[0]))#<class'numpy.ndarray'>###########################################print(outputs[0].shape)#(300,85)300,1200,4800isisthenumberofboundingboxes#print(outputs[1].shape)#(1200,85)#print(outputs[2].shape)#(4800,85)#print(outputs[0][0])##########################################findObjects(outputs,img)cv.imshow('Image',img)ifcv.waitKey(1)&0xFF==27:break
我们一口气讲完,准备了这些天,也不是白费的,当然有些地方,可能我讲的不是那么清楚,请见谅。但好在这次我将调试的所有过程都保留了下来,结合注释和我的讲解,7788应当是有的。
首先,开头部分都是些后来设置的默认条件,等用到的时候再将。我们需要导入我们的"coco.names文件",它是每个单词为一行,所以通过文件操作,将其中内容放入到一个新的列表当中,我们用到了read()、rstrip()、split()函数,不清楚的地方,可以去W3school上查询。其次,引入我们从官网下载的文件,用到了readNetFromDarknet()函数,它的参数是模型配置和权重配置,也就是我们下载的模块,他会读取存储在<ahref=”中的网络模型https://pjreddie.com/darknet/“>Darknet</a>模型文件,返回一个网络对象,这正是我们想要的。net.setPreferableBackend()要求网络使用其支持的特定计算后,它的参数需要我们给定为cv.dnn.DNN_BACKEND_OPENCV,因为它是具有一个默认的值。net.setPreferableTarget()要求网络在特定目标设备上进行计算,我选择使用的是CPU,当然要想获得更高的精度,就要使用GPU,但我并不了解,所以点到为止哈。其次,我们再来讲解whileTrue循环中的代码,读取摄像头,创建我们的网络,将图像转化为blob的形式,因为这是网络可以理解的形式,里面的参数我讲一下(whT,whT),其余的就是默认了,在开始时就已经定义了为320,那为什么是320,因为yolov3-320.cfg等,就是这个原因啦,它的分辨率就是320*320;net.setInput(blob)就是设置网络前行的通行证;接下来,我们要获得我们最感兴趣的那三层,用net.getLayerNames()函数获取所有层的名字,在得到三个不同的输出层的索引值,接着用列表生成式,根据索引将内容放进去,得到['yolo_82','yolo_94','yolo_106']。net.forward(outputNames)返回指定层的第一个输出的blob。再往下就是我的一些调试过程,我保留了调试时的注释,不懂的地方,不妨就取消注释,跑一遍就成。然后,再来讲解我们的findObjects(outputs,img)里面的内容,获取图像的宽高通道,设置空列表,放置边界框,Id,置信度等,那么下面的操作就是为了将这些空列表填满!!!,我们在上面有展示过outputs[0][0]的输出,我们不能将中心x,中心y,宽,高,置信度等作比较,因为它们相对较大,索引是从第五个开始,然后便是我所说的填满操作,应该不难,我们就此跳过。紧接着,来到尾声了,我们常会有检测时出现大小框,那么这是就需要处理,得到检测较大的那个框,让我们的检测更加的完善,cv.dnn.NMSBoxes()函数,参数confThreshold已经在开头定义,检测的大于50%,那就相当好了,nms_threshold用于非最大抑制的阈值,也是实现定义好了,这个用法我们在《Opencv项目实战:05物体检测》就讲到过。然后就是画框,放文本的操作,几乎我们每一期的实战项目都在讲。最后,引用findObjects(outputs,img)函数,开启摄像头,展示窗口,检测物体,完成后点击Esc键即可退出。
GitHub:Opencv-project-training/Opencvprojecttraining/08Yolov3atmain·Auorui/Opencv-project-training·GitHub
其中以下两个文件需要从官网下载,GitHub上面由于太大上传不了。
我写的较为的详细,几乎没有我这种风格的吧,我是学c语言出生的(是我们大一的必修课,说实话我以前根本就不知道的,可能这就是小镇做题家的原因吧),后来今年的二月自学的python,中途学了些爬虫,七月在参加实验室学了点单片机(我没有基础,也被刷下去了,keil5配文件麻烦死了),给我们安排的课程python的图像处理只有区区两节,也是这两节课才对Opencv感了兴趣,自己私下在学习,后来我发现刚好学的这些东西,都是涉及人工智能领域,计算机视觉的,我想我自己一定要做出点成就来,给大家更新的系列也是我学习的过程。
本次物体检测,将采用新的方法,相比于上一次,它的检测效果更好,具体在下面的项目介绍当中,本次检测的物品有手机、牙刷、剪刀、杯子、运动球、书等。检测的这些物品是方便展示的,本来还有水果的,但昨天都吃完了,只有核桃了,大家做好后,可以自己去试试
在本项目中,我们将用新的方法对物体的检测,采用了Yolov3,当然它又有检测范围,只能鉴定我们给予的文件当中的物体,但它相较于我们之前的物体检测又有更高的精度,没有出现边界框闪烁,重叠的问题。
如图所示,其中有些文件是我从官网上下载的,那么为了说清楚它的来源,我还是写下来,以免读者看了云里雾里。
输入此网址:YOLO:实时对象检测(pjreddie.com)https://pjreddie.com/darknet/yolo/
下载两种是为了比较一下它们的一些优缺点,320指的是分辨率320*320,它的检测能力属于中间吧,不过它的帧速率比起tiny要小很多,但又要比tiny的精度较高。
而coco.names是我从之前的《Opencv项目实战:05物体检测》的一个文件,ctrl+cv过来的,不知道的可以看看此篇。
再提一句,下载cfg是在Github里面,如果网速较慢的,可以给我评论,我考虑一下抽点时间,将Github的一些加速的方法总结一篇。
如有不知道的地方再回头来看,现在看一遍,加一点表面印象,不要求理解。
架构图:
我们可以看到这个网络,有很多层,中间的部分有很多的卷积层,而我们需要的就是末尾的那三层。
打印outputs[0][0]:
[3.8534008e-026.2166303e-024.4057447e-011.9734769e-015.1320876e-090.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+000.0000000e+00]
85的含义:
85含有中心x,y,宽,高,物体的置信度,其余的是每个类别的预测概率,也就是valuenumber
x,y=int((det[0]*wT)-w/2),int((det[1]*hT)-h/2)手绘图版本:
真的随手画,哈哈。大家可以理解到就成。
关于coco.names文件:
与项目5当中的文件有所区别,大家按照项目介绍当中的图对其中的内容进行删改即可。
importcv2ascvimportnumpyasnpcap=cv.VideoCapture(0)whT=320confThreshold=0.5nmsThreshold=0.2#theloweritisthemoreaggressiveitwillbeprint(f"以下是你可以检测的{80}种物品:")####LOADMODEL#########################################导入coco.names文件当中的内容classesFile="coco.names"#classNames=[]#withopen(classesFile,'rt')asf:#classNames=f.read().rstrip('\\n').split('\\n')#print(classNames)###########################################################ModelFiles#####################################################引进我们的模块modelConfiguration="yolov3-320.cfg"#modelWeights="yolov3-320.weights"#net=cv.dnn.readNetFromDarknet(modelConfiguration,modelWeights)#net.setPreferableBackend(cv.dnn.DNN_BACKEND_OPENCV)#net.setPreferableTarget(cv.dnn.DNN_TARGET_CPU)####################################################################deffindObjects(outputs,img):hT,wT,cT=img.shapebbox=[]classIds=[]confs=[]foroutputinoutputs:fordetinoutput:scores=det[5:]#我们需要寻找某一个类中,判别最高的classId=np.argmax(scores)confidence=scores[classId]ifconfidence>confThreshold:w,h=int(det[2]*wT),int(det[3]*hT)#值是百分比,乘以图像的大小才是正确的像素值x,y=int((det[0]*wT)-w/2),int((det[1]*hT)-h/2)bbox.append([x,y,w,h])classIds.append(classId)confs.append(float(confidence))indices=cv.dnn.NMSBoxes(bbox,confs,confThreshold,nmsThreshold)#置信度阈值以及nms的阈值#print(indices)foriinindices:box=bbox[i]x,y,w,h=box[0],box[1],box[2],box[3]#print(x,y,w,h)cv.rectangle(img,(x,y),(x+w,y+h),(255,0,255),2)cv.putText(img,f'{classNames[classIds[i]].upper()}{int(confs[i]*100)}%',(x,y-10),cv.FONT_HERSHEY_SIMPLEX,0.6,(255,0,255),2)whileTrue:success,img=cap.read()blob=cv.dnn.blobFromImage(img,1/255,(whT,whT),[0,0,0],1,crop=False)net.setInput(blob)layersNames=net.getLayerNames()#print(layersNames)#print(net.getUnconnectedOutLayers())outputNames=[(layersNames[i-1])foriinnet.getUnconnectedOutLayers()]#print(outputNames)outputs=net.forward(outputNames)#print(len(outputs))#检测是否取到我们需要的那三层,输出为3,Trueoutputs=list(outputs)#输出之前是元组#print(type(outputs[0]))#<class'numpy.ndarray'>###########################################print(outputs[0].shape)#(300,85)300,1200,4800isisthenumberofboundingboxes#print(outputs[1].shape)#(1200,85)#print(outputs[2].shape)#(4800,85)#print(outputs[0][0])##########################################findObjects(outputs,img)cv.imshow('Image',img)ifcv.waitKey(1)&0xFF==27:break
我们一口气讲完,准备了这些天,也不是白费的,当然有些地方,可能我讲的不是那么清楚,请见谅。但好在这次我将调试的所有过程都保留了下来,结合注释和我的讲解,7788应当是有的。
首先,开头部分都是些后来设置的默认条件,等用到的时候再将。我们需要导入我们的"coco.names文件",它是每个单词为一行,所以通过文件操作,将其中内容放入到一个新的列表当中,我们用到了read()、rstrip()、split()函数,不清楚的地方,可以去W3school上查询。其次,引入我们从官网下载的文件,用到了readNetFromDarknet()函数,它的参数是模型配置和权重配置,也就是我们下载的模块,他会读取存储在<ahref=”中的网络模型https://pjreddie.com/darknet/“>Darknet</a>模型文件,返回一个网络对象,这正是我们想要的。net.setPreferableBackend()要求网络使用其支持的特定计算后,它的参数需要我们给定为cv.dnn.DNN_BACKEND_OPENCV,因为它是具有一个默认的值。net.setPreferableTarget()要求网络在特定目标设备上进行计算,我选择使用的是CPU,当然要想获得更高的精度,就要使用GPU,但我并不了解,所以点到为止哈。其次,我们再来讲解whileTrue循环中的代码,读取摄像头,创建我们的网络,将图像转化为blob的形式,因为这是网络可以理解的形式,里面的参数我讲一下(whT,whT),其余的就是默认了,在开始时就已经定义了为320,那为什么是320,因为yolov3-320.cfg等,就是这个原因啦,它的分辨率就是320*320;net.setInput(blob)就是设置网络前行的通行证;接下来,我们要获得我们最感兴趣的那三层,用net.getLayerNames()函数获取所有层的名字,在得到三个不同的输出层的索引值,接着用列表生成式,根据索引将内容放进去,得到['yolo_82','yolo_94','yolo_106']。net.forward(outputNames)返回指定层的第一个输出的blob。再往下就是我的一些调试过程,我保留了调试时的注释,不懂的地方,不妨就取消注释,跑一遍就成。然后,再来讲解我们的findObjects(outputs,img)里面的内容,获取图像的宽高通道,设置空列表,放置边界框,Id,置信度等,那么下面的操作就是为了将这些空列表填满!!!,我们在上面有展示过outputs[0][0]的输出,我们不能将中心x,中心y,宽,高,置信度等作比较,因为它们相对较大,索引是从第五个开始,然后便是我所说的填满操作,应该不难,我们就此跳过。紧接着,来到尾声了,我们常会有检测时出现大小框,那么这是就需要处理,得到检测较大的那个框,让我们的检测更加的完善,cv.dnn.NMSBoxes()函数,参数confThreshold已经在开头定义,检测的大于50%,那就相当好了,nms_threshold用于非最大抑制的阈值,也是实现定义好了,这个用法我们在《Opencv项目实战:05物体检测》就讲到过。然后就是画框,放文本的操作,几乎我们每一期的实战项目都在讲。最后,引用findObjects(outputs,img)函数,开启摄像头,展示窗口,检测物体,完成后点击Esc键即可退出。
GitHub:https://github.com/Auorui/Opencv-project-training/tree/main/Opencv%20project%20training/08%20Yolov3
其中以下两个文件需要从官网下载,GitHub上面由于太大上传不了。
我写的较为的详细,几乎没有我这种风格的吧,我是学c语言出生的(是我们大一的必修课,说实话我以前根本就不知道的,可能这就是小镇做题家的原因吧),后来今年的二月自学的python,中途学了些爬虫,七月在参加实验室学了点单片机(我没有基础,也被刷下去了,keil5配文件麻烦死了),给我们安排的课程python的图像处理只有区区两节,也是这两节课才对Opencv感了兴趣,自己私下在学习,后来我发现刚好学的这些东西,都是涉及人工智能领域,计算机视觉的,我想我自己一定要做出点成就来,给大家更新的系列也是我学习的过程。
09物体尺寸测量
我们将以两种方式来展示我们这个项目的效果。
下面这是视频的实时检测,我分别用了盒子和盖子来检测,按理来说效果不应该怎么差的,但我实在没有找到合适的背景与物体。且我的摄像头使用的是外设,我不得不手持,所以存在一点点的抖动,但我可以保证,它是缺少了适合检测物体与背景。
我使用手机拍了一张照片并经过了ps修改了背景,效果不错。
本项目中,我将选用A4纸张为背景,找到放在该区域中对象的长、宽。打印出相关的数值。
所有的资源,你都可以在我的GitHub上找到,我将在末尾附上链接
在项目当中,我将引入utils,而utils是适用于在我们项目中所写的的文件。有了对它的理解能帮助我们更好的理解本项目,所以我觉得有必要在此叙述一番。
importcv2importnumpyasnpdefgetContours(img,cThr=[100,100],showCanny=False,minArea=1000,filter=0,draw=False):imgGray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)imgBlur=cv2.GaussianBlur(imgGray,(5,5),1)imgCanny=cv2.Canny(imgBlur,cThr[0],cThr[1])kernel=np.ones((5,5))imgDial=cv2.dilate(imgCanny,kernel,iterations=3)imgThre=cv2.erode(imgDial,kernel,iterations=2)ifshowCanny:cv2.imshow('Canny',imgThre)contours,hiearchy=cv2.findContours(imgThre,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)finalCountours=[]foriincontours:area=cv2.contourArea(i)ifarea>minArea:peri=cv2.arcLength(i,True)approx=cv2.approxPolyDP(i,0.02*peri,True)bbox=cv2.boundingRect(approx)iffilter>0:iflen(approx)==filter:finalCountours.append([len(approx),area,approx,bbox,i])else:finalCountours.append([len(approx),area,approx,bbox,i])finalCountours=sorted(finalCountours,key=lambdax:x[1],reverse=True)ifdraw:forconinfinalCountours:cv2.drawContours(img,con[4],-1,(0,0,255),3)returnimg,finalCountoursdefreorder(myPoints):#print(myPoints.shape)myPointsNew=np.zeros_like(myPoints)myPoints=myPoints.reshape((4,2))add=myPoints.sum(1)myPointsNew[0]=myPoints[np.argmin(add)]myPointsNew[3]=myPoints[np.argmax(add)]diff=np.diff(myPoints,axis=1)myPointsNew[1]=myPoints[np.argmin(diff)]myPointsNew[2]=myPoints[np.argmax(diff)]returnmyPointsNewdefwarpImg(img,points,w,h,pad=20):#print(points)points=reorder(points)pts1=np.float32(points)pts2=np.float32([[0,0],[w,0],[0,h],[w,h]])matrix=cv2.getPerspectiveTransform(pts1,pts2)imgWarp=cv2.warpPerspective(img,matrix,(w,h))imgWarp=imgWarp[pad:imgWarp.shape[0]-pad,pad:imgWarp.shape[1]-pad]returnimgWarpdeffindDis(pts1,pts2):return((pts2[0]-pts1[0])**2+(pts2[1]-pts1[1])**2)**0.5
接下来,我将按照惯例讲解,我们就以每个函数的意义来讲。
getContours()函数,曾在我以前的博客中出现过。正如它的命名,我们是为了得到轮廓。将原始图像依次经过这些转化:灰度图像、高斯模糊、canny检测边缘、膨胀、侵蚀等。cv2.findContours()从图像ROI中提取轮廓,然后在整个图像上下文中分析轮廓,参数cv2.RETR_EXTERNAL将会获取外部边缘;cv2.contourArea()计算轮廓面积;cv2.contourArea()计算轮廓周长或曲线长度;cv2.approxPolyDP()以指定精度近似多边形曲线;cv2.boundingRect()函数计算并返回指定点集或灰度图像非零像素的最小右上边界矩形;之后用finalCountours这个空列表来接受我们需要用到的信息,再对其轮廓的大小进行排序,因为我们需要的是最大的边界框。cv2.drawContours()绘制轮廓轮廓或填充轮廓,最后返回img,finalCountours。reorder函数,myPointsNew=np.zeros_like(myPoints),返回与myPoints具有相同形状和类型的零数组,在打印了myPoints.shape,它所返回的值是(4,1,2),不难理解,4指的是四个点,2指的是x,y,我们不需要中间的1,所以要对其进行重塑。np.argmin返回沿轴的最小值的索引,np.argmax返回沿轴的最大值的索引。所以此函数的作用是将顺序改为最下面的顺序。4.warpImg()函数,其实就是透视变换,详细的函数可以回头复习一下Opencv的文档,我在此不做多的讲述。
5.findDis()函数我们用一张图来解释,个人手绘:
importcv2importutils###################################webcam=Falsepath='1.png'cap=cv2.VideoCapture(1)cap.set(10,160)cap.set(3,1920)cap.set(4,1080)scale=3wP=210*scalehP=297*scale###################################whileTrue:ifwebcam:success,img=cap.read()else:img=cv2.imread(path)imgContours,conts=utils.getContours(img,minArea=50000,filter=4)iflen(conts)!=0:biggest=conts[0][2]#print(biggest)imgWarp=utils.warpImg(img,biggest,wP,hP)imgContours2,conts2=utils.getContours(imgWarp,minArea=2000,filter=4,cThr=[50,50],draw=False)iflen(conts)!=0:forobjinconts2:cv2.polylines(imgContours2,[obj[2]],True,(0,255,0),2)nPoints=utils.reorder(obj[2])nW=round((utils.findDis(nPoints[0][0]//scale,nPoints[1][0]//scale)/10),1)nH=round((utils.findDis(nPoints[0][0]//scale,nPoints[2][0]//scale)/10),1)cv2.arrowedLine(imgContours2,(nPoints[0][0][0],nPoints[0][0][1]),(nPoints[1][0][0],nPoints[1][0][1]),(255,0,255),3,8,0,0.05)cv2.arrowedLine(imgContours2,(nPoints[0][0][0],nPoints[0][0][1]),(nPoints[2][0][0],nPoints[2][0][1]),(255,0,255),3,8,0,0.05)x,y,w,h=obj[3]cv2.putText(imgContours2,'{}cm'.format(nW),(x+30,y-10),cv2.FONT_HERSHEY_COMPLEX_SMALL,1.5,(255,0,255),2)cv2.putText(imgContours2,'{}cm'.format(nH),(x-70,y+h//2),cv2.FONT_HERSHEY_COMPLEX_SMALL,1.5,(255,0,255),2)cv2.imshow('A4',imgContours2)img=cv2.resize(img,(0,0),None,0.5,0.5)cv2.imshow('Original',img)ifcv2.waitKey(1)&0xFF==27:break
那么,本项目的代码我看了一下,将utils.py文件看懂之后,不难理解,所以本项目我就不仔细讲解了。
GitHub:https://github.com/Auorui/Opencv-project-training/tree/main/Opencv%20project%20training/09%20Object%20Size%20Measurement
本项目主要是运用了之前扫描文档的思想,以A4纸为背景,检测其中区域的物体长和宽。我的摄像头无法固定,所以是手持的,且由于我在寝室里面是真的没有找到合适的测量物体以及背景色(全是米色或原木色的)。所以效果有所欠缺,但经过ps修改的图片,检测的效果还是很不错的。
那么祝你在本项目中玩的开心,否则我会在下一次项目中见到你!!!
还没有评论,来说两句吧...