对网站建设好学吗,网络小白如何建立个人网站,北京企业网站建设价格,天津做网站制作公司文章目录 博主精品专栏导航备注#xff1a;以下源码均可运行#xff0c;不同项目涉及的函数均有详细分析说明。11、图像项目实战#xff08;一#xff09;银行卡号识别 —— sort_contours()、resize()#xff08;二#xff09;文档扫描OCR识别 —— cv2.getPerspectiveT… 文章目录 博主精品专栏导航备注以下源码均可运行不同项目涉及的函数均有详细分析说明。11、图像项目实战一银行卡号识别 —— sort_contours()、resize()二文档扫描OCR识别 —— cv2.getPerspectiveTransform() cv2.warpPerspective()、np.argmin()、np.argmax()、np.diff()三全景拼接 —— detectAndDescribe()、matchKeypoints()、cv2.findHomography()、cv2.warpPerspective()、drawMatches()四停车场车位检测基于Keras的CNN分类 —— pickle.dump()、pickle.load()、cv2.fillPoly()、cv2.bitwise_and()、cv2.circle()、cv2.HoughLinesP()、cv2.line()五答题卡识别与判卷 —— cv2.putText()、cv2.countNonZero()六背景建模动态目标识别 —— cv2.getStructuringElement()、cv2.createBackgroundSubtractorMOG2()七光流估计轨迹点跟踪—— cv2.goodFeaturesToTrack()、cv2.calcOpticalFlowPyrLK()八DNN模块的分类 —— cv2.dnn.blobFromImage()九矩形涂鸦画板 —— cv.namedWindow()、cv.setMouseCallback()十创建轨迹条 —— createTrackbar()、cv2.getTrackbarPos()10.1、创建一个轨迹条用于阈值化图像10.2、创建一个轨迹条用于画板调色 十一基于二值化实现人像抠图与背景替换 —— np.where()、np.uint8() 22、图像基本操作一图像的读取、保存和显示 —— cv2.imread()cv2.imwrite()cv2.imshow()1.1图窗设置cv2.namedWindow()、cv2.resizeWindow()、cv2.moveWindow()、cv2.setWindowProperty()。1.2图窗关闭cv2.waitKey()、cv2.destroyAllWindows() 二视频读取与处理 —— cv2.VideoCapture()三图像的三色图 —— cv2.split() cv.merge()四图像的边缘填充 —— cv2.copyMakeBorder()五图像融合 —— cv2.addWeighted()六颜色空间转换 —— cv2.cvtColor()七阈值处理 —— cv2.threshold() cv2.adaptiveThreshold()八均值/高斯/方框/中值滤波 —— cv2.blur() cv2.boxFilter() cv2.GaussianBlur() cv2.medianBlur()九腐蚀与膨胀 —— cv2.erode() 与 cv2.dilate() np.zeros() 与 np.ones()十形态学变化 —— cv2.morphologyEx()十一边缘检测算子 —— cv2.sobel()、cv2.Scharr()、cv2.Laplacian()、cv2.Canny()十二图像金字塔 —— cv2.pyrUp()、cv2.pyrDown()十三图像轮廓检测 —— cv2.findContours()、cv2.drawContours()、cv2.arcLength()、cv2.approxPolyDP()、cv2.rectangle()十四模板匹配 —— cv2.matchTemplate()、cv2.minMaxLoc()十五直方图(均衡化) —— cv2.calcHist()、img.ravel()、cv2.bitwise_and()、cv2.equalizeHist()、cv2.createCLAHE()十六傅里叶变换 低通/高通滤波 —— cv2.dft()、cv2.idft()、np.fft.fftshift()、np.fft.ifftshift()、cv2.magnitud()十七Harris角点检测 —— cv2.cornerHarris()、np.float32()十八SIFT尺度不变特征检测 —— cv2.xfeatures2d.SIFT_create()、sift.detectAndCompute()、sift.detect()、sift.compute()、cv2.drawKeypoints十九暴力特征匹配 —— cv2.BFMatcher_create()、bf.match()、bf_knn.knnMatch()、cv2.drawMatches()二十图像缩放镜像平移旋转仿射变换透视变换 —— cv2.resize()、cv2.getRotationMatrix2D()、cv2.getAffineTransform()、cv2.getPerspectiveTransform()、cv2.warpPerspective()、cv2.warpAffine() 博主精品专栏导航 专栏Pytorch项目实战 Opencv 图像处理全 Opencv C图像处理全 Pillow 图像处理PIL.Image Pytorch基础全 Python常用内置函数全 卷积神经网络CNN的经典模型 卷积神经网络CNN的实战知识 三万字硬核详解yolov1、yolov2、yolov3、yolov4、yolov5、yolov7 备注以下源码均可运行不同项目涉及的函数均有详细分析说明。
11、图像项目实战
一银行卡号识别 —— sort_contours()、resize() 【信用卡检测流程详解】 11、提取模板的每个数字 1111、读取模板图像、转换成灰度图、转换成二值图 1122、轮廓检测、绘制轮廓、对得到的所有轮廓进行排序(编号) 1133、提取模板的所有轮廓 - 每一个数字 22、提取信用卡的所有轮廓 2211、读取待检测图像、转换为灰度图、顶帽操作、sobel算子操作、闭操作、二值化、二次膨胀腐蚀 2222、轮廓检测、绘制轮廓 33、提取银行卡《四个数字一组》轮廓然后每个轮廓与模板的每一个数字进行匹配得到最大匹配结果 3311、在所有轮廓中识别出《四个数字一组》的轮廓共有四个并进行阈值化、轮廓检测和轮廓排序 3322、在《四个数字一组》中提取每个数字的轮廓以及坐标并进行模板匹配得到最大匹配结果 44、在原图像上用矩形画出《四个数字一组》并在原图上显示所有的匹配结果 import cv2 # opencv读取的格式是BGR
import matplotlib.pyplot as plt # Matplotlib是RGB
import numpy as npdef sort_contours(cnt_s, methodleft-to-right):reverse Falseii_myutils 0if method right-to-left or method bottom-to-top:reverse Trueif method top-to-bottom or method bottom-to-top:ii_myutils 1bounding_boxes [cv2.boundingRect(cc_myutils) for cc_myutils in cnt_s] # 用一个最小的矩形把找到的形状包起来x,y,h,w(cnt_s, bounding_boxes) zip(*sorted(zip(cnt_s, bounding_boxes), keylambda b: b[1][ii_myutils], reversereverse))return cnt_s, bounding_boxesdef resize(image, widthNone, heightNone, intercv2.INTER_AREA):dim_myutils None(h_myutils, w_myutils) image.shape[:2]if width is None and height is None:return imageif width is None:r_myutils height / float(h_myutils)dim_myutils (int(w_myutils * r_myutils), height)else:r_myutils width / float(w_myutils)dim_myutils (width, int(h_myutils * r_myutils))resized cv2.resize(image, dim_myutils, interpolationinter)return resized######################################################################
# 11、提取模板的每个数字
######################################################################
# 读取模板图像银行卡对应0~9的数字模板
img cv2.imread(rocr_a_reference.png)
ref_gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 转换成灰度图
ref_BINARY cv2.threshold(ref_gray, 10, 255, cv2.THRESH_BINARY_INV)[1] # 转换成二值图像
#######################################
# 轮廓检测contours, hierarchy cv2.findContours(img, mode, method)
# 输入参数 mode: 轮廓检索模式
# 1RETR_EXTERNAL 只检索最外面的轮廓
# 2RETR_LIST 检索所有的轮廓但检测的轮廓不建立等级关系将其保存到一条链表当中
# 3RETR_CCOMP 检索所有的轮廓并建立两个等级的轮廓。顶层是各部分的外部边界内层是的边界信息;
# 4RETR_TREE 检索所有的轮廓并建立一个等级树结构的轮廓;最常用
# method: 轮廓逼近方法
# 1CHAIN_APPROX_NONE 存储所有的轮廓点相邻的两个点的像素位置差不超过1。 例如矩阵的四条边。最常用
# 2CHAIN_APPROX_SIMPLE: 压缩水平方向垂直方向对角线方向的元素只保留该方向的终点坐标。 例如矩形的4个轮廓点。
# 输出参数 contours所有的轮廓
# hierarchy每条轮廓对应的属性
# 备注0轮廓就是将连续的点连着边界连在一起的曲线具有相同的颜色或者灰度。轮廓在形状分析和物体的检测和识别中很有用。
# 备注1函数输入图像是二值图即黑白的不是灰度图。所以读取的图像要先转成灰度的再转成二值图。
# 备注2函数在opencv2只返回两个值contours, hierarchy。
# 备注3函数在opencv3会返回三个值img, countours, hierarchy
#######################################
refCnts, hierarchy cv2.findContours(ref_BINARY.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)#######################################
# 绘制轮廓v2.drawContours(image, contours, contourIdx, color, thickness) ———— (在图像上)画出图像的轮廓
# 输入参数 image: 需要绘制轮廓的目标图像注意会改变原图
# contours: 轮廓点上述函数cv2.findContours()的第一个返回值
# contourIdx: 轮廓的索引表示绘制第几个轮廓。-1表示绘制所有的轮廓
# color: 绘制轮廓的颜色(RGB)
# thickness: 可选参数轮廓线的宽度-1表示填充
# 备注图像需要先复制一份copy(), 否则赋值操作的图像与原图会随之一起改变。
#######################################
img_Contours img.copy()
cv2.drawContours(img_Contours, refCnts, -1, (0, 0, 255), 3)
# print(np.array(refCnts).shape)# 画图(图像处理并得到轮廓的图形化显示)
plt.subplot(221), plt.imshow(img, gray), plt.title((0)ref)
plt.subplot(222), plt.imshow(ref_gray, gray), plt.title((1)ref_gray)
plt.subplot(223), plt.imshow(ref_BINARY, gray), plt.title((2)ref_BINARY)
plt.subplot(224), plt.imshow(img_Contours, gray), plt.title((3)img_Contours)
plt.show()
#######################################
# 对得到的所有轮廓进行排序(编号)从左到右从上到下
refCnts sort_contours(refCnts, methodleft-to-right)[0]
#######################################
# 提取(模板的)所有轮廓 - 数字
digits {} # 保存每个模板的数字 - 元组初始化
for (i, c) in enumerate(refCnts):(x, y, w, h) cv2.boundingRect(c) # 得到轮廓(数字)的外接矩形的左上角的(x, y)坐标、宽度和长度roi ref_BINARY[y:y h, x:x w] # 获得外接矩形的坐标roi cv2.resize(roi, (57, 88)) # 将感兴趣区域的图像(数字)resize相同的大小digits[i] roi # 保存每个模板(数字)
######################################################################
# 22、提取信用卡的所有轮廓
######################################################################
# 初始化卷积核getStructuringElement(shape, ksize)
# 输入参数 shape形状
# (1) MORPH_RECT 矩形
# (2) MORPH_CROSS 十字型
# (3) MORPH_ELLIPSE 椭圆形
# ksize卷积核大小。例如(3, 3)表示3*3的卷积核
######################################
rect_Kernel cv2.getStructuringElement(cv2.MORPH_RECT, (9, 3))
square_Kernel cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
######################################
# 读取输入图像(待检测信用卡图像)并进行预处理
image_card cv2.imread(rimages\credit_card_01.png)
image_resize resize(image_card, width300)
image_gray cv2.cvtColor(image_resize, cv2.COLOR_BGR2GRAY)#######################################
# 形态学变化函数cv2.morphologyEx(src, op, kernel)
# 参数说明src传入的图片op进行变化的方式 kernel表示方框的大小
# op变化的方式有五种
# 开运算(open) cv2.MORPH_OPEN 先腐蚀再膨胀。 开运算可以用来消除小黑点。
# 闭运算(close) cv2.MORPH_CLOSE 先膨胀再腐蚀。 闭运算可以用来突出边缘特征。
# 形态学梯度(morph-grad) cv2.MORPH_GRADIENT 膨胀后图像减去腐蚀图像。 可以突出团块(blob)的边缘保留物体的边缘轮廓。
# 顶帽(top-hat) cv2.MORPH_TOPHAT 原始输入减去开运算结果。 将突出比原轮廓亮的部分。
# 黑帽(black-hat) cv2.MORPH_BLACKHAT 闭运算结果减去原始输入 将突出比原轮廓暗的部分。
#######################################
image_tophat cv2.morphologyEx(image_gray, cv2.MORPH_TOPHAT, rect_Kernel) # 礼帽操作突出更明亮的区域#######################################
# Sobel算子是一种常用的边缘检测算子。对噪声具有平滑作用提供较为精确的边缘方向信息但是边缘定位精度不够高。
# 边缘就是像素对应的灰度值快速变化的地方。如黑到白的边界
# 图像是二维的。Sobel算子在x,y两个方向求导故有不同的两个卷积核Gx, Gy且Gx的转置等于Gy。分别反映了每一点像素在水平方向和在垂直方向上的亮度变换情况.
########################################
# dst cv2.Sobel(src, ddepth, dx, dy, ksize)
# 输入参数 src 输入图像
# ddepth 图像的深度-1表示采用的是与原图像相同的深度。目标图像的深度必须大于等于原图像的深度
# dx和dy 表示的是求导的阶数0表示这个方向上没有求导一般为0、1、2。
# ksize 卷积核大小一般为3、5。
# 同时对x和y进行求导会导致部分信息丢失。不建议- 分别计算x和y再求和效果好
########################################
# (1)cv2.CV_16S的说明
# 1Sobel函数求完导数后会有负值还有会大于255的值。
# 2而原图像是uint8即8位无符号数。所以Sobel建立图像的位数不够会有截断。
# 3因此要使用16位有符号的数据类型即cv2.CV_16S。
# (2)cv2.convertScaleAbs(): 给图像的所有像素加一个绝对值
# 通过该函数将其转回原来的uint8形式。否则将无法显示图像而只是一副灰色的窗口。
########################################
# 进行sobel算子操作 ksize-1相当于用3*3的卷积核进行筛选ll内置的卷积核
image_gradx cv2.Sobel(image_tophat, ddepthcv2.CV_32F, dx1, dy0, ksize-1) # 检索图像的边界gradx是经过Sobel算子处理后的图像的像素点矩阵
image_gradx np.absolute(image_gradx) # 对数组中每一个元素求绝对值
(minVal, maxVal) (np.min(image_gradx), np.max(image_gradx)) # 找到最大边界差值和最小边界插值
image_gradx (255 * ((image_gradx - minVal) / (maxVal - minVal))) # 归一化公式将图像像素数据限制在0-1之间便于后续的操作
image_gradx image_gradx.astype(uint8) # 将gradx的矩阵元素改为数据类型uint8一般图像的像素点类型都是uint8sobel_Gx1 cv2.Sobel(image_tophat, ddepthcv2.CV_32F, dx1, dy0, ksize3) # 3*3卷积核
sobel_Gx_Abs1 cv2.convertScaleAbs(sobel_Gx1) # 1左边减右边2白到黑是正数黑到白就是负数且所有的负数会被截断成0所以要取绝对值。
sobel_Gy1 cv2.Sobel(image_tophat, cv2.CV_64F, 0, 1, ksize3)
sobel_Gy_Abs1 cv2.convertScaleAbs(sobel_Gy1)
sobel_Gx_Gy_Abs1 cv2.addWeighted(sobel_Gx_Abs1, 0.5, sobel_Gy_Abs1, 0.5, 0) # 权重值x 权重值y 偏置b########################################
# 闭操作先膨胀再腐蚀将银行卡分成四个部分每个部分的四个数字连在一起
image_CLOSE cv2.morphologyEx(image_gradx, cv2.MORPH_CLOSE, square_Kernel)
########################################
# 图像阈值 ret, dst cv2.threshold(src, thresh, max_val, type)
# 输入参数 dst 输出图
# src 输入图只能输入单通道图像通常来说为灰度图
# thresh 阈值
# max_val 当像素值超过了阈值或者小于阈值根据type来决定所赋予的值
# type 二值化操作的类型包含以下5种类型
# (1) cv2.THRESH_BINARY 超过阈值部分取max_val最大值否则取0
# (2) cv2.THRESH_BINARY_INV THRESH_BINARY的反转
# (3) cv2.THRESH_TRUNC 大于阈值部分设为阈值否则不变
# (4) cv2.THRESH_TOZERO 大于阈值部分不改变否则设为0
# (5) cv2.THRESH_TOZERO_INV THRESH_TOZERO的反转
########################################
# THRESH_OTSU 会自动寻找合适的阈值适合双峰需把阈值参数设置为0。
image_thresh cv2.threshold(image_CLOSE, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
# (二次)闭操作将四个连在一起的数字进行填充形成一个整体。
image_2_dilate cv2.dilate(image_thresh, square_Kernel, iterations2) # 膨胀(迭代次数2次)
image_1_erode cv2.erode(image_2_dilate, square_Kernel, iterations1) # 腐蚀(迭代次数1次)
image_2_CLOSE image_1_erode
# 计算轮廓
threshCnts, hierarchy cv2.findContours(image_2_CLOSE.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# cnts threshCnts # 代表图像轮廓的点集
image_Contours image_resize.copy()
cv2.drawContours(image_Contours, threshCnts, -1, (0, 0, 255), 3)plt.subplot(241), plt.imshow(image_card, gray), plt.title((0)image_card)
plt.subplot(242), plt.imshow(image_gray, gray), plt.title((1)image_gray)
plt.subplot(243), plt.imshow(image_tophat, gray), plt.title((2)image_tophat)
plt.subplot(244), plt.imshow(image_gradx, gray), plt.title((3)image_gradx)
plt.subplot(245), plt.imshow(image_CLOSE, gray), plt.title((4)image_CLOSE)
plt.subplot(246), plt.imshow(image_thresh, gray), plt.title((5)image_thresh)
plt.subplot(247), plt.imshow(image_2_CLOSE, gray), plt.title((6)image_2_CLOSE)
plt.subplot(248), plt.imshow(image_Contours, gray), plt.title((7)image_Contours)
plt.show()######################################################################
# 33、提取银行卡 四个数字一组 轮廓然后每个轮廓与模板的每一个数字进行匹配得到最大匹配结果
######################################################################
# 3311、识别出四个数字一组的所有轮廓理论上是四个
########################################
locs [] # 保存四个数字一组的轮廓坐标 - 列表初始化
for (i, c) in enumerate(threshCnts): # 遍历轮廓(x, y, w, h) cv2.boundingRect(c) # 计算矩形ar w / float(h) # 四个数字一组的长宽比# 匹配(四个数字为一组)轮廓的大小 —— 以实际图像大小进行调整if (2.0 ar and ar 4.0):if (35 w 60) and (10 h 20):locs.append((x, y, w, h)) # 符合的留下来
# 将符合的轮廓从左到右排序
locs sorted(locs, keylambda x:x[0])
########################################
# 3322、在四个数字一组中提取每个数字的轮廓坐标并进行模板匹配
########################################
output [] # 保存银行卡中每个数字的轮廓坐标 - 列表初始化
# 遍历银行卡的每一个数字
for (ii, (gX, gY, gW, gH)) in enumerate(locs): # ii 应为四组groupOutput [] # 信用卡每个数字的最后匹配结果存储group_digit image_gray[gY - 5:gY gH 5, gX - 5:gX gW 5] # 根据坐标提取每一个组将每个轮廓的结果放大一些避免信息丢失group_digit_th cv2.threshold(group_digit, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1] # 二值化digitCnts, hierarchy cv2.findContours(group_digit_th.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 获取轮廓digitCnts sort_contours(digitCnts, methodleft-to-right)[0] # 对获得的轮廓进行编号# 计算每一组中的每一个数值for jj in digitCnts: # jj 应为四个数字(x, y, w, h) cv2.boundingRect(jj) # 获取当前数值的轮廓roi group_digit[y:y h, x:x w] # 获取当前数值的坐标roi cv2.resize(roi, (57, 88)) # 修改尺寸大小该大小应与模板数字的大小相同cv2.imshow(Image, roi)cv2.waitKey(200) # 延迟200ms######################################### 模板匹配cv2.matchTemplate(image, template, method)# 输入参数 image 待检测图像# template 模板图像# method 模板匹配方法# 1cv2.TM_SQDIFF 计算平方差。 计算出来的值越接近0越相关# 2cv2.TM_CCORR 计算相关性。 计算出来的值越大越相关# 3cv2.TM_CCOEFF 计算相关系数。 计算出来的值越大越相关# 4cv2.TM_SQDIFF_NORMED 计算归一化平方差。 计算出来的值越接近0越相关# 5cv2.TM_CCORR_NORMED 计算归一化相关性。 计算出来的值越接近1越相关# 6cv2.TM_CCOEFF_NORMED 计算归一化相关系数。 计算出来的值越接近1越相关# 最好选择有归一化操作效果好######################################### 获取匹配结果函数min_val, max_val, min_loc, max_loc cv2.minMaxLoc(ret)# 其中 ret是cv2.matchTemplate函数返回的矩阵# min_val, max_val, min_loc, max_loc分别表示最小值最大值最小值与最大值在图像中的位置# 如果模板方法是平方差或者归一化平方差要用min_loc; 其余用max_loc########################################scores [] # 计算【轮廓中的数字: roi】和【模板中的数字: digitROI】的匹配分数for (kk, digitROI) in digits.items(): # kk 应为10数字对应模板的十个数result cv2.matchTemplate(roi, digitROI, cv2.TM_CCOEFF)(_, max_score, _, _) cv2.minMaxLoc(result) # max_score表示最大值scores.append(max_score) # 将对象max_score添加到列表scores后面groupOutput.append(str(np.argmax(scores))) # 将最大匹配分数对应的数字保存下来######################################### 添加文字及修改格式函数cv2.putText(img, str(i), (123, 456)), font, 2, (0, 255, 0), 3)# 输入参数依次是图片添加的文字左上角坐标字体字体大小颜色字体粗细######################################### 在原图像上用矩形将 四个数字一组 画出来应共有四个矩形对应四个组cv2.rectangle(image_resize, (gX - 5, gY - 5), (gX gW 5, gY gH 5), (0, 0, 255), 1)cv2.putText(image_resize, .join(groupOutput), (gX, gY - 15), cv2.FONT_HERSHEY_SIMPLEX, 0.65, (0, 0, 255), 2)# 将银行卡每一个数字对应的实际匹配值保存下来output.extend(groupOutput) # 将groupOutput列表添加到output列表后面# 打印结果在原图上显示所有的匹配结果
cv2.imshow(Image, image_resize)
cv2.waitKey(0)
深究 Pycharm shadows name ‘xxxx’ from outer scope 警告
二文档扫描OCR识别 —— cv2.getPerspectiveTransform() cv2.warpPerspective()、np.argmin()、np.argmax()、np.diff() 计算轮廓的长度cv2.arcLength(curve, closed) 找出轮廓的多边形拟合曲线approxPolyDP(contourMat, 10, true) 求最小值对应的索引np.argmin() 求最大值对应的索引np.argmax() 求同一行列与列之间的差值np.diff() import numpy as np
import cv2
import matplotlib.pyplot as plt # Matplotlib是RGB
######################################################################
# 计算齐次变换矩阵cv2.getPerspectiveTransform(rect, dst)
# 输入参数 rect输入图像的四个点四个角
# dst输出图像的四个点方方正正的图像对应的四个角
######################################################################
# 仿射变换cv2.warpPerspective(src, M, dsize, dstNone, flagsNone, borderModeNone, borderValueNone)
# 透视变换cv2.warpAffine(src, M, dsize, dstNone, flagsNone, borderModeNone, borderValueNone)
# src输入图像 dst输出图像
# M2×3的变换矩阵
# dsize变换后输出图像尺寸
# flag插值方法
# borderMode边界像素外扩方式
# borderValue边界像素插值默认用0填充
#
# Affine Transformation可实现旋转平移缩放变换后的平行线依旧平行。
# Perspective Transformation即以不同视角的同一物体在像素坐标系中的变换可保持直线不变形但是平行线可能不再平行。
#
# 备注cv2.warpAffine需要与cv2.getPerspectiveTransform搭配使用。
######################################################################def order_points(pts):rect np.zeros((4, 2), dtypefloat32) # 一共4个坐标点# 按顺序找到对应坐标0123分别是 左上右上右下左下# 计算左上右下s pts.sum(axis1)rect[0] pts[np.argmin(s)] # np.argmin() 求最小值对应的索引rect[2] pts[np.argmax(s)] # np.argmax() 求最大值对应的索引# 计算右上和左下diff np.diff(pts, axis1) # np.diff 求同一行列与列之间的差值rect[1] pts[np.argmin(diff)]rect[3] pts[np.argmax(diff)]return rectdef four_point_transform(image, pts):rect order_points(pts) # 获取输入坐标点(tl, tr, br, bl) rect # 获取四边形的四个点每个点有两个值对应x, y坐标# 计算输入的w和h值widthA np.sqrt(((br[0] - bl[0]) ** 2) ((br[1] - bl[1]) ** 2))widthB np.sqrt(((tr[0] - tl[0]) ** 2) ((tr[1] - tl[1]) ** 2))maxWidth max(int(widthA), int(widthB)) # 取四边形上下两边中最大的宽度heightA np.sqrt(((tr[0] - br[0]) ** 2) ((tr[1] - br[1]) ** 2))heightB np.sqrt(((tl[0] - bl[0]) ** 2) ((tl[1] - bl[1]) ** 2))maxHeight max(int(heightA), int(heightB)) # 取四边形左右两边中最大的高度# 变换后对应坐标位置dst np.array([[0, 0], [maxWidth - 1, 0], [maxWidth - 1, maxHeight - 1], [0, maxHeight - 1]], dtypefloat32)################################################################################ 计算齐次变换矩阵cv2.getPerspectiveTransform(rect, dst)###############################################################################M cv2.getPerspectiveTransform(rect, dst)################################################################################ 透视变换将输入矩形乘以齐次变换矩阵得到输出矩阵###############################################################################warped cv2.warpPerspective(image, M, (maxWidth, maxHeight))return warpeddef resize(image, widthNone, heightNone, intercv2.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, interpolationinter)return resized##############################################
image cv2.imread(rimages\receipt.jpg)
ratio image.shape[0] / 500.0 # resize之后坐标也会相同变化故记录图像的比率
orig image.copy()
image resize(orig, height500)
##############################################
gray cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # 转换为灰度图
gray cv2.GaussianBlur(gray, (5, 5), 0) # 高斯滤波操作
edged cv2.Canny(gray, 75, 200) # Canny算法边缘检测
##############################################
print(STEP 1: 边缘检测)
cv2.imshow(Image, image)
cv2.imshow(Edged, edged)
cv2.waitKey(0)
cv2.destroyAllWindows()
##############################################
# 轮廓检测
cnts, hierarchy cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) # 轮廓检测
cnts sorted(cnts, keycv2.contourArea, reverseTrue)[:5] # 选定所有轮廓中前五个轮廓并进行排序
for c in cnts:peri cv2.arcLength(c, True) # 计算轮廓近似approx cv2.approxPolyDP(c, 0.02 * peri, True) # 找出轮廓的多边形拟合曲线if len(approx) 4: # 如果当前轮廓是四个点矩形表示当前轮廓是所需求目标screenCnt approxbreak
##############################################
print(STEP 2: 获取轮廓)
cv2.drawContours(image, [screenCnt], -1, (0, 255, 0), 2) # 在原图上画出检测得到的轮廓
cv2.imshow(Outline, image)
cv2.waitKey(0)
cv2.destroyAllWindows()
##############################################
# 透视变换
warped four_point_transform(orig, screenCnt.reshape(4, 2) * ratio) # 得到的轮廓要乘以图像的缩放尺寸
warped cv2.cvtColor(warped, cv2.COLOR_BGR2GRAY) # 转换为灰度图
ref cv2.threshold(warped, 100, 255, cv2.THRESH_BINARY)[1] # 二值化处理
ref resize(ref, height500)
##############################################
print(STEP 3: 齐次变换)
cv2.imshow(Scanned, ref)
cv2.waitKey(0)
cv2.destroyAllWindows()##############################################
# 轮廓点绘制的颜色通道是BGR; 但是Matplotlib是RGB; 故在绘图时(0, 0, 255)会由BGR转换为RGB红 - 蓝
orig cv2.cvtColor(orig, cv2.COLOR_BGR2RGB) # BGR转换为RGB格式
edged cv2.cvtColor(edged, cv2.COLOR_BGR2RGB)
image cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
ref cv2.cvtColor(ref, cv2.COLOR_BGR2RGB)plt.subplot(2, 2, 1), plt.imshow(orig), plt.title(orig)
plt.subplot(2, 2, 2), plt.imshow(edged), plt.title(edged)
plt.subplot(2, 2, 3), plt.imshow(image), plt.title(contour)
plt.subplot(2, 2, 4), plt.imshow(ref), plt.title(rectangle)
plt.show()######################################################################
# 计算轮廓的长度retval cv2.arcLength(curve, closed)
# 输入参数 curve 轮廓曲线。
# closed 若为true,表示轮廓是封闭的若为false则表示打开的。布尔类型
# 输出参数 retval 轮廓的长度周长。
######################################################################
# 找出轮廓的多边形拟合曲线approxCurve approxPolyDP(contourMat, 10, true)
# 输入参数 contourMat 轮廓点矩阵集合
# epsilon (double类型)指定的精度, 即原始曲线与近似曲线之间的最大距离。
# closed (bool类型)若为true, 则说明近似曲线是闭合的; 反之, 若为false, 则断开。
# 输出参数 approxCurve 轮廓点矩阵集合当前点集是能最小包容指定点集的。画出来即是一个多边形
######################################################################
三全景拼接 —— detectAndDescribe()、matchKeypoints()、cv2.findHomography()、cv2.warpPerspective()、drawMatches() 函数功能利用sift算法实现全景拼接算法将给定的两幅图片拼接为一幅. 11:从输入的两张图片里检测关键点、提取(sift)局部不变特征。 22:匹配的两幅图像之间的特征(Lowe’s算法比较最近邻距离与次近邻距离) 33:使用RANSAC算法随机抽样一致算法利用匹配特征向量估计单映射变换矩阵homography单应性。 44:利用33得到的单映矩阵应用透视变换。 import cv2
import numpy as np
#########################################################
# 预定义框架说明
# 定义一个Stitcher类stitch()、detectAndDescribe()、matchKeypoints()、drawMatches()
# stitch() 拼接函数
# detectAndDescribe() 检测图像的SIFT关键特征点并计算特征描述子
# matchKeypoints() 匹配两张图片的所有特征点
# cv2.findHomography() 计算单映射变换矩阵
# cv2.warpPerspective() 透视变换作用缝合图像
# drawMatches() 建立直线关键点的匹配可视化
#
# 备注cv2.warpPerspective()需要与cv2.findHomography()搭配使用。
#########################################################class Stitcher:##################################################################################def stitch(self, images, ratio0.75, reprojThresh4.0, showMatchesFalse):(imageB, imageA) images # 获取输入图片(kpsA, featuresA) self.detectAndDescribe(imageA) # 检测A、B图片的SIFT关键特征点并计算特征描述子(kpsB, featuresB) self.detectAndDescribe(imageB)M self.matchKeypoints(kpsA, kpsB, featuresA, featuresB, ratio, reprojThresh) # 匹配两张图片的所有特征点返回匹配结果。if M is None: # 如果返回结果为空没有匹配成功的特征点退出算法return None# 否则提取匹配结果 #(matches, H, status) M # H是3x3视角变换矩阵result cv2.warpPerspective(imageA, H, (imageA.shape[1] imageB.shape[1], imageA.shape[0])) # 将图片A进行视角变换result是变换后图片result[0:imageB.shape[0], 0:imageB.shape[1]] imageB # 将图片B传入result图片最左端if showMatches: # 检测是否需要显示图片匹配vis self.drawMatches(imageA, imageB, kpsA, kpsB, matches, status) # 生成匹配图片return (result, vis)return result##################################################################################def detectAndDescribe(self, image):# gray cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # 将彩色图片转换成灰度图descriptor cv2.xfeatures2d.SIFT_create() # 建立SIFT生成器###################################################### 如果是OpenCV3.X则用cv2.xfeatures2d.SIFT_create方法来实现DoG关键点检测和SIFT特征提取。# 如果是OpenCV2.4则用cv2.FeatureDetector_create方法来实现关键点的检测DoG。#####################################################(kps, features) descriptor.detectAndCompute(image, None) # 检测SIFT特征点并计算描述子kps np.float32([kp.pt for kp in kps]) # 将结果转换成NumPy数组return (kps, features) # 返回特征点集及对应的描述特征##################################################################################def matchKeypoints(self, kpsA, kpsB, featuresA, featuresB, ratio, reprojThresh):matcher cv2.BFMatcher() # 建立暴力匹配器rawMatches matcher.knnMatch(featuresA, featuresB, 2) # 使用KNN检测来自A、B图的SIFT特征匹配对K2matches []for m in rawMatches:if len(m) 2 and m[0].distance m[1].distance * ratio: # 当最近距离跟次近距离的比值小于ratio值时保留此匹配对matches.append((m[0].trainIdx, m[0].queryIdx)) # 存储两个点在featuresA, featuresB中的索引值if len(matches) 4: # 当筛选后的匹配对大于4时计算视角变换矩阵# 投影变换矩阵3*3。有八个参数对应八个方程其中一个为1用于归一化。对应四对每对(x, y)ptsA np.float32([kpsA[i] for (_, i) in matches]) # 获取匹配对的点坐标ptsB np.float32([kpsB[i] for (i, _) in matches])(H, status) cv2.findHomography(ptsA, ptsB, cv2.RANSAC, reprojThresh) # 使用RANSAC算法利用匹配特征向量估计单映矩阵homography单应性return (matches, H, status)return None # 如果匹配对小于4时返回None##################################################################################def drawMatches(self, imageA, imageB, kpsA, kpsB, matches, status):(hA, wA) imageA.shape[:2](hB, wB) imageB.shape[:2]vis np.zeros((max(hA, hB), wA wB, 3), dtypeuint8)vis[0:hA, 0:wA] imageA # 将A、B图左右连接到一起vis[0:hB, wA:] imageBfor ((trainIdx, queryIdx), s) in zip(matches, status):if s 1: # 当点对匹配成功时画到可视化图上ptA (int(kpsA[queryIdx][0]), int(kpsA[queryIdx][1]))ptB (int(kpsB[trainIdx][0]) wA, int(kpsB[trainIdx][1]))cv2.line(vis, ptA, ptB, (0, 255, 0), 1)return vis # 返回可视化结果##################################################################################
if __name__ __main__:# 读取拼接图片imageA cv2.imread(left_01.png)imageB cv2.imread(right_01.png)# 把图片拼接成全景图stitcher Stitcher() # 调用拼接函数(result, vis) stitcher.stitch([imageA, imageB], showMatchesTrue)# 显示所有图片cv2.imshow(Image A, imageA)cv2.imshow(Image B, imageB)cv2.imshow(Keypoint Matches, vis)cv2.imshow(Result, result)cv2.waitKey(0)cv2.destroyAllWindows()
基于OpenCV全景拼接PythonSIFT/SURF
四停车场车位检测基于Keras的CNN分类 —— pickle.dump()、pickle.load()、cv2.fillPoly()、cv2.bitwise_and()、cv2.circle()、cv2.HoughLinesP()、cv2.line() 该项目共分为三个py文件Parking.py定义所有的功能函数、train.py训练神经网络、park_test.py开始检测停车位状态 1Parking.py #####################################################
# Parking.py
#####################################################
import matplotlib.pyplot as plt
import cv2
import os
import glob
import numpy as npclass Parking:def show_images(self, images, cmapNone):cols 2rows (len(images)1)//colsplt.figure(figsize(15, 12))for i, image in enumerate(images):plt.subplot(rows, cols, i1)cmap gray if len(image.shape) 2 else cmapplt.imshow(image, cmapcmap)plt.xticks([])plt.yticks([])plt.tight_layout(pad0, h_pad0, w_pad0)plt.show()def cv_show(self, name, img):cv2.imshow(name, img)cv2.waitKey(0)cv2.destroyAllWindows()def select_rgb_white_yellow(self, image):# 图像背景信息过滤即截取图像中指定范围的颜色lower np.uint8([120, 120, 120])upper np.uint8([255, 255, 255])# 1lower_red和高于upper_red的部分分别变成0# 2lower_redupper_red之间的值变成255white_mask cv2.inRange(image, lower, upper)self.cv_show(white_mask, white_mask)masked cv2.bitwise_and(image, image, maskwhite_mask)self.cv_show(masked, masked)return maskeddef convert_gray_scale(self, image):return cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)def detect_edges(self, image, low_threshold50, high_threshold200):return cv2.Canny(image, low_threshold, high_threshold)def filter_region(self, image, vertices):# 功能剔除掉不需要的地方提取出多边形所有车位的位置纯白显示###################################################### zeros_like(array, dtypefloat, orderC)# 作用返回一个给定形状和类型的数据填充全为0。# 输入参数 1array输入数据# 2dtype返回数组的数据类型可选参数默认float# 3orderC代表行优先F代表列优先可选参数#####################################################mask np.zeros_like(image) # 新建模板0纯黑色if len(mask.shape) 2:###################################################### 填充任意多边形cv2.fillPoly(img, ppt, Scalar);# 输入参数 1img 在该图像上绘图。# 2ppt 多边形的顶点集# 5Scarlar 填充多边形的颜色(255, 255, 255)即RGB的值为白色#####################################################cv2.fillPoly(mask, vertices, 255) # 填充多边形255纯白色self.cv_show(mask, mask)###################################################### cv2.bitwise_and() # 按位与# cv2.bitwise_or() # 或# cv2.bitwise_not() # 非# cv2.bitwise_xor() # 异或#################################### dst cv2.bitwise_and(src1, src2, maskmask)# src1/src2是相同类型和大小的图像# maskmask表示要提取的区域可选参数# 111100010000#####################################################return cv2.bitwise_and(image, mask) # 按位与操作def select_region(self, image):# 功能手动选择区域 —— 在原图中筛选出所有车位的位置并框成一个多边形。# 多边形的关键点位置由自定义设置详细如下:rows, cols image.shape[:2] # 获得图像的长和宽pt_1 [cols*0.05, rows*0.90] # 位置点1pt_2 [cols*0.05, rows*0.70] # 位置点2pt_3 [cols*0.30, rows*0.55] # 位置点3pt_4 [cols*0.6, rows*0.15] # 位置点4pt_5 [cols*0.90, rows*0.15] # 位置点5pt_6 [cols*0.90, rows*0.90] # 位置点6vertices np.array([[pt_1, pt_2, pt_3, pt_4, pt_5, pt_6]], dtypenp.int32) # 将数据转换为numpy数组point_img image.copy() point_img cv2.cvtColor(point_img, cv2.COLOR_GRAY2RGB) # 转换为灰度图for point in vertices[0]: # 遍历所有的位置点###################################################### 绘制圆型cv2.circle(图像, 圆心, 半径, 颜色, 厚度)# 输入参数 1图像在该图像上绘图。# 2圆心圆的中心坐标。坐标表示为两个值的元组, 即(X坐标值, Y坐标值)。# 3半径圆的半径。# 4颜色圆的边界线颜色。对于BGR, 我们传递一个元组。例如(255, 0, 0)为蓝色。# 5厚度正数表示线的粗细。其中-1表示实心圆。#####################################################cv2.circle(point_img, (point[0], point[1]), 10, (0, 0, 255), 4) # 在每一个位置点绘制一个空心圆self.cv_show(point_img, point_img)return self.filter_region(image, vertices)def hough_lines(self, image):###################################################### 检测图像中所有的线cv2.HoughLinesP(image, rho0.1, thetanp.pi / 10, threshold15, minLineLength9, maxLineGap4)# image 输入的图像需要是边缘检测后的结果# minLineLengh (线的最短长度比这个短的都被忽略)# MaxLineCap 两条直线之间的最大间隔小于此值认为是一条直线# rho 距离精度# theta 角度精度# threshod 超过设定阈值才被检测出线段#####################################################return cv2.HoughLinesP(image, rho0.1, thetanp.pi/10, threshold15, minLineLength9, maxLineGap4)def draw_lines(self, image, lines, color[255, 0, 0], thickness2, make_copyTrue):# 功能在原图上画出满足条件的所有线if make_copy:image np.copy(image) cleaned []for line in lines:for x1, y1, x2, y2 in line: # 一条线由两个点组成每个点的坐标为(x, y)# abs(y2-y1) 1 ———— 图像中都是直线斜率趋近于0# abs(x2-x1) 25 and abs(x2-x1) 55 ———— 线段自定义筛选依据实际情况设置if abs(y2-y1) 1 and abs(x2-x1) 25 and abs(x2-x1) 55:cleaned.append((x1, y1, x2, y2)) # 保存满足条件的所有线cv2.line(image, (x1, y1), (x2, y2), color, thickness) # 在原图上画出满足条件的所有线print( No lines detected: , len(cleaned))return imagedef identify_blocks(self, image, lines, make_copyTrue):###################################################### 功能识别出所有的车位# Step 1: 过滤部分直线提取有效的线即对应于车位的线# Step 2: 对直线进行排序# Step 3: 找到多个列每一列对应一排车# Step 4: 得到每一列矩形的坐标# Step 5: 把列矩形画出来#####################################################if make_copy:new_image np.copy(image)# Step 1: 过滤部分直线提取有效的线即对应于车位的线cleaned []for line in lines:for x1, y1, x2, y2 in line:if abs(y2-y1) 1 and abs(x2-x1) 25 and abs(x2-x1) 55:cleaned.append((x1, y1, x2, y2)) # 保存满足条件的所有线# Step 2: 对直线进行排序import operatorlist1 sorted(cleaned, keyoperator.itemgetter(0, 1)) # 给所有的线标记顺序排序从上到下从左到右# Step 3: 找到多个列每一列对应一排车clusters {} # 找到同一列的所有线dIndex 0clus_dist 10 # 列与最近一列的距离依据实际情况设置for i in range(len(list1) - 1):distance abs(list1[i1][0] - list1[i][0])if distance clus_dist:if not dIndex in clusters.keys(): clusters[dIndex] []clusters[dIndex].append(list1[i])clusters[dIndex].append(list1[i 1]) else:dIndex 1 # 同一列的线就汇总否则跳过# Step 4: 得到每一列矩形的坐标rects {}i 0for key in clusters: # 12列all_list clusters[key]cleaned list(set(all_list))if len(cleaned) 5: # 如果个数大于5则定义为一列cleaned sorted(cleaned, keylambda tup: tup[1])avg_y1 cleaned[0][1] # 提取每一列第一条线。 [0]表示第一条线avg_y2 cleaned[-1][1] # 提取每一列最后一条线 [-1]表示最后一条线avg_x1 0 # 由于不同线的 x 层次不齐故取均值avg_x2 0for tup in cleaned:avg_x1 tup[0]avg_x2 tup[2]avg_x1 avg_x1/len(cleaned) # x1是矩形的起始点avg_x2 avg_x2/len(cleaned) # x2是矩形的终止点rects[i] (avg_x1, avg_y1, avg_x2, avg_y2) # 得到每一列矩形的四点坐标i 1print(Num Parking Lanes: , len(rects)) # 共有12个矩形# Step 5: 把列矩形画出来buff 7for key in rects: # key表示第几列tup_topLeft (int(rects[key][0] - buff), int(rects[key][1]))tup_botRight (int(rects[key][2] buff), int(rects[key][3]))cv2.rectangle(new_image, tup_topLeft, tup_botRight, (0, 255, 0), 3)return new_image, rectsdef draw_parking(self, image, rects, make_copyTrue, color[255, 0, 0], thickness2, saveTrue):if make_copy:new_image np.copy(image)gap 15.5 # 固定每两个停车位之间的距离间隔y轴spot_dict {} # 字典一个车位对应一个位置tot_spots 0# 微调 ——— 由于检测得到的矩形具有一定的误差所以进行人为操作达到精度化adj_y1 {0: 20, 1: -10, 2: 0, 3: -11, 4: 28, 5: 5, 6: -15, 7: -15, 8: -10, 9: -30, 10: 9, 11: -32}adj_y2 {0: 30, 1: 50, 2: 15, 3: 10, 4: -15, 5: 15, 6: 15, 7: -20, 8: 15, 9: 15, 10: 0, 11: 30}adj_x1 {0: -8, 1: -15, 2: -15, 3: -15, 4: -15, 5: -15, 6: -15, 7: -15, 8: -10, 9: -10, 10: -10, 11: 0}adj_x2 {0: 0, 1: 15, 2: 15, 3: 15, 4: 15, 5: 15, 6: 15, 7: 15, 8: 10, 9: 10, 10: 10, 11: 0}for key in rects: # key表示第几列tup rects[key]x1 int(tup[0] adj_x1[key])x2 int(tup[2] adj_x2[key])y1 int(tup[1] adj_y1[key])y2 int(tup[3] adj_y2[key])cv2.rectangle(new_image, (x1, y1), (x2, y2), (0, 255, 0), 2) # 在图像上画出微调后的矩形num_splits int(abs(y2-y1)//gap) # 计算每一列可以平均停放多少辆车由于误差不能识别出精确的停车位故进行平均计算估计for i in range(0, num_splits1): # 切六刀则有七个停车位y int(y1 i*gap)###################################################### 画直线段cv2.line(img, pt1, pt2, color, thickness)# 输入参数 img 要划的线所在的图像;# pt1 直线起点# pt2 直线终点# color 直线的颜色# thickness1 线条粗细###################################################### 画出所有停车位的横线cv2.line(new_image, (x1, y), (x2, y), color, thickness)if 0 key len(rects) - 1: # 第一列与最后一列都是单排停车位其余都是双排停车位依据实际情况设置# 画出双排停车位之间的竖直线x int((x1 x2)/2) # 两个位置点的中点就是对应的竖直线坐标cv2.line(new_image, (x, y1), (x, y2), color, thickness)# 计算数量if key 0 or key (len(rects) - 1): # 如果是单排停车位直接1tot_spots num_splits 1else: # 如果是双排停车位就要1再乘以2tot_spots 2*(num_splits 1)# 用字典将每个停车位进行键值对一一对应if key 0 or key (len(rects) - 1): # 第一列或最后一列单排停车位for i in range(0, num_splits1):cur_len len(spot_dict)y int(y1 i*gap)spot_dict[(x1, y, x2, ygap)] cur_len 1 # 第一列和最后一列停车位的坐标else: # 双排停车位for i in range(0, num_splits1):cur_len len(spot_dict)y int(y1 i*gap)x int((x1 x2)/2) # 双排停车位对应的中点位置spot_dict[(x1, y, x, ygap)] cur_len 1 # 双排停车位的左边一排坐标spot_dict[(x, y, x2, ygap)] cur_len 2 # 双排停车位的右边一排坐标print(total parking spaces: , tot_spots, cur_len)if save:filename with_parking.jpgcv2.imwrite(filename, new_image)return new_image, spot_dictdef assign_spots_map(self, image, spot_dict, make_copyTrue, color[255, 0, 0], thickness2):if make_copy:new_image np.copy(image)for spot in spot_dict.keys():(x1, y1, x2, y2) spotcv2.rectangle(new_image, (int(x1), int(y1)), (int(x2), int(y2)), color, thickness)return new_imagedef save_images_for_cnn(self, image, spot_dict, folder_namecnn_data):# 功能裁剪停车位得到所有停车位对应的图像并保存到指定的文件夹路径下。提供数据给CNN训练。训练前需人工筛选图像分为两类车位是否被占用。for spot in spot_dict.keys(): # 遍历所有停车位 —— 字典的键进行索引(x1, y1, x2, y2) spot(x1, y1, x2, y2) (int(x1), int(y1), int(x2), int(y2)) # 坐标值取整spot_img image[y1:y2, x1:x2] # 裁剪停车位spot_img cv2.resize(spot_img, (0, 0), fx2.0, fy2.0) # 图像裁剪原图像是在太minispot_id spot_dict[spot] # 停车位坐标 —— 键对应的值filename spot str(spot_id) .jpg # 每个停车位用键来命名以此可以后续索引需求print(spot_img.shape, filename, (x1, x2, y1, y2))cv2.imwrite(os.path.join(folder_name, filename), spot_img) # 保存停车位图像到指定的文件夹cnn_data路径下def make_prediction(self, image, model, class_dictionary):# 预处理img image/255.# 转换成4D tensorimage np.expand_dims(img, axis0)# 用训练好的模型进行训练class_predicted model.predict(image)inID np.argmax(class_predicted[0])label class_dictionary[inID]return labeldef predict_on_image(self,image, spot_dict , model,class_dictionary,make_copyTrue, color[0, 255, 0], alpha0.5):if make_copy:new_image np.copy(image)overlay np.copy(image)self.cv_show(new_image, new_image)cnt_empty 0all_spots 0for spot in spot_dict.keys():all_spots 1(x1, y1, x2, y2) spot(x1, y1, x2, y2) (int(x1), int(y1), int(x2), int(y2))spot_img image[y1:y2, x1:x2]spot_img cv2.resize(spot_img, (48, 48)) label self.make_prediction(spot_img,model,class_dictionary) # 预测图像停车位是否被占用if label empty:cv2.rectangle(overlay, (int(x1), int(y1)), (int(x2), int(y2)), color, -1)cnt_empty 1cv2.addWeighted(overlay, alpha, new_image, 1 - alpha, 0, new_image) # 图像融合cv2.putText(new_image, Available: %d spots % cnt_empty, (30, 95), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2)cv2.putText(new_image, Total: %d spots % all_spots, (30, 125), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2)save Falseif save:filename with_marking.jpgcv2.imwrite(filename, new_image)self.cv_show(new_image, new_image)return new_imagedef predict_on_video(self, video_name, final_spot_dict, model, class_dictionary, retTrue):cap cv2.VideoCapture(video_name)count 0while ret:ret, image cap.read()count 1if count 5: # 每四帧图像判断一次count 0new_image np.copy(image)overlay np.copy(image)cnt_empty 0all_spots 0color [0, 255, 0] alpha 0.5for spot in final_spot_dict.keys():all_spots 1(x1, y1, x2, y2) spot(x1, y1, x2, y2) (int(x1), int(y1), int(x2), int(y2))spot_img image[y1:y2, x1:x2]spot_img cv2.resize(spot_img, (48,48)) label self.make_prediction(spot_img, model, class_dictionary) # 预测帧图像停车位是否被占用if label empty:cv2.rectangle(overlay, (int(x1), int(y1)), (int(x2), int(y2)), color, -1)cnt_empty 1cv2.addWeighted(overlay, alpha, new_image, 1 - alpha, 0, new_image)cv2.putText(new_image, Available: %d spots % cnt_empty, (30, 95), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2)cv2.putText(new_image, Total: %d spots % all_spots, (30, 125), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2)cv2.imshow(frame, new_image)if cv2.waitKey(10) 0xFF ord(q):breakcv2.destroyAllWindows()cap.release() 2train.py #####################################################
# train.py
#####################################################
import numpy
import os
from keras import applications
from keras.preprocessing.image import ImageDataGenerator
from keras import optimizers
from keras.models import Sequential, Model
from keras.layers import Dropout, Flatten, Dense, GlobalAveragePooling2D
from keras import backend as k
from keras.callbacks import ModelCheckpoint, LearningRateScheduler, TensorBoard, EarlyStopping
from keras.models import Sequential
from keras.layers.normalization import BatchNormalization
from keras.layers.convolutional import Conv2D
from keras.layers.convolutional import MaxPooling2D
from keras.initializers import TruncatedNormal
from keras.layers.core import Activation
from keras.layers.core import Flatten
from keras.layers.core import Dropout
from keras.layers.core import Densefiles_train 0
files_validation 0
########################################
cwd os.getcwd() # 获取当前工作路径
folder train_data/train # 训练数据
for sub_folder in os.listdir(folder):path, dirs, files next(os.walk(os.path.join(folder, sub_folder))) # 读取数据files_train len(files)
########################################
folder train_data/test # 测试数据
for sub_folder in os.listdir(folder):path, dirs, files next(os.walk(os.path.join(folder, sub_folder))) # 读取数据files_validation len(files)
########################################
print(files_train, files_validation)
########################################
# CNN训练参数指定
img_width, img_height 48, 48
train_data_dir train_data/train
validation_data_dir train_data/test
nb_train_samples files_train
nb_validation_samples files_validation
batch_size 32
epochs 15
num_classes 2
# 调用kera框架中的applications中的VGG16网络。里面封装了好几个网络模型VGG16、VGG19、Resnet50、MobileNet等等
# weightsimagenet 表示直接调用imagenet训练好的权重当前数据太少
model applications.VGG16(weightsimagenet, include_topFalse, input_shape(img_width, img_height, 3))
########################################
# 将前10层网络 冻起来
for layer in model.layers[:10]:layer.trainable False
x model.output
x Flatten()(x)predictions Dense(num_classes, activationsoftmax)(x)
model_final Model(inputmodel.input, outputpredictions)
model_final.compile(losscategorical_crossentropy, optimizer optimizers.SGD(lr0.0001, momentum0.9), metrics[accuracy])
########################################
# 数据增强
train_datagen ImageDataGenerator(rescale1./255, horizontal_flipTrue, fill_modenearest,zoom_range0.1, width_shift_range0.1, height_shift_range0.1, rotation_range5)
test_datagen ImageDataGenerator(rescale1./255, horizontal_flipTrue, fill_modenearest,zoom_range0.1, width_shift_range0.1, height_shift_range0.1, rotation_range5)
train_generator train_datagen.flow_from_directory(train_data_dir, target_size(img_height, img_width), batch_sizebatch_size, class_modecategorical)
validation_generator test_datagen.flow_from_directory(validation_data_dir, target_size(img_height, img_width), class_modecategorical)
########################################
checkpoint ModelCheckpoint(car1.h5, monitorval_acc, verbose1, save_best_onlyTrue, save_weights_onlyFalse, modeauto, period1)
early EarlyStopping(monitorval_acc, min_delta0, patience10, verbose1, modeauto)
history_object model_final.fit_generator(train_generator, samples_per_epochnb_train_samples, epochsepochs,validation_datavalidation_generator, nb_val_samplesnb_validation_samples, callbacks[checkpoint, early])
# 训练完之后会自动生成文件car1.h5
# 备注最终的训练结果只有百分之九十。1数据预处理还有进步空间2神经网络模型可优化 3park_test.py #####################################################
# park_test.py
#####################################################
from __future__ import division
import matplotlib.pyplot as plt
import cv2
import os
import glob
import numpy as npfrom keras.applications.imagenet_utils import preprocess_input
from keras.models import load_model
from keras.preprocessing import image
from PIL import Image
# PillowPIL是Python中较为基础的图像处理库主要用于图像的基本处理比如裁剪图像、调整图像大小和图像颜色处理等。
# 与Pillow相比OpenCV和Scikit-image的功能更为丰富所以使用起来也更为复杂主要应用于机器视觉、图像分析等领域比如众所周知的“人脸识别”应用 。
import picklefrom Parking import Parking # 导入自定义库
cwd os.getcwd()def img_process(test_images, park): # park实例化的类white_yellow_images list(map(park.select_rgb_white_yellow, test_images)) # select_rgb_white_yellow():图像背景信息过滤park.show_images(white_yellow_images)########################################################################################################gray_images list(map(park.convert_gray_scale, white_yellow_images)) # convert_gray_scale():转换为灰度图park.show_images(gray_images)########################################################################################################edge_images list(map(lambda image: park.detect_edges(image), gray_images)) # detect_edges():使用cv2.Canny算法进行边缘检测park.show_images(edge_images)########################################################################################################roi_images list(map(park.select_region, edge_images)) # select_region():筛选出多边形停车场的位置去除图像中冗余的区域park.show_images(roi_images)########################################################################################################list_of_lines list(map(park.hough_lines, roi_images)) # hough_lines():检测图像中所有的线########################################################################################################line_images []for image, lines in zip(test_images, list_of_lines):line_images.append(park.draw_lines(image, lines)) # draw_lines():画出图像中所有满足条件的线即停车线park.show_images(line_images)########################################################################################################rect_images [] # new_image 绘制有所有矩形的图像rect_coords [] # rects 每个矩形对应的四点坐标for image, lines in zip(test_images, list_of_lines):new_image, rects park.identify_blocks(image, lines) # identify_blocks(): 画出每一列的矩形rect_images.append(new_image)rect_coords.append(rects)park.show_images(rect_images) # 绘制矩形图像########################################################################################################delineated [] # new_image 绘制有微调后的所有矩形、以及所有停车位的图像spot_pos [] # spot_dict 每个停车位的坐标字典 - 数据结构for image, rects in zip(test_images, rect_coords):new_image, spot_dict park.draw_parking(image, rects) # draw_parking:画出停车位delineated.append(new_image)spot_pos.append(spot_dict)park.show_images(delineated) # 绘制矩形停车位图像final_spot_dict spot_pos[1] # 取出字典键值对的所有值每个值对应一个停车位的坐标位置。[1]值print(len(final_spot_dict)) # 打印所有的停车位数########################################################################################################with open(spot_dict.pickle, wb) as handle: # 打开文件open且自动关闭with###################################################### Python中的pickle模块实现了基本的数据序列与反序列化。序列化对象可以在磁盘上保存对象并在需要的时候读取出来。任何对象都可以执行序列化操作。###################################################### 1序列化-存档pickle.dump(obj, file, protocol)# 输入参数 对象就是你要存的东西类型可以是list、string以及其他任何类型# 文件就是要将对象存储的目标文件# 使用协议有3种索引0为ASCII默认值1是旧式2进制2是新式2进制协议# fw open(pickleFileName.txt, wb)# pickle.dump(try, fw)###################################################### 2反序列化-读档pickle.load(file)# fr open(pickleFileName.txt, rb)# result pickle.load(fr)#####################################################pickle.dump(final_spot_dict, handle, protocolpickle.HIGHEST_PROTOCOL) # 将当前预处理的结果保存下来以后直接调用即可。########################################################################################################park.save_images_for_cnn(test_images[0], final_spot_dict) # save_images_for_cnn(): 调用CNN神经网络对车位是否被占用进行识别return final_spot_dict########################################################################################################def keras_model(weights_path):# from keras.models import load_modelmodel load_model(weights_path) # load_model():可实现直接读取文件: car1.h5神经网络训练后生成的模型return modeldef img_test(test_images, final_spot_dict, model, class_dictionary):for i in range(len(test_images)):predicted_images park.predict_on_image(test_images[i], final_spot_dict, model, class_dictionary)# predict_on_image():def video_test(video_name, final_spot_dict, model, class_dictionary):name video_namecap cv2.VideoCapture(name)park.predict_on_video(name, final_spot_dict, model, class_dictionary, retTrue)if __name__ __main__:# 文件夹名test_imagestest_images [plt.imread(path) for path in glob.glob(test_images/*.jpg)]weights_path car1.h5video_name parking_video.mp4# class_dictionary {0: empty, 1: occupied} # 车位占用状态class_dictionary {} # 车位占用状态class_dictionary[0] empty # 车位为空class_dictionary[1] occupied # 车位已占用park Parking() # 类的实例化park.show_images(test_images)final_spot_dict img_process(test_images, park) # 图像预处理model keras_model(weights_path) # 加载神经网络训练好的模型img_test(test_images, final_spot_dict, model, class_dictionary)video_test(video_name, final_spot_dict, model, class_dictionary)
8种主流深度学习框架介绍 Python 中的 PIL 库
五答题卡识别与判卷 —— cv2.putText()、cv2.countNonZero() import cv2 # opencv读取的格式是BGR
import numpy as np
import matplotlib.pyplot as plt # Matplotlib是RGBdef order_points(pts):# 一共4个坐标点rect np.zeros((4, 2), dtypefloat32)# 按顺序找到对应坐标0123分别是 左上右上右下左下# 计算左上右下s pts.sum(axis1)rect[0] pts[np.argmin(s)]rect[2] pts[np.argmax(s)]# 计算右上和左下diff np.diff(pts, axis1)rect[1] pts[np.argmin(diff)]rect[3] pts[np.argmax(diff)]return rectdef four_point_transform(image, pts):# 获取输入坐标点rect order_points(pts)(tl, tr, br, bl) rect# 计算输入的w和h值widthA np.sqrt(((br[0] - bl[0]) ** 2) ((br[1] - bl[1]) ** 2))widthB np.sqrt(((tr[0] - tl[0]) ** 2) ((tr[1] - tl[1]) ** 2))maxWidth max(int(widthA), int(widthB))heightA np.sqrt(((tr[0] - br[0]) ** 2) ((tr[1] - br[1]) ** 2))heightB np.sqrt(((tl[0] - bl[0]) ** 2) ((tl[1] - bl[1]) ** 2))maxHeight max(int(heightA), int(heightB))# 变换后对应坐标位置dst np.array([[0, 0], [maxWidth - 1, 0], [maxWidth - 1, maxHeight - 1], [0, maxHeight - 1]], dtypefloat32)# 计算变换矩阵M cv2.getPerspectiveTransform(rect, dst) # 计算齐次变换矩阵cv2.getPerspectiveTransform(rect, dst)warped cv2.warpPerspective(image, M, (maxWidth, maxHeight)) # 透视变换将输入矩形乘以齐次变换矩阵得到输出矩阵return warpeddef sort_contours(cnts, methodleft-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](cnts, boundingBoxes) zip(*sorted(zip(cnts, boundingBoxes), keylambda b: b[1][i], reversereverse))return cnts, boundingBoxes#############################################################
# if __name__ __main__:
# 1“__name__”是Python的内置变量用于指代当前模块。
# 2当哪个模块被直接执行时该模块“__name__”的值就是“__main__”。
# 3当被导入另一模块时“__name__”的值就是模块的真实名称。
#############################################################
# 需给定每张图像对应选项的正确答案字典键对应行值对应每行的答案
ANSWER_KEY {0: 1, 1: 4, 2: 0, 3: 3, 4: 1}# 图像预处理
image cv2.imread(rimages/test_01.png)
contours_img image.copy()
gray cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # 转换为灰度图
blurred cv2.GaussianBlur(gray, (5, 5), 0) # 高斯滤波-去除噪音
edged cv2.Canny(blurred, 75, 200) # Canny算子边缘检测
cnts, hierarchy cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 轮廓检测
cv2.drawContours(contours_img, cnts, -1, (0, 0, 255), 3) # 画出轮廓答题卡
###################################################################
# 提取答题卡并进行透视变化
docCnt None
if len(cnts) 0:cnts sorted(cnts, keycv2.contourArea, reverseTrue) # 根据轮廓大小进行排序for c in cnts: # 遍历每一个轮廓peri cv2.arcLength(c, True) # 计算轮廓的长度approx cv2.approxPolyDP(c, 0.02*peri, True) # 找出轮廓的多边形拟合曲线if len(approx) 4: # 找到的轮廓是四边形对应四个顶点docCnt approxbreakwarped four_point_transform(gray, docCnt.reshape(4, 2)) # 透视变换齐次变换矩阵
warped1 warped.copy()
thresh cv2.threshold(warped, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1] # 0表示系统自动判断THRESH_OTSU自适应阈值设置
###############################
thresh_Contours thresh.copy()
cnts, hierarchy cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 找到每一个圆圈轮廓
cv2.drawContours(thresh_Contours, cnts, -1, (0, 0, 255), 3) # 画出所有轮廓
###################################################################
# 提取答题卡中所有的有效选项圆圈
questionCnts [] # 提取每个选项的轮廓
for c in cnts:(x, y, w, h) cv2.boundingRect(c) # 获取轮廓的尺寸ar w / float(h) # 计算比例if w 20 and h 20 and 0.9 ar 1.1: # 自定义设置大小根据实际情况questionCnts.append(c)
questionCnts sort_contours(questionCnts, methodtop-to-bottom)[0] # 按照从上到下对所有的选项进行排序
###############################
correct 0
for (q, i) in enumerate(np.arange(0, len(questionCnts), 5)): # 每排有5个选项cnts sort_contours(questionCnts[i:i 5])[0] # 对每一排进行排序bubbled Nonefor (j, c) in enumerate(cnts): # 遍历每一排对应的五个结果mask np.zeros(thresh.shape, dtypeuint8) # 使用mask来判断结果全黑0表示涂写答案正确cv2.drawContours(mask, [c], -1, 255, -1) # -1表示填充# cv_show(mask, mask) # 展示每个选项mask cv2.bitwise_and(thresh, thresh, maskmask) # maskmask表示要提取的区域可选参数total cv2.countNonZero(mask) # 通过计算非零点数量来算是否选择这个答案if bubbled is None or total bubbled[0]: # 记录最大数bubbled (total, j)color (0, 0, 255) # 对比正确答案k ANSWER_KEY[q]# 判断正确if k bubbled[1]:color (0, 255, 0)correct 1cv2.drawContours(warped, [cnts[k]], -1, color, 3) # 画出轮廓
###################################################################
# 展示结果
score (correct / 5.0) * 100 # 计算总得分
print([INFO] score: {:.2f}%.format(score))
###################################################################
# 在图像上添加文本内容: cv2.putText(img, str(i), (123,456), cv2.FONT_HERSHEY_PLAIN, 2, (0,255,0), 3)
# 各参数依次是图片添加的文字左上角坐标字体类型字体大小颜色字体粗细
# 添加的字体{:.2f}%.format(score) ———— 表示添加score字符串。并且保留全部的整数位小数点位保留两位。
###################################################################
cv2.putText(warped, {:.1f}%.format(score), (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 0, 255), 2)image cv2.cvtColor(image, cv2.COLOR_BGR2RGB) # opencv读取的格式是BGRMatplotlib是RGB
contours_img cv2.cvtColor(contours_img, cv2.COLOR_BGR2RGB)
plt.subplot(241), plt.imshow(image, cmapgray), plt.axis(off), plt.title(image)
plt.subplot(242), plt.imshow(blurred, cmapgray), plt.axis(off), plt.title(cv2.GaussianBlur)
plt.subplot(243), plt.imshow(edged, cmapgray), plt.axis(off), plt.title(cv2.Canny)
plt.subplot(244), plt.imshow(contours_img, cmapgray), plt.axis(off), plt.title(cv2.findContours)
plt.subplot(245), plt.imshow(warped1, cmapgray), plt.axis(off), plt.title(cv2.warpPerspective)
plt.subplot(246), plt.imshow(thresh_Contours, cmapgray), plt.axis(off), plt.title(cv2.findContours)
plt.subplot(247), plt.imshow(warped, cmapgray), plt.axis(off), plt.title(cv2.warpPerspective)
plt.show()
六背景建模动态目标识别 —— cv2.getStructuringElement()、cv2.createBackgroundSubtractorMOG2() ########################################################
# 背景建模检测动态目标
# 方法一帧差法
# 介绍由于场景中的目标在运动目标的影像在不同图像帧中的位置不同。
# 1该类算法对时间上连续的两帧图像进行差分运算不同帧对应的像素点相减判断灰度差的绝对值。
# 2当绝对值超过一定阈值时即可判断为运动目标从而实现目标的检测功能。
# 优缺点帧差法非常简单但是会引入噪音和空洞问题
# 方法二混合高斯模型
# 介绍1背景训练对图像中每个背景采用一个【混合高斯模型】进行模拟每个背景的混合高斯的个数可以自适应。
# 2测试阶段对新来的像素进行GMM匹配如果该像素值能够匹配其中一个高斯则认为是背景否则认为是前景。
# 特点1由于整个过程GMM模型在不断更新学习中所以对动态背景有一定的鲁棒性。
# 特点2在视频中对于像素点的变化情况应当是符合高斯分布背景的实际分布应当是多个高斯分布混合在一起每个高斯模型也可以带有权重。
# 混合高斯模型学习方法
# 1.首先初始化每个高斯模型矩阵参数。
# 2.取视频中T帧图像数据用来训练高斯混合模型并将第一个像素当做第一个高斯分布。
# 3.其后的像素值与前一个高斯分布的均值进行比较如果两者差值在3倍方差以内则属于同一个高斯分布并对其进行参数更新。否则用此像素创建一个新的高斯分布。
# 混合高斯模型测试方法
# 在测试阶段对新来像素点的值与混合高斯模型中的每一个均值进行比较如果其差值在2倍的方差之间的话则认为是背景否则认为是前景动态目标。
# 将前景赋值为255背景赋值为0。这样就形成了一副前景二值图。
########################################################import cv2
cap cv2.VideoCapture(test.avi) # 捕获摄像头
########################################################
# 构造卷积核cv2.getStructuringElement(shape, ksize, anchorNone)
# 输入参数 shape:1Enumerator
# 2MORPH_RECT 矩形
# 3MORPH_CROSS 十字型
# 4MORPH_ELLIPSE 椭圆形
# ksize: 卷积核大小(元组类型) 例如(3, 4)
# anchor: 元素内的描点位置默认为 (-1, -1)表示形状中心
# 前提背景是黑色值为0物体是白色值为1
########################################################
kernel cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3)) # 形态学操作需要使用
fgbg cv2.createBackgroundSubtractorMOG2() # 创建一个混合高斯模型用于背景建模
while True:ret, frame cap.read() # 读取帧图像# 移动的物体会被标记为白色背景会被标记为黑色的fgmask fgbg.apply(frame) # 将混合高斯模型应用于所有的帧图像得到前景的掩模白色。fgmask cv2.morphologyEx(fgmask, cv2.MORPH_OPEN, kernel) # 形态学开运算去噪点contours, hierarchy cv2.findContours(fgmask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 寻找视频中的轮廓for c in contours:perimeter cv2.arcLength(c, True) # 计算轮廓的长度if perimeter 188: # 人在图像中的尺寸根据实际的检测目标设置x, y, w, h cv2.boundingRect(c) # 获取矩形框的左上角位置点以及长宽cv2.rectangle(frame, (x, y), (xw, yh), (0, 255, 0), 2) # 绘制矩形边框在当前帧图像cv2.imshow(frame, frame) # 当前帧图像cv2.imshow(fgmask, fgmask) # 当前运动目标的轮廓k cv2.waitKey(10) 0xffif k 27: # 退出键break
cap.release()
cv2.destroyAllWindows()
mog2算法 opencv 8 --背景减除 – BackgroundSubtractorMOG2 OpenCV 中 getStructuringElement() 与 morphologyEx() 函数用法
七光流估计轨迹点跟踪—— cv2.goodFeaturesToTrack()、cv2.calcOpticalFlowPyrLK() ##########################################################################
# 光流是空间运动物体在观测成像平面上的像素运动的“瞬时速度”是利用图像序列中像素在时间域上的变化以及相邻帧之间的相关性来找到上一帧跟当前帧之间存在的相应关系从而实现目标跟踪。
# 三要素必要条件 1亮度恒定同一点随着时间的变化在连续帧之间其亮度像素强度不会发生改变。
# 2小运动相邻像素具有相似的运动。
# 因为只有小运动情况下才能用前后帧之间单位位置变化引起的灰度变化去近似灰度对位置的偏导数。
# 3空间一致一个场景上邻近的点投影到图像上也是邻近点且邻近点速度一致。
# 因为光流法基本方程约束只有一个而要求xy方向的速度有两个未知变量。所以需要连立n多个方程求解。
# - cv2.goodFeaturesToTrack() 确定要追踪的特征点
# - cv2.calcOpticalFlowPyrLK() 追踪视频中的特征点
##########################################################################
# 如果跟踪图像中的目标丢失或被遮掩则后续图像将始终不再现实轨迹角点待优化。
import numpy as np
import cv2
cap cv2.VideoCapture(test.avi)
feature_params dict(maxCorners150, qualityLevel0.3, minDistance12) # ShiTomasi角点检测的参数
lk_params dict(winSize(15, 15), maxLevel2) # Lucas Kanada光流检测的参数
color np.random.randint(0, 255, (100, 3)) # 构建随机颜色
#################################
count 0
while True:ret, old_frame cap.read() # 获取帧图像count count 1if count 235: # 挑选视频中指定的第N帧为第一帧图像break
old_gray cv2.cvtColor(old_frame, cv2.COLOR_BGR2GRAY) # 转化为灰度图
#################################################################
# 确定要追踪的特征点cv2.goodFeaturesToTrack( image, maxCorners, qualityLevel, minDistance, masknoArray(),
# blockSize3, bool useHarrisDetectorfalse, double k0.04 );
# 输入参数 image: 输入图像是八位的或者32位浮点型单通道图像所以有时候用灰度图
# maxCorners: 返回最大的角点数是最有可能的角点数如果这个参数不大于0那么表示没有角点数的限制。
# qualityLevel: 图像角点的最小可接受参数质量测量值乘以这个参数就是最小特征值小于这个数的会被抛弃。
# minDistance: 返回的角点之间最小的欧式距离。
# mask: 检测区域。如果图像不是空的(它需要具有CV_8UC1类型和与图像相同的大小)它指定检测角的区域。
# blockSize: 用于计算每个像素邻域上的导数协变矩阵的平均块的大小。
# useHarrisDetector 选择是否采用Harris角点检测默认是false.
# k: Harris检测的自由参数。
# 输出参数 corners: 输出为角点。
# 备注角点最大数量数量越多效率慢品质因子品质因子越大角点越少但越大越好、角点距离在角点距离范围内,取N个角点中最好的一个角点
#################################################################
p0 cv2.goodFeaturesToTrack(old_gray, maskNone, **feature_params) # 传入字典类型时需要两个**
mask np.zeros_like(old_frame) # 为绘制光流追踪图构建一个Mask
while True:ret, frame cap.read() # 循环获取帧图像if not ret:breakframe_gray cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)################################################################## 追踪视频中的特征点p1, status, err cv2.calcOpticalFlowPyrLK(old_gray, frame_gray, p0, None, winSize(15, 15), maxLevel2)# 输入参数 old_gray 前一帧图像# frame_gray 当前帧图像# p0 待跟踪的特征点向量# nextPts None# winSize 搜索窗口的大小# maxLevel 最大的金字塔层数# 输出参数 p1 跟踪特征点向量# status 特征点是否找到找到的状态为1未找到的状态为0#################################################################p1, st, err cv2.calcOpticalFlowPyrLK(old_gray, frame_gray, p0, None, **lk_params)# 选择轨迹点good_new p1[st 1] # st 1表示目标锁定如果目标丢失则后续都将不再找到目标。因为后续帧图像是依据第一帧图像识别检测的good_old p0[st 1]# 绘制轨迹for i, (new, old) in enumerate(zip(good_new, good_old)):a, b new.ravel()c, d old.ravel()a int(a); b int(b); c int(c); d int(d)mask cv2.line(mask, (a, b), (c, d), color[i].tolist(), 2)###################################################### 画直线段cv2.line(img, pt1, pt2, color, thickness)# 输入参数 img 要划的线所在的图像;# pt1 直线起点# pt2 直线终点# color 直线的颜色# thickness1 线条粗细#####################################################frame cv2.circle(frame, (a, b), 5, color[i].tolist(), -1)###################################################### 绘制圆型cv2.circle(图像, 圆心, 半径, 颜色, 厚度)# 输入参数 1图像在该图像上绘图。# 2圆心圆的中心坐标。坐标表示为两个值的元组, 即(X坐标值, Y坐标值)。# 3半径圆的半径。# 4颜色圆的边界线颜色。对于BGR, 我们传递一个元组。例如(255, 0, 0)为蓝色。# 5厚度正数表示线的粗细。其中-1表示实心圆。#####################################################img cv2.add(frame, mask) # 将轨迹线与帧图像叠加cv2.imshow(frame, img)k cv2.waitKey(50) 0xffif k 27: # 退出键breakold_gray frame_gray.copy() # 实时更新前一帧p0 good_new.reshape(-1, 1, 2)cv2.destroyAllWindows()
cap.release()
图文详解 OpenCV中光流以及视频特征点追踪稀疏光流追踪 优化版稀疏光流追踪密集光流追踪
八DNN模块的分类 —— cv2.dnn.blobFromImage() import utils_paths
import numpy as np
import cv2
##################################################################
# 提取标签文件中每一行的内容
# 1训练模型标签文件synset_words.txt
# 2使用open().read() 打开并读取txt文件中所有的字符串
# 3strip() 删除字符串两端的空格
# 4split(\n) 提取每一行的内容
rows open(synset_words.txt).read().strip().split(\n)
##################################################################
# 提取出每行第一个空格后的字符串
# 1对每一行的内容进行遍历遍历之后找每一行的空格(r.find( ))。
# 2找到位置后让位置1然后r提取到1的位置一直到最后
# 3以所有逗号为分隔符然后删除他们取分割的第一个值
classes [r[r.find( ) 1:].split(,)[0] for r in rows]
##################################################################
# 加载Caffe所需文件
# 1配置文件bvlc_googlenet.prototxt
# 2训练好的权重参数bvlc_googlenet.caffemodel
net cv2.dnn.readNetFromCaffe(bvlc_googlenet.prototxt, bvlc_googlenet.caffemodel)
##################################################################
# 读取图像路径
# 1utils_paths.py中的list_images()是提取images文件夹中所有图片的绝对路径
# 2将所有绝对路径作为元素组成迭代器
# 3使用sorted()进行排序。 这个是字符串之间的排序先比首字母再比第二个字母都相同时比长度。
imagePaths sorted(list(utils_paths.list_images(images/)))
##################################################################
# 单个图像预测
image cv2.imread(imagePaths[0]) # 先读取第0张图片
resized cv2.resize(image, (224, 224)) # 保持训练模型与测试模型数据大小相同
blob cv2.dnn.blobFromImage(resized, 1, (224, 224), (104, 117, 123))
print(First Blob: {}.format(blob.shape))net.setInput(blob) # 输入数据
preds net.forward() # 前向传播得到结果向量形式# 排序取分类可能性最大的 ———— 该Imagenet是一个千分类模型它会有1000个值对应1000个分类的概率
# np.argsort()是从小到大排序故逆序[::-1]然后取第一个值(最大值的索引)
idx np.argsort(preds[0])[::-1][0]
# 获取要写的内容1该索引对应的标签值2pred[0]的值乘以100然后保留其两位小数最后在后面加个百分号
text Label: {}, {:.2f}%.format(classes[idx], preds[0][idx] * 100)
# 将要写的内容写在未经处理的图片上
cv2.putText(image, text, (5, 25), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
# 显示预测结果
cv2.imshow(Image, image)
cv2.waitKey(0)
##################################################################
##################################################################
# 预测其余的所有图 ———— 方法与上述一样但数据是一个batch。
images [] # 定义一个空列表存图
# 处理除第0张外的所有图片
for p in imagePaths[1:]:image cv2.imread(p)image cv2.resize(image, (224, 224))images.append(image)
blob cv2.dnn.blobFromImages(images, 1, (224, 224), (104, 117, 123))
print(Second Blob: {}.format(blob.shape))net.setInput(blob) # 输入数据
preds net.forward() # 前向传播得到结果向量形式# 首先读进来图之后找到对应预测结果中最大的然后写上标签与概率
for (i, p) in enumerate(imagePaths[1:]): # i是序号p是图片路径image cv2.imread(p)idx np.argsort(preds[i])[::-1][0]text Label: {}, {:.2f}%.format(classes[idx], preds[i][idx] * 100)cv2.putText(image, text, (5, 25), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)cv2.imshow(Image, image)cv2.waitKey(0)
##################################################################
# blob cv2.dnn.blobFromImage() ———— 改变图像的大小然后令R,G,B三个通道分别减去均值去除光照影响。
# 输出参数 Blob 例如(1,3,224,224) 分别表示图片数量、图片通道数、图像的宽、图像的高
# 输入参数 resized 要改变的图像
# 缩放系数 我们当前用的时1所以不变
# (224,224) 图像大小
# (104,117,123) 图像三通道均值。这三个均值是Imagenet提供的。
# 预测一个结果cv2.dnn.blobFromImage() 处理单张图像
# 预测多个结果cv2.dnn.blobFromImages() 处理多张图像
##################################################################
opencv的DNN模块详细过程 DNN常用模块简介
九矩形涂鸦画板 —— cv.namedWindow()、cv.setMouseCallback() #########################################################################
# 编写一个矩形涂鸦画板
# 功能鼠标左键按下拖动绘制矩形鼠标左键弹起时完成绘制
# 1按 c 键清空画板
# 2按 ESC 键退出
#########################################################################
import numpy as np
import cv2
from random import randintclass Painter:def __init__(self) - None:self.mouse_is_pressed Falseself.last_pos (-1, -1)self.width 300self.height 512self.img np.zeros((self.width, self.height, 3), np.uint8)self.window_name painterself.color Nonedef run(self):print(画板拖动鼠标绘制矩形框按ESC退出按c键清空画板)cv2.namedWindow(self.window_name)cv2.setMouseCallback(self.window_name, lambda event, x, y, flags, param: self.on_draw(event, x, y, flags, param))while True:cv2.imshow(self.window_name, self.img)k cv2.waitKey(1) 0xFFif k ord(c): # 按 c 键清空画板self.clean() # 调用自定义函数清除画板elif k 27: # 按 ESC 键退出breakcv2.destroyAllWindows()def on_draw(self, event, x, y, flags, param):# TODO(You): 请正确实现画板事件响应完成功能# 触发左键按下 - 触发鼠标移动 - 开始画矩形 - 触发左键抬起 - 终止画矩形pos (x, y) # 鼠标按下的位置坐标if event cv2.EVENT_LBUTTONDOWN: # 触发左键按下self.mouse_is_pressed Trueself.last_pos poselif event cv2.EVENT_MOUSEMOVE: # 触发鼠标移动if self.mouse_is_pressed True: # 判断鼠标是否按下self.begin_draw_rectangle(self.last_pos, pos) # 调用自定义函数开始画矩形elif event cv2.EVENT_LBUTTONUP: # 触发左键抬起self.end_draw_rectangle(self.last_pos, pos) # 调用自定义函数终止画矩形self.mouse_is_pressed Falsedef clean(self):cv2.rectangle(self.img, (0, 0), (self.height, self.width), (0, 0, 0), -1)def begin_draw_rectangle(self, pos1, pos2):if self.color is None: # 设置颜色每个矩形的颜色都随机self.color (randint(0, 256), randint(0, 256), randint(0, 256)) # 随机生成三通道颜色cv2.rectangle(self.img, pos1, pos2, self.color, -1)def end_draw_rectangle(self, pos1, pos2):self.color Noneif __name__ __main__:p Painter() # 类的实例化p.run() # 调用类函数#########################################################################
# 11、创建鼠标回调函数cv2.setMouseCallback(windowName, MouseCallback, paramNone)
# 输入参数 windowName 窗口名称
# MouseCallback 鼠标响应回调函数
# param 响应函数传递的的参数
#########################################################################
# 22、MouseCallback(int event, int x, int y, int flags, * userdata)
# 输入参数 x 鼠标的x坐标
# y 鼠标的y坐标
# userdata 可选参数
# event 一个MouseEventTypes常量
# 1cv.EVENT_FLAG_LBUTTON 1, 左键拖拽
# 2cv.EVENT_FLAG_RBUTTON 2, 右键拖拽
# 3cv.EVENT_FLAG_MBUTTON 4, 中键不放
# 4cv.EVENT_FLAG_CTRLKEY 8, 按住ctrl不放
# 5cv.EVENT_FLAG_SHIFTKEY 16, 按住shift不放
# 6cv.EVENT_FLAG_ALTKEY 32, 按住alt不放
# flags 一个MouseEventFlags常量
# 1cv.EVENT_MOUSEMOVE 0, 鼠标移动
# 2cv.EVENT_LBUTTONDOWN 1, 左键按下
# 3cv.EVENT_RBUTTONDOWN 2, 右键按下
# 4cv.EVENT_MBUTTONDOWN 3, 中键按下
# 5cv.EVENT_LBUTTONUP 4, 左键释放
# 6cv.EVENT_RBUTTONUP 5, 右键释放
# 7cv.EVENT_MBUTTONUP 6, 中键释放
# 8cv.EVENT_LBUTTONDBLCLK 7, 左键双击
# 9cv.EVENT_RBUTTONDBLCLK 8, 右键双击
# 10cv.EVENT_MBUTTONDBLCLK 9, 中健双击
# 11cv.EVENT_MOUSEWHEEL 10, 滚轮滑动
# 12cv.EVENT_MOUSEHWHEEL 11 横向滚轮滑动
#########################################################################十创建轨迹条 —— createTrackbar()、cv2.getTrackbarPos()
10.1、创建一个轨迹条用于阈值化图像 import cv2img cv2.imread(1.png) # 加载图像
cv2.imshow(Image, img) # 显示图像
cv2.createTrackbar(Threshold, Image, 0, 255, lambda x: None) # 创建阈值滑动条
while True:threshold_value cv2.getTrackbarPos(Threshold, Image) # 获取滑动条的阈值threshold_img cv2.threshold(img, threshold_value, 255, cv2.THRESH_BINARY)[1] # 阈值化图像cv2.imshow(Threshold Image, threshold_img) # 显示图像if cv2.waitKey(1) 27: # Esc退出break
cv2.destroyAllWindows() # 关闭所有窗口
10.2、创建一个轨迹条用于画板调色
Python OpenCV 使用滑动条调色 python -opencv 使用滑动条调色画板 OpenCV学习——实现滑动条式调色板 python -opencv 使用滑动条图像膨胀 共有三个功能1创建轨迹条2打开控制开关根据RGB设置背景色3打开控制开关根据RGB设置画笔颜色在画板上画画。 #########################################################################
# 1滑动条控制R、G、B的值
# 2开关按钮switch用于确认是否使用自定义RGB改变原图。
# 0不改变原图 1调色 2:调色画板
#########################################################################
import cv2
import numpy as np# 定义回调函数此程序无需回调所以Pass即可
def nothing(x):passdef Mouseback(event, x, y, flags, param):if flags cv2.EVENT_FLAG_LBUTTON and event cv2.EVENT_MOUSEMOVE:cv2.circle(img, (x, y), 1, [b, g, r], 1)img np.zeros((300, 512, 3), np.uint8)
cv2.namedWindow(image, cv2.WINDOW_NORMAL)
cv2.createTrackbar(R, image, 0, 255, nothing)
cv2.createTrackbar(G, image, 0, 255, nothing)
cv2.createTrackbar(B, image, 0, 255, nothing)
switch OFF ON
cv2.createTrackbar(switch, image, 0, 2, nothing)
while (1):cv2.imshow(image, img)k cv2.waitKey(1)if k ord(q):breakr cv2.getTrackbarPos(R, image)g cv2.getTrackbarPos(G, image)b cv2.getTrackbarPos(B, image)s cv2.getTrackbarPos(switch, image)if s 0: # 不改变原图img[:] 0 elif s 1: # 调色img[:] [b, g, r]elif s 2: # 调色画板cv2.setMouseCallback(image, Mouseback)
cv2.destroyAllWindows()#########################################################################
# 11、创建一个滑动条: cv2.createTrackbar(Track_name, img, min, max, TrackbarCallback)
# 输入参数
# Track_name 滑动条的名字。
# img 滑动条所在画布。
# min 滑动条的最小值。
# max 滑动条的最大值。
# TrackbarCallback 滑动条的回调函数。# 22、获取滑动条的值: value cv2.getTrackbarPos(Track_name, img)
# 输入参数
# Track_name 滑动条的名字。
# img 滑动条所在画布。
# 输出参数 滑动条当前所在的位置值。
#########################################################################十一基于二值化实现人像抠图与背景替换 —— np.where()、np.uint8()
图像处理实战–Opencv实现人像迁移 # 检测原理
# 1将前景图像通过二值化进行抠图去除白色背景得到人像位置。
# 2将人像在背景图像中的位置置为0。
# 3将两张图像进行像素值累加。# 只适用于前景图像的物体背景为白色的图像背景图像随意。
# 因此采用二值化抠图故只能指定唯一像素而白色背景为常用背景。
import cv2
import numpy as np
import matplotlib.pyplot as pltq_img cv2.imread(black.png) # 1前景图像
b_img cv2.imread(starry_night.jpg) # 2背景图像
# 将风景图片尺寸调整为与人像图片一致, 需要进行图像像素累加计算。
q_img cv2.resize(q_img, (b_img.shape[1], b_img.shape[0]))
print(q_img.shape)
print(b_img.shape)# 3二值化抠图
img q_img.copy()
for i in range(img.shape[0]): # 高for j in range(img.shape[1]): # 宽# 颜色接近背景颜色的像素点置为1其余部分置为0if 255 img[i][j][0] and 255 img[i][j][1] and 255 img[i][j][2]: img[i][j] 255else:img[i][j] 0# 4人像迁移
# 黑白反转前景图像人像位置置为1其余位置置为0
img_t np.where(img 0, 1, 0)
img3 np.uint8(q_img * img_t)# 白黑反转背景图像人像位置置为0其余位置置为1
img_t np.where(img_t 1, 2, img_t)
img_t np.where(img_t 0, 1, img_t)
img_t np.where(img_t 2, 0, img_t)
img4 np.uint8(b_img * img_t) # 图像像素值累加尺寸必须相同
img5 img4 img3# 5绘图
titles [q_img, b_img, img, img3, img4, img5]
images [q_img, b_img, img, img3, img4, img5]
for ii in range(6):images[ii] cv2.cvtColor(images[ii], cv2.COLOR_BGR2RGB)plt.subplot(2, 3, ii1)plt.imshow(images[ii], gray)plt.axis(off)plt.xticks([]), plt.yticks([])
plt.show()22、图像基本操作 一图像的读取、保存和显示 —— cv2.imread()cv2.imwrite()cv2.imshow() 1多张图在同一个窗口同时显示 plt.subplot() 2cv2.imshow()和plt.imshow()的区别 #####################################################################
# cv2是opencv在python中的缩写;
# Matplotlib 是一个 Python 库可以通过 python 脚本创建二维图形和图表。
# Matplotlib 中的 pyplot 模块可以控制线条样式字体属性格式化轴等功能。且支持各种各样的图形绘制如直方图条形图功率谱误差图等。
#####################################################################
import cv2 # opencv读取图像的格式BGR图像的格式RGB
import matplotlib.pyplot as plt # plt默认RGB通道#####################################################################
# 11、读取图像cv2.imread(img_path, flag)
# 输入参数
# img_path: 图像的路径若路径错误则返回None。但不会报错
# flag cv2.IMREAD_COLOR也可以传入1 默认加载彩色图像RGB
# cv2.IMREAD_GRAYSCALE也可以传入0 将图像转换为灰度图
# cv2.IMREAD_UNCHANGED也可以传入-1 加载原图# 备注1OpenCV 支持JPG、PNG、TIFF等常见格式图像文件加载默认读取的格式是BGR图像的格式是RGB
# 备注2转义字符\可以转义很多字符比如\n表示换行\t表示制表符\\表示\。当然如果不需要转义可以使用(rcat.hpg);###################################
# 路径说明路径中不能出现中文否则系统异常提示。cat_path rC:\Users\my\Desktop\py_test\cat.jpg # 绝对路径cat_path rcat.jpg # 相对路径即当前同级目录不指定路径则默认当前.py文件的路径下。cat_path r./cat.jpg # 相对路径即当前同级目录与上同效。cat_path r../py_test/cat.jpg # 相对路径上级目录py_test表示存放当前.py文件的文件夹
#####################################################################
cat_path rC:\Users\my\Desktop\py_test\cat.jpg
img0 cv2.imread(cat_path)
img1 cv2.imread(cat_path, cv2.IMREAD_COLOR)
img2 cv2.imread(cat_path, cv2.IMREAD_GRAYSCALE)
img3 cv2.imread(cat_path, cv2.IMREAD_UNCHANGED)#####################################################################
# 22、保存图像cv2.imwrite(img_path_name, img)
# 输入参数 img_path_name: 自定义待保存图像的路径名字
# img: 待保存图像
#####################################################################
cv2.imwrite(gray_cat.png, img2)#####################################################################
# 33、显示图像cv2.imshow(window_title, img)
# 输入参数 window_title 自定义窗口的名字
# img 待显示图像
# 备注1窗口会自适应图像大小
# 备注2指定多个窗口名称可以显示多幅图像
# 备注3显示多幅图像的时候若cv2.imshow()指定相同的窗口名这样后面显示的图像会覆盖前面的图像从而只产生一个连续窗口。如视频
#####################################################################
cv2.imshow(raw_img, img0)
cv2.imshow(cv2.IMREAD_COLOR, img1)
cv2.imshow(cv2.IMREAD_GRAYSCALE, img2)
cv2.imshow(cv2.IMREAD_UNCHANGED, img3)
cv2.waitKey(1000) # 延迟一秒后自动关闭图像
cv2.destroyAllWindows() # 同时关闭所有图窗
#####################################################################
# 键盘绑定函数cv2.waitKey()
# 1cv2.waitKey(0) 表示无限期的等待键盘输入按任意键继续。如:空格键
# 2cv2.waitKey(delay) 当 delay0 (单位:ms)时使用表示等待一定时间。1秒(s) 1000毫秒
##########################################################################################################################################
# 44、在同一个窗口同时显示多张图
# plt.subplot(231)或者plt.subplot(2,3,1) # 该图指定了(row)2*3(col)的子图区域并且同一个坐标轴1,2,3,4,5,6内分别画图。
# plt.plot() # 直接在一张大的画布中画图相当于获取当前活跃的axes然后在上面作图。
# 备注1在jupyter notebook上单是plt.imshow()就可显示图片同时也显示其格式。
# 备注2在pycharm上单是plt.imshow()不显示图像需搭配plt.show()。而加上plt.show()后结果仅显示图片不显示格式。
##################################
plt.subplot(141), plt.imshow(img0, gray), plt.title(raw_img)
plt.subplot(142), plt.imshow(img1, gray), plt.title(cv2.IMREAD_COLOR)
plt.subplot(143), plt.imshow(img2, gray), plt.title(cv2.IMREAD_GRAYSCALE)
plt.subplot(144), plt.imshow(img3, gray), plt.title(cv2.IMREAD_UNCHANGED)
plt.show()#####################################################################
# 55、cv2.imshow()和plt.imshow()的区别
# cv2.imshow()常用于对读入图像进行一系列图像处理后的绘图;
# plt.imshow()常用语绘制热图; 热图即通过色差、亮度来展示数据的差异。
# 备注两者都可以但要注意图片的格式是RGB格式而opencv是BGR格式plt是RGB格式;
##################################
plt.imshow(img0)
plt.colorbar()
plt.show() 1.1图窗设置cv2.namedWindow()、cv2.resizeWindow()、cv2.moveWindow()、cv2.setWindowProperty()。 import cv2
window_name projector # 图窗标题
cv2.namedWindow(window_name, cv2.WINDOW_KEEPRATIO) # 创建命名窗口
cv2.resizeWindow(window_name, 10, 20) # 自定义窗口大小
cv2.moveWindow(window_name, 100, 200) # 设置窗口的位置
cv2.setWindowProperty(window_name, cv2.WND_PROP_TOPMOST, 1) # 设置窗口显示在最前面im cv2.imread(test01.png) # 读取图像
cv2.imshow(window_name, im) # 显示图像
cv2.waitKey(0) # 等待输入任意键
cv2.destroyAllWindows() # 摧毁所有图窗参数cv2.namedWindow(winname, flags)创建命名窗口1winname窗口名称用作窗口的标识符。2flags窗口属性设置标志。flagscv2.WINDOW_NORMAL用户可以手动改变窗口大小flagscv2.WINDOW_AUTOSIZE窗口大小自动适应图片大小并且不可手动更改。flagscv2.WINDOW_FREERATIO自适应比例flagscv2.WINDOW_KEEPRATIO保持比例flagscv2.WINDOW_OPENGL窗口创建的时候会支持OpenGLflagscv2.WINDOW_GUI_EXPANEDE创建的窗口允许添加工具栏和状态栏。flagscv2.WINDOW_GUI_NORMAL创建没有状态栏和工具栏窗口。flagscv2.WINDOW_AUTOSIZE窗口大小自动适应图片大小并且不可手动更改。
参数cv2.resizeWindow(winname, width, height)改变窗口大小1winname窗口名2width窗口宽度3height窗口高度
参数cv2.moveWindow(winname, x, y)设置窗口位置1winname窗口名2x窗口x轴位置3y窗口y轴位置
参数cv2.setWindowProperty(winname, prop_id, prop_value)设置窗口属性1winname窗口名2prop_id要编辑的窗口属性。如cv2.WINDOW_NORMAL、cv2.WINDOW_KEEPRATIO、cv2.WINDOW_FULLSCREEN等。3prop_value窗口属性的新值。如cv2.WND_PROP_FULLSCREEN, cv2.WND_PROP_AUTOSIZE, cv2.WND_PROP_ASPECT_RATIO等。 1.2图窗关闭cv2.waitKey()、cv2.destroyAllWindows() 参数cv2.waitKey()键盘绑定函数1cv2.waitKey(0)表示无限期的等待键盘输入按任意键继续。如:空格键2cv2.waitKey(delay)当 delay0 (单位:ms)时使用表示等待一定时间。1秒(s) 1000毫秒
参数cv2.destroyAllwindows()销毁窗口1cv2.destroyAllwindows()摧毁所有窗口2cv2.destroyWindow(winname)摧毁指定的窗口 二视频读取与处理 —— cv2.VideoCapture() OpenCV 保存视频 读取视频 检查视频是否可以打开 循环读取视频的每一帧图像并显示 import cv2 # cv2是opencv在python中的缩写; opencv读取图像的格式BGR图像的格式RGB# 1视频读取与处理 —— 读取视频
vc cv2.VideoCapture(rpicture\test.mp4)
# 2视频读取与处理 —— 检查视频是否可以打开
if vc.isOpened():open, frame vc.read()
else:open False
# 3视频读取与处理 —— 循环读取视频的每一帧图像
while open:ret, frame vc.read()# 如果读到的帧数不为空那么就继续读取如果为空就退出if frame is None:breakif ret True:gray cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # 将读取到视频的每一帧图像转换成灰度图cv2.imshow(result, gray)# 使用 waitKey 可以控制视频的播放速度数值越小播放速度越快if cv2.waitKey(10) 0xFF 27: # 27 表示退出键Escbreak
vc.release()
cv2.destroyAllWindows()###################################################################
# 11、cv2.VideoCapture可以捕获摄像头用数字来控制不同的设备。
# 0表示调用电脑自带摄像头。
# 1表示调用外接USB摄像头。# 22、vc.isOpened() 检查视频是否可以打开返回值True/False# 33、vc.read() 读取视频的每一帧图像返回值True/False图像彩色图# 44、cv2.imshow(frame,frame)将每一帧图像显示在一个叫frame的窗口上。
# 为什么会产生视频的效果通过while循环将图像固定显示在frame图窗上每一帧会覆盖上一帧就产生了视频的效果。
###################################################################三图像的三色图 —— cv2.split() cv.merge() 1图像分割得到三色图BGR 2将分割的三色图还原为彩色图 3保留R通道 保留G通道 保留B通道 import cv2 # cv2是opencv在python中的缩写; opencv读取图像的格式BGR图像的格式RGB
import matplotlib.pyplot as plt # 绘图展示# 截取部分图像
cat_address rC:\Users\my\Desktop\pythonProject\picture\cat.jpg
img cv2.imread(cat_address)
cat img[0:50, 0:200]#############################################
# 图像分割得到三色图: b, g, r cv2.split(img)
# 功能将多通道的图像分离成若干个单通道的图像分割后的单通道图像尺寸大小相同。
# 注意分割后任意单通道都属于灰度图而不是对应的颜色通道图
#############################################
b, g, r cv2.split(img)#############################################
# 将分割的三色图还原为彩色图: img cv2.merge((b, g, r))
# 功能将多幅图像合并成一幅多通道图像合并后的通道数是所有输入图像通道数的总和。
# 注意所有输入图像的通道数可以不相同但是所有图像需要具有相同的尺寸和数据类型
#############################################
img cv2.merge((b, g, r))# img.copy()复制原图进行图像处理可以避免改变原图
# 只保留红色R单通道G and B通道全部置0即可
cur_img_R img.copy()
cur_img_R[:, :, 0] 0
cur_img_R[:, :, 1] 0
# 只保留绿色G单通道R and B通道全部置0即可
cur_img_G img.copy()
cur_img_G[:, :, 0] 0
cur_img_G[:, :, 2] 0
# 只保留蓝色B单通道R and G通道全部置0即可
cur_img_B img.copy()
cur_img_B[:, :, 1] 0
cur_img_B[:, :, 2] 0plt.subplot(131), plt.imshow(cur_img_B), plt.title(Red)
plt.subplot(132), plt.imshow(cur_img_G), plt.title(Green)
plt.subplot(133), plt.imshow(cur_img_R), plt.title(Blue)
plt.show() 四图像的边缘填充 —— cv2.copyMakeBorder() import cv2 # cv2是opencv在python中的缩写opencv读取图像的格式是BGR图像的格式RGB
import matplotlib.pyplot as plt # 绘图展示########################################################
# cv2.copyMakeBorder()用于在像相框一样的图像周围创建边框。
# cv2.copyMakeBorder(src, top, bottom, left, right, borderType, value)
# 输入参数 src 原图像。
# top 顶部方向的边框宽度, 以像素数为单位。
# bottom 底部方向的边框宽度(以像素数为单位)。
# left 沿左方向的像素数量的边框宽度。
# right 沿右方向的像素数的边框宽度。
# borderType 描述要添加哪种边框。
# (1)BORDER_REPLICATE 复制法即用复制最边缘像素。
# (2)BORDER_REFLECT 反射法对感兴趣的图像中的像素在两边进行复制。例如fedcba | abcdefgh | hgfedcb
# (3)BORDER_REFLECT_101 反射法即用以最边缘像素为轴对称。gfedcb | abcdefgh | gfedcba
# (4)BORDER_WRAP 外包装法。abcdefgh | abcdefgh | abcdefgh
# (5)BORDER_CONSTANT 常量法即用常数值填充。
# value 可选参数, 如果边界类型为cv2.BORDER_CONSTANT, 则描述边界的颜色。
########################################################
cat_address rC:\Users\my\Desktop\pythonProject\picture\cat.jpg
img cv2.imread(cat_address)top_size, bottom_size, left_size, right_size (50, 50, 50, 50) # 指定边缘上下左右需要填充的宽度
replicate cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size, borderTypecv2.BORDER_REPLICATE)
reflect cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size, cv2.BORDER_REFLECT)
reflect101 cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size, cv2.BORDER_REFLECT_101)
wrap cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size, cv2.BORDER_WRAP)
constant cv2.copyMakeBorder(img, top_size, bottom_size, left_size, right_size, cv2.BORDER_CONSTANT, value0)plt.subplot(231), plt.imshow(img, gray), plt.title(ORIGINAL)
plt.subplot(232), plt.imshow(replicate, gray), plt.title(BORDER_REPLICATE)
plt.subplot(233), plt.imshow(reflect, gray), plt.title(BORDER_REFLECT)
plt.subplot(234), plt.imshow(reflect101, gray), plt.title(BORDER_REFLECT_101)
plt.subplot(235), plt.imshow(wrap, gray), plt.title(BORDER_WRAP)
plt.subplot(236), plt.imshow(constant, gray), plt.title(BORDER_CONSTANT)
plt.show() 五图像融合 —— cv2.addWeighted() 1图像截取 2图像加/减常数 3图像加/减另一个图像 4图像相加 cv2.add() import cv2 # cv2是opencv在python中的缩写opencv读取图像的格式是BGR图像的格式RGB
import matplotlib.pyplot as plt # 绘图展示img_cat cv2.imread(rpicture\cat.jpg)
img_dog cv2.imread(rpicture\dog.jpg)
print(img_cat.shape)
print(img_dog.shape)
########################################
# 图像截取
cat_piece img_cat[100:300, 0:200]
########################################
# 图像加/减一个常数 ———— 即图像的每个像素都加常数值
img_plus img_cat - 50
########################################
# 图像相加/相减 ———— 两个图像的尺寸要一样。
# 方式1在numpy中如果两个图像相加超过255将自动减去255然后得到剩下的值。相当于取余【% 256】
# 方式2cv2.add():如果两个图像相加超过255则等于255否则当前值保留不变
img_cat cv2.resize(img_cat, (400, 480))
img_dog cv2.resize(img_dog, (400, 480))
print(img_cat.shape)
print(img_dog.shape)res_add1 img_cat img_dog
res_add2 cv2.add(img_cat, img_dog)
########################################
plt.subplot(231), plt.imshow(img_cat, gray), plt.title(img_cat_resize)
plt.subplot(232), plt.imshow(img_dog, gray), plt.title(img_dog_resize)
plt.subplot(233), plt.imshow(cat_piece, gray), plt.title(cat_piece)
plt.subplot(234), plt.imshow(img_plus, gray), plt.title(fig1 - 50)
plt.subplot(235), plt.imshow(res_add1, gray), plt.title(fig1 fig2)
plt.subplot(236), plt.imshow(res_add2, gray), plt.title(cv2.add)
plt.show()#####################################################################
# 图像融合cv2.addWeighted(src1, alpha, src2, beta, gamma)
# 功能将两张相同shape的图像按权重进行融合
# 输入参数 src1/src2 图像1与图像2
# alpha/beta 图像1与图像2对应的权重融合后的图像偏向于权重高的一边
# gamma 相当于ya*xb中的截距。用于调节亮度
# 权重融合公式dst src1 * alpha src2 * beta gamma
#####################################################################
img_cat cv2.resize(img_cat, (500, 414)) # 将图像裁剪到指定尺寸
img_dog cv2.resize(img_dog, (500, 414)) # 将图像裁剪到指定尺寸
res cv2.addWeighted(img_cat, 0.35, img_dog, 0.65, 2)
plt.imshow(res)
plt.show() 六颜色空间转换 —— cv2.cvtColor() import cv2 # opencv读取的格式是BGR
import matplotlib.pyplot as plt # Matplotlib是RGB#####################################################################
# opencv中颜色空间转换函数cv2.cvtColor()
# opencv中有多种色彩空间包括 RGB、HSI、HSL、HSV、HSB、YCrCb、CIE XYZ、CIE Lab8种。
# 在opencv中默认的颜色空间是BGR。
#####################################################################
img_BGR cv2.imread(rpicture/cat.jpg) # BGR
plt.subplot(3, 3, 1), plt.imshow(img_BGR), plt.axis(off), plt.title(BGR)img_RGB cv2.cvtColor(img_BGR, cv2.COLOR_BGR2RGB)
plt.subplot(3, 3, 2), plt.imshow(img_RGB), plt.axis(off), plt.title(RGB)img_GRAY cv2.cvtColor(img_BGR, cv2.COLOR_BGR2GRAY)
plt.subplot(3, 3, 3), plt.imshow(img_GRAY), plt.axis(off), plt.title(GRAY)img_HSV cv2.cvtColor(img_BGR, cv2.COLOR_BGR2HSV)
plt.subplot(3, 3, 4), plt.imshow(img_HSV), plt.axis(off), plt.title(HSV)img_YcrCb cv2.cvtColor(img_BGR, cv2.COLOR_BGR2YCrCb)
plt.subplot(3, 3, 5), plt.imshow(img_YcrCb), plt.axis(off), plt.title(YcrCb)img_HLS cv2.cvtColor(img_BGR, cv2.COLOR_BGR2HLS)
plt.subplot(3, 3, 6), plt.imshow(img_HLS), plt.axis(off), plt.title(HLS)img_XYZ cv2.cvtColor(img_BGR, cv2.COLOR_BGR2XYZ)
plt.subplot(3, 3, 7), plt.imshow(img_XYZ), plt.axis(off), plt.title(XYZ)img_LAB cv2.cvtColor(img_BGR, cv2.COLOR_BGR2LAB)
plt.subplot(3, 3, 8), plt.imshow(img_LAB), plt.axis(off), plt.title(LAB)img_YUV cv2.cvtColor(img_BGR, cv2.COLOR_BGR2YUV)
plt.subplot(3, 3, 9), plt.imshow(img_YUV), plt.axis(off), plt.title(YUV)
plt.show() 七阈值处理 —— cv2.threshold() cv2.adaptiveThreshold() 1全局阈值分割cv2.threshold() 2自适应阈值分割cv2.adaptiveThreshold() import cv2 # opencv读取的格式是BGR
import matplotlib.pyplot as plt # Matplotlib是RGBimg_BGR cv2.imread(image.jpg, cv2.IMREAD_GRAYSCALE)
_, thresh1 cv2.threshold(img_BGR, 127, 255, cv2.THRESH_BINARY)
_, thresh2 cv2.threshold(img_BGR, 127, 255, cv2.THRESH_BINARY_INV)
_, thresh3 cv2.threshold(img_BGR, 127, 255, cv2.THRESH_TRUNC)
_, thresh4 cv2.threshold(img_BGR, 127, 255, cv2.THRESH_TOZERO)
_, thresh5 cv2.threshold(img_BGR, 127, 255, cv2.THRESH_TOZERO_INV)titles [Original Image, BINARY, BINARY_INV, TRUNC, TOZERO, TOZERO_INV]
images [img_BGR, thresh1, thresh2, thresh3, thresh4, thresh5]for ii in range(6):plt.subplot(2, 3, ii 1), plt.imshow(images[ii], gray)plt.title(titles[ii])plt.xticks([]), plt.yticks([])
plt.show()
#############################################################
# 函数介绍全局阈值分割 ———— 根据阈值将图像的像素分为两个类别高于阈值的像素和低于阈值的像素。
# 函数说明ret, dst cv2.threshold(src, thresh, max_val, type)
# 输入参数
# src: 输入灰度图像
# thresh: 阈值
# max_val: 阈值上限。通常为2558-bit。
# type: 二值化操作的类型包含以下5种类型
# (1) cv2.THRESH_BINARY 超过阈值部分取max_val最大值否则取0
# (2) cv2.THRESH_BINARY_INV THRESH_BINARY的反转
# (3) cv2.THRESH_TRUNC 大于阈值部分设为阈值否则不变
# (4) cv2.THRESH_TOZERO 大于阈值部分不改变否则设为0
# (5) cv2.THRESH_TOZERO_INV THRESH_TOZERO的反转
# 输出参数
# ret 浮点数表示最终使用的阈值。
# dst 经过阈值分割操作后的二值图像
#############################################################image cv2.imread(image.jpg, cv2.IMREAD_GRAYSCALE)
thresh1 cv2.adaptiveThreshold(image, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 2)
thresh2 cv2.adaptiveThreshold(image, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY_INV, 11, 2)
thresh3 cv2.adaptiveThreshold(image, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2)
thresh4 cv2.adaptiveThreshold(image, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 2)titles [gray Image, mean binary, mean binary_inv, gray Image, gaussian binary, gaussian binary_inv]
images [image, thresh1, thresh2, image, thresh3, thresh4]
for ii in range(6):plt.subplot(2, 3, ii 1), plt.imshow(images[ii], gray)plt.title(titles[ii])plt.xticks([]), plt.yticks([])
plt.show()##########################################################################
# 函数介绍自适应阈值分割 ———— 根据图像不同区域的像素值来自动确定阈值从而实现更好的图像分割效果。
# 函数说明adaptive_threshold cv2.adaptiveThreshold(src, maxValue, adaptiveMethod, thresholdType, blockSize, C)
# 输入参数
# src: 输入灰度图像。
# maxValue: 阈值上限。通常为2558-bit。
# adaptiveMethod: 自适应方法包含以下2种
# 1cv2.ADAPTIVE_THRESH_MEAN_C局部均值
# 2cv2.ADAPTIVE_THRESH_GAUSSIAN_C局部高斯加权均值
# thresholdType: 阈值类型。
# 1cv2.THRESH_BINARY 超过阈值部分取max_val最大值否则取0
# 2cv2.THRESH_BINARY_INV THRESH_BINARY的反转
# blockSize: 区域大小用于计算局部阈值。通常是一个奇数例如 3、5、7 等。
# C: 从均值中减去的常数用于调整阈值的灵敏度。
# 输出参数
# adaptive_threshold 自适应阈值
########################################################################## 八均值/高斯/方框/中值滤波 —— cv2.blur() cv2.boxFilter() cv2.GaussianBlur() cv2.medianBlur() import cv2 # opencv读取的格式是BGR
import matplotlib.pyplot as plt # Matplotlib是RGB
import numpy as npimg cv2.imread(rpicture/cat.jpg)
######################################
# 均值滤波cv2.blur(img, ksize) ———— 取卷积核所有元素的均值
# 输入参数 ksize 表示卷积核大小。 例如(3, 3)
# 作用对于椒盐噪声的滤除效果比较好。
######################################
blur cv2.blur(img, (3, 3))######################################
# 方框滤波cv2.boxFilter(img, -1, (3, 3), normalizeTrue)
# 输入参数 normalizeTrue 选择归一化 即取所有元素之和除以卷积核大小与均值滤波等同
# normalizeFalse 不选择归一化 【容易越界】且当“元素之和255”则等于255
######################################
box_T cv2.boxFilter(img, -1, (3, 3), normalizeTrue)
box_F cv2.boxFilter(img, -1, (3, 3), normalizeFalse)######################################
# 高斯滤波cv2.GaussianBlur()
# 特点高斯模糊的卷积核里的数值是满足高斯分布相当于更重视中间的
######################################
aussian cv2.GaussianBlur(img, (5, 5), 1)######################################
# 中值滤波cv2.medianBlur() ———— 取卷积核所有元素(从小到大排序)的中间值
# 作用中值滤波对消除椒盐噪声非常有效能够克服线性滤波器带来的图像细节模糊等弊端能够有效保护图像边缘信息;
######################################
median cv2.medianBlur(img, 5)plt.subplot(2, 3, 1), plt.imshow(img), plt.title(raw)
plt.subplot(2, 3, 2), plt.imshow(blur), plt.title(blur)
plt.subplot(2, 3, 3), plt.imshow(box_T), plt.title(box_T)
plt.subplot(2, 3, 4), plt.imshow(box_F), plt.title(box_F)
plt.subplot(2, 3, 5), plt.imshow(aussian), plt.title(aussian)
plt.subplot(2, 3, 6), plt.imshow(median), plt.title(median)
plt.show()
######################################
# np.hstack(img1, img2, img3) 在水平方向上平铺
# np.vstack(img1, img2, img3) 在竖直方向上堆叠
######################################
res np.hstack((blur, aussian, median))
cv2.imshow(median - Gaussian - average, res)
cv2.waitKey(0)
cv2.destroyAllWindows()res np.vstack((blur, aussian, median))
cv2.imshow(median - Gaussian - average, res)
cv2.waitKey(0)
cv2.destroyAllWindows() 九腐蚀与膨胀 —— cv2.erode() 与 cv2.dilate() np.zeros() 与 np.ones() import cv2 # opencv读取的格式是BGR
import numpy as np
import matplotlib.pyplot as plt # Matplotlib是RGB
###########################################################
# 腐蚀操作cv2.erode(src, kernel, iteration)
# 膨胀操作cv2.dilate(src, kernel, iteration)
# 两者参数说明相同: src表示输入的图片 kernel表示方框的大小 iteration表示迭代的次数
###########################################################
img cv2.imread(rpicture/dige.png)
kernel np.ones((3, 3), np.uint8) # 初始化卷积核大小dilate_1 cv2.dilate(img, kernel, iterations1) # 膨胀(迭代次数1次)
dilate_2 cv2.dilate(img, kernel, iterations2) # 膨胀
dilate_3 cv2.dilate(img, kernel, iterations3) # 膨胀erosion_1 cv2.erode(img, kernel, iterations1) # 腐蚀(迭代次数1次)
erosion_2 cv2.erode(img, kernel, iterations2) # 腐蚀
erosion_3 cv2.erode(img, kernel, iterations3) # 腐蚀plt.subplot(2, 3, 1), plt.imshow(dilate_1), plt.title(erode-1)
plt.subplot(2, 3, 2), plt.imshow(dilate_2), plt.title(erode-2)
plt.subplot(2, 3, 3), plt.imshow(dilate_3), plt.title(erode-3)
plt.subplot(2, 3, 4), plt.imshow(erosion_1), plt.title(dilate-1)
plt.subplot(2, 3, 5), plt.imshow(erosion_2), plt.title(dilate-2)
plt.subplot(2, 3, 6), plt.imshow(erosion_3), plt.title(dilate-3)
plt.show()
###########################################################
# np.zeros()与np.ones()分别创建全0与全1的数组 —— 需导入numpy模块
# 两者输入参数相同创建数组的方式也相同。
# 下面以np.zeros()为例
# np.zeros(shape, dtypefloat, orderC)
# 输入参数 (1)shape生成numpy数组
# (2)dtype指定生成的数据类型数据类型可选参数
# (3)order表示在内存中是以行为主存储还是以列为主存储可选参数c代表行优先(默认)F代表列优先
# 创建一维数组 np.zeros(5)
# 创建多维数组 np.zeros((5,2))
# 创建int类型的数组 np.zeros((5,2),dtypeint)
# 创建x为int类型y为float类型的数组np.zeros((5,2),dtype[(x,int),(y,float)]
###########################################################
python 中的np.zeros和np.ones函数 十形态学变化 —— cv2.morphologyEx() 主要内容开运算 闭运算 梯度计算 顶帽 黑帽 import cv2 # opencv读取的格式是BGR
import numpy as np
import matplotlib.pyplot as plt # Matplotlib是RGB
#######################################
# morphology
# n. 生物形态学语言学中的词法形态学结构形态
#######################################
# morph
# n. 形素语素形态图像变换
# v. 使图像变形将图像进行合成处理改变变化变形
#######################################
# 形态学变化函数cv2.morphologyEx(src, op, kernel)
# 参数说明src传入的图片op进行变化的方式 kernel表示方框的大小
# op变化的方式有五种
# 开运算(open) cv2.MORPH_OPEN 先腐蚀再膨胀。 开运算可以用来消除小黑点。
# 闭运算(close) cv2.MORPH_CLOSE 先膨胀再腐蚀。 闭运算可以用来突出边缘特征。
# 形态学梯度(morph-grad) cv2.MORPH_GRADIENT 膨胀后图像减去腐蚀图像。 可以突出团块(blob)的边缘保留物体的边缘轮廓。
# 顶帽(top-hat) cv2.MORPH_TOPHAT 原始输入减去开运算结果。 将突出比原轮廓亮的部分。
# 黑帽(black-hat) cv2.MORPH_BLACKHAT 闭运算结果减去原始输入 将突出比原轮廓暗的部分。
#######################################
img cv2.imread(rpicture/dige.png)
kernel np.ones((5, 5), np.uint8) # 卷积核初始化img_open cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel) # 开运算
img_close cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel) # 闭运算
img_grad cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel) # 梯度计算
img_top cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel) # 顶帽
img_black cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, kernel) # 黑帽plt.subplot(2, 3, 1), plt.imshow(img), plt.title(RAW)
plt.subplot(2, 3, 2), plt.imshow(img_open), plt.title(MORPH_OPEN)
plt.subplot(2, 3, 3), plt.imshow(img_close), plt.title(MORPH_CLOSE)
plt.subplot(2, 3, 4), plt.imshow(img_grad), plt.title(MORPH_GRADIENT)
plt.subplot(2, 3, 5), plt.imshow(img_top), plt.title(MORPH_TOPHAT)
plt.subplot(2, 3, 6), plt.imshow(img_black), plt.title(MORPH_BLACKHAT)
plt.show() 十一边缘检测算子 —— cv2.sobel()、cv2.Scharr()、cv2.Laplacian()、cv2.Canny() (1) 不同算子的差异Sobel算子、Scharr算子、Laplacian算子 (2) Canny 不同阈值的区别 import cv2
import matplotlib.pyplot as plt
import numpy as npimg cv2.imread(rpicture\lena.jpg)
############################################################################################
# 1左边减右边2白到黑是正数黑到白就是负数且所有的负数会被截断成0所以要取绝对值。
sobel_Gx cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize3)
sobel_Gx_Abs cv2.convertScaleAbs(sobel_Gx)
########################################
sobel_Gy cv2.Sobel(img, cv2.CV_64F, 0, 1, ksize3)
sobel_Gy_Abs cv2.convertScaleAbs(sobel_Gy)
# 分别计算x和y再求和
sobel_Gx_Gy_Abs cv2.addWeighted(sobel_Gx_Abs, 0.5, sobel_Gy_Abs, 0.5, 0) # 权重值x 权重值y 偏置b# 同时对x和y进行求导会导致部分信息丢失。不建议
# sobel_Gx cv2.Sobel(img, cv2.CV_64F, 1, 1, ksize3)
########################################
plt.subplot(2, 3, 1), plt.imshow(img), plt.title(RAW)
plt.subplot(2, 3, 2), plt.imshow(sobel_Gx), plt.title(sobel_Gx)
plt.subplot(2, 3, 3), plt.imshow(sobel_Gx_Abs), plt.title(sobel_Gx_Abs)
plt.subplot(2, 3, 4), plt.imshow(sobel_Gy), plt.title(sobel_Gy)
plt.subplot(2, 3, 5), plt.imshow(sobel_Gy_Abs), plt.title(sobel_Gy_Abs)
plt.subplot(2, 3, 6), plt.imshow(sobel_Gx_Gy_Abs), plt.title(sobel_Gx_Gy_Abs)
plt.show()########################################
# Sobel算子: 是一种常用的边缘检测算子。对噪声具有平滑作用提供较为精确的边缘方向信息但是边缘定位精度不够高。
# Sobel算子: 是离散微分算子discrete differentiation operator它结合了高斯平滑和微分求导用来计算图像灰度的近似梯度梯度越大越有可能是边缘。
# 边缘就是像素对应的灰度值快速变化的地方。如黑到白的边界
# 图像是二维的。Sobel算子在x,y两个方向求导故有不同的两个卷积核Gx, Gy且Gx的转置等于Gy。分别反映了每一点像素在水平方向和在垂直方向上的亮度变换情况.
########################################
# dst cv2.Sobel(src, ddepth, dx, dy, ksize)
# 输入参数 src 输入图像
# ddepth 图像的深度-1表示采用的是与原图像相同的深度。目标图像的深度必须大于等于原图像的深度
# dx和dy 表示的是求导的阶数0表示这个方向上没有求导一般为0、1、2。
# ksize 卷积核大小一般为3、5。
# 同时对x和y进行求导会导致部分信息丢失。不建议- 分别计算x和y再求和效果好
########################################
# (1)cv2.CV_16S的说明
# 1Sobel函数求完导数后会有负值还有会大于255的值。
# 2而原图像是uint8即8位无符号数。所以Sobel建立图像的位数不够会有截断。
# 3因此要使用16位有符号的数据类型即cv2.CV_16S。
# (2)cv2.convertScaleAbs(): 给图像的所有像素加一个绝对值
# 通过该函数将其转回原来的uint8形式。否则将无法显示图像而只是一副灰色的窗口。
############################################################################################
# 不同算子的差异Sobel算子、Scharr算子、laplacian算子
img cv2.imread(rpicture\lena.jpg, cv2.IMREAD_GRAYSCALE)
sobelx cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize3)
sobely cv2.Sobel(img, cv2.CV_64F, 0, 1, ksize3)
sobelx cv2.convertScaleAbs(sobelx)
sobely cv2.convertScaleAbs(sobely)
sobelxy cv2.addWeighted(sobelx,0.5,sobely,0.5,0)scharrx cv2.Scharr(img, cv2.CV_64F, 1, 0)
scharry cv2.Scharr(img, cv2.CV_64F, 0, 1)
scharrx cv2.convertScaleAbs(scharrx)
scharry cv2.convertScaleAbs(scharry)
scharrxy cv2.addWeighted(scharrx, 0.5, scharry, 0.5, 0)laplacian cv2.Laplacian(img, cv2.CV_64F)
laplacian cv2.convertScaleAbs(laplacian)res np.hstack((sobelxy, scharrxy, laplacian))
cv2.imshow(Sobel, Scharr, Laplacian, res)
cv2.waitKey(0)
cv2.destroyAllWindows()############################################################################################
# 边缘检测Canny算子
# (1)使用高斯滤波器以平滑图像滤除噪声。
# (2)计算图像中每个像素点的梯度强度和方向。
# (3)应用非极大值Non-Maximum Suppression抑制以消除边缘检测带来的杂散响应。保留大值去除小值。
# (4)应用双阈值Double-Threshold检测来确定真实的和潜在的边缘。
# (5)通过抑制孤立的弱边缘最终完成边缘检测。
############################################################################################
img cv2.imread(rpicture\lena.jpg, cv2.IMREAD_GRAYSCALE)
v1 cv2.Canny(img, 80, 150) # minVal越小检测出来的特征越多可能是假边界值maxVal越大检测出来的特征越少
v2 cv2.Canny(img, 50, 100)res np.hstack((v1, v2))
cv2.imshow(Canny, res)
cv2.waitKey(0)
cv2.destroyAllWindows()
opencv边缘检测sobel算子 opencv边缘检测Canny 十二图像金字塔 —— cv2.pyrUp()、cv2.pyrDown() import cv2
import matplotlib.pyplot as pltimg cv2.imread(rpicture\AM.png)
img_up cv2.pyrUp(img) # 高斯金字塔图像上采样放大一倍
img_up2 cv2.pyrUp(img_up) # 高斯金字塔二次图像上采样放大两倍
############################
img_down cv2.pyrDown(img) # 高斯金字塔图像下采样缩小一倍
img_down2 cv2.pyrDown(img_down) # 高斯金字塔二次图像下采样缩小两倍
############################
img_up_down cv2.pyrDown(img_up) # 高斯金字塔先上采样然后下采样
img_down_up cv2.pyrUp(img_down) # 高斯金字塔先下采样然后上采样
############################
img_laplacian img - img_down_up # 拉普拉斯金字塔(1)源图像先缩小后再放大(2)源图像减去(1)操作后的图像。
plt.subplot(2, 4, 1), plt.imshow(img), plt.title(RAW)
plt.subplot(2, 4, 2), plt.imshow(img_up), plt.title(img_up)
plt.subplot(2, 4, 3), plt.imshow(img_up2), plt.title(img_up2)
plt.subplot(2, 4, 4), plt.imshow(img_down), plt.title(img_down)
plt.subplot(2, 4, 5), plt.imshow(img_down2), plt.title(img_down2)
plt.subplot(2, 4, 6), plt.imshow(img_up_down), plt.title(img_up_down)
plt.subplot(2, 4, 7), plt.imshow(img_down_up), plt.title(img_down_up)
plt.subplot(2, 4, 8), plt.imshow(img_laplacian), plt.title(img_laplacian)
plt.show()############################################################################################
# 高斯金字塔: cv2.pyrUp 与 cv2.pyrDown
# cv2.pyrDown: 向下采样缩小一倍。 1对图像进行高斯内核卷积2将所有偶数行和列去除
# cv2.pyrUp: 向上采样放大一倍分辨率降低。1将图像每隔“一行与一列”全部填充02使用先前同样的高斯内核(乘以4)与放大后的图像卷积获得近似值
# 形成过程大致 1对原图像进行低通滤波和降采样得到一个粗尺度的近似图像即分解得到的低通近似图像
# 2对近似图像经过插值即上采样和低通滤波
# 3计算它和原图像的差值得到分解的带通分量。
# ——— 第一步源图像先缩小后再放大; 第二步源图像减去第一步操作后得到新图像。
# 图像缩放: 1图像金字塔2resize()函数; 后者效果更好不会降低分辨率。
############################################################################################
OpenCV计算机视觉学习 —— 图像金字塔高斯金字塔拉普拉斯金字塔图像缩放resize函数 十三图像轮廓检测 —— cv2.findContours()、cv2.drawContours()、cv2.arcLength()、cv2.approxPolyDP()、cv2.rectangle() (1) 轮廓的多边形拟合曲线cv2.approxPolyDP() (2) 用矩形画出轮廓的边界cv2.boundingRect()、cv2.rectangle() (3) 用外接圆画出轮廓的边界cv2.minEnclosingCircle()、cv2.circle() import cv2
import matplotlib.pyplot as plt # Matplotlib是RGB###################################
# 图像二值化 ———— 图像轮廓检测的输入图像是二值图即黑白的不是灰度图
img cv2.imread(rpicture\contours2.png)
img_gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 灰度图
ret, thresh cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY) # 二值化
###################################
# 1图像轮廓检测
draw_img1 img.copy()
contours, hierarchy cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
# 画出图像的轮廓(在图像上) —— 注意图像需要copy(), 否则原图会随之一起改变。
res1 cv2.drawContours(draw_img1, contours, -1, (0, 0, 255), 2)
###################################
# 2轮廓的多边形拟合曲线
draw_img2 img.copy()
contours1 contours[0]
epsilon 0.21*cv2.arcLength(contours1, True) # 系数k越小越接近于真实轮廓越大拟合越粗糙
approx cv2.approxPolyDP(contours1, epsilon, True)
# 画出图像的轮廓(在图像上) —— 注意图像需要copy(), 否则原图会随之一起改变。
res2 cv2.drawContours(draw_img2, [approx], -1, (0, 0, 255), 2)
###################################
# 3用矩形画出轮廓的边界
draw_img3 img.copy()
x, y, w, h cv2.boundingRect(contours1)
img_rectangle cv2.rectangle(draw_img3, (x, y), (xw, yh), (0, 255, 0), 2)
###################################
# 4用外接圆画出轮廓的边界
draw_img4 img.copy()
(x, y), radius cv2.minEnclosingCircle(contours1)
center (int(x), int(y))
radius int(radius)
img_circle cv2.circle(draw_img4, center, radius, (0, 255, 0), 2)
###################################
plt.subplot(2, 3, 1), plt.imshow(img), plt.title(RAW) # 轮廓点绘制的颜色通道是BGR; 但是Matplotlib是RGB;
plt.subplot(2, 3, 2), plt.imshow(res1), plt.title(findContours) # 故在绘图时(0, 0, 255)会由BGR转换为RGB红 - 蓝
plt.subplot(2, 3, 3), plt.imshow(res2), plt.title(approxPolyDP)
plt.subplot(2, 3, 4), plt.imshow(draw_img3), plt.title(rectangle)
plt.subplot(2, 3, 5), plt.imshow(draw_img4), plt.title(circle)
plt.show()######################################################################
# 1轮廓检测contours, hierarchy cv2.findContours(img, mode, method)
# 输入参数 mode: 轮廓检索模式
# 1RETR_EXTERNAL 只检索最外面的轮廓
# 2RETR_LIST 检索所有的轮廓但检测的轮廓不建立等级关系将其保存到一条链表当中
# 3RETR_CCOMP 检索所有的轮廓并建立两个等级的轮廓。顶层是各部分的外部边界内层是的边界信息;
# 4RETR_TREE 检索所有的轮廓并建立一个等级树结构的轮廓;最常用
# method: 轮廓逼近方法
# 1CHAIN_APPROX_NONE 存储所有的轮廓点相邻的两个点的像素位置差不超过1。 例如矩阵的四条边。最常用
# 2CHAIN_APPROX_SIMPLE: 压缩水平方向垂直方向对角线方向的元素只保留该方向的终点坐标。 例如矩形的4个轮廓点。
# 输出参数 contours所有的轮廓
# hierarchy每条轮廓对应的属性
# 备注0轮廓就是将连续的点连着边界连在一起的曲线具有相同的颜色或者灰度。轮廓在形状分析和物体的检测和识别中很有用。
# 备注1函数输入图像是二值图即黑白的不是灰度图。所以读取的图像要先转成灰度的再转成二值图。
# 备注2函数在opencv2只返回两个值contours, hierarchy。
# 备注3函数在opencv3会返回三个值img, countours, hierarchy
######################################################################
# 2绘制轮廓v2.drawContours(image, contours, contourIdx, color, thickness) ———— (在图像上)画出图像的轮廓
# 输入参数 image: 需要绘制轮廓的目标图像注意会改变原图
# contours: 轮廓点上述函数cv2.findContours()的第一个返回值
# contourIdx: 轮廓的索引表示绘制第几个轮廓。-1表示绘制所有的轮廓
# color: 绘制轮廓的颜色(RGB)
# thickness: 可选参数轮廓线的宽度-1表示填充
# 备注图像需要先复制一份copy(), 否则赋值操作的图像与原图会随之一起改变。
######################################################################
# 3计算轮廓的长度retval cv2.arcLength(curve, closed)
# 输入参数 curve 轮廓曲线。
# closed 若为true,表示轮廓是封闭的若为false则表示打开的。布尔类型
#
# 输出参数 retval 轮廓的长度周长。
######################################################################
# 4找出轮廓的多边形拟合曲线approxCurve approxPolyDP(contourMat, epsilon, closed);
# 输入参数 contourMat 轮廓点矩阵集合
# epsilon (double类型)指定的精度, 即原始曲线与近似曲线之间的最大距离。
# closed (bool类型)若为true, 则说明近似曲线是闭合的; 反之, 若为false, 则断开。
#
# 输出参数 approxCurve 轮廓点矩阵集合当前点集是能最小包容指定点集的。画出来即是一个多边形
######################################################################
# 5绘制矩形边框:cv2.rectangle(img, (x, y), (xw, yh), (0, 255, 0), 2)
# (x, y) 矩形定点
# (xw, yh) 矩形的宽高
# (0,0,225) 矩形的边框颜色
# 2 矩形边框宽度
###################################################################### 十四模板匹配 —— cv2.matchTemplate()、cv2.minMaxLoc() ############################################################################################
# 模板匹配和卷积原理很相似模板在原图像上从原点开始滑动并计算模板与图像被模板覆盖的地方的相似程度
# 【假如】原图形大小: AxB; 而模板大小: axb; 则输出结果的矩阵大小: (A-a1)x(B-b1)
############################################################################################
import cv2
import matplotlib.pyplot as plt # Matplotlib是RGBimg cv2.imread(rpicture/lena.jpg, 0) # 读取目标图片(0/1/2,表示RGB单通道)
template cv2.imread(rpicture/face.jpg, 0) # 读取模板图片
h, w template.shape[::1] # 获得模板图片的高宽尺寸
##############################
# 如果模板方法是平方差或者归一化平方差要用min_loc; 其余用max_loc
##############################
res1 cv2.matchTemplate(img, template, cv2.TM_SQDIFF) # 执行模板匹配采用的匹配方式cv2.TM_SQDIFF_NORMED
min_val1, max_val1, min_loc1, max_loc1 cv2.minMaxLoc(res1) # 寻找矩阵一维数组当做向量用Mat定义中的最大值和最小值的匹配结果及其位置
top_left1 min_loc1
bottom_right1 (top_left1[0] w, top_left1[1] h)
##############################
res2 cv2.matchTemplate(img, template, cv2.TM_CCORR)
min_val2, max_val2, min_loc2, max_loc2 cv2.minMaxLoc(res2)
top_left2 max_loc2
bottom_right2 (top_left2[0] w, top_left2[1] h)
##############################
res3 cv2.matchTemplate(img, template, cv2.TM_CCOEFF)
min_val3, max_val3, min_loc3, max_loc3 cv2.minMaxLoc(res3)
top_left3 max_loc3
bottom_right3 (top_left3[0] w, top_left3[1] h)
##############################
res4 cv2.matchTemplate(img, template, cv2.TM_SQDIFF_NORMED)
min_val4, max_val4, min_loc4, max_loc4 cv2.minMaxLoc(res4)
top_left4 min_loc4
bottom_right4 (top_left4[0] w, top_left4[1] h)
##############################
res5 cv2.matchTemplate(img, template, cv2.TM_CCORR_NORMED)
min_val5, max_val5, min_loc5, max_loc5 cv2.minMaxLoc(res5)
top_left5 max_loc5
bottom_right5 (top_left5[0] w, top_left5[1] h)
##############################
res6 cv2.matchTemplate(img, template, cv2.TM_CCOEFF_NORMED)
min_val6, max_val6, min_loc6, max_loc6 cv2.minMaxLoc(res6)
top_left6 max_loc6
bottom_right6 (top_left6[0] w, top_left6[1] h)# 画矩形
img1 img.copy(); img2 img.copy(); img3 img.copy()
img4 img.copy(); img5 img.copy(); img6 img.copy()cv2.rectangle(img1, top_left1, bottom_right1, 255, 2)
cv2.rectangle(img2, top_left2, bottom_right2, 255, 2)
cv2.rectangle(img3, top_left3, bottom_right3, 255, 2)
cv2.rectangle(img4, top_left4, bottom_right4, 255, 2)
cv2.rectangle(img5, top_left5, bottom_right5, 255, 2)
cv2.rectangle(img6, top_left6, bottom_right6, 255, 2)
##############################################
# plt.imshow(img1) 彩图显示
# plt.imshow(img1, cmapgray) 灰色图
plt.subplot(231), plt.imshow(img1, cmapgray), plt.axis(off), plt.title(cv2.TM_SQDIFF)
plt.subplot(232), plt.imshow(img2, cmapgray), plt.axis(off), plt.title(cv2.TM_CCORR)
plt.subplot(233), plt.imshow(img3, cmapgray), plt.axis(off), plt.title(cv2.TM_CCOEFF)
plt.subplot(234), plt.imshow(img4, cmapgray), plt.axis(off), plt.title(cv2.TM_SQDIFF_NORMED)
plt.subplot(235), plt.imshow(img5, cmapgray), plt.axis(off), plt.title(cv2.TM_CCORR_NORMED)
plt.subplot(236), plt.imshow(img6, cmapgray), plt.axis(off), plt.title(cv2.TM_CCOEFF_NORMED)
plt.show()
##############################################
# 模板匹配cv2.matchTemplate(image, template, method)
# 输入图像检测对象的图像
# 模板图像待检测的对象特征
# 模板匹配方法
# 1cv2.TM_SQDIFF 计算平方差。 计算出来的值越接近0越相关
# 2cv2.TM_CCORR 计算相关性。 计算出来的值越大越相关
# 3cv2.TM_CCOEFF 计算相关系数。 计算出来的值越大越相关
# 4cv2.TM_SQDIFF_NORMED 计算归一化平方差。 计算出来的值越接近0越相关
# 5cv2.TM_CCORR_NORMED 计算归一化相关性。 计算出来的值越接近1越相关
# 6cv2.TM_CCOEFF_NORMED 计算归一化相关系数。 计算出来的值越接近1越相关
# 最好选择有归一化操作效果好
##############################################
# 获取匹配结果函数min_val, max_val, min_loc, max_loc cv2.minMaxLoc(ret)
# 其中 ret是cv2.matchTemplate函数返回的矩阵
# min_val, max_val, min_loc, max_loc分别表示最小值最大值最小值与最大值在图像中的位置
# 如果模板方法是平方差或者归一化平方差要用min_loc; 其余用max_loc
##############################################
opencv 实现模板匹配、特征点匹配 十五直方图(均衡化) —— cv2.calcHist()、img.ravel()、cv2.bitwise_and()、cv2.equalizeHist()、cv2.createCLAHE() import cv2 # opencv读取的格式是BGR
import matplotlib.pyplot as plt # Matplotlib是RGB
import numpy as np
##############################################
img cv2.imread(rpicture\cat.jpg, 0) # 0表示灰度图
hist cv2.calcHist([img], [0], None, [256], [0, 256])
plt.hist(img.ravel(), 256) # img.ravel() 将图片转化成一维数组; 256 是BIN的数目
plt.show()
# hist(): 用于绘制直方图。
##############################################
# 不同颜色通道的直方图
img1 cv2.imread(rpicture\cat.jpg, 1) # 0表示灰度图
color (blue, green, red)
for i, col in enumerate(color):hist1 cv2.calcHist([img1], [i], None, [256], [0, 256]) # img必须是单通道图像,否则报错error: (-215)plt.plot(hist1, colorcol)
plt.show()
##############################################
# 统计每个像素的众数(备注输入参数需用方括号[]表示)
# 直方图: cv2.calcHist(images,channels,mask,histSize,ranges)
# 输入参数 images: 原图像图像格式必须为 uint8 或 float32。
# channels: 1灰度图[0]; 2彩色图像[0] [1] [2]分别对应着BGR。
# mask: 掩模图像。1统计整幅图像的直方图则设置为 None。2统计图像某一区域的直方图则制作一个掩模图像。
# histSize: BIN的数目。可以理解为迭代范围。如[1]表示0,1,2...256;如[10]表示0~1011~20...如[256]表示0~256。
# ranges: 统计像素值范围。通常为[0~256]。##############################################
# 创建掩膜mask
mask np.zeros(img.shape[:2], np.uint8) # np.uint8八位无符号整型0~255
mask[100:300, 100:400] 255 # 掩膜区域显示255
masked_img cv2.bitwise_and(img, img, maskmask) # 与操作
hist_full cv2.calcHist([img], [0], None, [256], [0, 256])
hist_mask cv2.calcHist([img], [0], mask, [256], [0, 256])
plt.subplot(221), plt.imshow(img, gray), plt.title(Raw)
plt.subplot(222), plt.imshow(mask, gray), plt.title(mask)
plt.subplot(223), plt.imshow(masked_img, gray), plt.title(cv2.bitwise_and)
plt.subplot(224), plt.plot(hist_full), plt.plot(hist_mask), plt.title(hist_full hist_mask)
plt.subplot(224), plt.plot(hist_full), plt.plot(hist_mask), plt.title(hist_full hist_mask)
plt.xlim([0, 256])
plt.show()##############################################
# 直方图均衡化
img cv2.imread(rpicture\cat.jpg, 0) # 0表示灰度图
equ cv2.equalizeHist(img) # 将0~255两端的像素进行整幅图像的均匀化。即去掉极黑/极白像素
# 自适应直方图均衡化
clahe cv2.createCLAHE(clipLimit2.0, tileGridSize(8, 8)) # 将图像切分成8*8份分别进行直方图均衡化有效果降低过度处理
res_clahe clahe.apply(img)
plt.subplot(131), plt.imshow(img, gray), plt.title(Raw)
plt.subplot(132), plt.imshow(equ, gray), plt.title(cv2.equalizeHist)
plt.subplot(133), plt.imshow(res_clahe, gray), plt.title(cv2.createCLAHE)
plt.show()
##############################################
matplotlib.pyplot.hist()函数 像素点直方图统计、掩膜图像 错误提示cv::binary_op 错误提示cv::histPrepareImages 十六傅里叶变换 低通/高通滤波 —— cv2.dft()、cv2.idft()、np.fft.fftshift()、np.fft.ifftshift()、cv2.magnitud() 傅里叶变换 以时间作为参照来观察动态世界的方法我们称其为时域分析。 世间万物都在随着时间不停的改变并且永远不会静止下来。但在频域中你会发现世界是静止的、永恒不变的。 傅里叶告诉我们任何周期函数都可以看作是不同振幅不同相位正弦波的叠加。 举例利用对不同琴键不同力度不同时间点的敲击可以组合出任何一首乐曲。 傅里叶分析可分为傅里叶级数Fourier Serie和傅里叶变换(Fourier Transformation)。 傅里叶变换的作用 1高频变化剧烈的灰度分量例如边界/图像的轮廓 2低频变化缓慢的灰度分量例如一片大海 滤波器 1低通滤波器只保留低频会使得图像模糊 2高通滤波器只保留高频会使得图像细节增强 ##############################################
# 傅里叶变换cv2.dft(np.float32, cv2.DFT_COMPLEX_OUTPUT)
# 输入参数 1输入图像需要先转换成np.float32 格式。
# 2转换标识 - cv2.DFT_COMPLEX_OUTPUT - 用来输出一个复数阵列
# 逆傅里叶变换cv2.idft(dft_shift)
# 输入参数 1傅里叶变换后并位置转换后的频谱图像。# 在OpenCV中我们通过cv2.dft()来实现傅里叶变换使用cv2.idft()来实现逆傅里叶变换。
# 注意1变换后得到原始图像的频谱信息。其中频率为0的部分零分量会在左上角需要使用numpy.fft.fftshift()函数将其移动到中间位置。
# 注意2变换后的频谱图像是双通道的实部虚部。需要使用cv2.magnitude函数将幅度映射到灰度空间[0,255]内使其以灰度图像显示出来。# cv2.magnitude(x-实部y-虚部)
# 输入参数: 1浮点型x坐标值实部
# 2浮点型y坐标值虚部
# 备注两个参数的必须具有相同的大小size
############################################### 频谱图像设计
img cv2.imread(rpicture\lena.jpg, 0) # 0表示灰度图
dft cv2.dft(np.float32(img), flagscv2.DFT_COMPLEX_OUTPUT) # 傅里叶变换np.float32 格式
dft_shift np.fft.fftshift(dft) # 移动到中心位置
magnitude_spectrum 20*np.log(cv2.magnitude(dft_shift[:, :, 0],dft_shift[:, :, 1])) # 理解为固定公式即可
# 频谱最中心的频率最小像圆一样向外扩散越来越大。# 备注20*np.log(cv2.magnitude())
##############################################
# 低通滤波设计
rows, cols img.shape
crow, ccol int(rows/2), int(cols/2) # 获取图像中心位置mask_low np.zeros((rows, cols, 2), np.uint8)
mask_low[crow-30:crow30, ccol-30:ccol30] 1fshift_low dft_shift * mask_low
f_ishift_low np.fft.ifftshift(fshift_low)
img_low cv2.idft(f_ishift_low) # 逆傅里叶变换
img_low cv2.magnitude(img_low[:, :, 0], img_low[:, :, 1]) # 频谱图像转灰度图像
##############################################
# 高通滤波设计
mask_high np.ones((rows, cols, 2), np.uint8)
mask_high[crow-30:crow30, ccol-30:ccol30] 0fshift_high dft_shift * mask_high
f_ishift_high np.fft.ifftshift(fshift_high)
img_high cv2.idft(f_ishift_high) # 逆傅里叶变换
img_high cv2.magnitude(img_high[:, :, 0], img_high[:, :, 1]) # 频谱图像转灰度图像
##############################################
plt.subplot(141), plt.imshow(img, cmapgray), plt.title(Input Image), plt.xticks([]), plt.yticks([])
plt.subplot(142), plt.imshow(magnitude_spectrum, cmapgray), plt.title(Magnitude Spectrum), plt.xticks([]), plt.yticks([])
plt.subplot(143), plt.imshow(img_low, cmapgray), plt.title(Low pass filter), plt.xticks([]), plt.yticks([])
plt.subplot(144), plt.imshow(img_high, cmapgray), plt.title(High pass filter), plt.xticks([]), plt.yticks([])
plt.show()
傅里叶分析之详细剖析完整版-强烈推荐 十七Harris角点检测 —— cv2.cornerHarris()、np.float32() import cv2
import numpy as npimg cv2.imread(rpicture\Black_and_white_chess.jpg)
print(img.shape:, img.shape)gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # OpenCV读取图像的颜色是BGR
gray np.float32(gray)
#################################################
# Harris角点检测res cv2.cornerHarris(img_gray, blockSize, k_size, k)
# 输入参数 img_gray 数据类型为 float32 的输入图像。
# blockSize 角点检测中要考虑的领域大小 (一般等于2)
# k_size Sobel求导中使用的窗口大小 (一般等于3)
# k 方程中检测器的自由参数, 取值参数为 [0,04,0.06].
# 角点定义 角点是一个无论框框往哪边移动 框框内像素值都会变化很大的情况而定下来的点。
##################################################
# float16 半精度浮点数包括1 个符号位5 个指数位10 个尾数位
# float32 单精度浮点数包括1 个符号位8 个指数位23 个尾数位
# float64 双精度浮点数包括1 个符号位11 个指数位52 个尾数位
##################################################
Harris_dst cv2.cornerHarris(gray, 2, 3, 0.04)
print(dst.shape:, Harris_dst.shape)# 最佳阈值因图而异如果角点角点最大值*0.01就判断为角点
img[Harris_dst 0.01 * Harris_dst.max()] [0, 0, 255] # [0, 0, 255] 表示角点用红色表示cv2.imshow(Harris_dst, img)
cv2.waitKey(0)
cv2.destroyAllWindows()
OpenCV特征提取与检测之Harris角点检测 十八SIFT尺度不变特征检测 —— cv2.xfeatures2d.SIFT_create()、sift.detectAndCompute()、sift.detect()、sift.compute()、cv2.drawKeypoints #########################################################
# SIFT 图像特征检测算法
# Scale-invariant feature transformSIFT尺度不变特征变换。
# 特点具有尺度不变性。即对图片进行放缩、变形、模糊、明暗变化、光照变化、添加噪声甚至是使用不同的相机拍摄不同角度的照片的情况下SIFT都能检测到稳定的特征点并建立对应关系。
# 缺点计算量比较大很难实时
# 对比Harris角点检测算法最大的缺陷是不具有尺度不变性。当图片放大后原来能检测到的角点就变成了边线就检测不到了
#########################################################
# 在Opencv中SIFT函数从3.4.3版本以上已经涉及到专利保护。顾Opencv需要降版本使用。
# 卸载旧版本pip uninstall opencv-python
# pip uninstall opencv-contrib-python
# 安装新版本pip install opencv-python3.4.1.15
# pip install opencv-contrib-python3.4.1.15
#########################################################
import cv2 # OpenCV读取图像的颜色是BGRimg cv2.imread(test_1.jpg)
gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 转换为灰度图sift cv2.xfeatures2d.SIFT_create() # 实例化一个sift()函数
#########################################################
# 检测关键点并计算描述子key_points, des sift.detectAndCompute(img, None)
# 输出参数key_points为图像关键点dst为sift特征向量通常是128维。
#
# 其中sift.detectAndCompute()可以拆分为以下两个函数sift.detect()和sift.compute()。
# key_points sift.detect(gray, None) # 找出图像中的关键点
# kp, dst sift.compute(key_points) # 计算关键点对应的sift特征向量
#########################################################
key_points, des sift.detectAndCompute(gray, None) # 找出图像中的关键点#########################################################
# 在图中画出关键点ret cv2.drawKeypoints(gray, key_points, img)
# 输入参数gray表示输入图片kp表示关键点img表示输出的图片
#########################################################
img cv2.drawKeypoints(gray, key_points, img) # 在图中画出关键点cv2.imshow(key_points, img)
cv2.waitKey(0)
cv2.destroyAllWindows() 十九暴力特征匹配 —— cv2.BFMatcher_create()、bf.match()、bf_knn.knnMatch()、cv2.drawMatches() ########################################################
# 暴力特征检测主要流程
# 1先在查询描述符中取一个关键点的描述符将其与训练描述符中的所有关键点描述符进行比较。
# 2每次比较后会计算出一个距离值距离最小的值对应最佳匹配结果。
# 3所有描述符比较完后匹配器返回匹配结果列表。
########################################################
# 在Opencv中SIFT函数从3.4.3版本以上已经涉及到专利保护。顾Opencv需要降版本使用。
# 卸载旧版本pip uninstall opencv-python
# pip uninstall opencv-contrib-python
# 安装新版本pip install opencv-python3.4.1.15
# pip install opencv-contrib-python3.4.1.15
########################################################
import cv2 # opencv读取的格式是BGR
import matplotlib.pyplot as plt # Matplotlib是RGBimg1 cv2.imread(rpicture\box.png)
img2 cv2.imread(rpicture\box_in_scene.png)
#####################################
sift cv2.xfeatures2d.SIFT_create() # 创建SIFT特征检测器
##########################
kp1, des1 sift.detectAndCompute(img1, None) # 获取第一张图关键点kp1与特征向量des1
kp2, des2 sift.detectAndCompute(img2, None) # 获取第二张图关键点kp2与特征向量des2
#####################################
# 方法1match()匹配最佳结果
bf cv2.BFMatcher_create(cv2.NORM_L1, crossCheckFalse)
matches bf.match(des1, des2)
matches sorted(matches, keylambda x: x.distance)
result cv2.drawMatches(img1, kp1, img2, kp2, matches[:15], None)
#####################################
# 方法二knnMatch()匹配指定数量的最佳结果
bf_knn cv2.BFMatcher_create(cv2.NORM_HAMMING, crossCheckFalse)
ms_knn bf_knn.knnMatch(des1, des2, k2)
# 应用比例测试选择要使用的匹配结果
good []
for m, n in ms_knn:if m.distance 0.75 * n.distance:good.append(m)
img_DEFAUL cv2.drawMatches(img1, kp1, img2, kp2, good[:20], None, flagscv2.DrawMatchesFlags_DEFAUL)
img_NO_POINTS cv2.drawMatches(img1, kp1, img2, kp2, good[:20], None, flagscv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)
img_KEYPOINTS cv2.drawMatches(img1, kp1, img2, kp2, good[:20], None, flagscv2.DrawMatchesFlags_DRAW_RICH_KEYPOINTS)
#####################################
plt.subplot(231), plt.imshow(img1), plt.title(raw_img1)
plt.subplot(232), plt.imshow(img2), plt.title(raw_img2)
plt.subplot(233), plt.imshow(result), plt.title(match_result)plt.subplot(234), plt.imshow(img_DEFAUL), plt.title(knnMatch_DEFAUL)
plt.subplot(235), plt.imshow(img_NO_POINTS), plt.title(knnMatch_NO_POINTS)
plt.subplot(236), plt.imshow(img_KEYPOINTS), plt.title(knnMatch_KEYPOINTS)
plt.show()
########################################################
# 暴力匹配器bf cv2.BFMatcher_create(normType, crossCheck)
# 输出参数 bf 返回的暴力匹配器对象
# 输入参数 crossCheck 默认为False, 表示匹配器为每个查询描述符找到k个距离最近的匹配描述符。若为True, 则只返回满足交叉验证条件的匹配结果。
# normType 距离测量类型
# 方法1【SIFT】描述符使用cv2.NORM_L1或cv2.NORM_L2默认为cv2.NORM_L2。
# 方法2【ORB】描述符使用cv2.NORM_HAMMING
###########################
# 1匹配最佳结果ms bf.match(des1, des2)
# 输出参数 ms 为每个关键点的最佳匹配结果(距离值越小匹配度越高)
# 输入参数 des1 为查询描述符
# des2 为训练描述符
###########################
# 2匹配指定数量的最佳结果ms knnMatch(des1, des2, kn)
# 输出参数 ms 为返回的匹配结果, 每个列表元素是一个子列表, 它包含了由参数k指定个数的DMatch对象
# 输入参数 des1 为查询描述符
# des2 为训练描述符
# k 为返回的最佳匹配个数
########################################################
# 绘制最佳匹配outImg cv2.drawMatches(img1, keypoints1, img2, keypoints2, matches1to2[, matchColor[, singlePointColor[, matchesMask[, flags]]]])
# 输出参数 outImg为返回的绘制结果图像, 图像中查询图像与训练图像中匹配的关键点个两点之间的连线为彩色
# 输入参数 1img1为查询图像 2keypoints1为img1的关键点
# 3img2为训练图像 4keypoints2为img2的关键点
# 5matches1to2 img1与img2的匹配结果
# 6matchColor 关键点和链接线的颜色, 默认使用随机颜色
# 7singlePointColor 单个关键点的颜色, 默认使用随机颜色
# 8matchesMask 掩膜, 用于决定绘制哪些匹配结果, 默认为空, 表示绘制所有匹配结果
# flags为标志, 可设置为下列参数值:
# 1cv2.DrawMatchesFlags_DEFAUL 默认方式绘制两个源图像、匹配项和单个关键点, 没有围绕关键点的圆以及关键点的大小和方向
# 2cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS 不会绘制单个关键点
# 3cv2.DrawMatchesFlags_DRAW_RICH_KEYPOINTS 在关键点周围绘制具有关键点大小和方向的圆圈
########################################################
OpenCV特征匹配 SIFT demo图解 OpenCV特征检测之SIFT算法原理详解 OpenCV特征检测之特征匹配方式详解 二十图像缩放镜像平移旋转仿射变换透视变换 —— cv2.resize()、cv2.getRotationMatrix2D()、cv2.getAffineTransform()、cv2.getPerspectiveTransform()、cv2.warpPerspective()、cv2.warpAffine() import cv2
import numpy as np
import matplotlib.pyplot as plt # 绘图展示
################################################
img cv2.imread(rpicture/1.jpg, 1)
imgInfo img.shape
height imgInfo[0]; width imgInfo[1]; deep imgInfo[2]
################################################################################################
# 图像缩放
# 1直接进行缩放操作
dstHeight int(height/2)
dstWidth int(width/2)
dst_resize_dir cv2.resize(img, (dstWidth, dstHeight))
# 2使用邻域插值法进行缩放
dst_resize_linear np.zeros([dstHeight, dstWidth, 3], np.uint8)
for i in range(dstHeight):for j in range(dstWidth):iNew i * (height * 1.0 / dstHeight)jNew j * (width * 1.0 / dstWidth)dst_resize_linear[i, j] img[int(iNew), int(jNew)]
################################################################################################
# 镜像
dst_mirror np.zeros([height * 2, width, deep], np.uint8)
for i in range(height):for j in range(width):dst_mirror[i, j] img[i, j]dst_mirror[height * 2 - i - 1, j] img[i, j]
for i in range(width):dst_mirror[height, i] (0, 0, 255)
################################################################################################
# 图像平移
dst_trans np.zeros(imgInfo, np.uint8)
for i in range(height):for j in range(width - 200): # 平移大小100dst_trans[i, j100] img[i, j] # 新图像截取原图像部分数据
################################################################################################
# 图像旋转
matRotate cv2.getRotationMatrix2D((height*0.5, width*0.5), 45, 0.7) # 获取旋转矩阵
dst_rotate cv2.warpAffine(img, matRotate, (height, width)) # 仿射变换
################################################################################################
# 仿射变换
matSrc np.float32([[0, 0], [0, height-1], [width-1, 0]]) # 原图的三个点坐标
matDst np.float32([[50, 50], [100, height-50], [width-200, 100]]) # 仿射的三个点坐标
matAffine cv2.getAffineTransform(matSrc, matDst) # 获取仿射变换矩阵
dst_affine cv2.warpAffine(img, matAffine, (height, width)) # 仿射变换
################################################################################################
# 透视变换
matDst1 np.float32([[50, 50], [100, height-50], [width-200, 100], [width-200, height-50]]) # 仿射的三个点坐标
matSrc1 np.float32([[0, 0], [0, height-1], [width-1, 0], [width-1, height-1]]) # 原图的三个点坐标
matwarp cv2.getPerspectiveTransform(matDst1, matSrc1) # 参数1输入图像的四个点坐标 参数2输出图像的四个点坐标方方正正的图像
dst_Perspective cv2.warpPerspective(img, matwarp, (height, width))
dst_Perspective np.hstack((dst_affine, dst_Perspective))
################################################################################################
plt.subplot(241), plt.imshow(img, gray), plt.title(img)
plt.subplot(242), plt.imshow(dst_resize_dir, gray), plt.title(dst_resize_dir (coordinates))
plt.subplot(243), plt.imshow(dst_resize_linear, gray), plt.title(dst_resize_linear (coordinates))
plt.subplot(244), plt.imshow(dst_mirror, gray), plt.title(dst_mirror)
plt.subplot(245), plt.imshow(dst_trans, gray), plt.title(dst_trans)
plt.subplot(246), plt.imshow(dst_rotate, gray), plt.title(dst_rotate)
plt.subplot(247), plt.imshow(dst_affine, gray), plt.title(dst_affine)
plt.subplot(248), plt.imshow(dst_Perspective, gray), plt.title(dst_Perspective)
plt.show()################################################
# 图像缩小或放大cv2.resize(src, dsize, fx0, fy0, interpolationINTER_LINEAR)
# 输入参数 src 输入图片
# dsize 1矩阵参数缩放到指定大小(widthheight) 例如cv2.resize(img_dog, (500, 414))
# 2矩阵参数为(0,0)原图像缩放倍数通过fx, fy来控制 例如cv2.resize(img_dog, (0, 0), fx4, fy4)
# fx, fy 沿x轴y轴的缩放系数
# interpolation 插值方法有以下五种可选参数
# (1)INTER_NEAREST 最近邻插值 (2)INTER_LINEAR 双线性插值默认设置
# (3)INTER_AREA 使用像素区域关系进行重采样。 (4)INTER_CUBIC 4x4像素邻域的双三次插值
# (5)INTER_LANCZOS4 8x8像素邻域的Lanczos插值
################################################
# 获取旋转矩阵rot_mat cv2.getRotationMatrix2D(center, angle, scale)
# 输入参数 center 旋转的中心点。一般是图像的中心取图像长宽的一半
# angle 旋转的角度。正值是顺时针旋转负值是逆时针旋转
# scale 缩放比例。
################################################
# 获取仿射变换矩阵matAffine cv2.getAffineTransform(matSrc, matDst)
# 输入参数 matSrc 原图的三个点坐标
# matDst 仿射的三个点坐标
# 输出参数 matAffine 仿射变换矩阵
################################################
# 计算齐次变换矩阵cv2.getPerspectiveTransform(rect, dst)
# 输入参数 rect输入图像的四个点四个角
# dst输出图像的四个点方方正正的图像对应的四个角
################################################
# 仿射变换cv2.warpPerspective(src, M, dsize, dstNone, flagsNone, borderModeNone, borderValueNone)
# 透视变换cv2.warpAffine(src, M, dsize, dstNone, flagsNone, borderModeNone, borderValueNone)
# src输入图像 dst输出图像
# M2×3的变换矩阵
# dsize变换后输出图像尺寸
# flag插值方法
# borderMode边界像素外扩方式
# borderValue边界像素插值默认用0填充
#
# Affine Transformation可实现旋转平移缩放变换后的平行线依旧平行。
# Perspective Transformation即以不同视角的同一物体在像素坐标系中的变换可保持直线不变形但是平行线可能不再平行。
#
# 备注cv2.warpAffine需要与cv2.getRotationMatrix2D/cv2.getAffineTransform/cv2.getPerspectiveTransform搭配使用。
################################################