计算机视觉opencv之抠图流光估计物体追踪
一、抠图抠图只不过是一个大家比较熟悉的叫法其实实现抠图运用到的就是opencv中的一些方法。对图片进行抠图抠出扇子现要求使用 Python 结合 OpenCV 库编写代码实现图片1.读取图片将尺寸设置为宽640高480然后逆时针旋转90度import cv2 import numpy as np #读取图片 img cv2.imread(shanzi.jpg) #调整尺寸 img_resized cv2.resize(img, (640, 480)) #旋转 img_rotated cv2.rotate(img_resized, cv2.ROTATE_90_COUNTERCLOCKWISE)2.使用Canny边缘检测提取1处理后的边缘#Canny边缘检测 gray cv2.cvtColor(img_rotated, cv2.COLOR_BGR2GRAY) blurred cv2.GaussianBlur(gray, (5, 5), 0) edges cv2.Canny(blurred, 50, 150)3.在提取边缘的基础上查找轮廓并选取扇子的外轮廓生成相应的掩膜#查找轮廓并生成掩模 contours cv2.findContours(edges.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[-2]4.通过掩膜与原图进行按位与操作将对应部分提取出来并把最终结果保存下来。# 创建掩模 mask np.zeros(gray.shape, dtypenp.uint8) if len(contours) 0: # 找到面积最大的轮廓扇子外轮廓 max_area 0 largest_contour None for cnt in contours: if len(cnt) 0: cnt_float cnt.astype(np.float32)# 转换为float32避免类型错误 area cv2.contourArea(cnt_float) if area max_area: max_area area largest_contour cnt # 绘制填充轮廓到掩模 cv2.drawContours(mask, [largest_contour], -1, 255, cv2.FILLED) #按位与操作提取扇子 result cv2.bitwise_and(img_rotated, img_rotated, maskmask) # 保存结果 cv2.imwrite(koutu_shanzi.png, result) # 显示结果可选 cv2.imshow(yuan, img_rotated) cv2.imshow(canny, edges) cv2.imshow(mask, mask) cv2.imshow(result, result) cv2.waitKey(0) cv2.destroyAllWindows()结果二、流光估计是计算机视觉中估计图像序列中物体运动的技术。color np.random.randint(0, 255, (100, 3))是生成100个bgr颜色每个颜色是三元组用于后续给不同追踪点绘制不同颜色的轨迹线灰度转换是为了减少计算量光流算法通常在灰度图上操作角点检测中参数意思为最多检测100个特征点角点质量阈值0.3表示保留质量在前30%的角点角点之间的最小像素距离为7避免角点太密集import numpy as np import cv2 #打开视屏文件 cap cv2.VideoCapture(rD:\learn\计算机视觉\tupian\test.avi) # 随机生成颜色用于绘制轨迹 color np.random.randint(0, 255, (100, 3)) # 读取第一帧 ret, old_frame cap.read() #将第一帧转换为灰度图像 old_gray cv2.cvtColor(old_frame, cv2.COLOR_BGR2GRAY) # Shi-Tomasi角点检测参数 feature_params dict(maxCorners100, # 最大角点数量 qualityLevel0.3, # 角点质量的阈值 minDistance7) # 最小距离用于分散角点使用角点检测方法找到特征点goodFeaturesToTrack(imagemaxCornersqualityLevelminDistancecornersNonemaskNoneblockSizeNoneuseHarrisDetectorNone)image输入单通道图像用灰度图 maxCorners设定最大的角点格式是最有可能得角点数如果这个参数不大于0那么表示没有角点数的限制qualituLevel图像角点的最小可接受参数质量测量值乘以这个参数就是最小特征数小于这个数的会被抛弃minDistance角点之间最小的欧式距离mask检测区域如果图像不是空的他指定检测角点区域corners返回所有角点坐标位置**:关键字参数解包用于将字典解包为关键字参数这里是把字典展开为三个参数maxCorners100, qualityLevel0.3, minDistance7定义LK流光算法的参数winsize就是设置窗口大小这里是15x15的金字塔层数为2用于处理大运动。这串代码完成了光流追踪的初始化准备好角点绘制掩膜和算法参数# 检测角点 p0 cv2.goodFeaturesToTrack(old_gray, maskNone, **feature_params) # 创建掩模用于绘制轨迹 mask np.zeros_like(old_frame) # 光流跟踪参数 lk_params dict(winSize(15, 15), # 窗口大小 maxLevel2) # 金字塔层数计算光流获取新的特征点位置和状态calcopticalFLowPyrLK(prevImg, nextImg, prevPts, nextPts, status-None, err-None, winsize-lone, maxLevelNone,criteria None, flags None, minEigThreshold None)prevImg:前一帧图像nextImg:当前帧图像prevPts:前一帧图像中特征点坐标nextPts:当前帧图像中特征点坐标可以为NonewinSize:搜索窗口的大小maxLevel:金字塔层数criteria:停止迭代的准则返回值:nextPts:在当前帧中估计出的特征点坐标status:一个与prevPts一样大小的状态向量用于表示特征点是否被成功跟踪到。err一个prevPts样大小的误差向量用于表示估计误差这里的old_gray是前一帧灰度图frame_gray是当前帧灰度图p0是前一帧的特征点返回p1为当前帧中对应特征点的位置st是状态1就是追踪成功0就是失败err是误差值。绘制轨迹使用了一个for循环为每对成功追踪成功的点绘制彩色轨迹线这里的color[i].tolist使用的就是我们一开始准备好的随机颜色线宽设置为2像素#主循环 while True: #读取下一帧 ret, frame cap.read() #检查是否成功读取到帧 if not ret: break #将当前帧转换为灰度图 frame_graycv2.cvtColor(frame,cv2.COLOR_BGR2GRAY) #计算LK光流金字塔lucas-kanade光流法 p1,st,errcv2.calcOpticalFlowPyrLK(old_gray,frame_gray,p0,None,**lk_params) #选择好的点状态为1的点 good_newp1[st1] good_oldp0[st1] #绘制轨迹 for i,(new,old) in enumerate(zip(good_new,good_old)): a,bnew#获取新点的坐标 c,dold#获取旧点的坐标 a,b,c,dint(a),int(b),int(c),int(d)#转换为整数 #在掩膜上绘制线段连接新点和旧点 maskcv2.line(mask,(a,b),(c,d),color[i].tolist(),2) cv2.imshow(mask,mask) #将掩膜添加到当前帧上生成最终图像 imgcv2.add(frame,mask) cv2.imshow(frame,img) kcv2.waitKey(150) if k 27:#esc键退出 break old_grayframe_gray.copy()#当前帧作为下一轮的前一帧 p0good_new.reshape(-1,1,2)#当前成功追踪到的点作为下一轮的初始点 cap.release() cv2.destroyAllWindows()结果三、物体追踪这里创建一个跟踪器实例有很多种办法有些办法运行可能会出错所以可以轮流试验这里的追踪器的使用是和opencv版本有关的。可以自行查找选择合适的tracker cv2.TrackerCSRT_create()tracker cv2.legacy.TrackerCSRT_create()tracker cv2.TrackerCSRT.create()tracker cv2.Tracker_create(CSRT)import cv2 # 创建一个CSRT跟踪器实例 tracker cv2.TrackerKCF_create() # 跟踪标志默认为False tracking False # 打开默认摄像头通常编号为0 cap cv2.VideoCapture(0)#当然也可以读取视频wiatKey1这个是触发按键事件这里总共运用了两次第一次是s键用于去截取需要追踪的物体第二次是退出循环也就是关闭窗口。selectROI是阻塞函数会暂停主循环直到我们选择完毕这里是我们截取需要追踪的物体后按下空格或回车循环就会继续进行。tracking.init是初始化roi如果想取消操作的时候可以按c键那么就会初始化失败也就是取消选中物体如果用户选择了追踪那就进行 if tracking:语句while True: # 从摄像头读取一帧图像 ret, frame cap.read() # 如果没有正确读取到图像则退出循环 if not ret: break # 检查是否有按键被按下如果是a键则设置跟踪标志为True并选择ROI if cv2.waitKey(1) ord(s): tracking True # 让用户在当前帧中选择一个矩形区域作为要跟踪的对象 roi cv2.selectROI(windowNameTracking, imgframe, showCrosshairFalse) # 是否显示十字线 # 初始化跟踪器传入当前帧和选定的ROI tracker.init(frame, roi) # 如果跟踪标志为True则更新跟踪器 if tracking: success, box tracker.update(frame) # 如果跟踪成功获取对象的位置 if success: x, y, w, h [int(v) for v in box] # 确保所有坐标都是整数 # 在frame上绘制矩形框以显示跟踪结果 cv2.rectangle(frame, pt1(x, y), pt2(x w, y h), color(0, 255, 0), thickness2) # 显示处理后的帧 cv2.imshow(Tracking,frame) # 检查是否按下ESC键ASCII码27如果按下则退出循环 if cv2.waitKey(1) 27: break # 释放摄像头资源 cap.release() # 关闭所有OpenCV创建的窗口 cv2.destroyAllWindows()注意我们按键的时候要保持输入法是英文格式下s键按下后窗口视频会暂停长按鼠标左键框选需要追踪的物体如果想取消框选就按c键如果没取消框选好物体后按空格或者回车就可以继续进行追踪物只要在镜头中就会被框出来这个就是物体追踪。