Hello World / plɹoM ollǝH

Programmers Live in Vain

cv2 voronoi mosaic in python

Python版のサンプルが意外となかったのでメモ

Input Output
f:id:dungeonneko:20200224042947p:plain:w240 f:id:dungeonneko:20200224042958p:plain:w240
import cv2
import numpy as np

def voronoi_facets(in_img, in_k):
    h, w = in_img.shape[0], in_img.shape[1]
    subdiv = cv2.Subdiv2D()
    subdiv.initDelaunay((0, 0, w, h))
    points = np.append(np.random.rand(in_k) * (w - 1), np.random.rand(in_k) * (h - 1)).reshape((in_k, 2), order='F')
    points = np.append(points, ([0, 0], [w - 1, 0], [0, h - 1], [w - 1, h - 1]), axis=0)
    subdiv.insert(tuple(map(tuple, points)))
    return subdiv.getVoronoiFacetList(None)


def polygon_color(in_img, in_polygon):
    c = 0
    i = 0
    h, w = in_img.shape[0], in_img.shape[1]
    for v in in_polygon:
        x, y = int(v[0]), int(v[1])
        if (w > x >= 0) and (h > y >= 0):
            c += in_img[y][x].astype(float)
            i += 1
    return c / i if i > 0 else 0


if __name__ == '__main__':
    img = cv2.imread("lena.png")
    dst = np.zeros(in_img.shape, np.uint8)
    polygons, centers = voronoi_facets(img, 512)
    for p in polygons:
        c = polygon_color(img, p)
        cv2.fillConvexPoly(dst, points=np.array(p).reshape((-1, 1, 2)).astype(np.int32), color=c)
    cv2.imwrite("result.png", img)
