MATLAB ロゴを使った MATLAB ロゴのモザイクアート



先月行われたMATLAB Central 20周年記念の [MATLAB Mini Hack](https://www.mathworks.com/matlabcentral/contests/20th-anniversary-matlab-minihack.html)．280文字以内のMATLABコードでどれだけ美しい画像が描けるか，というとても面白いコンテストでした．[1700近くのエントリー](https://www.mathworks.com/matlabcentral/communitycontests/contests/4/entries/?filter=all&sort=views_count%20desc)がありました．本当に280字以内で描いたのか，というものがたくさんありました．




私はあまり数学的な美しい図は思いつかなかったので，MATLABのロゴを使ったモザイクアートを作ってみました．ここでそのコードを解説します．


![logo_mosaic.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/194780/a4fcca78-4cd0-9356-2f3b-8a926ef2a57a.gif)




コンテストで使ったコードはこちらになります：[Mosaic Membrane](https://www.mathworks.com/matlabcentral/communitycontests/contests/4/entries/3806)




ただ，その後もう少し考えてみたらもっと簡単にできることが判明しました．今回は簡単な方を紹介します．



```matlab:Code(Display)
logo;
c = getframe;
im = im2double(c.cdata);
im2 = imresize(im, 1/8);
im3 = imresize(im, [20 20]);
im4 = imresize(im, [1 1]);
im_diff = im2 - im4;
[r,c,~] = size(im2);
for i1 = 1:r
    for i2 = 1:c
        out{i1,i2} = im3 + im_diff(i1,i2,:);
    end
end
imshow(cell2mat(out))
```

# 解説
## 1. MATLAB ロゴ


まずはモザイクを作る画像とベースとなるタイル（今回は両方とも同じ画像）の MATLAB ロゴの画像を用意するのですが，標準デモ関数（スクリプト）の `logo` を使って，表示されるロゴのスクリーンキャプチャーを `getframe` 関数で取得します．



```matlab:Code
logo;
c = getframe
```

![figure_0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/194780/f66572d0-d010-cd31-acc5-7cfbaf6468c9.png)



```text:Output
c = 
       cdata: [840x818x3 uint8]
    colormap: []
```



`c` は構造体で，その中の `cdata` フィールドに画像データが含まれています．通常 `uint8` 型で定義してありますが，後にいろいろ演算を行うので `double` 型に変換します．



```matlab:Code
im = im2double(c.cdata);
whos im
```


```text:Output
  Name        Size                  Bytes  Class     Attributes

  im        840x818x3            16490880  double              
```

## 2. モザイク用画像の準備


モザイク画像とは，それぞれのピクセルを別の画像で表現して作り上げるので，最終的にできあがる画像はもとの画像よりも大きくなります．よって，今回は処理時間を短縮するために元の画像の大きさを小さくします．



```matlab:Code
im2 = imresize(im, 1/8);    % 1/8の大きさ
whos im2
```


```text:Output
  Name        Size                Bytes  Class     Attributes

  im2       105x103x3            259560  double              
```



また，各ピクセルを作り上げる画像の大きさを設定します．今回は 20 x 20 の大きさに調整します．



```matlab:Code
im3 = imresize(im, [20 20]);
whos im3
```


```text:Output
  Name       Size              Bytes  Class     Attributes

  im3       20x20x3             9600  double              
```



つまり，最終画像は 2100 x 2060 の大きさになります．


## 3. ピクセルに近似させるには


モザイク画像を作成するためには，タイルとして使う画像をうまく組み合わせて元の画像を再現するのですが，タイルとして使う画像が MATLAB ロゴの一枚となるとどうすればよいのでしょうか．




それを実現するためにロゴの画像の色を調整しました．




例えば，ロゴに赤み，緑み，青みを増すには



```matlab:Code
imR = im2 + reshape([0.5 0 0],1,1,3);
imG = im2 + reshape([0 0.5 0],1,1,3);
imB = im2 + reshape([0 0 0.5],1,1,3);
figure, tiledlayout(1,3,"TileSpacing","tight","Padding","tight")
nexttile
imshow(imR), title("赤み","Color","red")
nexttile
imshow(imG), title("緑み","Color","red")
nexttile
imshow(imB), title("青み","Color","red")
```

![figure_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/194780/4187f172-5467-257d-94ef-8965112f8758.png)


## 4. 色の距離の計算


色みを付ける方法が分かったので，後はそれぞれのタイルの色をどの程度調整するかを計算するだけです．




まずは，タイルの "平均の色" を計算するために，画像を１ピクセルに縮小します．



```matlab:Code
im4 = imresize(im,[1 1])
```


```text:Output
im4 = 
im4(:,:,1) =
    0.2236
im4(:,:,2) =
    0.1066
im4(:,:,3) =
    0.0474
```


```matlab:Code
figure, imshow(im4)
```

![figure_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/194780/ff08e68c-7ae0-4462-5d95-6951cb8ef8bc.png)




なるほど．背景が黒いので全体的に黒いですね．ちょっとオレンジ・茶色がかっていますね．




さて，この色からもともとのロゴの画像の各ピクセルの色との差を計算すればよいのです．



```matlab:Code
im_diff = im2 - im4;
whos im_diff
```


```text:Output
  Name           Size                Bytes  Class     Attributes

  im_diff      105x103x3            259560  double              
```



`im_diff` はもとの画像と同じ大きさで，各ピクセルの値は１ピクセルロゴとの色の差を表しています．


## 5. モザイク画像の組み立て


これで準備完了．最後にそれぞれのピクセルをタイル（＋上で求めた色の差分）に置き換えれば完了です．ただし，タイルは 20 x 20 の大きさなので単純に１ピクセルを置き換えるわけにはいかないので，セル配列で集約します．



```matlab:Code
[r,c,~] = size(im2);
for i1 = 1:r
    for i2 = 1:c
        out{i1,i2} = im3 + im_diff(i1,i2,:);
    end
end

% 最初の3行3列を見てみよう
out(1:3,1:3)
```

| |1|2|3|
|:--:|:--:|:--:|:--:|
|1|20x20x3 double|20x20x3 double|20x20x3 double|
|2|20x20x3 double|20x20x3 double|20x20x3 double|
|3|20x20x3 double|20x20x3 double|20x20x3 double|



最後にすべてをくっつけます．



```matlab:Code
imOut = cell2mat(out);
whos imOut
```


```text:Output
  Name          Size                    Bytes  Class     Attributes

  imOut      2100x2060x3            103824000  double              
```


```matlab:Code
imshow(imOut)
```

![figure_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/194780/4da3749c-8f11-a4da-dd3f-90f42d35b275.png)


## おしまい
試しに２階層のモザイクアートを作ってみました．ロゴの原型が分かるようにすると画素数が大きくなってしまい，ちょっと処理が重くなりましたが，もっと性能の良いPCだったらいろいろ楽しめると思います．


![large_mosaic2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/194780/ecd316dd-00b6-23d6-b64d-8fa480fa7475.gif)