LoginSignup
5

More than 3 years have passed since last update.

posted at

updated at

Organization

Go言語の標準パッケージだけで画像処理をする その1 (入出力)

ZOZOテクノロジーズ #5 Advent Calendar 2019の記事です。
昨日は @satto_sann さんの「Alexaのアカウントリンクをデバッグする方法」でした。

本記事では、Go言語の標準パッケージでの画像処理について書いていきます。

はじめに

最初に明言しておきますが、これはGo言語での画像処理を勧める記事ではありません。
あくまで、自分にメリットがありそうという方のみ参考にしていただければと思います。

自分はZOZOテクノロジーズの中でも、アパレル生産におけるファクトリーオートメーションという分野を担当しています。

担当分野が広いというのと、自動化の対象がアパレル関係ということもあり、
開発環境を実行環境に入れることができなかったり、実行環境により使う言語を変えたりと手間がかかってしまう場面がよく発生します。

特に画像処理関係でプロトタイプをサクッと作る際には、開発環境をその都度作るのが面倒だったりします。

そんな手間を無くせないかなーとふと思い、本記事シリーズを書くことにしました。

A36FD16C-29EF-4FA3-89A6-717EDFF2409B.jpeg

Go言語 image パッケージ
Package image

ファイルの入力

filepathを利用することで、os間のパス違いを意識せずにコードが書けます。
自分は以下のソースのようにdataファイルを用意し、その中に処理したい画像を置いて読み込ませる方法をよく使います。
プロトタイプを軽く動かす時なんかは便利です。

package main

import (
    "image"
    "log"
    "os"
    "path/filepath"
)

func main() {

    // 実行ファイル直下のパスを取得
    path, _ := os.Getwd()
    dataPath := filepath.Join(path, "data")
    // dataフォルダ直下の画像を一括で読み込む
    jpgPath := filepath.Join(dataPath, "*.jpg")
    jpegPath := filepath.Join(dataPath, "*.jpeg")
    pngPath := filepath.Join(dataPath, "*.png")

    fileList, _ := filepath.Glob(jpgPath)
    f, _ := filepath.Glob(jpegPath)
    fileList = append(fileList, f...)
    f, _ = filepath.Glob(pngPath)
    fileList = append(fileList, f...)

    // 画像を1枚づつ読み込む
    for _, file := range fileList {
        // 画像を読み込む
        img := Input(file)
        println(file, " : " , img)
    }
}

// 画像を読み込む処理
func Input (filePath string) image.Image {

    // 画像を読み込む
    file, err := os.Open(filePath)

    // 画像が読み込めなかった場合
    if err != nil {
        log.Fatal(err)
    }

    // 変換
    img, _, err := image.Decode(file)

    return img
}

ファイルの出力

出力したい拡張子によって処理を分けます。
ここではjpgとpngの出力を紹介します。

const imgQt int = 60

func Output (outputImage image.Image, filePath string, format string) {

    dst, err := os.Create(filePath)

    if err != nil {
        log.Fatal(err)
    }

    switch format {
    case "png":
        // PNGの場合
        err = png.Encode(dst, outputImage)
        if err != nil {
            log.Fatal(err)
        }
        break
    case "jpg":
        // JPGの場合
        qt := jpeg.Options{
            Quality:imgQt,
        }
        err = jpeg.Encode(dst, outputImage, &qt)
        if err != nil {
            log.Fatal(err)
        }
        break
    default:
        // 標準で対応していないフォーマットの場合
        log.Fatal("Unsupported format.")
    }
}

画素値の参照

以下では読み込んだ画像から画素値を参照したり、操作を行なったりしています。

func EditPixel(img image.Image) image.Image {

    // アウトプット画像を定義
    size := img.Bounds()
    // 画像のサイズを変える場合
    // size.Max.X = "任意の数値"
    // size.Max.Y = "任意の数値"
    outputImage := image.NewRGBA(size)

    // 画像の左上から順に画素を読み込む
    for imgRow := size.Min.Y; imgRow < size.Max.Y; imgRow++ {
        for imgCol := size.Min.X; imgCol < size.Max.X; imgCol++ {

            // 画素を取得
            pixel := img.At(imgCol, imgRow)
            println("pixel : ", pixel)
            r, g, b, a := pixel.RGBA()
            println("r : ", r, "g : ", g, "b : ", b, "a : ", a)

            // 画素を操作
            var outputColor color.RGBA64
            // 例(真っ黒な画像にする)
            outputColor.R = 0
            outputColor.G = 0
            outputColor.B = 0
            outputColor.A = 100

            outputImage.Set(imgCol, imgRow, outputColor)
        }
    }

    return outputImage
}

おわりに

ZOZOテクノロジーズ #5 Advent Calendar 2019
明日は「Go言語の標準パッケージだけで画像処理をする その2 (回転、反転)」という記事を書きます。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
5