Golang实现图片的笔画提取和图像修复的方法

1. 前言

对于数字图像处理,图片修复技术是其中的一个重要方面。当图像存在噪声、模糊和缺失等问题时,我们需要一些方法对图像进行恢复。针对这个问题,本文将介绍Golang实现图片的笔画提取和图像修复的方法。

2. 图片的笔画提取

笔画提取是指在一张二值图像中提取出图形的轮廓线。这里介绍一种基于边缘检测的笔画提取方法,简单易懂。

2.1 边缘检测

边缘检测主要是指在图像中找到像素值变化的位置,其中著名的算法有Sobel、Prewitt、Roberts、Canny等。下面介绍一下Sobel算法:

func sobel(gImg image.Image) image.Image {

gMat := img2Matrix(gImg)

m, n := gMat.Dims()

dx := mat.NewDense(m, n, nil)

dy := mat.NewDense(m, n, nil)

for i := 1; i < m-1; i++ {

for j := 1; j < n-1; j++ {

dx.Set(i, j, -gMat.At(i-1, j-1) - 2*gMat.At(i-1, j) - gMat.At(i-1, j+1) + gMat.At(i+1, j-1) + 2*gMat.At(i+1, j) + gMat.At(i+1, j+1))

dy.Set(i, j, -gMat.At(i-1, j-1) - 2*gMat.At(i, j-1) - gMat.At(i+1, j-1) + gMat.At(i-1, j+1) + 2*gMat.At(i, j+1) + gMat.At(i+1, j+1))

}

}

img := &image.Gray{Pix: make([]uint8, m*n), Stride: n, Rect: image.Rect(0, 0, n, m)}

for i := 0; i < m; i++ {

for j := 0; j < n; j++ {

pix := uint8(math.Sqrt(math.Pow(dx.At(i, j), 2) + math.Pow(dy.At(i, j), 2)))

img.SetGray(j, i, color.Gray{Y: pix})

}

}

return img

}

以上代码中,变量gImg是输入的二值图像,函数返回值为提取后的边缘图像。具体实现是根据Sobel算子来对图像进行卷积操作,得到x方向和y方向的梯度值,然后合并成一个边缘图像。

2.2 轮廓线提取

对于得到的边缘图像,需要做一些处理才能得到想要的轮廓线。下面介绍一种连通分量和轮廓线提取算法。

func bwLabel(img image.Image) ([][]image.Point, []image.Image) {

m, n := img.Bounds().Max.Y, img.Bounds().Max.X

pixels := img.(*image.Gray).Pix

visited := make([]bool, m*n)

labels := make([][]int, m)

for i := range labels {

labels[i] = make([]int, n)

}

label := 1

var areas []int

var rects []image.Rectangle

var compPixels [][]image.Point

var visit []func(x, y int)

visit = []func(x, y int){

func(x, y int) {

visited[y*n+x] = true

labels[y][x] = label

if compPixels[label] == nil {

compPixels[label] = []image.Point{{x, y}}

} else {

compPixels[label] = append(compPixels[label], image.Point{x, y})

}

},

func(x, y int) {

if x > 0 && !visited[y*n+x-1] && pixels[y*n+x-1] == 0xff {

visit[len(visit)-1](x-1, y)

}

if x < n-1 && !visited[y*n+x+1] && pixels[y*n+x+1] == 0xff {

visit[len(visit)-1](x+1, y)

}

if y > 0 && !visited[(y-1)*n+x] && pixels[(y-1)*n+x] == 0xff {

visit[len(visit)-1](x, y-1)

}

if y < m-1 && !visited[(y+1)*n+x] && pixels[(y+1)*n+x] == 0xff {

visit[len(visit)-1](x, y+1)

}

},

}

var dfs func(x, y int)

dfs = func(x, y int) {

visit[len(visit)-1](x, y)

for compPixels[label+1] != nil {

label++

}

rects = append(rects, boundingBox(compPixels[label]))

areas = append(areas, len(compPixels[label]))

}

for y := 0; y < m; y++ {

for x := 0; x < n; x++ {

if labels[y][x] == 0 && pixels[y*n+x] == 0xff {

compPixels = append(compPixels, nil)

areas = append(areas, 0)

rects = append(rects, image.Rect(x, y, x+1, y+1))

visit = append(visit, dfs)

dfs(x, y)

}

}

}

var retLabels [][]image.Point

retImages := make([]image.Image, len(rects))

for i := range rects {

r := compPixels[i+1]

retImages[i] = image.NewGray(rects[i])

retLabels = append(retLabels, r)

for _, p := range r {

retImages[i].SetGray(p.X-rects[i].Min.X, p.Y-rects[i].Min.Y, color.Gray{Y: 0xff})

}

}

return retLabels, retImages

}

