20201021のGoに関する記事は4件です。

Go Modules(vgo)について

Go Modulesとは

Goの依存関係管理ツールです。一昔前まではdepが多く使われていましたが、Go1.11から導入され、多く使われているそうです。

ちなみに、Go1.13から本格的に導入で、Go1.11~1.12は移行期ということなので該当している場合は、バージョンアップします。また、下記のコマンドで環境変数の確認をし、GO111MODULEonにすることでも使えるようになるようです。

$ go env
GO111MODULE="on"
GOARCH="amd64"
GOBIN=""
.
.
.  //下に続く

Go Modulesの使い方

実際にプロジェクトを作るところから一連の流れに沿っていきます。まず、任意のディレクトリで任意のディレクトリで新規にプロジェクトを作成します。

また、Go Modulesを使う場合、GOPATH外でも置くことは出来ますが、保存先はGOPATH下になるそうです。→参考記事
※推奨は$GOPATH/src/github.com/username/任意プロジェクト

(自分の場合: $GOPATH/src/github.com/username/testproject

mkdir $GOPATH/src/github.com/username/testproject

作成したプロジェクトに移動しgo mod initを実行します。

go mod init github.com/username/testproject

testprojectと同じ階層にgo.modというファイルが生成されると思います。

go.mod
module github.com/username/testproject

go 1.**  //各々のバージョン

ここにパッケージなどのgo getによるインストールが記させていきます。試しにGoのフレームワークである、Ginをインストールしてみます。

go get github.com/gin-gonic/gin

go.modファイルに追記があるはずです。適宜、他ファイルでインポートして使用します。また、新しくgo.sumというファイルも生成されます。ここに依存関係が記録されていきます。

go.mod
module github.com/username/testproject

go 1.**  //各々のバージョン

require github.com/gin-gonic/gin v1.6.3
go.sum
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14=
.
.
.  //下に続く

パッケージの削除

使用されていないパッケージは下記のコマンドで削除できます。また、そういった場合はエラーで教えてくれます。

go mod tidy github.com/gin-gonic/gin  //例

最後に

今回はGo Modulesについて最低限目ものして残しておきました〜。次はGoの基本型について何回かに分けて更新していこうと思います!ちょくちょく別の内容でもメモ残していくと思いますが!!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Go言語で簡単な画像処理のツールの類をつくってみた。

Go言語初学者です。普段の生息界隈はJS/TS+Javaですが、サーバーサイド言語の処理をもっと得意になりたいという理由から、今年からGo言語に挑戦しています。挑戦理由は「モダン, マルチスレッド, コンテナ関連での活躍」が挙げられます。

やはり、実際に何かを作って習得していくスタイルが自分には合っているので、今回は「画像処理」をテーマに、CLIとしてもAPIとしても使えるツールyellow-high5/pictarを作ってみました。画像処理といってもCNNを使って画像認識させるような高度なものではないです。

  

Go標準のimageパッケージ

まずはGo標準のimageパッケージがどんな仕組みになっているか簡単に確認してみました。

Point, Rectangle

座標点PointはintのXとYで構成されていて、長方形領域RectangleはPointのMinとMaxで構成されています。

image.png

Color

  • Alpha...透明度
  • CMYK...シアン、マゼンタ、イエロー、ブラック(Key Plate)で示した色の表現方法
  • RGB...レッド、グリーン、ブルーで示した色の表現方法
  • Gray..グレースケールはRGBだと3つの値全てが同じ値になります。

image.NRGBA

この構造体では画像をPixRed,Green,Blue,Alphaを繰り返す1次元配列として扱います。Strideとは画像の横一列分のサイズを表しています。

image.png

imagingライブラリを読んでみる

画像処理が専門領域ではない人間には、難しい計算式を理解できないのでライブラリを使用します。今回はdisintegration/imagingを利用します。ソース自体も簡潔にまとまっていて、とても読みやすいです。機能としては以下のようなことができます。

画像処理

  • adjust(調整)...グレースケール、反転、コントラスト、サチュレーション
  • convolution(畳み込み)...3x3圧縮、5x5圧縮
  • effects...ぼかし、シャープ
  • histogram(正規化されたヒストグラム)...256(16x16)の配列に明るさを表現する
  • resize...サイズ変更、切り抜き、スケール変更(fit)、サムネイル化
  • transform...反転(Flip)、転置(Transpose)、回転(Rotate)

補助ユーティリティ

  • io...画像読み込み、画像を開く、画像書き込み、画像保存、画像の向き(EXIFフラグ)の読み取り、変換、修正
  • scanner...長方形で指定された領域を読み込む
  • tools...新規画像作成、コピー、ペースト、透過
  • utils...parallel(並列処理)、その他ユーティリティ

番外編:画像処理の用語集

ツールを作るには、画像処理の用語をある程度理解しておく必要があると感じたので、知識を整理しておきます

  • HSV色空間...色相(Hue)、彩度(Saturation)、明度(Value)の3つからなる成分空間。原色の加減法混合で決まるRGB空間より直感的でわかりやすいらしいです。
  • HLS色空間...色相(Hue)、輝度(Lightness)、彩度(Saturation)の3つからなる成分空間。HSV空間と似ています。
  • 彩度...高いと画像の色が濃くなり、低いと画像の色が薄くなるイメージ。
  • コントラスト...高いと画像の明暗差がはっきりし、低いとぼんやりするイメージ。
  • 明度...高いと白っぽくなり、低いと黒っぽくなるイメージ。
  • ガンマ補正...素直な比例関係ではなく、人間の視覚特性に合わせたRGBの補正方法。
  • ガウシアンぼかし...シグマ値がぼかす量にあたる。
  • シグモイド関数...DeepLearningでは、「この画像に書かれている数字は1である確率」を算出するのにお馴染みの関数でしたが、画像処理ではコントラストを調整するのに使われているようです。

並行処理

disintegration/imagingでは、画像を処理する際に並行処理を利用しています。これにより比較的早い処理ができるようです。画像処理の速度について計測している方がいらっしゃったので、詳しく知りたい人はこちらを参考にすると良いかと思います。

OpenCV, GoCV, Go言語における画像処理のパフォーマンスの比較 - ZOZO Technologies TECH BLOG

では、このライブラリではgoroutineでどのような並行処理が施されているのでしょうか。ヒントは以下のparallel関数にありました。
  

imaging/utils.go
// parallel processes the data in separate goroutines.
func parallel(start, stop int, fn func(<-chan int)) {
    count := stop - start
    if count < 1 {
        return
    }

    procs := runtime.GOMAXPROCS(0)
    limit := int(atomic.LoadInt64(&maxProcs))
    if procs > limit && limit > 0 {
        procs = limit
    }
    if procs > count {
        procs = count
    }

    c := make(chan int, count)
    for i := start; i < stop; i++ {
        c <- i
    }
    close(c)

    var wg sync.WaitGroup
    for i := 0; i < procs; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            fn(c)
        }()
    }
    wg.Wait()
}

