[squeak-dev] Who understand bilinear interpolation for reducing image size?

tim Rowledge tim at rowledge.org
Mon Dec 8 20:15:04 UTC 2014


The ScratchPlugin implements a prim to shrink a 32bpp image by use of bilinear interpolation. Unfortunately it completely ignores the alpha channel in 32bpp pixels and does some rather odd futzing to kinda-sorta fake handling of transparency.

I can see how to add in (what I think would be) proper ARGB interpolating, and I think that simply removing the futzing would be correct - but I’d much rather have some input from somebody with a bit of image processing theory so there is some hope of my final result being actually correct.

This the core of the code -
	inX := inY := 0.					"source x and y, scaled by 1024"
	xIncr := (inW * 1024) // outW.	"source x increment, scaled by 1024"
	yIncr := (inH * 1024) // outH.		"source y increment, scaled by 1024"

	0 to: (outH - 1) do: [:outY |
		inX := 0.
		0 to: (outW - 1) do: [:outX |
			"compute weights, scaled by 2^20"
			w1 := (1024 - (inX bitAnd: 1023))	* (1024 - (inY bitAnd: 1023)).
			w2 := (inX bitAnd: 1023)			* (1024 - (inY bitAnd: 1023)).
			w3 := (1024 - (inX bitAnd: 1023))	* (inY bitAnd: 1023).
			w4 := (inX bitAnd: 1023)			* (inY bitAnd: 1023).

			"get source pixels"
			t := ((inY >> 10) * inW) + (inX >> 10).
			p1 := in at: t.
			((inX >> 10) < (inW - 1)) ifTrue: [p2 := in at: t + 1] ifFalse: [p2 := p1].
			(inY >> 10) < (inH - 1) ifTrue: [t := t + inW].  "next row"
			p3 := in at: t.
			((inX >> 10) < (inW - 1)) ifTrue: [p4 := in at: t + 1] ifFalse: [p4 := p3].

			"deal with transparent pixels"
			tWeight := 0.
			p1 = 0 ifTrue: [p1 := p2. tWeight := tWeight + w1].
			p2 = 0 ifTrue: [p2 := p1. tWeight := tWeight + w2].
			p3 = 0 ifTrue: [p3 := p4. tWeight := tWeight + w3].
			p4 = 0 ifTrue: [p4 := p3. tWeight := tWeight + w4].
			p1 = 0 ifTrue: [p1 := p3. p2 := p4].  "both top pixels were transparent; use bottom row"
			p3 = 0 ifTrue: [p3 := p1. p4 := p2].  "both bottom pixels were transparent; use top row"

			outPix := 0.
			tWeight < 500000 ifTrue: [  "compute an (opaque) output pixel if less than 50% transparent"
				t := (w1 * ((p1 >> 16) bitAnd: 255)) + (w2 * ((p2 >> 16) bitAnd: 255)) + (w3 * ((p3 >> 16) bitAnd: 255)) + (w4 * ((p4 >> 16) bitAnd: 255)).
				outPix := ((t >> 20) bitAnd: 255) << 16.
				t := (w1 * ((p1 >> 8) bitAnd: 255)) + (w2 * ((p2 >> 8) bitAnd: 255)) + (w3 * ((p3 >> 8) bitAnd: 255)) + (w4 * ((p4 >> 8) bitAnd: 255)).
				outPix := outPix bitOr: (((t >> 20) bitAnd: 255) << 8).
				t := (w1 * (p1 bitAnd: 255)) + (w2 * (p2 bitAnd: 255)) + (w3 * (p3 bitAnd: 255)) + (w4 * (p4 bitAnd: 255)).
				outPix := outPix bitOr: ((t >> 20) bitAnd: 255).
				outPix = 0 ifTrue: [outPix := 1]].

			out at: (outY * outW) + outX put: outPix.
			inX := inX + xIncr].
		inY := inY + yIncr].

Note that it doesn’t do any clipping, relying upon having only a full 32bpp input Form and a pre-built correctly sized 32bpp output Form.
On a Pi this prim is roughly 5 times faster than using a warpblt, so it would be nice to keep it in use.

tim
--
tim Rowledge; tim at rowledge.org; http://www.rowledge.org/tim
Strange OpCodes: BPP: Branch Pretty Please




More information about the Squeak-dev mailing list