【画像処理】Go言語で平滑化処理【サンプルコード付】

golang

 

こんにちは!zhackです。

これまで、さまざまな画像処理をGo言語で行ってきましたが、
今回は空間フィルタリングを行っていきます!

先日、X方向Y方向微分の記事を掲載しましたが、本日は空間フィルタリングの一つ、平滑化処理を紹介します!

【画像処理】Go言語で輪郭抽出!X方向Y方向微分【サンプルコード付き】
こんにちは!zhackです。 Go言語で画像処理シリーズ第3弾! 今回は、エッジ検出について説明していきます。 先日、フィルタ処理に関する記事を掲載しました。 その中の輪郭抽出である、X方向及びY方向の微分に...

前提

実行環境

今回の実行環境は以下の通りです。

  • Debian GNU/Linux8
    ※Dockerコンテナで環境構築
  • プログラム名称:smoothing.go
  • 入力データ:lena.jpg

  • 実行コマンド
    $ go run プログラム名 < 入力画像のパス > 出力画像のパス 
    今回の場合は
    $ go run smoothing.go < lena.jpg > lena_smoothed.jpg
  • Gitにも掲載しています。ご参考まで。

Dockerのインストール方法やGo言語の環境構築については以下の記事をご参考下さい。

画像付き:Dockerのインストール手順(Windows OS)
zhack(私)が実際に行ったDockerのWindowsOSへのインストール手順です。インストールなしで試してみたい方向けにPlay with Dockerの利用方法も簡単に説明します。
DockerでGo言語開発環境構築
Dockerを使ったGo言語の開発環境構築手順を紹介します!簡単に仮想環境を構築できるDockerに、最近サーバサイドの開発で使われつつあるGo言語の開発環境を構築しました。今回はその手順についてご紹介します。

プログラムのひな型

これまで同様、実装したプログラムのひな型を紹介します。

package main

// 必要なライブラリのインストール
import (
    "image"
    "image/color"
    "image/jpeg"
    "os"
)
// メイン関数
func main() {

    // 入力データの読み込み
    img, _ := jpeg.Decode(os.Stdin)

    // 入力データを走査するデータの作成
    bounds := img.Bounds()
  // 出力用の入れ物を作成
    dest := image.NewRGBA(bounds)

  // 画像を1ピクセルずつ走査
    for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
        for x := bounds.Min.X; x < bounds.Max.X; x++ {
            // (1) 必要な処理
        }
    }

    // 処理結果を画像形式で出力
    err := jpeg.Encode(os.Stdout, dest, nil)
    if err != nil {
        panic("Failed to encode JPEG gradient image.")
    }
}

上記、プログラムにおける“(1) 必要な処理”と書いているところに平滑化処理用のコードが入ります。

Go言語のImageパッケージを用いたときの色情報の取得方法については、【画像処理】Go言語で二値化処理!【サンプルプログラムあり】をご参考ください。

Go言語で平滑化処理

フィルタの説明

今回扱うフィルタは、このようなフィルタになります。

先日の「フィルタ処理とは?」で、平均化処理と呼んでいたフィルタですね。

【画像処理】空間フィルタリングとは?
こんにちは!zhackです。 今回は画像処理でよく使われる空間フィルタリングについて、紹介します! 空間フィルタリングとは? 画像中の注目しているある画像に対して、注目している画素とその周囲の画素から、注目している画素を変換する処...

今回はこのフィルタを使っていきます。

プログラム

(1)必要な処理に入るプログラムはこんな感じ。

// 注目画素と8近傍の画素を取得
c1 := img.At(x-1, y-1)
c2 := img.At(x, y-1)
c3 := img.At(x+1, y-1)
c4 := img.At(x-1, y)
c5 := img.At(x, y)
c6 := img.At(x+1, y)
c7 := img.At(x-1, y+1)
c8 := img.At(x, y+1)
c9 := img.At(x+1, y+1)

// 一つの配列にまとめて、関数にほりこむ!
c := []color.Color{c1,c2,c3,c4,c5,c6,c7,c8,c9}
col := filtering(c,smooth_filter)
// 出力画像としてセット 
dest.Set(x, y, col)

そして、このプログラムの中にある、変数smooth_filterと、関数filteringは以下のように定義します。

// main関数内のどこかに定義
filter := []float64{1/9.0,1/9.0,1/9.0,1/9.0,1/9.0,1/9.0,1/9.0,1/9.0,1/9.0}
// 空間フィルタリング
func filtering(c[] color.Color, filter[] float64) *color.RGBA {
    // 画素の値を格納するための配列
    var rArray[] uint32
    var gArray[] uint32
    var bArray[] uint32
    var aArray[] uint32

    // 各画素のRGBA値を取得
    for index, _ := range c {
        r, g, b, a := (c[index]).RGBA()
        r, g, b, a = r>>8, g>>8, b>>8, a>>8
        rArray = append(rArray,r)
        gArray = append(gArray,g)
        bArray = append(bArray,b)
        aArray = append(aArray,a)
    }
    // 出力する画素値格納用変数の初期化
    R := float64(0)
    G := float64(0)
    B := float64(0)
    A := float64(0)

    // 空間フィルタリング
    for i:=0; i<len(rArray);i++{
        R += filter[i] * float64(rArray[i])
        G += filter[i] * float64(gArray[i])
        B += filter[i] * float64(bArray[i])
        A += filter[i] * float64(aArray[i])
    }
    // 0未満もしくは255以上のものは修正
    if R < 0 { 
        R = 0
    } else if R > 255{
        R = 255
    } 
    if G < 0 { 
        G = 0
    } else if G > 255{
        G = 255
    } 
    if B< 0 { 
        B = 0
    } else if B > 255{
        B = 255
    } 
    if A < 0 { 
        A = 0
    } else if A > 255{
        A = 255
    }
    // main関数へreturn
    return &color.RGBA{
        R : uint8(R),
        G : uint8(G),
        B : uint8(B),
        A : uint8(A),
    }
}

 

実行結果

少しプログラムが長くなってしまいましたが、実行結果です!

今回は違いがわかるように、複数回平滑化処理を行ってみました。

いかがでしょうか。
だんだんと画像がボケていっているのがわかると思います。

さいごに

今回は平滑化処理を行いました。

実は今回のプログラム、変数filterの中身を変えてしまえばいろんな空間フィルタリングを行うことができます。

次回は、このプログラムをいろんな空間フィルタリングを行ってみます!

ではでは!

 

 

 

コメント

  1. […] 今日は、先日掲載しましたプログラムを使って、いろんな空間フィルタリングをやっていきます。 […]

  2. […] […]

タイトルとURLをコピーしました