【问题标题】:Frames of type double must be in the range of 0 to 1: MATLABdouble 类型的帧必须在 0 到 1 的范围内:MATLAB
【发布时间】:2016-12-21 01:16:09
【问题描述】:

我有一个视频,我在 MATLAB 上为它制作了一个 Sobel 掩码。现在我必须通过for 循环读取每一帧,在视频的每一帧上应用 Sobel 掩码。这个过程是这样的:

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

在这里,当我尝试在生成的video.avi 文件上写入框架时应用掩码后,我收到以下错误:

"double 类型的帧必须在 0 到 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);

【问题讨论】:

    标签: matlab image-processing matlab-cvst


    【解决方案1】:

    for 循环中的rim2 行正在使用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);
    

    【讨论】:

    • 感谢您的快速回复,实际上我接到了一项任务,我必须制作自己的视频,并且必须在每一帧中找到我身体的边缘。为此,该帧必须是灰度图像,因此我已将其转换为 rgb2gray,现在,如果我不使用双精度,我会收到“atan”错误,因为 atan 不接受 unit8 图像作为输入参数。所以我把它转换成双倍。在所有这些处理之后,我必须将找到的边缘帧写入一个新的视频文件。
    • @MehranKhan 啊,我明白了。好的,所以看起来你的水平和垂直渐变是好的......你想找到角度。我建议您改用atan2,因为它尊重您在空间中的点所在的象限。试试我的编辑,看看它是否有效。 min-max 归一化应该适合您的目的....但我认为您只想计算幅度,而不是角度。
    • 如果我不计算天使,它不会产生预期的结果,但它适用于天使计算。我想给你看图片,但我不知道如何在这里发布图片。
    • 再次感谢您的帮助,我完全了解 imfilter 和其他方法,并且与他们合作过。但我应该以我正在做的方式去做,因为这是我老师分配的任务。实际上,我们正在学习如何自己创建蒙版并将其用于图像和视频。
    • 是的,我正在尝试你的出路。非常感谢:)
    【解决方案2】:

    rim2 末尾有[-pi/2, pi/2] 范围,这与期望 [0,1] 范围的写入函数不兼容。 使用mat2gray 函数将其转换为[0,1] 范围,即

    writeVideo(write, mat2gray(rim2));
    

    然后您的代码将按预期工作(在我的机器上确认)。

    顺便说一句,这不会影响您的代码,但大概您打算执行im2double(A) 而不是double(A)。前者在 [0,1] 范围内生成“正确”的灰度图像,而后者只是将 [0,255] 范围内的 uint8 图像转换为 double 格式(即 [0.0, 255.0])。

    【讨论】:

    • 感谢您的帮助,您对mat2gray 的建议奏效了。但是我想了解所有这些东西的概念,所以如果你能给我一点时间,我想和你聊聊。
    • 当然,我很乐意。感谢您接受我的回答;我怀疑你更喜欢它而不是@rayryeng,因为它很短而且直截了当(即“解决了问题”),这是我贡献它的意图;然而,rayryeng 为您提供了对您任务中涉及的问题和概念的非常有用的分解;你至少可以通过支持他的贡献并传播一些爱来承认他的努力(即奖励声誉:))你需要理解所涉及的概念的所有背景信息都很好地布置了。 (ray:对不起,我不是故意要偷的:p)
    • 不不,我不是有意让@rayryeng 失望或伤害。毫无疑问,他的建议很棒,但我对我的感觉是,尽管我对他的代码有所了解(但无法理解全部),但我很难理解它们,这是我的问题,因为我不擅长图像处理,所以这可能是我无法理解他的代码的原因。你的建议很短,所以我把它放在我的代码中,这就是为什么我要求清除我的概念。
    • 你根本没有偷任何东西。除此之外,我的声望比你多 6 万左右,所以你需要一些哈哈。我倾向于在一篇文章中喋喋不休地提出所有建议,以使答案更加丰富,但不利于使读者感到厌烦。不过,很好的答案,我已经投了赞成票。
    • 啊哈哈,我知道是对的,我也是这样做的……(另外,谢谢:p)
    猜你喜欢
    • 2018-02-22
    • 2018-02-28
    • 2020-06-24
    • 2019-12-05
    • 1970-01-01
    • 2018-04-29
    • 2018-08-31
    • 2023-02-11
    • 2021-01-08
    相关资源
    最近更新 更多