今回は、上の画像のように、画像を分裂させて画質を下げる方法を解説します。実装はPythonです。実行環境は google colaboratory です。
無料オンライン相談を活用しよう!
Pythonというプログラミング言語は機械学習の人気の高まりなどもあり、様々なスクールが無料説明会を開催しています。
その中でも「Freeks(フリークス)|業界初!10,780円のサブスク型プログラミングスクール」がオススメです。Pythonを効率よく学びたいという方はまずは適性を知るためにも無料説明会を利用しましょう。
なぜこうなるのか?
理解しやすいように、分裂した後の画像を、拡大してみましょう。この画像は分裂後の1羽を拡大させたものです。画像がガタガタしているのが分かると思います。
このように、元の画像を切り出して交互につなぎ合わせると、鳥は解像度が大きく下がってしまいます。しかし、動画ではそこまでガタガタになっているようには感じなかったと思います。
その理由は、対象物の大きさが切り取った方向で半分になるからです。解像度が下がったとしても、対象物自体が小さくなるので、そこまで違和感のない画像が出力されるのですね。

解像度を上げることはできないのか?
スムージング処理など、上の画像のドット絵のようなガタガタを改善することは可能ですが、解像度を上げることはできません。解像度を上げる取り組みとしては、機械学習などの最先端な技術を用いて取り組まれているそうですが、あまりうまくいっていないのが現状です。
解像度を上げるとは、画像に含まれる情報量を多くするということです。しかし、元の画像以上に情報量を増やすことは不可能です。1個しかないリンゴを2個に増やそうとしても無理ですよね?それと同じです。
写真や動画を編集することができる「Photoshop」などで、解像度を上げる設定がありますが、画像をより高解像度っぽく見せる技術を使っているのです。その例が、スムージング処理やシャープネス処理です。
余談ですが、最近では、機械学習を用いて、モザイク処理を行った動画を、あたかも処理前のように見せかける技術を使い、18禁の動画を制作販売した事例が話題を呼びました。
なかなか素晴らしい技術ですね笑
実装
実装手順は、動画の手順に従ってプログラムを作成していきます。
まずは、下の画像の様に交互に画像を分裂させていき、それぞれ別の画像A, 画像Bに保存していきます。実際に画像を切り出す間隔は 、10pixelで1セット分の画像を抽出するようにしているため、画像の粗さは5pixelずつになります。
縦で切り取った後、2つの画像をつなぎ合わせると、鳥が2羽に分裂します。この時、縦に切り取っているため、出力画像は、縦で見ると解像度は下がっていませんが、横で見ると粗くなっているのが確認できます。
この作業を横でも同じように繰り返すことで 、2羽から 4羽に増えていきます。

