- 投稿日:2020-01-17T23:25:16+09:00
GoCVを用いてGoで集めた画像で壁紙を作ってみました
概要
集めた画像からGo言語を用いて集めた画像から壁紙を作ってみようと思います。ライブラリとしてはGoCVを利用してみました。
以前、同じことをPythonとJuliaで行いました。実際にコードを書いてみた私的な感想としては、PythonやJuliaで書いたほうが書きやすかったですね...( *´艸`)
実行環境
- Windows10 Pro
- go version go1.13.1 windows/amd64
- OpenCV 4.1.2
- GoCV
GoCVのインストール方法
画像を操作するためにGoCVを利用するために事前に準備する必要があります。以下の公式サイトのインストール手順に従っていけばインストールできると思います。
注意点としては上記のセットアップの途中で再起動しないと認識されない場合がありました。
ソースコード
パッケージのインポート
package main import ( "fmt" "gocv.io/x/gocv" "image" "image/jpeg" "os" "path/filepath" "math/rand" "log" "strconv" "time" )指定した範囲で被りなしの整数を生成するための関数
以下のリンクを参考にさせていただきました。
- min-maxの範囲からn個の整数をランダム抽出する方法(ただし重複は含まない)func allKeys(m map[int]bool) []int { i := 0 result := make([]int, len(m)) for key, _ := range m { result[i] = key i++ } return result } func pickup(min int, max int, num int) []int { numRange := max - min selected := make(map[int]bool) rand.Seed(time.Now().UnixNano()) for counter := 0; counter < num; { n := rand.Intn(numRange) + min if selected[n] == false { selected[n] = true counter++ } } keys := allKeys(selected) // sort.Sort(sort.IntSlice(keys)) return keys }実際の処理
func main(){ startT1 := time.Now() datapath := "../../../100.data/1.Input/photo/fankiru/*.jpg" dirpath := "../../../100.data/2.Output/go/photo/fankiru/" files, err := filepath.Glob(datapath) if err != nil { log.Fatal(err) } name := "fankiru" sizeHeight := 3024 sizeWidth := 4032 rh := 5 rw := 9 rowSize := int(float64(sizeHeight) * float64(rh)) colSize := int(float64(sizeWidth) * float64(rw)) outputImg := gocv.NewMatWithSize(rowSize, colSize, gocv.MatTypeCV8UC3) for count := 1; count <= 100; count++ { selectnums := pickup(0, len(files)-1, rh*rw) selectnum := 0 for row := 0; row <= sizeHeight * rh - sizeHeight; row += sizeHeight { for col := 0; col <= sizeWidth * rw - sizeWidth; col += sizeWidth { img := gocv.IMRead(files[selectnums[selectnum]], gocv.IMReadColor) if img.Empty() { fmt.Printf("cannot read image \n") return } defer img.Close() rect := outputImg.Region(image.Rectangle{ image.Point{X: col, Y: row}, image.Point{X: col + sizeWidth, Y: row + sizeHeight}, }) img.CopyTo(&rect) selectnum++ } } image, err := outputImg.ToImage() if err != nil { log.Fatal(err) } if err := os.MkdirAll(dirpath, 0777); err != nil { log.Fatal(err) } file, err := os.Create(dirpath + name + "_" + strconv.Itoa(count) + ".jpg") if err != nil { log.Fatal(err) } defer file.Close() jpeg.Encode(file, image, &jpeg.Options{ Quality:100, }) } endT1 := time.Now() fmt.Printf("making wallpaper done %f[sec]\n", (endT1.Sub(startT1)).Seconds()) }出力された画像
イベントで撮影してきた写真を素材にして、以下のように出力されました。生成された画像の解像度が大きすぎたので縮小した画像を載せました。
感想
GoCVを利用すれば私のやりたかったことはできました。しかし、やはりPythonやJuliaのほうが書きやすかったですね。ただ、通常の画像処理で利用するならGoCVでいろいろできそうだなーと思いました。
- 投稿日:2020-01-17T20:06:13+09:00
Goの環境構築
Go 開発環境構築
最近Goの勉強をはじめました。
このあたりは、ググったら同じような記事が出てくるので、自分の備忘録も兼ねて記事にしています。
便利なパッケージ等があったら更新していくかもしれません。
ほんの少しでも、Goを始めようと思っている方への力になれたら幸いです。環境
- macOS Mojave (10.14.6)
- zsh
- Homebrew 2.2.1
- IntelliJ IDEA
Go のインストール
- Homebrew でインストール
% brew install go
- バージョン確認
# バージョンの確認 % go version go version go1.13.5 darwin/amd64 # GOROOTの確認 % go env GOROOT /usr/local/Cellar/go/1.13.5/libexec # GOPATHの確認 % go env GOPATH /path/to/gopathIntelliJ の設定
プラグインのインストール
Preferences > Plugin
から、JetBrains 製の、Go のプラグインをインストールGOROOT の設定
Preferences > Language & Frameworks > GO > GOROOT
で設定する。GOPATH の設定
Preferences > Language & Frameworks > GO > GOPATH
で設定する。
go get
のパッケージダウンロード先を指定する。
デフォルトは$HOME/go
が自動的に指定される。パッケージを探す
Goのパッケージは以下のサイトなどでドキュメントが見れるので、検索すると良さそう。
https://godoc.org/Docについて
いろいろ調べてまとめようとしたが、この記事を読んでおいたら良さそう。
とても勉強になりました。ありがとうございます?
チョットできるGoプログラマーになるための詳解GoDoc最後に
Goの環境構築、思っていたよりも簡単にサクッとできました。
環境構築の際にぶつかる壁がほとんどないので、よかったら始めてみてください!
- 投稿日:2020-01-17T13:27:47+09:00
Go×CloudWatchでファイル取得状況をカスタムメトリクス化する
今回はAWS-SDKを用いて、大量のデータを取得するEC2インスタンスの1時間当たりのファイル取得量をCloudWatchでカスタムメトリクス化して取得状況を監視するシステムを作成したので、一部をご紹介します。
AWS関連の部分以外はGoの標準パッケージのみで作るシンプルなものになっています。
Goでファイル取得数を計算する
下記のプログラムで現在のファイル取得数と経過時間を計算します。
コード自体はとてもシンプルです。package calculator import ( "fmt" "io/ioutil" "math" "os" "path/filepath" "sort" ) func GetFetchSpeed() (float64, error) { dir := `取得したいディレクトリ` //ディレクトリからファイルを取得 files, err := ioutil.ReadDir(filepath.Dir(dir)) if err != nil { return 0, err } //編集日時順にファイルをソートします。 sort.Slice(files, func(i, j int) bool { return files[i].ModTime().Unix() < files[j].ModTime().Unix() }) firstFile, err := os.Stat(dir + files[0].Name()) if err != nil { return 0, err } lastFile, _ := os.Stat(dir + files[len(files)-1].Name()) if err != nil { return 0, err } //最初のファイルを取得してからの経過時間を計算 elapsedTime := lastFile.ModTime().Sub(firstFile.ModTime()) if elapsedTime < 0 { elapsedTime *= -1 } //1時間ごとのファイル取得数 elapsedMinute := math.Trunc(elapsedTime.Minutes()) fetchedPerHour := len(files) / int(elapsedMinute) * 60 return float64(fetchedPerHour), nil }取得した情報をCloudWatchでメトリクス化する。
package metrics import ( "fmt" "io/ioutil" "net/http" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/session" "github.com/aws/aws-sdk-go/service/cloudwatch" ) func getInstanceID() string { //このアドレスにアクセスするとEC2インスタンスのインスタンスIDを取得することができます。 resp, err := http.Get("http://169.254.169.254/latest/meta-data/instance-id") if err != nil { fmt.Println(err) } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { fmt.Println(err) } return string(body) } //メトリクスを作成します func CreateMetrics(value float64) { cw := cloudwatch.New(session.New(), &aws.Config{Region: aws.String("ap-northeast-1")}) dimensionParam := &cloudwatch.Dimension{ Name: aws.String("InstanceId"), Value: aws.String(getInstanceID()), } metricDataParam := &cloudwatch.MetricDatum{ Dimensions: []*cloudwatch.Dimension{dimensionParam}, MetricName: aws.String("Files per 1Hour"), Unit: aws.String("Count"), Value: aws.Float64(value), } putMetricsDataInput := &cloudwatch.PutMetricDataInput{ MetricData: []*cloudwatch.MetricDatum{metricDataParam}, //メトリクスの名前空間 Namespace: aws.String("EC2"), } cw.PutMetricData(putMetricsDataInput) }この二つのパッケージをmain.goで実行します。
func main() { value, err := calculator.GetFetchSpeed() if err != nil { fmt.Printf("Error while calculatoring speed:%s\n", err) } if value > 0 { metrics.CreateMetrics(value) } }以上になります。
このメトリクス化する仕組みを用いればいろんなものを可視化することができるので、監視や運用に役立つかと思います。
- 投稿日:2020-01-17T12:48:36+09:00
【Golang wire】なんとなく理解した備忘録
Git
https://github.com/google/wire/tree/master/_tutorial
何をしているか
struct間の依存関係を記述するのを自動で生成してくれる。
作るべきファイル
1. 依存関係を実装しているファイル(main.goとか)
2. 自動生成するにあたってヒントを与えるファイル(wire.go)↓を実行
$ wire gen
- 同じディレクトリにwire_gen.goが出来上がっている。
多分、実際の処理で利用していくファイルはwire_gen.goを使って処理をしてくはず。
wire gen
を実行するまではmain.goのInitialEventが無いっておこられているから。
wire_gen.goが出来上がるとそのエラーはなくなる。
- 結果
src main.go wire.go wire_gen.go // wire getで生成されたファイルmain.gopackage main import ( "fmt" ) type Event struct { Greeter Greeter } type Greeter struct { Message Message } type Message string func NewEvent(g Greeter) (Event) { return Event{Greeter: g} } func NewGreeter(m Message) Greeter { return Greeter{Message: m} } func NewMessage(p string) Message { return Message(p) } func (e Event) Start() { msg := e.Greeter.Great() fmt.Println(msg) } func (g Greeter) Great() Message { return g.Message } func main() { e := InitializeEvent("takutakutakujiro") e.Start() }wire.go//+build wireinject package test import "github.com/google/wire" func InitializeEvent(phrase string) Event { wire.Build(NewEvent, NewGreeter, NewMessage) return Event{} }wire_gen.go// Code generated by Wire. DO NOT EDIT. //go:generate wire //+build !wireinject package test // Injectors from wire.go: func InitializeEvent(phrase string) Event { message := NewMessage(phrase) greeter := NewGreeter(message) event := NewEvent(greeter) return event }
- 投稿日:2020-01-17T09:17:22+09:00
Google App Engine に Go言語 1.13 の複数サービスを deploy する
はじめに
ちょうど3日前に Google App Engine (GAE) と Go言語を初めて触ってみました。
Go言語がバージョン 11 以降、少し勝手が違ったことで、構築時に若干迷ったので記事にしてみました。いろんなドキュメントを見て判断はしていますが、なんせ経験が浅いので間違い等あれば指摘ください。
はじめる前に…
Go言語と GAE について私が学んだサイト等まとめておきます。
- 下記サイトで Go言語の学習
- Quickstart
- Building a Go App on App Engine
環境
OS
- Windows 10
言語
- go version go1.13.6 windows/amd64
どういう構成にしようか。
まずは GAE の複数サービス構築についてのドキュメントを読んでみる。
まず、私が見たのは下記サイト。
英語は自身無いのですが、要約すると、下記のような感じしょうか。
-app.yaml
でアプリケーションを定義します
-service1.yaml
,service2.yaml
みたいにサービス分けることができる
- ディレクトリ構造はサービス毎にディスプレイ切ってもいいし、yaml をルートに置いてソースコードだけディレクトリ切ってもいい
-dispatch.yaml
,index.yaml
,cron.yaml
などの定義ファイルはルートに置いてね
- default サービス (app.yaml
) は最初に必ず deploy してねどうやら Go言語にはディレクトリ構造の流儀みたいなのがあるらしい
詳しくは下記を参照ください。
- Goにはディレクトリ構成のスタンダードがあるらしい。
- Golangプロジェクトのディレクトリ構成について考えてみた
- Golangパッケージの配置ルールとディレクトリ構成目標のディレクトリ構成
GAE と Go言語の流儀から、私はこんな感じがいいんでないかな?と思いました。
gae-sample (application root directory) +-- dispatch.yaml +-- app.yaml +-- service1.yaml +-- src +-- cmd | +-- default | | +-- main.go | | +-- main_test.go | +-- service1 | +-- main.go | +-- main_test.go +-- api +-- pkg +-- lib※ api, pkg, lib はこの記事では使用しません。
環境構築
アプリケーションのルートディレクトリに移動して git init
$ cd gae-sample $ git initGo言語の初期化(モジュール化)
$ go mod init gae-sample
パッと書いていますが、ここも迷った点で、
Go言語の 11 以降はモジュール化すれば $GOPATH 配下にいなくても OK ?GAE の yaml ファイル作成
$ type NUL > app.yaml $ type NUL > dispatch.yaml $ type NUL > service1.yamlapp.yaml# デフォルト app.yaml です。 service: default runtime: go113 main: ./src/cmd/defaultservice1.yaml# service1 の app.yaml です。 service: service1 runtime: go113 main: ./src/cmd/service1dispatch.yamldispatch: - url: "*/service1/*" service: service1Go言語の必要ディレクトリを作成
※必要なければスキップしてください。
$ mkdir src $ cd src $ mkdir cmd $ mkdir pkg $ mkdir libmain package を作成
$ cd cmd $ mkdir default $ mkdir service1 $ cd default $ echo package main > main.go $ echo package main > main_test.go $ cd ..\service1 $ echo package main > main.go $ echo package main > main_test.gomain.go は GAE の Quickstart でも動かした helloworld さんを使います。(service1 で若干改修)
ほんと、コピメでごめんなさい。cmd/default/main.go// Copyright 2019 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // [START gae_go111_app] // Sample helloworld is an App Engine app. package main // [START import] import ( "fmt" "log" "net/http" "os" ) // [END import] // [START main_func] func main() { http.HandleFunc("/", indexHandler) // [START setting_port] port := os.Getenv("PORT") if port == "" { port = "8080" log.Printf("Defaulting to port %s", port) } log.Printf("Listening on port %s", port) if err := http.ListenAndServe(":"+port, nil); err != nil { log.Fatal(err) } // [END setting_port] } // [END main_func] // [START indexHandler] // indexHandler responds to requests with our greeting. func indexHandler(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/" { http.NotFound(w, r) return } fmt.Fprint(w, "Hello, World!") } // [END indexHandler] // [END gae_go111_app]cmd/default/main_test.go// Copyright 2019 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package main import ( "net/http" "net/http/httptest" "testing" ) func TestIndexHandler(t *testing.T) { req, err := http.NewRequest("GET", "/", nil) if err != nil { t.Fatal(err) } rr := httptest.NewRecorder() handler := http.HandlerFunc(indexHandler) handler.ServeHTTP(rr, req) if status := rr.Code; status != http.StatusOK { t.Errorf( "unexpected status: got (%v) want (%v)", status, http.StatusOK, ) } expected := "Hello, World!" if rr.Body.String() != expected { t.Errorf( "unexpected body: got (%v) want (%v)", rr.Body.String(), "Hello, World!", ) } } func TestIndexHandlerNotFound(t *testing.T) { req, err := http.NewRequest("GET", "/404", nil) if err != nil { t.Fatal(err) } rr := httptest.NewRecorder() handler := http.HandlerFunc(indexHandler) handler.ServeHTTP(rr, req) if status := rr.Code; status != http.StatusNotFound { t.Errorf( "unexpected status: got (%v) want (%v)", status, http.StatusNotFound, ) } }cmd/service1/main.go// Copyright 2019 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // [START gae_go111_app] // Sample helloworld is an App Engine app. package main // [START import] import ( "fmt" "log" "net/http" "os" ) // [END import] // [START main_func] func main() { http.HandleFunc("/", indexHandler) http.HandleFunc("/service1/", service1Handler) // [START setting_port] port := os.Getenv("PORT") if port == "" { port = "8080" log.Printf("Defaulting to port %s", port) } log.Printf("Listening on port %s", port) if err := http.ListenAndServe(":"+port, nil); err != nil { log.Fatal(err) } // [END setting_port] } // [END main_func] // [START indexHandler] // indexHandler responds to requests with our greeting. func indexHandler(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/" { http.NotFound(w, r) return } fmt.Fprint(w, "Hello, service1 World!") } // [END indexHandler] // [START service1Handler] // indexHandler responds to requests with our greeting. func service1Handler(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/service1/" { http.NotFound(w, r) return } fmt.Fprint(w, "This is the service1 page!") } // [END service1Handler] // [END gae_go111_app]cmd/service1/main_test.go// Copyright 2019 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package main import ( "net/http" "net/http/httptest" "testing" ) func TestService1Handler(t *testing.T) { req, err := http.NewRequest("GET", "/service1/", nil) if err != nil { t.Fatal(err) } rr := httptest.NewRecorder() handler := http.HandlerFunc(service1Handler) handler.ServeHTTP(rr, req) if status := rr.Code; status != http.StatusOK { t.Errorf( "unexpected status: got (%v) want (%v)", status, http.StatusOK, ) } expected := "This is the service1 page!" if rr.Body.String() != expected { t.Errorf( "unexpected body: got (%v) want (%v)", rr.Body.String(), "This is the service1 page!", ) } } func TestService1HandlerNotFound(t *testing.T) { req, err := http.NewRequest("GET", "/service1/404", nil) if err != nil { t.Fatal(err) } rr := httptest.NewRecorder() handler := http.HandlerFunc(service1Handler) handler.ServeHTTP(rr, req) if status := rr.Code; status != http.StatusNotFound { t.Errorf( "unexpected status: got (%v) want (%v)", status, http.StatusNotFound, ) } }deploy apps
$ cd <application root directory> $ gcloud app deploy app.yaml service1.yaml dispatch.yaml $ gcloud app browse $ gcloud app browse -s service1
gcloud app browse
でブラウザが開き、「Hello, World」が表示されたら OK です。gcloud app browse -s service1
でブラウザが開き、「Hello, service1 World」が表示されたら OK です。- 最後に default サービスの URL 末尾に
/service1/
を付け、その URL にアクセスすると、「This is the service1 page!」と表示されれば、dispatch.yaml
も正常に機能しているはずです。さいごに
Go言語 ver 1.13 で複数サービスを作成し、GAE にアップロードしてみました。
まだ Go言語の GOPATH と Module が曖昧な感じもあるので、むしろ助言いただけると助かります。
ご参考までに…。