Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
2
Help us understand the problem. What is going on with this article?
@jyuko

Minecraft Pi Editionで画像をブロック化して描画する

More than 3 years have passed since last update.

前回の記事でラズパイを購入して、まだBluetoothしか使っていない訳ですが、私は気付いていました。
そう、Raspbianにマインクラフトがインストールされていることを!

マイクラやってみたかったので、少し遊んでみます。

Minecraft Pi Edition

まとめサイトを見つけました。
https://matome.naver.jp/m/odai/2142545327953860701

Pi Editionの特徴は、以下のようです。

  • 無料
  • プログラミング機能あり
  • クリエイティブモードのみ
  • ワールドの広さに制限
  • クラフト不可

サバイバルモードを有効にする非公式のパッチはあるみたいですね。
平面の広さが256×256しかないので、プログラミングして遊んで、本格的にやりたくなったらPC版を買う感じかな。

公式のドキュメントもプログラミングすること前提で書かれているみたい。

作るもの

256×256と聞いて思い浮かぶのは、地図タイルですね!(職業病)
https://en.m.wikipedia.org/wiki/Tiled_web_map

試しに、地図タイルを描画してみましょう。

使ったもの

  • Minecraft Pi Edition v0.1.1
  • Python 2.7.9
  • python-opencv 2.4.9

Python3系が使えるかわからなかったので、Python2系にしました。

実装

OpenCVで画像を読み込んで各ピクセルのRGB値を調べ、その色に近いブロックを置いていきます。

OpenCVのインストール

以下の記事にある手順でインストールできました。
http://qiita.com/suppy193/items/91609e75789e9f458c39

$ sudo apt-get update
$ sudo apt-get install libopencv-dev
$ sudo apt-get install python-opencv

画像の読み込み&ピクセルのRGB値を取得

OpenCVを使えば簡単です。

import cv2

img = cv2.imread('image.png')

column = 10
row = 20
pixel = img[column, row]
print(pixel)

上記を実行すると、以下のような出力になります。
RGBではなく、BGRの順になっています。

>>>
[ 57  70 255]

近い色のブロックを置く

16色に塗り分けられるwool(羊毛)を使います。
各色のRGB値は、以下に記載されていました。
http://minecraft.gamepedia.com/Wool

ブロックを置くためのコードは以下のような感じです。
実行すると、プレイヤーの足元にあるブロックがオレンジになります。

from mcpi import minecraft
mc = minecraft.Minecraft.create()
x, y, z = mc.player.getPos()

wool = 35
selectedColor = 1 # Orange
mc.setBlock(x, y-1, z, wool, selectedColor)

各ピクセルにどの色を使うかですが、RGB値の差をnumpy.linalg.normで求めて、最も差が小さい色を使うことにします。

dist = numpy.linalg.norm(woolColor - pixel)

ループさせて画像を描画する

RGB値に近い色のブロックを置く処理をループさせ、画像の各ピクセルをブロックに変換します。

最終的なコード全文は、以下です。

minecraft.py
from mcpi import minecraft
import cv2
import numpy

mc = minecraft.Minecraft.create()

wool = 35

# wool color BGR
woolColors = [
    [221,221,221],  # 0: White
    [62,125,219], # 1: Orange
    [188,80,179], # 2: Magenta
    [201,138,107], # 3: Light blue
    [39,166,177], # 4: Yellow
    [56,174,65], # 5: Lime
    [153,132,208], # 6: Pink
    [64,64,64], # 7: Gray
    [161,161,154], # 8: Light gray
    [137,110,46], # 9: Cyan
    [181,61,126], # 10: Purple
    [141,56,46], # 11: Blue
    [31,50,79], # 12: Brown
    [27,70,53], # 13: Green
    [48,52,150], # 14: Red
    [22,22,25] # 15:Black
]

img = cv2.imread('image.png')
img = cv2.resize(img, (256, 256))

height, width = img.shape[:2]
x, y, z = mc.player.getPos()

for column in range(width):
    for row in range(height):
        pixel = img[column, row]

        selectedColor = 0
        minDist = None
        for i, woolColor in enumerate(woolColors):
            dist = numpy.linalg.norm(woolColor - pixel)
            if  minDist == None or minDist > dist:
                minDist = dist
                selectedColor = i

        mc.setBlock(-153+row, y-1, -116+column, wool, selectedColor)

mc.postToChat("Create Image")

x,z座標はワールド端を基点にしているのですが、何故か[-153,-116]でした。
y座標はプレイヤーの位置から-1して、プレイヤーが立っている平面にブロックを並べています。

実行結果

Minecraft Pi Editionを起動した状態で、Pythonのスクリプトを実行します。
「F5」キーを押すか、"Run" > "Run Module"で実行できます。

65,536ピクセルを16色と比較しているため、結構時間が掛かります。
気長に数分待ってください。

元画像は、OpenStreetMapの地図タイル(渋谷駅周辺)を使ってみました。

IMG_1436.jpg

IMG_1438.jpg

© OpenStreetMap contributors
http://www.openstreetmap.org/copyright

カメラワークの都合上、全体を一度に見渡すことはできません。
アイコンの形はしっかり出てますが、注記の文字はがんばってなんとか読める程度まで崩れています。
また、淡いグレーや淡いブルーが白のブロックになってしまい、建物や敷地の境界が消えてしまったので、地図としてはちょっと微妙な結果になりました。

まとめ

シンプルなロジックで思ったよりも描画できていますが、いかんせん色数が足りない印象です。
wool以外のブロックも使って、不足している色を割り当てれば画質はよくなりそうですが、さらに処理時間が増えるので考えものです。

オマケ(本編)

256×256のサイズありきで地図タイルを試したんですが、縦横が同じピクセル数の画像であれば、OpenCVでresizeしてから処理すればいいんですよね。(コード例にも仕込んでます)

で、Twitterアイコン用に配布されている画像って、正方形で解像度も小さいじゃないですか。

適当に読み込んでみましょう。

IMG_1441.jpg

IMG_1442.jpg

IMG_1443.jpg

こっちの方が全然上手く描けてるじゃん!

髪や肌など、色の淡い部分が白ブロックになってしまう傾向は変わりません。肌色や茶色に近いブロック(SandstoneやStaind Clay)を足すといいかもしれないですね。

2
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
jyuko
新潟県長岡市出身。たぶんWeb系エンジニア。 マイブーム:A-Frame、Tango、ドローン、好きなAWS:CloudFront、Lambda

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
2
Help us understand the problem. What is going on with this article?