仮想環境のネットワーク接続をMACVLANとMACVTAPに切り替えてみた
今自分のメインPCでは、下記のOSが動いています。
OS | 環境 | 用途 |
---|---|---|
Arch Linux | ホスト(物理マシン) | デスクトップ |
Debian GNU/Linux | コンテナ(systemd-nspawn) | サーバー |
Windows 10 Pro | 仮想マシン(libvirt) | ゲーム |
今までDebian GNU/LinuxとWindows 10 Proはソフトウェアブリッジ経由でネットワークに接続されていたのですが、これを性能が良いというMACVLAN/MACVTAP経由に切り替えてみることにしました。
systemd-nspawnでMACVLAN接続
設定ファイル中の下記のような記述を、
[Network] Bridge=nm-bridge
次のように書き換えます。
[Network] MACVLAN=eth0
libvirtでMACVTAP接続
設定ファイル中の下記のような記述を、
<interface type='bridge'> <mac address='xx:xx:xx:xx:xx:xx'/> <source bridge='br0'/> ... </interface>
次のように書き換えます。
<interface type='direct'> <mac address='xx:xx:xx:xx:xx:xx'/> <source dev='eth0' mode='bridge'/> ... </interface>
ホストと仮想環境での通信の設定
MACVLAN/MACVTAPで仮想環境をネットワークに接続する場合、そのままではホストと仮想環境の間の通信ができません。ただし、MACVLAN/MACVTAP同士の通信はできます。例えば今回の場合では、Arch LinuxとDebian GNU/Linuxの間、Arch LinuxとWindows 10 Proの間の通信ができませんが、Debian GNU/LinuxとWindows 10 Proの間の通信は可能です。なので、ホストのArch LinuxもMACVLAN経由でネットワークで接続するようにしてしまえば、ホストと仮想環境の間で通信ができるようになります。
これをsystemd-networkdで実現する場合、下記のようにします。
# # macvlan.netdev # [NetDev] Name=macvlan0 Kind=macvlan [MACVLAN] Mode=bridge
# # macvlan.network # [Match] Name=macvlan0 [Network] Address=192.168.x.y/24 ...
# # eth0.network # [Match] MACAddress=xx:xx:xx:xx:xx:xx [Network] MACVLAN=macvlan0
画像の乗算、スクリーン、オーバーレイ
SSを撮ったときに、なんか暗いなあと思うと画像をコピーしてスクリーン処理をする、ということがよくあります。ですが、スクリーンとかオーバーレイって何をする処理だっけ?とたまになるので、そのあたりの覚え書きです。
乗算
かけ算です。ただし、画像ファイルのデータの255を1.0とみなします。1.0より小さい値同士のかけ算なので、必ず元の値以下になります。
上の画像の値を、下の画像の値を、結果の画像の値をとすると、
となります。
もし、つまり自分自身に乗算処理をした場合、グラフは以下のようになります。青の実線がオレンジの破線()より下にあり、暗くなることがわかります。
スクリーン
乗算とは逆の処理です。
この処理は、2つの画像を反転して乗算処理をして、その結果をさらに反転する、という処理と等価になります。乗算とは逆に必ず元の値以上になります。
もし、つまり自分自身にスクリーン処理をした場合、グラフは以下のようになります。青の実線がオレンジの破線より上にあり、明るくなることがわかります。
オーバーレイ
乗算とスクリーンを合体させた処理です。下の画像が暗いと乗算、明るいとスクリーンになります。
もし、つまり自分自身にオーバーレイ処理をした場合、グラフは以下のようになります。暗いところはより暗く、明るいところはより明るくなります。
FF14のSSで試してみる
元の画像。
自身に乗算処理。
自身にスクリーン処理。
自身にオーバーレイ処理。
シグモイド関数でコントラスト強調
たくさんの画像のコントラストを上げようとしたのですが、どんなアプリを使えばいいのかわからず、そもそもコントラストを上げると言っても、単純に値の上下数%を飽和させる方法とか、イコライザを使う方法とかいくつもあるようなので、自分の勉強も兼ねて適当に実装してみることにしました。今回はとりあえず目的に合っていそうだった、シグモイド関数を使ったコントラスト強調を試してみます。
ガンマ補正
いきなり本題とは少しずれた話題ですが、ほとんどのカラーの画像(sRGBの画像)ファイルにはガンマ補正がかかった値が格納されています(sRGBではない、例えばHDRの画像やグレースケールの画像はガンマ補正がないっぽいです)。PhotoshopやGIMPだとそのあたり自動で処理してくれているはずなのですが、自分で実装する場合は考慮した方がいいと思います。コントラストの強調だけなら無視してもよさそうですが…
ガンマ補正というのは、昔のCRTディスプレイが入力に対して出力の特性が直線ではなく、
に近い特性になっていて、これを補正するための処理のことです。具体的には
となるような処理が画像ファイルのデータにはかけられています。
今回処理しようとした画像はsRGBで、上記の補正がかかっているので、画像処理をかける前にガンマ補正を除去する処理を行います。
シグモイド関数
シグモイド関数というのは下記の関数で、S字に似た形をしています。結構いろんなところで活躍しているひとらしいです。
この形を利用して、明るいところはより明るく、暗いところはより暗くしようというのが今回の目的です。
コントラスト強調
素のままのシグモイド関数は、変曲点がになっています。コントラスト強調に使用するため、軸をだけずらして
とします。は、コントラストを強調したい場所になります。例えば、値が20%の周囲でコントラストを強調したいなら、とします。は、どのくらいコントラストを強調するかですが、決定には試行錯誤が必要になると思います。
また、このままだとの範囲がからになっていないので、スケーリングを行います。最終的に、今回のコントラスト強調は下記のようになります。
上記のグラフはの場合ですが、値が0.5より低いところではより暗く、0.5より高いところではより明るく、またのときは、のときはになっているのがわかります。
Pythonで実装してみる
import math import numpy as np from PIL import Image import sys import os def sigmoid(x): a = 5.0 b = 0.5 return 1.0 / (1.0 + math.exp(a * (b - x))) lut = np.empty(256) sigmoid0 = sigmoid(0.0) sigmoid1 = sigmoid(1.0) for i in range(256): x = i / 255.0 x = x ** 2.2 # ガンマ補正を外す x = (sigmoid(x) - sigmoid0) / (sigmoid1 - sigmoid0) # コントラスト補正をかける x = x ** (1.0/2.2) # 再びガンマ補正をかける lut[i] = 255.0 * x for fn in sys.argv[1:]: img = np.asarray(Image.open(fn)) img = lut[img] ofn = os.path.splitext(fn)[0] + "-out.png" Image.fromarray(np.uint8(img)).save(ofn, quality=95) print("%s done." % fn)
numpy便利!
FF14のSSで試してみる
元の画像。
とした場合。
のときは、全体が明るくなります。 とした場合。