double 类型的帧必须在 0 到 1 的范围内:MATLAB
Frames of type double must be in the range of 0 to 1: MATLAB
我有一个视频,我在 MATLAB 上为它制作了一个 Sobel 掩码。现在我必须通过 for
循环读取每一帧,在视频的每一帧上应用 Sobel 掩码。这个过程是这样的:
- 第 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);
双 for
循环中的 rim2
行使用 atan
,它将生成正值和负值 - 从 -pi/2 到 + pi/2 没错。 rim2
的值预计仅在 [0,1]
之间。我无法弄清楚你到底在做什么,但看起来你正在计算每个像素位置的幅度和梯度角度。如果要计算量级,就得对结果取平方根,而不是简单地乘以1/2
。梯度的计算(...甚至是整个Sobel滤波器的计算...)很搞笑
我只是假设这对您有用,所以我不确定如何更改 rim2
的输出以适合显示,但也许您可以将其缩放到 [=19= 的范围] 在你写视频之前让它在这个范围内。
在你编写框架之前,类似这样的东西会起作用:
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
and ensure you use the 'same
' flag or 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);
rim2
的末尾范围为 [-pi/2, pi/2]
,这与期望范围为 [0,1] 的写入函数不兼容。
使用 mat2gray
函数将其转换为 [0,1]
范围,即
writeVideo(write, mat2gray(rim2));
您的代码将按预期工作(在我的机器上确认)。
顺便说一下,这不会影响您的代码,但您可能打算执行 im2double(A)
而不是 double(A)
。前者生成 [0,1] 范围内的 "proper" 灰度图像,而后者只是将 [0,255] 范围内的 uint8
图像转换为 double
格式(即 [0.0, 255.0]).
我有一个视频,我在 MATLAB 上为它制作了一个 Sobel 掩码。现在我必须通过 for
循环读取每一帧,在视频的每一帧上应用 Sobel 掩码。这个过程是这样的:
- 第 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);
双 for
循环中的 rim2
行使用 atan
,它将生成正值和负值 - 从 -pi/2 到 + pi/2 没错。 rim2
的值预计仅在 [0,1]
之间。我无法弄清楚你到底在做什么,但看起来你正在计算每个像素位置的幅度和梯度角度。如果要计算量级,就得对结果取平方根,而不是简单地乘以1/2
。梯度的计算(...甚至是整个Sobel滤波器的计算...)很搞笑
我只是假设这对您有用,所以我不确定如何更改 rim2
的输出以适合显示,但也许您可以将其缩放到 [=19= 的范围] 在你写视频之前让它在这个范围内。
在你编写框架之前,类似这样的东西会起作用:
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
and ensure you use the 'same
' flag or 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);
rim2
的末尾范围为 [-pi/2, pi/2]
,这与期望范围为 [0,1] 的写入函数不兼容。
使用 mat2gray
函数将其转换为 [0,1]
范围,即
writeVideo(write, mat2gray(rim2));
您的代码将按预期工作(在我的机器上确认)。
顺便说一下,这不会影响您的代码,但您可能打算执行 im2double(A)
而不是 double(A)
。前者生成 [0,1] 范围内的 "proper" 灰度图像,而后者只是将 [0,255] 范围内的 uint8
图像转换为 double
格式(即 [0.0, 255.0]).