Example #1
1
//ProjectGray returns a greyscale sinogram (or radon projection) of img
// N(default: 360): number of image rotation on which a projection will be done
// A naive simplistic approach
// Sinograms looks like this :
// θ1 θ2 θ3...θN
// |  |  |    |
// |  |  |    |
func ProjectGray(src image.Image, N int) (*image.Gray, error) {
	if N == 0 {
		N = 360
	}
	step := 180.0 / float64(N)

	size := src.Bounds().Size()
	overX := int(float64(size.X) * 1.1)
	overY := int(float64(size.Y) * 1.1)
	var img image.Image = image.NewGray(image.Rect(0, 0, size.X+overX, size.Y+overY))
	img = imaging.Overlay(img, src, image.Pt(overX/2, overY/2), 1)
	size = img.Bounds().Size()

	D := max(size.X, size.Y)
	out := image.NewGray(image.Rect(0, 0, N, D))

	// for each given angle θ
	for n := 0; n < N; n++ {
		θ := float64(n) * step
		draw := image.NewRGBA(image.Rect(0, 0, img.Bounds().Dy(), img.Bounds().Dx()))
		//have a duplicate img rotated by θ
		err := graphics.Rotate(draw, img, &graphics.RotateOptions{Angle: manipulator.Rad(θ)})
		if err != nil {
			return out, err
		}

		sinogram := make([]float64, size.X)
		// get column average profile
		for y := 0; y < size.Y; y++ {
			for x := 0; x < size.X; x++ {
				greyColor, _ := color.GrayModel.Convert(draw.At(x, y)).(color.Gray)
				sinogram[x] = sinogram[x] + float64(greyColor.Y)
			}
		}

		//Set out line with sinogram
		for d := 0; d < D; d++ {
			out.Set(n, d, color.Gray{uint8(sinogram[d] / float64(size.Y))})
		}
	}

	return out, nil
}
Example #2
0
//BackProjectGray computes back projection of img
// in Gray16 by performing an addition
// of backprojection by line.
// 16Gray avoids white noise.
func BackProjectGray(img image.Gray) (*image.Gray16, error) {
	size := img.Bounds().Size()
	width := size.Y
	nbProj := size.X
	step := 180.0 / float64(nbProj)

	out := image.NewGray16(image.Rect(0, 0, width, width))

	for X := 0; X < nbProj; X++ {
		//Extract a 1D-projection (one row Y of sinogram)
		line := img.SubImage(image.Rect(X, 0, X+1, width)).(*image.Gray)

		// 3- Do the backprojection and rotate accordingly
		wideLine := resize.Resize(uint(width), uint(width), line, resize.Lanczos3).(*image.Gray)

		θ := manipulator.Rad(float64(X)*step) + math.Pi/2
		rotatedWideLine := image.NewGray(image.Rect(0, 0, width, width))
		err := graphics.Rotate(rotatedWideLine, wideLine, &graphics.RotateOptions{Angle: θ})
		if err != nil {
			return out, err
		}

		// 4- Add the rotated backprojection in the output image
		for x := 0; x < width; x++ {
			for y := 0; y < width; y++ {
				point := uint16(out.At(x, y).(color.Gray16).Y) + uint16(rotatedWideLine.At(x, y).(color.Gray).Y)
				out.Set(x, y, color.Gray16{uint16(point)})
			}
		}
	}

	return out, nil
}