Beispiel #1
0
func analyse(img *floatimage.FloatImg) (min, max, mean, variance float32) {
	var sum float64
	bounds := img.Bounds()
	if img.Bounds().Empty() {
		return 0, 0, 0, 0
	}

	sum = 0.0
	min = img.Pix[0]
	max = img.Pix[0]
	for y := bounds.Min.Y + 1; y < bounds.Max.Y-1; y++ {
		for x := bounds.Min.X + 1; x < bounds.Max.X-1; x++ {
			value := img.AtF(x, y)[0]
			if value < min {
				min = value
			}
			if value > max {
				max = value
			}
			sum += float64(value)
		}
	}
	imgsize := float64(bounds.Dx()-2) * float64(bounds.Dy()-2)
	mean = float32(sum / imgsize)
	variance = 0.0
	for y := bounds.Min.Y + 1; y < bounds.Max.Y-1; y++ {
		for x := bounds.Min.X + 1; x < bounds.Max.X-1; x++ {
			temp := img.AtF(x, y)[0] - mean
			variance += temp * temp
		}
	}
	variance = float32(float64(variance) / imgsize)
	return
}
func flow(alpha float32, derivs, oldvec, vecField *floatimage.FloatImg) {
	bounds := vecField.Bounds()

	help := 1.0 / alpha
	var nn int
	var uSum, vSum float32
	var uv []float32
	for j := bounds.Min.Y; j < bounds.Max.Y; j++ {
		for i := bounds.Min.X; i < bounds.Max.X; i++ {
			nn = 0
			uSum, vSum = 0, 0
			if i > bounds.Min.X {
				nn++
				uv = oldvec.AtF(i-1, j)
				uSum += uv[0]
				vSum += uv[1]
			}

			if i < bounds.Max.X-1 {
				nn++
				uv = oldvec.AtF(i+1, j)
				uSum += uv[0]
				vSum += uv[1]
			}

			if j > bounds.Min.Y {
				nn++
				uv = oldvec.AtF(i, j-1)
				uSum += uv[0]
				vSum += uv[1]
			}

			if j < bounds.Max.Y-1 {
				nn++
				uv = oldvec.AtF(i, j+1)
				uSum += uv[0]
				vSum += uv[1]
			}
			dvs := derivs.AtF(i, j)
			fxij, fyij, fzij := dvs[Fxc], dvs[Fyc], dvs[Fzc]
			uv = oldvec.AtF(i, j)
			uSum -= help * fxij * (fyij*uv[1] + fzij)
			uSum /= float32(nn) + help*fxij*fxij
			vSum -= help * fyij * (fxij*uv[0] + fzij)
			vSum /= float32(nn) + help*fyij*fyij
			uv = vecField.AtF(i, j)
			uv[0], uv[1] = uSum, vSum
		}
	}
}
// MagImage generates a magnitude image from an optic flow
// field and returns it as a single channel floatimage.FloatImg
func MagImage(uv *floatimage.FloatImg) (magImg *floatimage.FloatImg) {
	bounds := uv.Bounds()
	// Magnitude image
	magImg = floatimage.NewFloatImg(bounds, 1)
	// Calculate
	for j := bounds.Min.Y; j < bounds.Max.Y; j++ {
		for i := bounds.Min.X; i < bounds.Max.X; i++ {
			vec := uv.AtF(i, j)
			tmp := vec[0]*vec[0] + vec[1]*vec[1]
			magImg.Set(i, j, 0, float32(math.Sqrt(float64(tmp))))
		}
	}
	return

}
func deriveMixed(f1, f2 *floatimage.FloatImg) *floatimage.FloatImg {
	const hx = 1.0
	const hy = 1.0
	bounds := f1.Bounds()
	derivs := floatimage.NewFloatImg(bounds, 3)
	for j := bounds.Min.Y + 1; j < bounds.Max.Y-1; j++ {
		for i := bounds.Min.X + 1; i < bounds.Max.X-1; i++ {
			Fx := (f1.AtF(i+1, j)[0] - f1.AtF(i-1, j)[0] + f2.AtF(i+1, j)[0] - f2.AtF(i-1, j)[0]) / (4.0 * hx)
			Fy := (f1.AtF(i, j+1)[0] - f1.AtF(i, j-1)[0] + f2.AtF(i, j+1)[0] - f2.AtF(i, j-1)[0]) / (4.0 * hy)
			Fz := f2.AtF(i, j)[0] - f1.AtF(i, j)[0]
			dvs := derivs.AtF(i, j)
			dvs[Fxc], dvs[Fyc], dvs[Fzc] = Fx, Fy, Fz
		}
	}
	return derivs
}
// OpticFlowHornSchunk computes the optic flow between two images
// the images need to have Dummie borders (see floatimage.Dummies())
// applied.
// It returns the optic flow field as a 2 channel floatimage.FloatImg
func OpticFlowHornSchunk(f1, f2 *floatimage.FloatImg, alpha float32, iterations int) (uv *floatimage.FloatImg) {
	// Compute fx, fy, fz derivatives as FloatImg with 3 channels for faster access
	derivs := deriveMixed(f1, f2)
	// bounds without dummies
	bounds := f1.Bounds()

	// vector field as FloatImg with 2 channels
	uv = floatimage.NewFloatImg(bounds, 2)
	// temporary storage for vector field from previous iteration
	uvOld := floatimage.NewFloatImg(bounds, 2)
	// Process image using the Jacobi method to incrementally compute the vector field
	for k := 1; k <= iterations; k++ {
		flow(float32(alpha), derivs, uvOld, uv)
		uvOld.Copy(uv)
	}

	return
}