参考(C++

aa-deb.hatenablog.com

PySide drag start from QPushButton

Qt (PySide) は一部のWidget以外でドラッグ開始を実装しようとすると意外と面倒
ググると大体受け入れる側のサンプル出てきちゃうし

class MyButton(QPushButton):
    def __init__(self, parent):
        super().__init__(parent)
        self._startPos = QPoint()

    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            self._startPos = event.pos()
        super().mousePressEvent(event)

    def mouseMoveEvent(self, event):
        if 0 != (event.buttons() & Qt.LeftButton):
            if (event.pos() - self._startPos).manhattanLength() >= QApplication.startDragDistance():
                self.startDrag()
                self.setDown(False)
                return
        super().mouseMoveEvent(event)

    def startDrag(self):
        drag = QDrag(self)
        mime = QMimeData(self)
        mime.setText('hogehoge')
        drag.setMimeData(mime)
        drag.start(Qt.CopyAction)

QToolButtonなどでも同様
mousePressEvent, mouseMoveEventあたりが継承できるWidgetはこれでいけそう

Unityの回転値を右手座標系に変換

まず平行移動のX方向が逆なのでxに-1を掛けます

trans.x *= -1.0f;
return glm::translate(glm::mat4(), trans);

回転値はZXYオーダーで、ZとY回転に-1を掛けます

glm::mat4 m;
m = glm::rotate(glm::mat4(), -rotate.z, glm::vec3(0.f,0.f,1.f)) * m;
m = glm::rotate(glm::mat4(), +rotate.x, glm::vec3(1.f,0.f,0.f)) * m;
m = glm::rotate(glm::mat4(), -rotate.y, glm::vec3(0.f,1.f,0.f)) * m;
return m;

あとはお好きにどうぞ

ここがクソだよ Insta360 GO(修理手続き編)

前回、買ったその日にレンズに傷を付けてしまい、修理手続きしたのでその記録

TLDR

Insta360 GOはレンズ修理できない本体取り寄せ

本体99USD+送料17USD

1. 私がとった手順

真似しないほうがいいです

公式サイトに修理用の入力フォームが用意されていたので
とりあえず手順に従って入力を進めようとしました

https://www.insta360.com/support/workorder

しかし日本で購入した場合は「RMA Code」という欄の入力を要求されます
サポートにメールで教えてもらえって書いてあるのでメールします

f:id:dungeonneko:20200108131306p:plain

以下やりとり(実際には英文メールだと思ってもらえればと)

Insta360 GOを修理してほしいのですが、修理フォームを入力してたらRMAを入力してくれと言われました。どうしたら良いでしょう?

~半日後~

サポート

連絡ありがとうございます。もう症状を少し詳しく教えてください。 Insta360 GOは中身が複雑で外部要因の故障は修理できないため新品への取り替えになります。 本体のみの場合は99USDです。

地面に落としてレンズに傷が付いてしまいました。他に問題はありません。 私にはどんな選択肢が用意されているのでしょうか?

(え?1回の往復に半日かかるの?)

~さらに半日後~

サポート

残念ながら本体取り寄せになります。

本体の支払いが必要なのは理解しました。 早速取り寄せてほしいのですが、私は何をしたら良いでしょう?

~1日経過~

サポート

このアカウント(paypal/XXX)にペイパルで支払ってスクショを添付してください。
それから、名前と発送先の住所と電話番号を教えてください。
とくに問題がなければカメラ本体を発送します。

ありがとうございます。これがスクショと名前と住所と電話番号です。
よろしくお願いいたします。

2. どうすべきだったか

さすがにメールで3日かかるとは思いませんでした。ただの被害妄想かもしれませんが、実際のメール対応はもうちょっとダラダラした感じが文面から滲み出ています。中華対応舐めてました。

次に本体取り寄せするときは1往復で終わるように

I dropped my Insta360 GO and the lens has been scratched, so I want to replace it with new one. Please tell me where to pay for the replacement and what information I need to provide. (本体のスクリーンショット

などとメールで書くか、チャットで直接サポートスタッフに連絡するようにしたいですね。ともあれ、これで傷アリの本体が手元に残ったので、こっちは何も気にせず乱暴に扱っていきたいと思います。

ここがクソだよ Insta360 GO

辛口レビュー

いいところはあちこちで散々書かれるので私がクソな点をまとめます
YouTuberの販促動画だけ見て買って不幸になる人(私)がでないようにするためです
まだ買ったばかりなので、使い込んでみての感想はまた別に書くかもしれません

TLDR

Don't Buy.

1. 一度地面に落としたら最後。高確率でレンズに傷がつく

買ったその日に落としましたわ

レンズには傷が付いて、撮影した動画はモヤモヤしたゴミが映る感じになりました
(只今、修理手続き中です)

Insta360 GOは180度撮影するカメラなのでレンズが割と出っ張っています

まぁそれはいいのですが、レンズは強化ガラスでも何でもないようで、本体が18gしかないにもかかわらず傷が付きやすいようです

f:id:dungeonneko:20200108010321j:plain
レンズ上部に傷が付いてしまいました

Insta360 Careというサービスに入っていないと購入直後でも修理は有料っぽいです

Insta360 Careに入るには
公式Webサイトから購入しないといけない

っぽいので、保証が欲しい人は公式サイトから購入したほうが良いでしょう
Insta360 Careに入ると1年間保証が付くようです

Insta360 | Action Cameras | 360 Cameras | VR Cameras

私はAmazonで買ってしまったので、速攻で保護ケースも買いました

2. ペンダントが安心して使えない

Insta360 GOは磁石がくっつくペンダントを服の下に提げて、本体だけ服の上からカチッとつけられるというスマートな見た目がポイントなのですが

これがだいぶ危なっかしい

私がInsta360 GOを落としてレンズを割ったときは

  • 薄いウインドブレーカーの下にペンダント
  • ウインドブレーカーの上から本体

だったのですが、服を引っ張ってしまったのが落下の原因になったようでした

f:id:dungeonneko:20200108023313g:plain
引っ張るとすぐ取れてしまいます

摩擦や紐の範囲外への移動にはかなり弱いわけですね。ペンダントの紐は伸縮性がないので、首から提げた状態で下方向に服か本体をずらしたら一発アウトです

伸び縮みする紐にして欲しいですね

3. 充電ケースが使いづらい

3-1. iPhoneユーザーはスマホケース使ってるとデータ転送できない

充電ケースはlightinig端子がニョキっと伸びていて、普段は(本体バッテリーがそんなに持たないので)充電ケースにいれて持ち歩きます

f:id:dungeonneko:20200108011018j:plain
端子の部分にはカバーが付いてます

f:id:dungeonneko:20200108011054j:plain
短っ

撮影したデータをスマホに保存するには充電ケースごと端子で接続しないといけないのですが iPhoneスマホカバーをつけている人はそのまま接続することができません

データ転送に充電ケースごと有線接続要求する意味ある?

f:id:dungeonneko:20200108024925j:plain
これで高速データ転送とかしてるんですかね?

とりあえずlightinig延長コードを買おうと思ったのですが、まともそうな商品なかなか見つからず。apple純正品の延長コードってないんですかね?

3-2. 入れる向きを間違えると充電&認識されない

最初買ったときはこれが全然わからなくて「全然認識されないなー」とか言ってイライラしていました。今はそれがわかったので、そのクソデザインにイライラしてます

めちゃくちゃ取り出しづらいです

少し手が乾燥していたり、油っぽかったりするともうイライラが止まりません

f:id:dungeonneko:20200108005422g:plain
反対向きにつけてしまうとさらに厄介

ペンダントのときは微妙な磁力だったくせに…

  • なんで間違った方向でもピタッとハマるデザインにしたの?
  • どっちでも接続できるようにするとか
  • 接着したままグルっと回せるようにするとか
  • 指を掛けやすくしとくとかさぁ、やりよういくらでもあるじゃん?

設計者への疑問は尽きません…

f:id:dungeonneko:20200108005241g:plain
ちなみにカバーも取り外しずらい

3-3. 充電ケースの充電はUSB繋がないといけない

1つの製品をiPhoneAndroid両方のユーザーに売ろうとした結果がこれ

f:id:dungeonneko:20200108005935j:plain
iPhoneだと充電にしか使わないUSB端子(メス)

結局USBケーブルいるなら充電ケースからlightning端子出てる意味ある?

せめてそのUSBからlightningの充電と本体に接続できる変換ケーブルを付けて欲しかった

4. 本体の状態がわかりづらい

撮影中?電源ON?スリープ中?

本体のLEDが一応点灯したり点滅したりしてるんですよね

f:id:dungeonneko:20200108022347g:plain
撮影が始まって点滅するLED

本体身に付けてたら LED見れないので 意味ないですけどね

f:id:dungeonneko:20200108022216j:plain
撮影者視点

覗き込んだら自分の顔映るし

まとめ

散々Disってきましたが、コンセプトや本体の見た目は素晴らしく、今のところライフログ系では代替が効かない製品なので、今後の改良(またはライバル出現)に期待しています

改善してほしい点
  • レンズを強化ガラスにして
  • データ転送時に有線接続を求めないようにして
  • 意味不明な充電ケースの端子減らす
  • ペンダントの紐には伸縮性を持たせて
  • 充電ケースと本体は簡単に分離できるようにして
  • 本体の状態は撮影者にわかりやすく伝えるようにして
  • シリアルコードトラッキングするなら年間保障標準で付けてください

どうしても使ってみたいっていう人は、借りるとか中古で買うとかして気に入ったら中古を買値で売って、Insta360 Care付きで新品買えば良いと思います

追記:10ヵ月使用した後の感想もあわせてどうぞ dungeonneko.hatenablog.com

Tech Toolbox for Game Programmers @GDC2016

せっかくだから俺はこの動画を要約するぜ

www.youtube.com

1. The Poor Man's Dialogue Tree

お金を掛けないダイアログツリーの作り方

普通のやり方
  • Unityのアセットストア等で買うと高い
  • サードパーティ製(本当に必要なものではない可能性がある)
  • 退屈!(人にやらせるなら楽しい仕事のほうがいいよね)
  • 大量のデータを作るためにちゃんとしたツール(GUIなども)を用意してあげる必要がある
  • パフォーマンス重要でゲームのコードも共有する必要がでてくる(C++C#
我々のやり方
  • 8割問題を解決するための2割(本当に必要なもの)を自分で書く
  • HTML5クロスプラットフォーム、実装簡単、パフォーマンスは重要じゃない、色々なライブラリが使える、JSONみんな使える)
  • JointJSとNW.jsを使ってノードグラフが動くデスクトップアプリを作成
  • NW.jsつかえばファイルリネームするだけでデスクトップアプリができるのでめっちゃ便利
  • ファイルフォーマットは3種類用意(編集用JSON、最適化JSONローカライズ用のテキストをxlsxに)
  • なぜExcelか→テキストデータがExcel形式だと有志に手伝ってもらいやすい
まとめ

2. Automating Data Implementation With IDs

Darkest Dungeonでどのようにデータが実装されたか

  • Darkest Dungeon → ターンベースRPG、プロシージャル。プログラム2人。C++の内製(?)エンジンとミドルウェア
  • 定義したIDから必要なデータ(ファイルパス)やコードが自動生成される
  • コード生成はマクロとプリプロセッサ

特別なことはしてないけど、ゲーム内容にあった実装を正しく選択した感じ

3. Tracery - generating texts, graphics, and more!

自動生成システムTracery.jsの紹介

  • SporeとかSimCityにも携わったKate Compton(@galaxykate)さん、プロシージャルコンテンツ生成をしている
  • Tracery最初はテキスト生成のToyを作ろうと思ったが、多目的言語ができて、TwitterBotを作るサービスができた
  • Botで絵文字(AA)や画像を自動生成する人もでてきた
  • ゲームにも使えるんじゃないですかね?ストーリー、音楽、コードの自動生成等々

機能

  • ハッシュタグで囲まれた文字列をルールに沿って置換する({"greetings": ["hello", "nihao"], "origin": "#greetings#, World!"}的な)
  • 再帰的置換、テキストのモディファイア(例:複数形への変換)、生成されたテキストの保存と再利用

4. Putting the "Game" in "edi-game-tor"

A Good Snowman Is Hard To Build のレベルデザインPuzzleScriptを使ったよという話

  • ほとんどのゲームはレベルエディタが必要
  • 「外部ツール 」か「ゲーム内エディタ」のどちらかを選択する
  • 第三の選択として「エディタ内のゲーム」がある → PuzzleScript
  • イテレーションを加速する既存のツールを使おう

5. Making Your Own Tools & Hiden Benefits

自作ツールの隠れたメリット

  • 何故自作ツールが必要なのか→「とにかく始められる&レベルデザイン」にフォーカスしすぎで「システムの理解とオーサリング」が足りない
  • ゲームロジックとデータを可視化して、チームで問題を素早く解決したい
  • imguiがめっちゃ便利
  • ツールはドキュメントの代わりになる(常に最新&ナレッジも共有される)

C++でインゲームGUIつくるならimgui一択か

程々に快適なゲーミングPCを5万円台で組む

経緯

GPD POCKET(初代)のバッテリーが膨張してしまったので、もうUMPCは懲り懲りということで久しぶりにデスクトップPCにしようと思い立ちました。ゲーム制作&遊ぶ用に安くてある程度3Dゲームも動くPCを探そうと思いましたがどれも予算オーバーなのでコスパが良いという噂のRyzen自作PCを組んでみることに(十数年ぶりN回目)。久しぶりの自作PCで苦労したくないので日和ってベアボーン買いました。

用意したもの(合計¥54,974)

マザボ ¥17,156

CPU ¥16,920

AMD CPU Ryzen 5 2400G with Wraith Stealth cooler YD2400C5FBBOX

AMD CPU Ryzen 5 2400G with Wraith Stealth cooler YD2400C5FBBOX

  • 発売日: 2018/02/13
  • メディア: Personal Computers

メモリ ¥13,338

DDR3しか持ってなかったので仕方なく買った

SSD ¥7,560

これも本来ノートPCの部品を流用する予定だったがMNVeではなくAHCIだったので購入

キーボード ¥0

家にあったものを使用

マウス ¥0

家にあったものを使用

OS ¥0

使っていないPCのWindows10ライセンスを移行して事なきを得た

ライセンス移行手順メモ

  1. 移行元PCでUSBメモリ(8GBくらいでOK)でWindows10のインストールメディアを作成する
  2. 移行元PCのログイン方法をWindowsアカウントに切り替えてログインしておく
  3. 移行先PCにUSB挿して起動→インストール→同じアカウントでログイン
  4. 移行先PCで設定→ライセンス認証→このデバイス上のハードウェアを最近変更しました→まだ怒られる
  5. 移行元PCでプロンプトから「wmic path softwarelicensingservice get OA3xOriginalProductKey」でプロダクトキー表示→移行先PCに入力して移行完了

承認されてなくても起動できてWebからライセンス購入もできるっぽいですね

LANケーブル ¥0

家にあったものを使用。Wifi Kitを買うのが癪だったのでケチった(でも¥3,000くらい) [asin:B07MGHCN61:detail]

PCモニタ¥0

家にあったものを使用

まとめと反省

数年間UMPCの沼にどっぷり浸かってたせいで、メモリもストレージも使いまわせずに予想外の出費でした(普通にノートかデスクトップ使ってれば3万円くらいで済んだよね…)。とりあえず1080pでApex Legendsも普通に動きますし、YouTubeAmazon Prime Videoもサクサクだし良しとしましょう。今度はもっとお金を使わずに地を這って必要なものを手に入れていきたいと思いました。

追記(購入後にやること)

ドライバのインストール

ヘッドホン挿しても音が出ないなーと思っていたらRealtek入れてなかった https://www.asrock.com/nettop/AMD/DeskMini%20A300%20Series/index.jp.asp#Download