1 目标功能(本节)
通过openCV调用摄像头,通过颜色空间转换及阈值判断筛选出目标物体,并通过轮廓处理将目标物体在图上的坐标返回。
2 开发环境
win10+Anaconda3(python3.7.2)+openCV4.1.2+tensorflow1.15
3 涉及方法
3.1 openCV-python 调用笔记本摄像头
from cv2 import cv2 # 如果直接写import cv2 会导致cv2下出现红线
# 开启摄像头
cap = cv2.VideoCapture(0) # 函数返回一个VideoCapture对象,其参数可以为0,1,2,笔记本摄像头一般为0
# 创建主循环(循环显示)
while True:
#从摄像头读取图片
sucess,img=cap.read() # success为bool值,判断是否获取到了视频帧,img为图像(帧)
#转为灰度图片
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
#显示摄像头拍摄的画面
cv2.imshow("img_gray",gray) # 灰度。
cv2.imshow("img_rgb",img) # 彩色
#保持画面的持续。
k=cv2.waitKey(1) # waitKey()内参数实际上可以看作延时或者帧率控制,
if k == 27: # k即 waitKey()的返回值在此处,如果有按键按下则返回按键的ASCll码
#通过esc键退出摄像(毫无疑问,27就是esc的ASCll码值)
break
# if cv2.waitKey(50) & 0xFF == ord('q'): # ord()获取对应按键的ASCll值,&0xff是只使低16位数字有效
# break
# 也可以如此,使用q键退出
# 关闭摄像头
cap.release()
# 关闭所有窗口
cv2.destroyAllWindows()
3.2 直方图均衡化
3.2.1 灰度
# 我的理解为对比度增强,
# 直方图均衡化是将原图像的灰度级均匀地映射到整个灰度级的范围内 # 注意原函数参数只能是灰度图哦!
# 在均衡化处理中综合考虑了统计概率与HVS的均衡
# 直方图均衡化原理:
# 1.计算累计直方图
# 2.对累计直方图进行区间转换
# 直方图均衡化处理
# 使用函数cv2.equalizeHist(src,dst = None) 其中src为8位单通道图像 函数返回值为处理后的结果
# 直方图均衡前后直方图的对比
from cv2 import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread(r"D:\anaconda\vscode-python\timg.jpg",0) #读取图像第一个参数为图像路径,个人喜欢写+r的绝对路径,第二个参数为图像的读取情况,0为灰度读取,若不加则默认为彩图
equ = cv.equalizeHist(img) # 直方图均衡
# 创建窗口
plt.figure("666",figsize=(10,5),facecolor='w',edgecolor='g')
# 参数分别名字,尺寸,视窗背景颜色,文字描边
# 原始图像直方图
plt.subplot(121),plt.hist(img.ravel(),256)
# 均衡化结果直方图
plt.subplot(122),plt.hist(equ.ravel(),256)
# 函数plt.hist():
# plt.hist(X,BINS)
# x 为数据源(一维)图像通常是二维,需要使用ravel()将图像的二维数组降为一维的
# BINS 表示灰度的分组情况
plt.show()
# 图像的实际效果
'''
from cv2 import cv2 as cv
img = cv.imread(r"D:\anaconda\vscode-python\timg.jpg",0)
equ = cv.equalizeHist(img)
cv.imshow("img",img)
cv.imshow("equ",equ)
cv.waitKey()
cv.destroyAllWindows()
'''
3.2.2 RGB
# 彩色图像直方图均衡 (v1)
def hisEqulColor(img):
# 转到y_cr_cb空间
ycrcb = cv2.cvtColor(img, cv2.COLOR_BGR2YCR_CB)
# 图像拆分
channels = cv2.split(ycrcb)
# dst为自己,即自己为掩模
cv2.equalizeHist(channels[0], channels[0])
# 图像组合
cv2.merge(channels, ycrcb)
# 从y_cr_cb空间转回BGR
cv2.cvtColor(ycrcb, cv2.COLOR_YCR_CB2BGR, img)
# 返回
return img
#这里只放一个函数,参数为BGR图像,返回值为直方图均衡过的BGR图像
3.3 阈值筛选
from cv2 import cv2
import numpy as np
# 开启摄像头
cap = cv2.VideoCapture(0)
# 阈值设置(蓝色)
lower_blue = np.array([78,43,46])
upper_blue = np.array([110,255,255])
# 主循环
while(1):
# 获取视频帧
ret, frame1 = cap.read()
cv2.imshow('Capture', frame) # bgr
# 将获取的视频帧转换为hsv格式
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) # hsv
# 利用inRange()函数和HSV模型中蓝色范围的上下界获取mask,mask中原视频中的蓝色部分会被弄成白色,其他部分黑色。
mask_1= cv2.inRange(hsv, lower_blue, upper_blue)
# 中值滤波(消除椒盐噪声)
mask = cv2.medianBlur(mask_1,5)
cv2.imshow('Mask', mask) # 灰度(二值)图像
# 将mask于原视频帧进行按位与操作,则会把mask中的白色用真实的图像替换:
# 就是将低于lower_red和高于upper_blue的部分分别变成0,lower_red~upper_blue之间的值变成255
res = cv2.bitwise_and(frame, frame, mask=mask)
cv2.imshow('Result', res)
# 设置帧率及按键控制返回
if cv2.waitKey(50) & 0xFF == ord('q'):
break
# 释放摄像头,关闭所有窗口
cap.release()
cv2.destroyAllWindows()
3.4 轮廓筛选
# 轮廓筛选(返回中心值)--mask
def contoursCho(mask):
# 寻找轮廓,contours为轮廓可将其看作是
contours,hierarchy = cv2.findContours(mask,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
# 返回值contours :
# 该值返回的是一组轮廓信息,是由若干点构成的 例如:contourd[i][j]表示的是第i个轮廓内的第j个点
# 轮廓的个数可由 len(contours) 表示
n = len(contours)
max = 0
m = 0
# 遍历所有轮廓,取其面积最大者,其轮廓编号储存在m中
for i in range(n):
if cv2.contourArea(contours[i]) > max:
max = cv2.contourArea(contours[i])
m = i
# 绘制最大轮廓
x,y,w,h = cv2.boundingRect(contours[m])
brcnt = np.array([[x,y],[x+w,y],[x+w,y+h],[x,y+h]])
cv2.drawContours(mask,[brcnt],-1,(255,255,255),2)
# 直接在mask(实参)原图上操作
# 返回x,y,w,h
return x,y,w,h # 分别为原轮廓的左上顶点x,y坐标,轮廓宽度及高度
# 同样也是只写函数,该函数参数为二值图像,返回值为轮廓的位置及大小信息
4 完整程序
# 颜色检测 -- 天蓝色 #
from cv2 import cv2
import numpy as np
# 彩色图像直方图均衡 (v1)
def hisEqulColor(img):
# 转到y_cr_cb空间
ycrcb = cv2.cvtColor(img, cv2.COLOR_BGR2YCR_CB)
# 图像拆分
channels = cv2.split(ycrcb)
#
cv2.equalizeHist(channels[0], channels[0])
# 图像组合
cv2.merge(channels, ycrcb)
# 从y_cr_cb空间转回BGR
cv2.cvtColor(ycrcb, cv2.COLOR_YCR_CB2BGR, img)
# 返回
return img
# 轮廓筛选(返回中心值)--mask (v1)
def contoursCho(mask):
contours,hierarchy = cv2.findContours(mask,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
n = len(contours)
max = 0
m = 0
# 遍历所有轮廓,取其面积最大者
for i in range(n):
if cv2.contourArea(contours[i]) > max:
max = cv2.contourArea(contours[i])
m = i
# 绘制最大轮廓
x,y,w,h = cv2.boundingRect(contours[m])
brcnt = np.array([[x,y],[x+w,y],[x+w,y+h],[x,y+h]])
cv2.drawContours(mask,[brcnt],-1,(255,255,255),2)
# 直接在mask(实参)原图上操作
# 返回中心点
return x+w/2,y+h/2
# 开启摄像头
cap = cv2.VideoCapture(0)
# 阈值设置(蓝色)
lower_blue = np.array([78,43,46])
upper_blue = np.array([110,255,255])
# 主循环
while(1):
# 获取视频帧
ret, frame1 = cap.read() # ret为bool值,检测是否准确的获取了视频帧(图像)
# 直方图均衡
frame = hisEqulColor(frame1)
cv2.imshow('Capture', frame) # bgr
# 将获取的视频帧转换为hsv格式
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) # hsv
# 利用inRange()函数和HSV模型中蓝色范围的上下界获取mask,mask中原视频中的蓝色部分会被弄成白色,其他部分黑色。
mask_1= cv2.inRange(hsv, lower_blue, upper_blue)
# 中值滤波(消除椒盐噪声)
mask = cv2.medianBlur(mask_1,5)
# 轮廓处理并返回中心值
x,y = contoursCho(mask)
cv2.imshow('Mask', mask) # 灰度(二值)图像
# 将mask于原视频帧进行按位与操作,则会把mask中的白色用真实的图像替换:
# 就是将低于lower_red和高于upper_blue的部分分别变成0,lower_red~upper_blue之间的值变成255
res = cv2.bitwise_and(frame, frame, mask=mask)
cv2.imshow('Result', res)
# 中心坐标显示
print("目标中心点横坐标 : ",x)
print("目标中心点纵坐标 : ",y)
# 设置帧率及按键控制返回
if cv2.waitKey(50) & 0xFF == ord('q'):
break
# 释放摄像头,关闭所有窗口
cap.release()
cv2.destroyAllWindows()