2016-08-14 132 views
1

我有一个视频,我在MATLAB上为它制作了Sobel蒙板。现在我必须通过for循环读取每一帧来在视频的每个帧上应用Sobel掩码。该过程是这样的:double类型的框架必须在0到1的范围内:MATLAB

  • 第1步:阅读框架。
  • 第2步:使用rgb2gray将其转换为灰度。
  • 第3步:将其转换为双精度。

这里,将面膜当我尝试写在框架上产生的video.avi文件后,我收到以下错误:

"Frames of type double must be in the range of 0 to 1"

什么是错我的代码?我写的代码如下所示:

vid = VideoReader('me.mp4'); 
frames = read(vid); 
total = get(vid, 'NumberOfFrames'); 
write = VideoWriter('me.avi'); 
open(write); 
mask1 = [-1 -2 -1; 0 0 0; 1 2 1]; % Horizontal mask 
mask2 = [-1 0 1; -2 0 2; -1 0 1]; %Vertical Mask 
for k = 1 : 125 
    image = frames(:,:,:,k); 
    obj = image; 
    obj1 = rgb2gray(obj); 
    obj2=double(obj1); 
    for row = 2 : size(obj2, 1) - 1 
     for col = 2 : size(obj2, 2) - 1 
      c1 = obj2(row - 1, col - 1) * mask1(1 ,1); 
      c2 = obj2(row - 1, col) * mask1(1 ,2); 
      c3 = obj2(row - 1, col + 1) * mask1(1 ,3); 
      c4 = obj2(row, col - 1)*mask1(2, 1); 
      c5 = obj2(row, col)*mask1(2, 2); 
      c6 = obj2(row, col + 1)*mask1(2, 3); 
      c7 = obj2(row + 1, col - 1)*mask1(3,1); 
      c8 = obj2(row + 1, col)*mask1(3,2); 
      c9 = obj2(row + 1, col + 1)*mask1(3,3); 
      c11 = obj2(row - 1, col - 1)*mask2(1 , 1); 
      c22 = obj2(row, col - 1)*mask2(2, 1); 
      c33 = obj2(row + 1, col - 1)*mask2(3, 1); 
      c44 = obj2(row -1, col)*mask2(1, 2); 
      c55 = obj2(row, col)*mask2(2 , 2); 
      c66 = obj2(row +1, col)*mask2(2 , 3); 
      c77 = obj2(row - 1, col + 1)*mask2(1 , 3); 
      c88 = obj2(row, col +1)*mask2(2 , 3); 
      c99 = obj2(row + 1, col + 1)*mask2(3 , 3); 
      result = c1 + c2 + c3 +c4 +c5+ c6+ c7+ c8 +c9; 
      result2 = c11 + c22 + c33 + c44 + c55 + c66 + c77 + c88 + c99; 
      %result = double(result); 
      %result2 = double(result2); 
      rim1(row, col) = ((result^2+result2^2) *1/2); 
      rim2(row, col) = atan(result/result2); 
     end 
    end 
    writeVideo(write, rim2); %This line has the problem with rim2 as rim2 is the frame i'm trying to write on the video file. 
end 
close(write); 

回答

2

rim2有范围在[-pi/2, pi/2]的末尾,这与预期[0,1]范围的写入功能不兼容。 使用mat2gray功能,那么即

writeVideo(write, mat2gray(rim2)); 

您的代码将如预期其转换为[0,1]范围(证实了我的机器上)。

顺便说一句,这不会影响你的代码,但可能你的意思是做im2double(A)而不是double(A)。前者在[0,1]范围内生成“合适的”灰度图像,而后者仅将uint8图像的范围[0,255]转换为double格式(即[0.0,255.0])。

+0

感谢您的帮助,您对'mat2gray'的建议奏效。但我想理解所有这些事情的概念,所以如果你能给我一点时间,我想和你聊聊。 –

+0

当然,我很乐意。感谢您接受我的回答;我怀疑你比@ rayryeng更喜欢它,因为它很短,并直接指向了这个问题(即“解决了问题”),这是我的贡献意图;然而rayryeng已经给你提供了有关你的任务中涉及的问题和概念的令人惊讶的帮助分解;你至少可以通过加强他的贡献并传播一些爱(即奖励声誉:))来承认他的努力。)理解所涉及的概念所需的所有背景信息都很好地展现出来。 (雷:对不起,并不意味着要偷:p) –

+0

