1. 首页
  2. Python

OpenCV on ubuntu using Python

up 用的开发平台是 Ubuntu 16.04LTSquad with quad OpenCV4.0
以下是对做去年视觉作业的一些笔记分享:
主要做的是 基于OpenCV的动态手势跟踪识别,根据分类识别手势,并依据“剪刀石头布”规则瞬间做出赢人类玩家的反应的程序。
就是一个机器人跟你玩剪刀石头布,当你快出来的时候,机器识别你的手势,迅速给出反应。

以下是实现的效果:

OpenCV on ubuntu using Pythonhttps://www.zhihu.com/video/1027966682396049408

以下是实现的原理:

1. 滤波去噪

由于边缘检测容易受到噪音影响,所以第一步是使用高斯滤波器去除噪声。

2. 去除背景,提取手部的轮廓

2.1方法一:肤色检测手部区域

利用肤色来检测手部是手部检测最直接的方法。皮肤颜色稳定,不轻易受到缩放、平移和旋转的影响,且对图像的尺寸、拍摄方向和角度的依赖性较小

颜色空间主要有两种,分别是YCbCr颜色空间和HSV颜色空间,根据Enamin D. Zarit等人对肤色在这些彩色空间分布的研究,以及在检测中性能的分析,本文通过对手部皮肤颜色进行特征分析(选取黄种人的肤色),选用HSV颜色空间进行手部区域检测。

RGB颜色空间和YCbCr颜色空间的混合肤色检测器。像素值满足如下条件:

begin{cases} R>Gwedge R>B \ (Ggeq Bwedge 5R-12G+7Bgeq 0) vee(G<Bland5R-7G+12Bgeq 0) \ C_rin (135,180)land C_bin (85,135)land Y >80 end{cases}

然而,利用python编程的结果很卡顿。

结论分析:有点卡顿,这与python计算能力有关,若用c++,则没有此现象,故使用方法二。

此方法也有一个技术难点就是生成新的二值图像时,需要注意图像格式的问题。后来我使用了深复制的思想,完整地实现了。

2.2方法二:灰度图像,阈值分割:

图像阈值化分割是一种传统的最常用的图像分割方法,因其实现简单、计算量小、性能较稳定而成为图像分割中最基本和应用最广泛的分割技术。它特别适用于目标和背景占据不同灰度级范围的图像。难点在于如何选择一个合适的阈值实现较好的分割。

我们将RGB图像转变为灰度图像,便于后续处理。

2.3 方法三:k-means分割

Kmeans是最简单的聚类算法之一,应用十分广泛,Kmeans以距离作为相似性的评价指标,其基本思想是按照距离将样本聚成不同的簇,两个点的距离越近,其相似度就越大,以得到紧凑且独立的簇作为聚类目标。

缺点:易受光源影响,参数需根据光源修改。

3. 找出轮廓:

利用Opencv中通过使用findContours函数,简单几个的步骤就可以检测出物体的轮廓。

4. 凸包

凸包(凸壳)是指如果在集合A内连接任意两个点的直线段都在A的内部,则称集合A是凸形的。简单点理解,就是一个多边型,没有凹的地方。凸包(凸壳)能包含点集中所有的点

5. 求moment,后求质心(用mean shift的方法求质心)

计算手指的个数,来识别手势特征并进行跟踪。首先要提取手掌轮廓,计算轮廓形状特征有:轮廓的质心、轮廓的最短最长径长、轮廓的外接圆(圆心和半径)、轮廓的周长和面积、轮廓在图像中的矩形框位置、轮廓的外包络点集合、轮廓的点集合、轮廓的各阶矩、轮廓的有效的特征向量的提取、手指指尖的定位。手的位置特征是指手掌的质心位置,针对二维图像,质心位置是可以通过计算零阶距和X、Y的一阶距得到的。假设二值化之后的图像为 I ( X , Y ) ,质心 ( x c , y c ) 计算公式如下:

M_{00}=sum_{x}sum_{y} I(x,y)

M_{10}=sum_{x}sum_{y} xI(x,y)

M_{01}=sum_{x}sum_{y} yI(x,y)

