MATLAB でスピード感のあるアニメーション作成



先日、同僚がTeamsの録画にチャットのテキストをテロップとして動画に焼き付けて流しているのを見て、ちょっと遊んでみようと思いました。




画像にテキストを焼き付けるのは Computer Vision Toolbox があれば比較的簡単にできちゃいます。もちろん MATLAB 本体に入っている [`text`](https://www.mathworks.com/help/matlab/ref/text.html) 関数を使ってもできますが、画像そのものに焼き付ける場合は Computer Vision Toolbox のほうが楽です。今回使うのは [`insertText`](https://www.mathworks.com/help/vision/ref/inserttext.html) 関数。



```matlab:Code
txt = "ビューン";
im = 255*ones(720,1080,"uint8");
figure
for id = 1:300
    im2 = insertText(im,[900-id*3, 300],txt,"Font","Meiryo","FontSize",100,"BoxOpacity",0);
    imshow(im2,"InitialMagnification",100)
    drawnow
end
```



こんな感じでテロップのアニメーションはできちゃいます。




![image_0.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/194780/99cc69e9-8289-6919-47d3-8a28dd4ce16b.gif)





ただ、「ビューン」というテロップがのろのろ画面を横切るのはちょっとカッコ悪い。。。




スピード的にはこんな感じで動いてほしいかな。



```matlab:Code
txt = "ビューン";
figure
for id = 1:10
    im2 = insertText(im,[900-id*90, 300],txt,"Font","Meiryo","FontSize",100,"BoxOpacity",0);
    imshow(im2,"InitialMagnification",100)
    drawnow
end
```



スピードを上げるためにループごとの移動距離を長くしました。




![image_1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/194780/6c12158e-5be6-dbf8-df0a-6cd1df9868b5.gif)




確かに見た目は速いのですが、一回一回の移動距離が長いのでパラパラ漫画感が否めません。滑らかでないので目がチカチカしますね。




何か良い解決法ないでしょうか。




実は、物体の動きが速い動画を見てみると分かるのですが、ハイスピードカメラで撮ってない限りフレームはぼけています。




![image_2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/194780/710fe64e-ac24-2687-0fb9-2057ce130a3e.gif)




となると、適切なぼかしを入れることによってスピード感を表現できるのでは、と思いました。




やってみよう。




動きによるぼかしを加えるには Image Processing Toolbox の [`fspecial`](https://www.mathworks.com/help/images/ref/fspecial.html) 関数を使います。



```matlab:Code
H = fspecial("motion",50,0);
```



`"motion"` というのはカメラの線形移動を近似するフィルターです。ここでは 50 ピクセルの水平移動（０度）を表しています。


これを画像に適用させるとこんな感じになります。


```matlab:Code
im2 = insertText(im,[500, 300],txt,"Font","Meiryo","FontSize",100,"BoxOpacity",0);
im3 = imfilter(im2(:,:,1),H,"replicate");
imshow(im3)
```
![figure_0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/194780/5c5fcb4f-ca86-6d96-f08f-450f3566c446.png)


いい感じでぼやけてます。




では、全てのフレームに適用させてみよう。



```matlab:Code
txt = "ビューン";
figure
for id = 1:10
    im2 = insertText(im,[900-id*90, 300],txt,"Font","Meiryo","FontSize",100,"BoxOpacity",0);
    im3 = imfilter(im2(:,:,1),H,"replicate");
    imshow(im3,"InitialMagnification",100)
    drawnow
end
```



![image_3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/194780/9ed900b7-6aa1-82e3-4857-c8b1934e9b8d.gif)



おお。なんとなくビューンって感じになりました。




でも終わりはくっきりと見える方がいいかもしれませんね。



```matlab:Code
txt = "ビューン";
figure
for id = 1:10
    im2 = insertText(im,[900-id*90, 300],txt,"Font","Meiryo","FontSize",100,"BoxOpacity",0);
    im3 = imfilter(im2(:,:,1),H,"replicate");
    if id == 10
        im3 = im2(:,:,1);
    end
    imshow(im3,"InitialMagnification",100)
    drawnow
end
```



![image_4.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/194780/75be03c0-cb69-c2a0-1b4a-b178943f99e6.gif)




`fspecial` 関数では、ぼかしの方向も指定できるのでこんな感じにグルグル回る動きも表現できます。



```matlab:Code
pos = [   691   319
    648   227
    523   195
    371   223
    295   379
    334   576
    543   626
    769   526
    855   298
    784   110
    624    56
    374    66
    225   171
    129   341];
d_pos = pos(2:end,:) - pos(1:end-1,:);
H_angles = atan2d(-d_pos(:,2),d_pos(:,1));

txt = "グルグル";
figure
for id = 1:size(pos,1)-1
    H = fspecial("motion",50,H_angles(id));
    im2 = insertText(im,pos(id,:),txt,"Font","Meiryo","FontSize",60,"BoxOpacity",0);
    im3 = imfilter(im2(:,:,1),H,"replicate");
    imshow(im3,"InitialMagnification",100)
    drawnow
end
im2 = insertText(im,pos(end,:),txt,"Font","Meiryo","FontSize",60,"BoxOpacity",0);
imshow(im2,"InitialMagnification",100)
```


![image_5.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/194780/750fd48f-6e5a-b71c-6c2c-ec28fbf601de.gif)




最後に雨を降るのを見ながら終わりましょう。



```matlab:Code
txt_list = ["ポタ", "ザー"];
figure
im = 255*ones(720,1080,"uint8");
H = fspecial("motion",50,90);
for id0 = 1:2
    txt = txt_list(id0);
    for id1 = 1:10
        xpos = randi([50 900],1);
        if id0 == 1
            len = 10;
        else
            len = 5;
        end
        for id2 = 1:len
            im2 = insertText(im,[xpos, (500/len)*id2],txt,"Font","Meiryo","FontSize",80,"BoxOpacity",0);
            im3 = imfilter(im2(:,:,1),H,"replicate");
            if id2 == len
                im3 = im2(:,:,1);
            end
            imshow(im3,"InitialMagnification",100)
            drawnow
        end
    end
end
```



![image_6.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/194780/603e6e14-a582-3b73-6c5d-5cac3df77e65.gif)