[英]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.