上海網(wǎng)站制作優(yōu)化公司臨沂做網(wǎng)絡(luò)優(yōu)化的公司
? ? ? ? 這個簡單的AR項(xiàng)目效果是,通過給定一張靜態(tài)圖片作為要視頻中要替換的目標(biāo)物品,當(dāng)在視頻中檢測到圖片中的物體時,通過單應(yīng)矩陣做投影,將視頻中的物體替換成一段視頻播放。這個項(xiàng)目的所有素材來自自己的手機(jī)拍的視頻。
? ? ? ? 靜態(tài)圖片:
????????
? ? ? ? 當(dāng)我在原視頻中檢測到這本書時,會將書替換成另一個視頻里的內(nèi)容。
? ? ? ? 關(guān)于opencv里的透視投影,單應(yīng)矩陣等概念,請自行百度。下面是代碼:
import cv2 as cv
import numpy as npvideoOriginal = cv.VideoCapture("../../SampleVideos/NationalGeography.mp4")
videoReplace = cv.VideoCapture("../../SampleVideos/Milo1.mp4")
targetImg = cv.imread("./book.png", cv.IMREAD_COLOR)
targetH,targetW,targetC = targetImg.shape#創(chuàng)建ORB對象
orb = cv.ORB_create(nfeatures=1500)
#提取ORB關(guān)鍵點(diǎn)和特征描述符
kpImg,descsImg = orb.detectAndCompute(targetImg, None)
#調(diào)試:繪制關(guān)鍵點(diǎn)
#imgDebug = cv.drawKeypoints(targetImg, kpImg, None)
#cv.imshow("ORB Keypoints", imgDebug)
#匹配距離閾值
matchDistanceThr = 0.75while True:ret,frame = videoOriginal.read()if ret == False:break;#frameAug表示最終合成的增強(qiáng)現(xiàn)實(shí)的結(jié)果圖片frameAug = frame.copy()ret,frameReplace = videoReplace.read()if ret == False:break;#將視頻大小調(diào)整到和待替換目標(biāo)圖片大小frameReplace = cv.resize(frameReplace, (targetW,targetH), interpolation=cv.INTER_AREA)kpVideo,descsVideo = orb.detectAndCompute(frame, None)#frame = cv.drawKeypoints(frame, kpVideo, None)#進(jìn)行特征匹配bf = cv.BFMatcher()matches = bf.knnMatch(descsImg, descsVideo, k=2)goodMatches = []for m,n in matches:if m.distance < matchDistanceThr * n.distance:goodMatches.append(m)#print(len(goodMatches))#調(diào)試:繪制匹配結(jié)果imgFeatureMatching = cv.drawMatches(targetImg, kpImg, frame, kpVideo, goodMatches, None, flags=2)#找到單應(yīng)矩陣#首先找到srcPts和dstPtsif (len(goodMatches) > 20):srcPts = np.float32([kpImg[m.queryIdx].pt for m in goodMatches]).reshape(-1,1,2)dstPts = np.float32([kpVideo[m.trainIdx].pt for m in goodMatches]).reshape(-1,1,2)#找到單應(yīng)矩陣matrix,mask = cv.findHomography(srcPts, dstPts, cv.RANSAC, 5)#print(matrix)#映射targetImg的四個角點(diǎn)到目標(biāo)平面targetPts = np.float32([[0,0],[0,targetH],[targetW,targetH],[targetW, 0]]).reshape(-1,1,2)targetOnVideoPts = cv.perspectiveTransform(targetPts, matrix)#print("Target shape:", targetImg.shape)#print("Frame shape:", frame.shape)#print(targetPts)#print('maps to:')#print(targetOnVideoPts)#print()#繪制待替換目標(biāo)圖像的位置映射到視頻幀后的邊框結(jié)果imgTargetOnVideoBox = cv.polylines(frame, [np.int32(targetOnVideoPts)], True, (255,0,255), 3)#調(diào)用warpPerspective將要替換的視頻文件幀圖像投影到視頻幀的圖像imgWarp = cv.warpPerspective(frameReplace, matrix, (frame.shape[1],frame.shape[0]))#獲得掩碼圖#首先將視頻幀中要替換的區(qū)域內(nèi)容的mask標(biāo)記為全1(白色)maskForReplace = np.zeros((frame.shape[0],frame.shape[1]), np.uint8)cv.fillPoly(maskForReplace, [np.int32(targetOnVideoPts)], (255,255,255))#獲得原視頻幀內(nèi)容的mask,將maskForReplace取反即可maskForVideo = cv.bitwise_not(maskForReplace)#生成增強(qiáng)現(xiàn)實(shí)的幀frameAug = cv.bitwise_and(frameAug, frameAug, mask = maskForVideo)frameAug = cv.bitwise_or(imgWarp, frameAug)cv.imshow('Augmented Video', frameAug)cv.moveWindow('Augmented Video', imgFeatureMatching.shape[1],0)cv.imshow('FeatureMatchResult', imgFeatureMatching)cv.moveWindow('FeatureMatchResult', 0,0)#cv.imshow('Mask For Video', maskForVideo)#cv.imshow('Mask For Replace', maskForReplace)#cv.imshow('WarpImage', imgWarp)#cv.moveWindow("WarpImage", 800,0)#cv.imshow('TargetOnVideo', imgTargetOnVideoBox)#cv.imshow('VideoPlayer', frame)if cv.waitKey(33) & 0xFF == ord('q'):break;videoOriginal.release()
videoReplace.release()
cv.destroyAllWindows()
? ? ? ? 運(yùn)行結(jié)果:
Python Opencv實(shí)踐簡單的AR項(xiàng)目