x_c= frac{M_{10}}{M_{00}}

Y_c= frac{M_{01}}{M_{00}}

6. 标出手指和手掌

质心处即为手掌,手指求法如下:

OpenCV on ubuntu using Python
OpenCV on ubuntu using Python

7. 判断手势和形状

7.1方法一:特征点

把提取的特征点和手势字典进行对比,然后判断手势和形状

7.2方法二:手指的个数

根据图像中凹凸点中的 (开始点, 结束点, 远点)的坐标, 利用余弦定理计算两根手指之间的夹角, 其必为锐角, 根据锐角的个数判别手势。

7.3方法三:轮廓的匹配程度

函数 cv2.matchShape() 可以帮我们比较两个形状或轮廓的相似度。如果返回值越小,匹配越好。它是根据 Hu 矩来计算的。

8. 输出结果:

动态输出克制当前输出的手势(依据角刀石头布规则)

以下是实现的代码

import cv2 import numpy as np import math ##输入结果库 pic_1 = cv2.imread('v1.png') pic_2 = cv2.imread('v2.png') pic_3 = cv2.imread('v3.png') ##摄像机输入 cap = cv2.VideoCapture(0) while( cap.isOpened() ) :     ret,img = cap.read()     gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) blur = cv2.GaussianBlur(gray,(5,5),0) ##阈值分割     ret,thresh1 = cv2.threshold(blur,70,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)   	 aa,contours, hierarchy = cv2.findContours(thresh1,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE) ##深复制     drawing = np.zeros(img.shape,np.uint8)      max_area=0    	##找轮廓     for i in range(len(contours)):             cnt=contours[i]             area = cv2.contourArea(cnt)             if(area>max_area):                 max_area=area                 ci=i     cnt=contours[ci]     hull = cv2.convexHull(cnt)#0621     ##meanshift求质心     moments = cv2.moments(cnt)     #print len(cnt)     #print hull 	##求质心公式     if moments['m00']!=0:                 cx = int(moments['m10']/moments['m00']) # cx = M10/M00                 cy = int(moments['m01']/moments['m00']) # cy = M01/M00                    centr=(cx,cy)            cv2.circle(img,centr,5,[0,0,255],2)     #cv2.circle(img,centr,5,[0,255,255],2)#0621     #cv2.rectangle(original, p1, p2, (77, 255, 9), 1, 1)#0621         cv2.drawContours(drawing,[cnt],0,(255,255,0),2)      #cv2.drawContours(drawing,[hull],0,(0,0,255),2)                 cnt = cv2.approxPolyDP(cnt,0.01*cv2.arcLength(cnt,True),True)     hull = cv2.convexHull(cnt,returnPoints = False)      ndefects = 0 #0622 for counting finger_number ###根据图像中凹凸点中的 (开始点, 结束点, 远点)的坐标, 可利用余弦定理计算两根手指之间的夹角,     if(1):                defects = cv2.convexityDefects(cnt,hull)                #mind=0                #maxd=0                for i in range(defects.shape[0]):                     s,e,f,d = defects[i,0]                     start = tuple(cnt[s][0])                     end = tuple(cnt[e][0])                     far = tuple(cnt[f][0])                     #dist = cv2.pointPolygonTest(cnt,centr,True) 		    a = np.sqrt(np.square(start[0]-end[0])+np.square(start[1]-end[1]))#0622 		    b = np.sqrt(np.square(start[0]-far[0])+np.square(start[1]-far[1]))#0622 		    c = np.sqrt(np.square(end[0]-far[0])+np.square(end[1]-far[1]))#0622                       angle   = math.acos((b ** 2 + c ** 2 - a ** 2) / (2 * b * c)) # * 57#0622 	##其必为锐角, 根据锐角的个数判别手势                     if angle <= math.pi/2 :#90:#0622                           ndefects = ndefects + 1#0622                      #cv2.line(img,start,end,[0,255,255],2)                     cv2.line(img,start,centr,[0,255,255],2)                     cv2.circle(img,start,20,[0,255,255],4)                       #cv2.circle(img,end,20,[0,255,0],4)                		                     cv2.circle(img,far,5,[0,0,255],-1)                #print(i) 	       print ndefects                i=0              	       if ndefects == 0: 			print 07 			cv2.imshow("RESULT",pic_3) 	       else: 		 if ndefects == 1: 			print 27 			cv2.imshow("RESULT",pic_2) 		 else:  			if ndefects == 4: 				print 57 				cv2.imshow("RESULT",pic_1) 			else:  			 	print 0000 	            cv2.imshow('output',drawing)     cv2.imshow('input',img)                      k = cv2.waitKey(10) #Esc     if k == 27: 		break

