どうも、7月にとあるプロジェクトの振り返り記事の前編を書いて以来、後半を書かずに4ヶ月経過している大里です。 冨樫先生を見習い、堂々と長期休載してゆく覚悟です。ウソです。
遅くなりましたが、11/14に行われた golang.tokyo #19 にブログ枠で参加させてもらいましたので、せっせとレポします。
テーマは 「golang × 画像処理」
(チラ裏に描いたgopherくん)
golang.tokyoでは毎回 golang×何らかのテーマ(テスト、並行処理、文字列処理…)とゆるくテーマが設定されていますが、今回のテーマは画像処理 でした。
我らが外資就活ドットコムでも、さる9月に 「外資就活相談室」という新サービスをリリースしました。
平たく言うと今流行りの質問箱のようなサービスですが、回答者は運営側で厳選しているため普段なかなか会うことの出来ないすごい社会人(+内定者)に誰でも気軽に質問できるよー、というのが好評を博しています。
質問箱系のサービスで必須なのがOGP画像ですね。
↓のように、「質問」を画像で、「回答」をTweetの本文で表現したりします。
よく言われていますが、ソフトウェア開発を労働集約的産業と捉えているから、というのが理由の1つであるように思います。(cf. https://t.co/OW1tq1sDTY…#外資就活相談室 https://t.co/3VB8k9wT26
— J.K (@J_K_AMA) 2018年10月25日
このOGP画像はgoで生成してるのですが、開発にあたり色々と苦労があったので、レポの後にその辺の話もチョロっと書きます。
会場はGunosyさん
みなさんご存知 Gunosy社は六本木ヒルズ森タワー内にあります。
何度か来てますが、僕は毎度 入館の仕方を忘れます。
着くの早すぎ、ほぼ一番乗り。
ウェルカムドリンク。青鬼があるあたり心憎いですね。
LTのタイムアップを知らせる用と思われる銅鑼(ドラ)。しかし鳴らすと近所迷惑にも程があるらしく、主催者さんの首が飛ぶらしいです。
発表×2、LT×4→解散
今回は懇親会パートなどは無く、ドリンクを飲みながら発表を聞く、というスタイルでした。 タメになったこと、気になったことなどザッと記していきます。
発表①: Head First Golang Image Package (@timakinさん)
- 相談室の開発で自分が経験したことととても近い内容の発表でした。
- 自分のやってたことが世間と大きくズレていなかったぽい、ということを確認できました。
発表②: Goにおける画像ファイル処理(@harukasanさん)
- そもそも「画像とは何か?」「人間とは画像をどのように認識するか?」という話。
- 人間は色情報より輝度情報に敏感なので、色情報は多少サンプリングしてもOKらしい。なるほど。
- JPEG、GIF、PNG、WebPなど、それぞれの画像フォーマットの歴史。
- golangの image.Image はどのフォーマットでも表現できるように上手いこと抽象化してくれてるぽい。
- なので、フォーマットの異なる画像を合成することができる。ふむふむ。
- 普通に実装しているとなかなかここまで深く知る機会は無いので勉強になりました。さすが画像を扱うプロ集団のPixivさんですね。
LT①: Go画像と東京アメッシュ(@otiai10さん)
- ターミナル上に画像を出す話。
- 一番熱量が高く、会場の笑いをさらってました。
LT②: goのimagemagickを使ってレンチキュラー写真を作ったハナシ(@junpaymentさん)
- ドット単位で打ち込み位置を計算すれば、2つの画像をマージしたレンチキュラー写真(見る角度によって絵が変わるアレ)も作れる、というアイデア作。
- やろうと思えばマジで何でも出来るんだなと勇気をもらいました。
- 「デジタルの世界と紙の世界は違う」という深い示唆を頂きました。
- 唯一
gographics/imagick
を使った事例を紹介されていて、トラウマが開く音がしました。
LT③: とあるライブラリをGoに移植した結果……(@makki_dさん)
- 移植駆動学習すごい、の一言。
- golangにまだ無いサードパーティ製のライブラリを見つけては他言語の実装に倣って移植すると学習が捗る。
- ついでに既存ライブラリのバグを見つけて修正PRを送るチャンスまである。
- 移植元のライブラリを叩けば入出力のペアを簡単に得られるのでテストを書きやすい。
- テストカバレッジを測るとどこが理解できてないか可視化出来る。
LT④: とあるgopherがOpenCVをさわってみた話(@usk81さん)
- CERNでPython→golangの乗り換えがあったらしい。
- 機械学習系でgoの機運?
- もれなくシュタゲを連想するなど。
- GoCVを使うと、集合写真を認識して個々人の顔だけ切り出したりできる。
- 「画像生成」だけじゃなくて「画像認識」もgoでできる、という啓示を得られた気分でした。
OGP画像をgoで作った時の苦労話
先述の通り、外資就活相談室のOGP画像をgoで実装しましたので、こぼれ話をいくつか紹介します。
ImageMagick を使って爆死
「golangで画像を扱うなら標準の image パッケージでしょ?」と、今なら言えます。そう、今ならね。
夏頃に「よっしゃ実装や!」と張り切っていた時、「golangでImageMagickを触りたい」という記事を発見。「これは天恵!」とばかりに、gographics/imagick
を使って実装を始め一通り完成に至りました。
しかしこの時、完全にデプロイのことを考えていませんでした。
外資就活のgoのAPIはAWS ECSのコンテナ上で動いているのですが、軽量な alpine
のコンテナ内にクロスコンパイルした実行ファイルをポンと置く、というシンプルな手順でデプロイしています。
gographics/imagick
は実行環境で apt-get install libmagickwand-dev
などして依存するライブラリをインストールしておく必要があるのですが、これでは「クロスコンパイルして実行ファイル置くだけ良い」というgolangの旨味をまったく享受できません。また、開発環境や実行ファイルのビルドには golang
イメージを 、本番での実行環境では軽量な alpine
イメージをと使い分けているため、開発環境と本番環境で動作が異なる可能性も出てきてしまいます。
さらに追い打ちのように「ImageMagickに脆弱性があるかも!!」というNEWSが飛び込んだため、ImageMagickとの訣別を決めました。
さよならっ!!!!
読みやすく改行するため禁則処理をライトに実装
Webページであれば文字の折返しはブラウザが良い感じにやってくれますが、画像に文字を埋め込むとなると画像から文字が溢れないように改行する処理も自前で実装する必要があります。
画像に対する文字サイズや余白の広さ、使用するフォントなどは仕様次第で変わるため、この辺はトライアンドエラーを繰り返してマジックナンバーを探し出す必要がありました。
そんなこんなで改行を実装した結果が↓左側です。
「ャ」や「、」などの文字が行頭に来てしまい読みづらいでです。英文に至っては英単語の途中で改行されてしまうため、とても読める状態ではありません…。
ここで必要になるのが 禁則処理 です。
ブラウザやワープロ系のソフトウェアに実装されているアレです。(このとき禁則処理という言葉を初めて知りました)
さすがにこんなニッチなライブラリをgoで見つけることは出来なかったため、自前で実装することにしました。
試行錯誤の末、以下の様なアルゴリズムで文章を改行可能な単位の文字列(ブロック)に分割しスライスに格納。
今度はこのブロックごとに行を組み立てていき、文字幅を計算して溢れそうになったら次の行を追加してまた結合…、を繰り返します。
画像にレンダリングした後の文字列の正確な幅を取得するのは骨が折れますが、全角/半角を考慮して大体の文字列幅を計算し、試行錯誤を繰り返して係数をチューニングしていけば、そこそこの精度で文字を置くことができます。
全角/半角を考慮した文字幅の取得には mattn/go-runewidth
を使わせて頂きました。ありがてぇ。
もちろん真面目に禁則処理を考えるとこんなにライトな実装ではツッコミどころ満載かとは思いますが、まぁ今のところ必要十分に機能しています。
まとめ
- golang.tokyoに参加するのは今回で3回目ですが、画像処理は直近で向き合っていたテーマだったのでいつも以上に深い理解を得られました。
Go書きたいエンジニア募集中!
ハウテレビジョンでは
- 「Goを書いてみたい」
- 「とにかくGoが大好き」
- 「好きすぎてgopher君に顔が似てきた」
- 「Goのことなんて全然好きじゃないんだからねっ!(好き)」
というエンジニアを絶賛採用中です!
ご興味ある方はぜひぜひ!、まずはカジュアル面談でお会いしましょう。
ご連絡はこちらから!