2016-08-14 7 views
1

J'ai une vidéo et j'ai créé un masque Sobel sur MATLAB. Maintenant, je dois appliquer ce masque Sobel sur chaque image de la vidéo en lisant chaque image à travers for boucle. Le processus est quelque chose comme:Les cadres de type double doivent être de l'ordre de 0 à 1: MATLAB

  • Étape 1: Cadre de lecture.
  • étape 2: Conversion en échelle de gris en utilisant rgb2gray.
  • Étape 3: Conversion en double.

Ici, après l'application du masque lorsque je tente d'écrire le cadre sur le fichier video.avi résultant, je reçois l'erreur suivante:

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

Quel est le problème avec mon code? Le code que j'ai écrit est présenté ci-dessous:

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); 

Répondre

2

rim2 a à la fin [-pi/2, pi/2], ce qui n'est pas compatible avec la fonction d'écriture qui attend la plage [0,1]. Convertir à [0,1] plage en utilisant la fonction mat2gray, à savoir

writeVideo(write, mat2gray(rim2)); 

Votre code sera alors fonctionner comme prévu (confirmé sur ma machine). Par ailleurs, cela n'affecte pas votre code, mais vous vouliez probablement faire im2double(A) plutôt que double(A). Le premier produit une image en niveaux de gris «correcte» dans la plage [0,1], tandis que le dernier convertit simplement votre image uint8 dans la plage [0,255] au format double (c'est-à-dire [0,0, 255,0]).

+0

Merci pour votre aide, votre suggestion de 'mat2gray' travaillé. mais je voudrais comprendre le concept de toutes ces choses, donc si vous pouvez me donner un peu de temps, j'aimerais discuter avec vous. –

+0

Bien sûr, je serais heureux de. Merci d'avoir accepté ma réponse. Je soupçonne que vous l'avez préféré sur @ Rayryeng parce que c'était court et est allé droit au but (c.-à-d. «Réglé le problème»), ce qui était mon intention de le faire; Cependant Rayryeng vous a fourni une analyse très utile des problèmes et des concepts impliqués dans votre tâche; vous pourriez au moins reconnaître son effort en valorisant sa contribution et en répandant un peu d'amour (c'est-à-dire la réputation de récompense :)) Toutes les informations de base dont vous avez besoin pour comprendre les concepts impliqués sont bien présentées. (rayon: désolé, ne voulait pas voler: p) –

+0

non non je ne voulais pas décevoir ou blesser @rayryeng.sans doute ses suggestions sont super mais ce que j'ai ressenti pour moi, ils étaient assez difficiles à comprendre même si j'ai eu une idée de son code (mais je ne comprenais pas tout), et c'était mon problème parce que je ne suis pas bon le traitement d'image encore, donc peut-être c'est la raison pour laquelle je ne pouvais pas comprendre son code. et votre suggestion était courte, donc je l'ai juste mis dans mon code, c'est pourquoi j'ai demandé d'effacer mes concepts à ce sujet. –

2

La ligne de rim2 dans votre double boucle for utilise atan, qui va générer des valeurs qui sont à la fois positives et négatives - de -pi/2 à + pi/2 exactement . rim2 devrait avoir des valeurs qui sont seulement entre [0,1]. Je n'arrive pas à comprendre exactement ce que vous faites, mais il semble que vous calculiez l'amplitude et l'angle de gradient à chaque emplacement de pixel. Si vous voulez calculer la magnitude, vous devez prendre la racine carrée du résultat, et non simplement multiplier par 1/2. Le calcul du gradient (... ou même le calcul du filtre Sobel entier ...) est très amusant. Je vais juste supposer que cela fonctionne pour vos besoins, donc je ne suis pas sûr de savoir comment changer la sortie de rim2 pour l'affichage approprié, mais peut-être vous pourriez l'échelle à la plage de [0,1] avant d'écrire la vidéo de sorte qu'il est dans cette gamme.

Quelque chose comme ça fonctionnerait avant d'écrire le cadre:

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

Ce qui précède est votre normalisation typique min-max que l'on voit dans la pratique. Plus précisément, ce qui précède fera en sorte que la plus petite valeur est 0 tandis que la plus grande valeur est de 1 par trame. Si vous voulez être cohérent sur toutes les images, ajoutez simplement pi/2 puis divisez par pi. Cela suppose que le minimum est -1 et le maximum est +1 sur toutes les images cependant.

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

Cependant, je suppose que vous voulez écrire l'importance de déposer, et non l'angle. Par conséquent, remplacez l'écriture vidéo avec rim1 en tant qu'image à écrire au lieu de rim2, puis normaliser après. Assurez-vous que votre calcul de gradient est correct si:

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

maintenant écrire le fichier:

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

Cependant, si je peux fournir une méthode d'efficacité, ne pas utiliser for boucles pour calculer le gradient et l'angle.Utilisez conv2 et assurez-vous d'utiliser le drapeau 'same 'ou imfilter de la boîte à outils de traitement d'image pour effectuer le filtrage pour vous, puis calculer le gradient et l'angle vectorisés. Convertissez également en niveaux de gris et lancez votre image en une fois dans la boucle principale. Je suppose que vous avez la boîte à outils de traitement d'images comme ayant la boîte à outils de vision par ordinateur (vous avez ce que vous utilisez un objet VideoWriter), ainsi que la boîte à outils de traitement d'image est ce que la plupart des gens ont:

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

merci pour la réponse rapide, en fait, j'ai reçu une tâche dans laquelle je devais faire une vidéo de moi-même et je dois trouver les bords de mon corps dans chaque image. à cette fin, la trame doit être une image en niveaux de gris donc je l'ai convertie avec rgb2gray, maintenant, si je n'utilise pas double, je reçois une erreur avec "atan" car atan n'accepte pas l'image unit8 comme paramètres d'entrée. donc je l'ai converti en double. après tout ce traitement, je dois écrire que les bords ont trouvé le cadre dans un nouveau fichier vidéo. –

+0

@MehranKhan Ah je vois. OK, donc il semble que vos gradients horizontaux et verticaux sont OK ... et vous voulez trouver l'angle. Je vous suggère d'utiliser 'atan2' à la place car il respecte le quadrant dans lequel se trouvent vos points dans l'espace. Essayez ma modification et voyez si cela fonctionne. La normalisation min-max devrait convenir à vos objectifs .... mais je pense que vous voulez simplement calculer l'ampleur, pas l'angle. – rayryeng

+0

si je ne calcule pas l'ange, cela ne produit pas le résultat désiré mais cela fonctionne bien avec le calcul de l'ange. Je veux vous montrer l'image mais je ne sais pas comment poster une image ici. –