不,不,我并不是想让@rayryeng失望或伤害。毫无疑问,他的建议是伟大的,但我对我的感觉是,虽然我对他的代码有一些想法(但无法理解所有),但我很难理解,这是我的问题,因为我不擅长图像处理,但可能是这是我无法理解他的代码的原因。你的建议很短,所以我只是把它放在我的代码中,这就是为什么我要求清除我的概念。 –

2

rim2您的双for循环中的线是使用atan,这将产生均为正值和负值 - 从-pi/2到+ pi/2恰好。预计rim2的值仅在[0,1]之间。我无法弄清楚你在做什么,但看起来你正在计算每个像素位置的大小和倾斜角度。如果你想计算幅度,你必须取结果的平方根,而不是简单乘以1/2。梯度(...或者甚至整个Sobel滤波器计算...)的计算非常有趣。

我只是假设这是为你的目的工作,所以我不知道如何改变适合显示的rim2的输出,但也许你可以将它缩放到[0,1]的范围,然后再编写视频,在此范围内。你写的帧之前

像这样的工作:

rim2 = (rim2 - min(rim2(:)))/(max(rim2(:)) - min(rim2(:))); 
writeVideo(write, rim2); 

以上是典型的最小 - 最大规范化是在实践中看到。具体而言,以上将确保最小值为0,而最大值为每帧1。如果你想在所有帧上保持一致,只需添加pi/2然后除以pi。然而,这假定最小值为-1,最大值为+1 ,但是在所有帧上。

rim2 = (rim2 + pi/2)/pi; 
writeVideo(write, rim2); 

不过,我怀疑你想要写的幅度文件,而不是角。因此,用rim1代替rim2代替视频写入帧,然后归一化。确保您的梯度计算是正确的,虽然:

rim1(row, col) = ((result^2+result2^2)^(1/2)); 
% or use sqrt: 
% rim1(row, col) = sqrt(result^2 + result2^2); 

现在写入文件:

rim1 = (rim1 - min(rim1(:)))/(max(rim1(:)) - min(rim1(:))); 
writeVideo(write, rim1); 

但是,如果我可以提供效率的方法,不使用for循环计算渐变和角度。使用conv2并确保使用图像处理工具箱中的'same'标记或imfilter为您执行过滤,然后计算向量化的渐变和角度。此外,转换为灰度并在主循环中一次性投射你的画面。我假设你有图像处理工具箱具有计算机视觉工具箱(你有这样的作为您使用的是VideoWriter对象)连同图像处理工具箱是大多数人有:

vid = VideoReader('me.mp4'); 
frames = read(vid); 
total = get(vid, 'NumberOfFrames'); 
write = VideoWriter('me.avi'); 
open(write); 
mask1 = [-1 -2 -1; 0 0 0; 1 2 1]; % Horizontal mask 
mask2 = [-1 0 1; -2 0 2; -1 0 1]; %Vertical Mask 
for k = 1 : 125 
    obj2 = double(rgb2gray(frames(:,:,:,k))); % New 
    grad1 = imfilter(obj2, mask1); % New 
    grad2 = imfilter(obj2, mask2); % New 
    rim1 = sqrt(grad1.^2 + grad2.^2); % New 
    rim2 = atan2(grad1, grad2); % New 

    % Normalize 
    rim2 = (rim2 - min(rim2(:)))/(max(rim2(:)) - min(rim2(:))); 
    writeVideo(write, rim2); 
end 
close(write); 
+0

感谢您的快速回复,实际上我得到了一项任务,我必须制作自己的视频,并且必须在每个框架中找到我身体的边缘。为此,帧必须是灰度图像,所以我已经将其与rgb2gray进行了转换,现在,如果我不使用double,我会收到“atan”错误,因为atan不接受unit8图像作为输入参数。所以我已将其转换为双倍。在所有这些处理之后,我必须将找到的边缘帧写入新的视频文件。 –

+0

@MehranKhan啊我明白了。好吧,看起来您的水平和垂直渐变都可以...并且您想要找到角度。我建议你使用'atan2',因为它尊重你的空间点所在的象限。尝试我的编辑,看看它是否工作。 min-max标准化应该适合您的目的......但我认为您只是想计算幅度,而不是角度。 – rayryeng

+0

如果我不计算天使,它不会产生所需的结果,但它与天使计算效果很好。我想向您展示图片,但我不知道如何在此发布图片。 –

相关问题