1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

golangによる細線化処理

Posted at

以下注意点です。

hiditchの方法

http://qiita.com/TatsuyaOGth/items/45965e1632f41f3eb139
に似たようなことが書かれていました。
こんなことをしようと何年か前のテキストから把握しております。

にしても、ここもあっちも関数が長くて読む気がしません。
でもまぁ、やってみましょう。

解釈の概要

周囲8点を観察して、ある条件に一致すればその点(今後注目点と記載)を白にする
で、ある条件が下です

  • 注目点が画像の端でないこと
  • 注目点の画素が白くなっても連結数が保たれること
  • 線幅2が消滅しないこと

一つ目は線の端ではないことを考慮します。周囲の黒の数が3以下なら端と判断します。
二つ目は連結数を解釈しないといけない、個人的には以下で解釈しました。

連結数

複数の直線には平行でなければ当然交点が存在します。注目点には一体何本の線が交差しているのか?を定義するのが連結数と定義します。
従って、
周囲をぐるっと走破して、白→黒の変化がいくつか?で連結数を調べます。

三つ目は周囲をぐるっと走破して一つずつ消した時に連結数が変化しないこと、更に対象となるのは注目点の上3つと左側だそうです。何故かは記載されておらず「そういうもんだよ」って感じでした、書いてよ。
無理やり解釈すると、左上から左下に向かって処理をするからで、どちらかでやればいいのだろうというのが大方の予想。両方でやると出るけど、線がガタツクと予想する。

ソースコード

func Thinning(srcImg image.Image) image.Image {
	//白を出すだけの関数
	white := func(aVal uint32) color.Color {
		return color.RGBA64{ex.ColorWidth, ex.ColorWidth, ex.ColorWidth, uint16(aVal)}
	}
	//出力画像
	var workImg *image.RGBA
	for {
		workImg = image.NewRGBA(srcImg.Bounds())
		draw.Copy(workImg, image.Point{0, 0}, srcImg, srcImg.Bounds(), draw.Src, nil)
		counter := 0
		icom.ImageLoop(srcImg, func(x int, y int) {
			//判定を行う値かチェックする
			if false == isCheckValue(x, y, srcImg) {
				return
			}
			//周囲8の値を取得する
			srcAround, sum := getArounds(srcImg, x, y)
			workAround, _ := getArounds(workImg, x, y)
			//aの値を取得しておく
			_, _, _, a := workImg.At(x, y).RGBA()
			switch sum {
			case 0:
				workImg.Set(x, y, white(a))
			case 2, 3, 4, 5:
				if true == doesKeepConnect(srcAround, workAround) {
					workImg.Set(x, y, white(a))
				}
			}
			r, _, _, _ := workImg.At(x, y).RGBA()
			if r == ex.ColorWidth {
				counter++
			}
		})
		if counter == 0 {
			break
		}
		// 元画像に戻す
		srcImg = workImg
	}
	return workImg
}

全貌でございます。
処理順序は以下になります。

  1. 現状と比較したいので、元画像をワークにコピーする
  2. 判定を行うところかチェックする(画像の端、すでに白い所は無視):isCheckValue
  3. ワークと元画像の近傍を取得する
  4. 白でない場所の数(0〜8)から処理を分割して、白くできる場合は白くする
  5. 一旦1画像すべて走査して、どこかを変えたらもう一回やる。なかったら終了

以上です。
ここまでくれば面倒なのは、黒を1で表現しやがって、今までRGBの値でどーのこーのやってたくせにどう言うことだと言いたいテキストと4番目の関数(doesKeepConnect)の中身でしょう

func doesKeepConnect(srcAround, workAround Around) bool {
	flg := false
	if countConnect(srcAround) == 1 && countConnect(workAround) == 1 {
		var tmpArd Around
		isAll := true
		for i := 1; i < 5; i++ {
			if workAround[i] != 0 {
				tmpArd = srcAround
				tmpArd[i] = ex.ColorWidth
				if countConnect(tmpArd) != 1 {
					isAll = false
					break
				}
			}
		}
		if isAll == true {
			flg = true
		}
	}
	return flg
}

連結数は1であるか?、そのあとに上と左をぐるっと走査して連結数に変化がないことをチェックしています。この記事を書いてる時に

if workAround[i] != 0 {

が単なる高速化を目指してる気がしてきた。いらん気がする。

出力結果

input

test_vari_th.png

output

test_thinning.png

結果、数式ってのはわかる。だんだん人工知能の匂いがしてきた気がします。

1
0
0

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
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?