以上代码中,变量img是输入的边缘图像,该函数返回值为一个切片和一个切片,第一个切片中包含不同连通分量的轮廓线的像素点坐标,第二个切片中包含对应的轮廓线图像。

3. 图像修复

上一部分介绍了有关图片笔画提取的内容,本部分将实现一个简单的图像修复方法——根据周围像素值的平均值来恢复图像

3.1 恢复算法

假设我们现在有一个图像,其中一部分像素点的值已被损坏或丢失。下面是一种简单的修复方法:用周围像素值的平均值来代替损坏或丢失的像素值。

func fixImage(img image.Image, mask [][]bool) image.Image {

m, n := img.Bounds().Max.Y, img.Bounds().Max.X

rgb := img.(*image.RGBA)

pix := make([][]*color.RGBA, m)

for i := range pix {

pix[i] = make([]*color.RGBA, n)

}

for i := range mask {

for j := range mask[i] {

if mask[i][j] {

pix[i][j] = rgb.At(j, i).(*color.RGBA)

}

}

}

for i := range mask {

for j := range mask[i] {

if !mask[i][j] {

var r, g, b uint32

var count int

if i > 0 && mask[i-1][j] {

count++

c := pix[i-1][j]

r += uint32(c.R)

g += uint32(c.G)

b += uint32(c.B)

}

if j > 0 && mask[i][j-1] {

count++

c := pix[i][j-1]

r += uint32(c.R)

g += uint32(c.G)

b += uint32(c.B)

}

if i+1 < m && mask[i+1][j] {

count++

c := pix[i+1][j]

r += uint32(c.R)

g += uint32(c.G)

b += uint32(c.B)

}

if j+1 < n && mask[i][j+1] {

count++

c := pix[i][j+1]

r += uint32(c.R)

g += uint32(c.G)

b += uint32(c.B)

}

if count > 0 {

rgb.SetRGBA(j, i, color.RGBA{uint8(r / uint32(count)), uint8(g / uint32(count)), uint8(b / uint32(count)), 0})

}

}

}

}

return rgb

}

以上代码中,输入图像为变量img,mask是一个二维切片,表示哪些像素点是损坏或丢失的;函数返回恢复后的图像。

3.2 实现效果

下面把笔画提取和图像修复两部分合在一起,在一张已损坏图像上实现自动修复。首先,我们需要载入一张测试图片。

func loadImage(name string) image.Image {

file, err := os.Open(name)

if err != nil {

log.Fatal(err)

}

defer file.Close()

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

if err != nil {

log.Fatal(err)

}

return img

}

func main() {

img := loadImage("damaged.png")

mask, edges := getMask(img, 30, 128)

for i, e := range edges {

saveImage("edge"+strconv.Itoa(i+1)+".png", e)

}

fixed := fixImage(img, mask)

saveImage("fixed.png", fixed)

}

3.3 实现效果

以下是输入、笔画提取和恢复后的输出。

输入图像:

笔画提取:

恢复后的图像:

4. 总结

本文介绍了Golang实现图片的笔画提取和图像修复的方法。笔画提取主要是使用边缘检测方法,得到图像的轮廓线;而图像修复则是基于周围像素值的平均值来进行,实现简单但效果较好。以上所述内容,仅供参考,读者可以自行尝试实现不同的方法,并对其进行不断优化。

免责声明:本文来自互联网,本站所有信息(包括但不限于文字、视频、音频、数据及图表),不保证该信息的准确性、真实性、完整性、有效性、及时性、原创性等,版权归属于原作者,如无意侵犯媒体或个人知识产权,请来电或致函告之,本站将在第一时间处理。猿码集站发布此文目的在于促进信息交流,此文观点与本站立场无关,不承担任何责任。

后端开发标签