以下这份是加了肤色检测的程序

import cv2 import numpy as np  cap = cv2.VideoCapture(0) while( cap.isOpened() ) : 	ret,img = cap.read() 	# load an original image 	#img = cv2.imread(imgFile) 	rows,cols,channels = img.shape 	# convert color space from rgb to ycbcr 	imgYcc = cv2.cvtColor(img, cv2.COLOR_BGR2YCR_CB)  	# convert color space from bgr to rgb                         	img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)  	# prepare an empty image space 	imgSkin = np.zeros(img.shape, np.uint8) 	# copy original image/深复制 	imgSkin = img.copy()     	for r in range(rows): 	    for c in range(cols): 		 		# non-skin area if skin equals 0, skin area otherwise         		skin = 0        		 		# get values from rgb color space 		R = img.item(r,c,0) 		G = img.item(r,c,1) 		B = img.item(r,c,2) 		 		# get values from ycbcr color space    		Y = imgYcc.item(r,c,0) 		Cr = imgYcc.item(r,c,1) 		Cb = imgYcc.item(r,c,2)                                                                                                                                         	 	 		# skin color detection 		 		if R > G and R > B: 		        if (133 <= Cr and Cr <= 173) and (77 <= Cb and Cb <= 127): 		            skin = 1 		            # print 'Skin detected!' 		 		if 0 == skin: 		    imgSkin.itemset((r,c,0),0) 		    imgSkin.itemset((r,c,1),0)                 		    imgSkin.itemset((r,c,2),0) 		if 1 == skin: 		    imgSkin.itemset((r,c,0),255) 		    imgSkin.itemset((r,c,1),255)                 		    imgSkin.itemset((r,c,2),255)  	cv2.imshow("RESULT",imgSkin)  	k = cv2.waitKey(10) 	if k == 27: 		break

以下是一些学习心得和笔记:

import cv2 #opencv函數大多數都在cv2模塊內,並不是針對2.x.x版本的

这些程序的文件格式都是.py,是用python语言编写的
只需要在文件所在路径>打开Terminal>输入:python 文件名.py即可运行
结束运行只需要Ctrl+C或者Ctrl+Z

#查询 OpenCV 库函数

docs.opencv.org/3.4.1/d

#OpenCV官方教程:

我一般看3.4.1版本/python的

docs.opencv.org/3.4.1/d

numpy:

还挺重要和挺常用的

MJ: https://www.yiibai.com/numpy/numpy_array_from_numerical_ranges.html net: https://blog.csdn.net/scorpion_zs/article/details/52982872  numpy.zeros(np.zeros)使用方法--python学习笔记31 https://blog.csdn.net/qq_26948675/article/details/54318917  ndarray :n维数组 py文件名字不能叫numpy.py  x = np.arange(5) print x result(in terminal): [0  1  2  3  4]  ... numpy.ndarray.item  np.random.randint产生一个范围内的数据 owners = np.random.randint(15000, high=73001, size=398, dtype='l') 官方文档中给出的用法是:numpy.random.randint(low,high=None,size=None,dtype) 生成在半开半闭区间[low,high)上离散均匀分布的整数值;若high=None,则取值区间变为[0,low)  eg: x = np.random.randint(9, size=(3, 3))  print x print x.item(3) print x.item(7) print x.item((0, 1)) 默认high=none 取值区间[0,9),生成3*3的数组 比如随机生成了: [[5 7 3]  [6 6 7]  [4 5 5]] print x.item(3)即从0位开始数,0;1;2;;3;4;5;;6;7;8; “3”对应的是6 print x.item(7)对应是5 print x.item((0, 1))即从第0行第0列开始,则0行1列是7   Z = img.reshape((-1,3)) numpy.reshape https://docs.scipy.org/doc/numpy-1.13.0/reference/generated/numpy.reshape.html https://blog.csdn.net/qq_28618765/article/details/78083895  # convert to np.float32 Z = np.float32(Z) Numpy 中文用户指南 3.1 数据类型: https://segmentfault.com/a/1190000004681332