countは、実行する必要のある処理の数です。画像処理の例だと画素数や画像横一列分などがこれにあたります。
procsは、同時実行させる処理の数です。(デフォルトはCPUの数になっています。limitで同時処理するgoroutineの数を指定した場合はlimitが採用されます。)

チャネルにcount数の入力値を送信しておき、procs数のgoroutineがチャネルから入力値を受信し、渡された関数で並列的に処理させます。

  
以下にimaging.FlipH(画像の左右を反転させる処理)がどのような過程で並行処理して出力するのかを表した絵を描いてみました。

image.png

上の絵を実現しているコード
func FlipH(img image.Image) *image.NRGBA {
    src := newScanner(img)
    dstW := src.w
    dstH := src.h
    rowSize := dstW * 4
    dst := image.NewNRGBA(image.Rect(0, 0, dstW, dstH))
    // 画像の高さの数だけ並行処理の仕事をさせる
    parallel(0, dstH, func(ys <-chan int) {
        // 1行分の画素群を反転させる
        for dstY := range ys {
            // 反転時の場所に各画素を配置
            i := dstY * dst.Stride
            srcY := dstY
            src.scan(0, srcY, src.w, srcY+1, dst.Pix[i:i+rowSize])
            reverse(dst.Pix[i : i+rowSize])
        }
    })
    return dst
}

  

