我想知道是否可以用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);
但我意识到手的颜色不是“真实的”而且它们是透明的。有没有更好的方法从视频中提取它们保持颜色和不透明度水平利用第一帧(背景)?
编辑:好吧,我已经为vision.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);
...我的电脑崩溃了。一些建议?
答案 0 :(得分:1)
所以你试图取消背景,使其变黑,对吗? 最简单的方法是过滤它,你可以通过将差异数据与阈值进行比较,然后使用结果作为索引来设置自定义背景。
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,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矩阵,下标[n m p]
的线性索引可以计算为ind = (p-1)*M*N + (m-1)*N + n
。使用我们的值,我们得到以下结果:
[2 5 1] => 202
[2 5 2] => 2702
[2 5 3] => 5202
ind2sub
证实了这一点。
答案 1 :(得分:0)
是的,还有更好的方法。计算机视觉系统工具箱包含一个vision.ForegroundDetector
对象,可以满足您的需求。它实现了背景减法的高斯混合模型算法。