#數組

b=[[1,1],[1,1]]#定义了一个2*2的,且初始为0的二维数组? from Python数组定义方法_python_脚本之家 c = [[0]*10]*10 #定义10*10初始为0的二维数组 src = np.zeros((100, 100)) #使用np.zeros可以构造一个相应大小的全部由0组成的矩阵 100行100列 這用了numpy src[49][49] = 255  #第49行49列的元素爲255

#讀取攝像頭

看了很多教程,最后发现只要下面几句是必要的:

just need one order:  cap = cv2.VideoCapture(1) while( cap.isOpened() ) :     ret,img = cap.read()     then use the img

#改变inshow的位置

这个找了好久才找到这个解决方案,很不错。

https://www.2cto.com/kf/201611/568821.html中的  	cv2.imshow('draw_result',result) 	cv2.moveWindow('draw_result',1000,500)

#关于plot的一点知识

solution:https://blog.csdn.net/u011333059/article/details/38079833 代码如下:  [python] view plain copy  import matplotlib.pyplot as plt   input_image = root/to/your/image  plt.imshow(input_image)    运行后发现图片无法显示,  解决方法是: 首先import pylab 在需要显示图片的代码下一行加上 pylab.show()    这种方法可以显示图片,但是不关掉这个图片窗口,代码就不会继续运行下去,暂时还没有找到更合适的方法。 希望有知道解决方法的可以告诉我,谢谢!  问题来了,为什么显示的颜色与原图不同呢? 后来网上搜索后才知道,对于opencv的像素是BGR顺序,然而matplotlib所遵循的是RGB顺序。 opencv的一个像素为:[B,G,R] ,matplotlib的一个像素为:[R,G,B]。这就是为什么本来发红的区域变得有些发蓝了。 from 博客 :https://www.cnblogs.com/visionfeng/p/6094423.html

#关于wait.Key的一点笔记

from https://stackoverflow.com/questions/14494101/using-other-keys-for-the-waitkey-function-of-opencv  You can use ord() function in Python for that. For example, if you want to trigger 'a' key press, do as follows :  if cv2.waitKey(33) == ord('a'):    print "pressed a" To find the key value for any key is to print the key value using a simple script as follows : import cv2 img = cv2.imread('sof.jpg') # load a dummy image while(1):     cv2.imshow('img',img)     k = cv2.waitKey(33)     if k==27:    # Esc key to stop         break     elif k==-1:  # normally -1 returned,so don't print it         continue     else:         print k # else print its value  With this code, I got following values : Upkey : 2490368 DownKey : 2621440 LeftKey : 2424832 RightKey: 2555904 Space : 32 Delete : 3014656

#补充一个自己和喜欢的小功能

将两个不同角度拍摄的同一个场景的照片拼接为一张,以下是拼接效果,非常好玩。可以用于照片合成,将两个不同时间的自己合成到同一张照片上。

OpenCV on ubuntu using Python

代码如下:

import cv2  stitcher = cv2.createStitcher(False) foo = cv2.imread("v1.jpg") bar = cv2.imread("v2.jpg") result = stitcher.stitch((foo,bar))  cv2.imwrite("v3.jpg", result[1])  cv2.imshow("v3.jpg", result[1]) cv2.waitKey(0)

原文始发于:OpenCV on ubuntu using Python

主题测试文章,只做测试使用。发布者:熱鬧獨處,转转请注明出处:http://www.cxybcw.com/11780.html

联系我们

13687733322

在线咨询:点击这里给我发消息

邮件:1877088071@qq.com

工作时间:周一至周五,9:30-18:30,节假日休息

QR code