cobraでCLIツール

これらのライブラリをラップしてCLIをcobraを使って作成していきます。
まずはCLIをデザインする場合はそのコマンドで実行するサブコマンドとオプションを洗い出しておきましょう。さらに、オプションはグローバルで適用できるようにするのかも考慮しておくと良いです。

基本的にデザインパターンでいうところのビルダーパターンで作成しています。デザインの参考としてはcobraの実績でも取り扱われていますが、Hugoを模してみました。

hugo/commands GitHub

Hugoではサブコマンドを定義するときは以下のように定義します。

「hoge」というサブコマンドを定義する場合
package commands


//構造体でオプションを定義している
type hogeCmd struct {
  *baseBuilderCmd

  /*オプションを書き込んでいる*/
  ...
}

// コマンドビルダーでオプションを返している
func (b *commandsBuilder) newHogeCmd() *hogeCmd {
  // オプションの空インタフェースを定義
  cc := &hogeCmd{}

  // cobraでコマンド定義
  cmd := &cobra.Command{
        Use:   "hoge",
        Short: "Short Description",
        Long: `Long Description`,
    RunE: func(cmd *cobra.Command, args []string) error {...},
    }
  // サブサブコマンドがあれば、定義
  cmd.AddCommand(...)

  // オプションをフラグとして定義
  cmd.Flags().StringVarp(...)

  // ビルダーを登録しておく
  cc.baseBuilderCmd = b.newBuilderBasicCmd(cmd)

  return cc
}

コマンドビルダーに必要なサブコマンドを追加していけば完成していきます。コマンドビルダーの設計についてはこのファイルを見るとよく理解できます。

  

Ginで画像処理サーバー

画像をhttpでPOSTすると、画像を加工してオブジェクトストレージ(今回はS3)に保存するという機能を作成しました。加工内容は設定ファイルから読み込む仕組みです。アプリでプロフィール画像の登録やサムネイル作成などに使える機能を想定して実装しました。

Ginのロジック

Go製のWebフレームワークであるGinのGoDocを読んで大雑把に絵にしました。かなり端折ってしまっていますが、簡略化するとこんな感じかと。処理をHandlerFunc(ミドルウェア)でつないで、HTTPリクエストからHTTPレスポンスを返すロジックを作成しているようです。

↓イメージ
image.png

  • Engine...フレームワークのインスタンス(gin.Default()あるいはgin.New()で生成される)
  • Context...最も重要な部分。受け取ったリクエストからレスポンスを返すまでの情報を保持する。
  • HandlerFunc...処理ロジック(Dファイル処理からロギングまで多様な処理を記述できる)
  • HandlersChain...処理ロジックを集めた配列。一連の処理の流れを作るチェーン。
  • RouterGroup...処理ロジックとURIのエンドポイントを繋ぐ

HTTP処理をミドルウェアチェーンで表現するあたりは、Node.jsのExpressとよく似てます。

S3へのファイルアップロード

脱線しましたが、本題のファイルアップロードの処理に話を戻します。処理の流れは大まかに3ステップ。

  1. HTTPリクエストボディで指定されたクライアントからの画像を読み込みサーバーのファイルシイステムへ保存。
  2. 読み込んだファイルをimagingライブラリで加工処理する。
  3. 加工処理を施した画像ファイルをS3へアップロードして、成功ステータスを返す。

Goへのファイルアップロードについては以下を参考にしました。詳細な設定を行う場合はAmazon Web Services - Go SDKを参考にしてください。

Go言語(golang)でS3へファイルをアップロードする | Developers.IO