関数「disassembly」
この関数では、画像の分裂を行っています。
def disassembly(picture):
# 縦に連結(結合): cv2.vconcat()
# 横に連結(結合): cv2.hconcat()
H, W = picture.shape[0], picture.shape[1]
# 分裂させる幅の大きさ
d = 10
d_half = int(d / 2)
# 元画像を出力
cv2_imshow(picture)
print("===============================")
# 前半の処理。A, Bには、縦に切り取った画像をぞれぞれつなぎ合わせて保存する。
A = cv2.hconcat([picture[:, w * d : w * d + d_half, :] for w in range(W // d)])
B = cv2.hconcat([picture[:, w * d + d_half : (w + 1) * d, :] for w in range(W // d)])
# 切り取ったA, Bをつなげる。
output1 = cv2.hconcat([A, B])
# お好みでA, Bの画像を見てあげてください。
#cv2_imshow(A)
#cv2_imshow(B)
cv2_imshow(output1)
print("===============================")
# 画像のサイズが微妙に変わるので画像サイズを取得する。
H, W = output1.shape[0], output1.shape[1]
# 後半の処理。A, Bには、横に切り取った画像をぞれぞれ保存する。
A = cv2.vconcat([output1[h * d : h * d + d_half, :, :] for h in range(H // d)])
B = cv2.vconcat([output1[h * d + d_half : (h + 1) * d, :, :] for h in range(H // d)])
# 切り取ったA, Bをつなげる。
output2 = cv2.vconcat([A, B])
#cv2_imshow(A)
#cv2_imshow(B)
cv2_imshow(output2)メイン関数
メイン関数です。対象の画像は作業ディレクトリに置きましょう。
google colaboratory では、 「google drive」にファイルを保存することが出来ます。その場合、以下のコマンドを打ちましょう。
cd drive/MyDrive/
# google colaboratory上で画像出力するために必要
from google.colab.patches import cv2_imshow
import cv2
if __name__ == "__main__":
FileName = "bird.jpg"
# 画像を読みとる
picture = cv2.imread(FileName)
# 関数を呼び出す
disassembly(picture)全体のコード
今回は、サンプルコードがすごく短いですが、1からプログラムを作成するには少し難易度が高いような気がします。
from google.colab.patches import cv2_imshow
import cv2
def disassembly(picture):
H, W = picture.shape[0], picture.shape[1]
d = 10
d_half = int(d / 2)
cv2_imshow(picture)
print("===============================")
A = cv2.hconcat([picture[:, w * d : w * d + d_half, :] for w in range(W // d)])
B = cv2.hconcat([picture[:, w * d + d_half : (w + 1) * d, :] for w in range(W // d)])
output1 = cv2.hconcat([A, B])
cv2_imshow(output1)
print("===============================")
H, W = output1.shape[0], output1.shape[1]
A = cv2.vconcat([output1[h * d : h * d + d_half, :, :] for h in range(H // d)])
B = cv2.vconcat([output1[h * d + d_half : (h + 1) * d, :, :] for h in range(H // d)])
output2 = cv2.vconcat([A, B])
cv2_imshow(output2)
if __name__ == "__main__":
FileName = "bird.jpg"
picture = cv2.imread(FileName)
disassembly(picture)出力結果
ここからは、出力画像を見ていきます。
元画像

分裂1回

分裂2回

もっと鳥と増やしてみた!
ゲシュタルト崩壊を起こしそう?ですね笑
ここまでくると完全に解像度が荒いことが確認できます。
ただ、かわいい鳥さんがたくさん見れて幸せハッピーです!
かわいいねぇ~!


この処理は同じことを繰り返しているので関数を別で定義するなどコードをもっと短くできますが、疲れたのですでに作成したプログラムを伸ばしただけです。勘弁してください笑
def disassembly(picture):
H, W = picture.shape[0], picture.shape[1]
d = 10
d_half = int(d / 2)
cv2_imshow(picture)
print("===============================")
A = cv2.hconcat([picture[:, w * d : w * d + d_half, :] for w in range(W // d)])
B = cv2.hconcat([picture[:, w * d + d_half : (w + 1) * d, :] for w in range(W // d)])
output1 = cv2.hconcat([A, B])
cv2_imshow(output1)
print("===============================")
H, W = output1.shape[0], output1.shape[1]
A = cv2.vconcat([output1[h * d : h * d + d_half, :, :] for h in range(H // d)])
B = cv2.vconcat([output1[h * d + d_half : (h + 1) * d, :, :] for h in range(H // d)])
output2 = cv2.vconcat([A, B])
cv2_imshow(output2)
print("===============================")
H, W = output2.shape[0], output2.shape[1]
A = cv2.hconcat([output2[:, w * d : w * d + d_half, :] for w in range(W // d)])
B = cv2.hconcat([output2[:, w * d + d_half : (w + 1) * d, :] for w in range(W // d)])
output3 = cv2.hconcat([A, B])
cv2_imshow(output3)
print("===============================")
H, W = output3.shape[0], output3.shape[1]
A = cv2.vconcat([output3[h * d : h * d + d_half, :, :] for h in range(H // d)])
B = cv2.vconcat([output3[h * d + d_half : (h + 1) * d, :, :] for h in range(H // d)])
output4 = cv2.vconcat([A, B])
cv2_imshow(output4)
print("===============================")
H, W = output4.shape[0], output4.shape[1]
A = cv2.hconcat([output4[:, w * d : w * d + d_half, :] for w in range(W // d)])
B = cv2.hconcat([output4[:, w * d + d_half : (w + 1) * d, :] for w in range(W // d)])
output5 = cv2.hconcat([A, B])
cv2_imshow(output5)
print("===============================")
H, W = output5.shape[0], output5.shape[1]
A = cv2.vconcat([output5[h * d : h * d + d_half, :, :] for h in range(H // d)])
B = cv2.vconcat([output5[h * d + d_half : (h + 1) * d, :, :] for h in range(H // d)])
output6 = cv2.vconcat([A, B])
cv2_imshow(output6)
if __name__ == "__main__":
FileName = "bird.jpg"
picture = cv2.imread(FileName)
disassembly(picture)まとめ
今回は、オブジェクトの分裂方法や、画像の解像度を下げる方法を解説しました。なかなか面白い内容だったのではないかなと思っております。
また、解像度のお勉強にもなったと思います。今後も面白い内容を発信していきますので当ブログをよろしくお願いいたします。
無料の説明会を有効活用しよう!
独学での学習は孤独感を感じやすく挫折してしまう初心者も多いです。また、参考書を購入しても全く読む気にならないという方も多いはずです。
それでも、なんとかPythonの勉強を行い、高スキルなエンジニアを目指したいという方は無料で受けられるオンライン説明会に参加してみることも一つの手です。
Pythonというプログラミング言語は機械学習の人気の高まりなどもあり、様々なスクールが無料説明会を開催しています。
その中でも「Freeks(フリークス)|業界初!10,780円のサブスク型プログラミングスクール」がオススメです。Pythonを効率よく学びたいという方はまずは適性を知るためにも無料説明会を利用しましょう。
ナノトイラボ 
