[英]A way to extract hands from a video
我想知道是否可以使用Matlab從視頻中僅提取手。 在視頻中執行一些手勢。 因為第一幀只是背景,所以我嘗試用這種方式:
readerObj = VideoReader('VideoWithHands.mp4');
nFrames = readerObj.NumberOfFrames;
fr = get(readerObj, 'FrameRate');
writerObj = VideoWriter('Hands.mp4', 'MPEG-4');
set(writerObj, 'FrameRate', fr);
open(writerObj);
bg = read(readerObj, 1); %background
for k = 1 : nFrames
frame = read(readerObj, k);
hands = imabsdiff(frame,bg);
writeVideo(writerObj,hands);
end
close(writerObj);
但是我意識到雙手的顏色不是“真實的”,而是透明的。 是否有更好的方法利用第一幀(背景)從保持色彩和不透明度的視頻中提取它們?
編輯:嗯,我已經找到了理想的視覺設置。ForegroundDetector對象,現在手是白色的邏輯區域,但是當我嘗試使用以下方法將其可視化時:
videoSource = vision.VideoFileReader('VideoWithHands.mp4', 'VideoOutputDataType', 'uint8');
detector = vision.ForegroundDetector('NumTrainingFrames', 46, 'InitialVariance', 4000, 'MinimumBackgroundRatio', 0.2);
videoplayer = vision.VideoPlayer();
hands = uint8(zeros(720,1280,3));
while ~isDone(videoSource)
frame = step(videoSource);
fgMask = step(detector, frame);
[m,n] = find(fgMask);
a = [m n];
if isempty(a)==true
hands(:,:,:) = uint8(zeros(720,1280,3));
else
hands(m,n,1) = frame(m,n,1);
hands(m,n,2) = frame(m,n,2);
hands(m,n,3) = frame(m,n,3);
end
step(videoplayer, hands)
end
release(videoplayer)
release(videoSource)
或使用以下命令將它們放入視頻文件中:
eaderObj = VideoReader('Video 9.mp4');
nFrames = readerObj.NumberOfFrames;
fr = get(readerObj, 'FrameRate');
writerObj = VideoWriter('hands.mp4', 'MPEG-4');
set(writerObj, 'FrameRate', fr);
detector = vision.ForegroundDetector('NumTrainingFrames', 46, 'InitialVariance', 4000, 'MinimumBackgroundRatio', 0.2);
open(writerObj);
bg = read(readerObj, 1);
frame = uint8(zeros(size(bg)));
for k = 1 : nFrames
frame = read(readerObj, k);
fgMask = step(detector, frame);
[m,n] = find(fgMask);
hands = uint8(zeros(720,1280));
if isempty([m n]) == true
hands(:,:) = uint8(zeros(720,1280));
else
hands(m,n) = frame(m,n);
end
writeVideo(writerObj,mani);
end
close(writerObj);
...我的電腦崩潰了。 有什么建議嗎?
所以您要取消背景,將其設為黑色,對嗎? 最簡單的方法應該是過濾它,可以通過將差異數據與閾值進行比較,然后將結果用作索引來設置自定義背景來進行過濾。
filtered = imabsdiff(frame,bg);
bgindex = find( filtered < 10 );
frame(bgindex) = custombackground(bgindex);
其中custombackground是要放入背景中的任何圖像文件。 如果希望它只是黑色或白色,請使用0或255而不是custombackground(bgindex)
。 請注意,數字取決於您的視頻數據格式,並且可能不准確(0除外,此數字應始終正確)。 如果太多被過濾掉,則降低上面的10
,如果仍有太多未過濾,增加10
。
最后,您將更改的幀寫回到視頻中,因此它僅替換了代碼中的hands
變量。
另外,根據您的格式,您可能必須對RGB值進行比較。 這稍微復雜一點,因為它需要同時檢查3個值,並對索引做一些魔術。 這是RGB版本(適用於包含3個色帶的任何東西):
filtered = imabsdiff(frame,bg); % differences at each pixel in each color band
totalfiltered = sum(filtered,3); % sums up the differences
% in each color band (RGB)
bgindex = find( totalfiltered < 10 ); % extracts indices of pixels
% with color close to bg
allind = sub2ind( [numel(totalfiltered),3] , repmat(bgindex,1,3) , ...
repmat(1:3,numel(bgindex),1) ); % index magic
frame(allind) = custombackground(allind); % copy custom background into frame
編輯:
這是索引魔術的詳細說明。
讓我們假設一個50x50的圖片。 假設發現第2行第5列的像素是背景,則bgindex
將包含數字202(對應於[2,5] = (5-1)*50+2
線性索引)。 我們需要一組與矩陣坐標[2,5,1]
, [2,5,2]
和[2,5,3]
對應的3個索引。 這樣,我們可以更改對應於該像素的所有3個色帶。 為了使計算更容易,此方法實際上假定了圖像的線性索引,因此將其轉換為2500x1圖像。 然后擴展3個色帶,創建2500x3矩陣。 現在,我們[202,1]
構造索引[202,1]
, [202,2]
和[202,3]
。
為此,我們首先通過重復我們的值來構建索引矩陣。 repmat
為我們執行此操作,它創建了矩陣[202 202 202]
和[1 2 3]
。 如果bgindex
有更多像素,則第一個矩陣將包含更多行,每行重復線性像素坐標3次。 第二個矩陣將包含其他[1 2 3]
行。 sub2ind
的第一個參數是矩陣的大小,在這種情況下為2500x3,因此我們計算了將numel
應用於總和向量的像素數(該像素將圖像的3個波段折疊為1個值,因此每個像素有1個值)並在第二維中添加一個靜態3。
現在sub2ind
將第一個矩陣中的每個元素作為行索引,將第二個矩陣中的每個對應元素作為列索引,並將它們轉換為線性索引,轉換成我們之前確定的大小的矩陣。 在我們的示例中,這導致了索引[202 2702 5202]
。 sub2ind
保留輸入的形狀,因此,如果我們有10個背景像素,則此結果的大小將為10x3。 但是,由於線性索引並不關心索引矩陣的形狀,因此僅采用所有這些值。
為了確認這是正確的,讓我們還原示例中的值。 原始圖像數據的大小為50x50x3。 對於NxMxP矩陣,下標[nmp]
的線性索引可以計算為ind = (p-1)*M*N + (m-1)*N + n
。 使用我們的值,我們得到以下信息:
[2 5 1] => 202
[2 5 2] => 2702
[2 5 3] => 5202
ind2sub
確認了這一點。
是的,有更好的方法。 計算機視覺系統工具箱包含vision.ForegroundDetector
您需求的vision.ForegroundDetector
對象。 它實現了高斯混合模型算法進行背景扣除。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.