viperを使えば、オブジェクトストレージの接続設定や画像の保存名など詳細設定をの設定ファイル(config.jsonなど)に外出しすることも可能です。

  

まとめ

調べていくうちにGinの実績でも紹介されているGo製の画像処理サーバーが見つかりました。

こちらの方が私のような初心者なんちゃってツールより流石によく設計されています。サービス実装で作るときは遠慮なくこちらを使おうと思いました。自分で作ろうとしていたものの解が見つかると学習がより深まります。

  

  
  
とりあえずは、Goの標準パッケージや並行処理を使いこなせるようになるのが自分の課題だと感じました。Goのパッケージ類は見通しがよく、あまり疲れないのでしばらく鍛錬できそうです。
  
  

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Golangのinterface型

interface型

  • あらゆる型と互換性のある型
  • Objectクラスのようなもの
  • あくまで、全ての型の値を汎用的に表すものなので、演算などはできない
main.go
package main

import (
    "fmt"
)

func main() {
    var x interface{}
    fmt.Printf("%#v", x)
}

出力すると、となる。
int型では0が初期値としてセットされるが、interface型ではnilとなる

$ go run main.go 
<nil>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Go】WSL2にGoをインストールする手順

WSL2にGoをインストールする

いままでWindowsにインストールしたGoを使用してたけどどうせならWSL2で開発したいのでWSL2にGoをインストールしてみる

実行環境

OSはWindows 10 Pro 64bit (バージョン2004 OSビルド19041.572)
WSL2でOSはUbuntu-20.04

1.インストーラーをダウンロードする

まずはDownload and install - The Go Programming Language を開き「Linux」を選択し、Linux用のインストーラーをダウンロードしてくる。

FireShot Capture 139 - Download and install - The Go Programming Language - golang.org.png

この時にダウンロードしてきたインストーラー(例では go1.15.3.linux-amd64.tar.gz)を自分のわかりやすいところへ移動しておく

2.WSLを立ち上げる

次にコマンドプロンプトかWindowsのターミナルを開き、wslコマンドを実行してWSLを立ち上げる

Microsoft Windows [Version 10.0.19041.572]
(c) 2020 Microsoft Corporation. All rights reserved.

C:\Users\sola>wsl
root@sola-pc:/mnt/c/Users/sola#

3.公式サイトに記載されてるコマンドを実行する

無いとは思いますが予めGoがインストールされている場合はアンインストールしておいてくださいとのこと

まず以下のコマンドで/usr/local 以下に展開
※先ほどダウンロードしてきたインストーラー(例では go1.15.3.linux-amd64.tar.gz)を置いた場所へ移動してから実行すること

tar -C /usr/local -xzf go1.15.3.linux-amd64.tar.gz

4.ルートへ移動後エクスプローラーを立ち上げる

終了後、ルートへ移動し、そこでエクスプローラーを立ち上げる

root@sola-pc:/mnt/c/Users/sola# cd ~
root@sola-pc:~# explorer.exe .
root@sola-pc:~#

explorer.exe . を実行すると以下のようなエクスプローラーが立ち上がる

スクリーンショット 2020-10-21 132322.jpg

(※環境によってファイルなどに差異はあるとおもいますので、あくまでこんな感じのディレクトリが開かれるというイメージで見てください)

5.環境変数の設定

.bashrcをテキストエディタで開き、以下の行を追加し保存する。

export GOROOT=/usr/local/go
export GOPATH=$HOME/go
export PATH=$GOPATH/bin:$GOROOT/bin:$PATH

その後、コマンドプロンプトorターミナルを再起動させて再度WSLを立ち上げる

6.Goがインストールされているか確認

wsl コマンドで立ち上げたのち、go versionでインストールされているか確認しておく

Microsoft Windows [Version 10.0.19041.572]
(c) 2020 Microsoft Corporation. All rights reserved.

C:\Users\sola>wsl
root@sola-pc:/mnt/c/Users/sola# go version
go version go1.15.3 linux/amd64
root@sola-pc:/mnt/c/Users/sola#

参考URL

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む