百度做网站推广电话,做网站要求付全款,千图网在线编辑,郴州网站建设企业打印一个图片可以做出一个函数#xff1a;
def cv_show(img,name):cv2.imshow(name,img)cv2.waitKey()cv2.destroyAllWindows()
1、轮廓特征与近似
1.1 轮廓特征
前面我们计算了这个图片的轮廓#xff1a; 它的轮廓信息保存在了contours中#xff0c;取出第一个轮廓
def cv_show(img,name):cv2.imshow(name,img)cv2.waitKey()cv2.destroyAllWindows()
1、轮廓特征与近似
1.1 轮廓特征
前面我们计算了这个图片的轮廓 它的轮廓信息保存在了contours中取出第一个轮廓计算相关参数
cnt contours[0]
cv2.contourArea(cnt)
cv2.arcLength(cnt,True)
打印结果 8500.5 437.9482651948929 这是分别求出了周长和面积这里的True表示的是否是闭合的。
1.2 轮廓近似 如图第一个图是原图如果将它的轮廓计算出来应该是第三个图的结果但是我不想要这样一些带坑坑洼洼的结果我只想要图2这样的结果呢
原图中含有一些曲线比如有一条曲线这条曲线有A、B两个点先将这两个点连上在曲线中选到一个C点使得这个C点到AB这条直线上距离最大如果这个距离d小于指定的阈值t那么这个AB直线就可以当做曲线的近似了。
那如果大于设定的阈值呢那么曲线就会被分解成两个部分变成两个曲线AC和BC然后AC和BC继续去做前面的判断操作一直到找到近似直线。
但是在代码的实现却非常简单
img cv2.imread(contours2.png)gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
contours, hierarchy cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
cnt contours[0]draw_img img.copy()
res cv2.drawContours(draw_img, [cnt], -1, (0, 0, 255), 2)
cv_show(res,res)
每行代码的意思
读进来图像还是前面的图像做二值处理找轮廓信息 找出第一个轮廓深度复制图像提取轮廓信息将轮廓图像打印
打印结果 接下来做轮廓近似的处理
epsilon 0.1*cv2.arcLength(cnt,True)
approx cv2.approxPolyDP(cnt,epsilon,True)draw_img img.copy()
res cv2.drawContours(draw_img, [approx], -1, (0, 0, 255), 2)
cv_show(res,res)
关键代码approx cv2.approxPolyDP(cnt,epsilon,True)
cv2.approxPolyDP这是计算轮廓的函数第一个参数表示计算的轮廓第二个是指定的阈值这个阈值是自己指定的一般通过周长来计算所以approx是计算的轮廓信息再用cv2.drawContours将轮廓拟合出来打印图像。
打印结果 这就是近似完的结果这里可以调整前面计算周长的权重0.1多执行几次这个值指定的越小结果越接近原始轮廓。
1.3 边界矩阵 继续用上面的图片如何将一个轮廓的外接矩形标出来呢不废话直接上代码
img cv2.imread(contours.png)gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
contours, hierarchy cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
cnt contours[5]x,y,w,h cv2.boundingRect(cnt)
img cv2.rectangle(img,(x,y),(xw,yh),(0,255,0),2)
cv_show(img,img)
前面几行都已经学习过了直接看到这里
x,y,w,h cv2.boundingRect(cnt)
cnt是轮廓信息通过cv2.boundingRect可以计算出四个值x,y,w,h一个坐标加上长宽有这个信息就可以得到一个确定的矩形。
通过这个函数cv2.rectangle依次传进去图像坐标1坐标2颜色线条宽度拟合出这个轮廓
打印结果 计算外接矩形和原始图形的面积比值
area cv2.contourArea(cnt)
x, y, w, h cv2.boundingRect(cnt)
rect_area w * h
extent float(area) / rect_area
print (轮廓面积与边界矩形比,extent)
第一行是计算原始面积第二行第三行计算外接矩形的面积然后计算比值打印出来 轮廓面积与边界矩形比 0.5154317244724715 外接圆
(x,y),radius cv2.minEnclosingCircle(cnt)
center (int(x),int(y))
radius int(radius)
img cv2.circle(img,center,radius,(0,255,0),2)
cv_show(img,img) 2、模板匹配方法
模板匹配在openCV中是非常重要的内容和卷积原理很像模板在原图像上从原点开始滑动计算模板与图像被模板覆盖的地方的差别程度这个差别程度的计算方法在opencv里有6种然后将每次计算的结果放入一个矩阵里作为结果输出。假如原图形是AxB大小而模板是axb大小则输出结果的矩阵是(A-a1)x(B-b1) 如图这是两个图片我需要做的是将lena脸的部分框出来然后右图相当于是标签假如左图是一个9*9的图像右图是一个3*3的图像那么左图可以分解成9个3*3的图像将右图与这9个区域的图像进行比对通过计算两个图像的像素匹配程度来判断是这9个区域的那一个区域9个区域就是从左至右从上至下一个一个进行匹配。
那这个匹配程度怎么计算呢openCV提供了多种方法来计算比如计算对应位置之间的像素值差异差异值就是量化匹配程度当然差异值越小说明匹配程度越接近。具体的匹配方法
TM_SQDIFF计算平方不同计算出来的值越小越相关TM_CCORR计算相关性计算出来的值越大越相关TM_CCOEFF计算相关系数计算出来的值越大越相关TM_SQDIFF_NORMED计算归一化平方不同计算出来的值越接近0越相关TM_CCORR_NORMED计算归一化相关性计算出来的值越接近1越相关TM_CCOEFF_NORMED计算归一化相关系数计算出来的值越接近1越相关
这里给出一个openCV官网链接是上面这些匹配方法的计算公式 OpenCV: Object Detection 分别将lena和模板lena的脸读进来转化为灰度图后打印出大小
# 模板匹配
img cv2.imread(lena.jpg, 0)
template cv2.imread(face.jpg, 0)
h, w template.shape[:2]
print(img.shape)
print(template.shape)
h和w是模板的长和宽打印的shape值为 (263, 263) (110, 85) 调用模板匹配操作
methods [cv2.TM_CCOEFF, cv2.TM_CCOEFF_NORMED, cv2.TM_CCORR,cv2.TM_CCORR_NORMED, cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED]
res cv2.matchTemplate(img, template, cv2.TM_SQDIFF)
print(res.shape)
methods是所有方法 cv2.matchTemplate的参数分别为原始图像、模板、匹配方法
然后打印shape值
打印结果 (154, 179) 这里的154263-1101,179263-851
用这个结果去定位一下最小损失的那个像素点的位置
min_val, max_val, min_loc, max_loc cv2.minMaxLoc(res)
print(min_val, max_val, min_loc, max_loc) 打印结果 39168.0 74403584.0 (107, 89) (159, 62) 在这个匹配方法中我们需要的是min_loc这个点的坐标再加上模板的长宽就可以得到我们想要框住的区域了。
3、模板匹配效果
用6种不同的匹配方法进行模板匹配看下结果的差异
for meth in methods:img2 img.copy()# 匹配方法的真值method eval(meth)print (method)res cv2.matchTemplate(img, template, method)min_val, max_val, min_loc, max_loc cv2.minMaxLoc(res)# 如果是平方差匹配TM_SQDIFF或归一化平方差匹配TM_SQDIFF_NORMED取最小值if method in [cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED]:top_left min_locelse:top_left max_locbottom_right (top_left[0] w, top_left[1] h)# 画矩形cv2.rectangle(img2, top_left, bottom_right, 255, 2)plt.subplot(121), plt.imshow(res, cmapgray)plt.xticks([]), plt.yticks([]) # 隐藏坐标轴plt.subplot(122), plt.imshow(img2, cmapgray)plt.xticks([]), plt.yticks([])plt.suptitle(meth)plt.show()
对这个代码块逐行解释
for循环深度复制图像取出当前匹配方法名称前面有一个数组存了全部的6个方法加上eval的原因是不能传进来一个字符串计算一个结果找出最好结果和最坏结果的差异程度值和坐标判断当前方法是算最小值为最佳结果还是最大值为最佳结果6已解释6已解释6已解释计算出右下角的坐标通过对焦的两个点的坐标画出一个矩形将目标区域框出来后面全是将结果打印出来
打印结果几乎都是一样的就只列出一个了 左边的图好理解就是将lena的脸框出来了我们完成了任务右边就是计算出了一个最亮的位置也就是前面res变量的输出结果。
没有加上归一化操作的结果会稍微差点。
同样的道理我们做一下多个模板的匹配比如一张图上有多个模板需要全部框出来
img_rgb cv2.imread(mario.jpg)
img_gray cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)
template cv2.imread(mario_coin.jpg, 0)
h, w template.shape[:2]res cv2.matchTemplate(img_gray, template, cv2.TM_CCOEFF_NORMED)
threshold 0.8
# 取匹配程度大于%80的坐标
loc np.where(res threshold)
for pt in zip(*loc[::-1]): # *号表示可选参数bottom_right (pt[0] w, pt[1] h)cv2.rectangle(img_rgb, pt, bottom_right, (0, 0, 255), 2)cv2.imshow(img_rgb, img_rgb)
cv2.waitKey(0)
打印结果