Googles appar
Huvudmeny

Post a Comment On: cbloom rants

"03-24-11 - Image filters and Gradients"

10 Comments -

1 – 10 of 10
Blogger won3d said...

The half-pel gradient thing is one of those things that should be obvious but usually isn't, since most people think grid-aligned.

An old co-worker of mine once told me that there was "more information" in a gradient image because you have a value at each edge instead of each center. He was obviously smoking crack, but there is some merit to the point that it is sometimes better to think of those differences living on half-pels. Apparently this helps for fluid solving.

March 24, 2011 at 5:41 PM

Blogger ryg said...

"Costella shows that Lanczos and Bicubic create nasty grid artifacts. This is not true, he simply has a bug in his upsamplers."
Note his description on that page. He doesn't do *one* resampling operation - to get the 8x size image, he doubles the size 3 times.

The effective upsampling kernel you get from that operation isn't a real bicubic / Lanczos resample, and has different (worse) properties. Bilinear fares better in his comparison simply because bilin_2x(bilin_2x(img)) happens to be the same as bilin_4x(img). But of course for more general upsamplers, a small upscaling filter iterated twice isn't the same as a large upscaling filter!

March 25, 2011 at 5:58 PM

Blogger cbloom said...

"Note his description on that page. He doesn't do *one* resampling operation - to get the 8x size image, he doubles the size 3 times."

Yes, true, though this isn't his major problem.

A direct 1 -> 8 Lanczos rescale is different (and somewhat better) than doing 1->2 three times, true.

However, doing 1->2 three times properly does *not* create nasty grid artifacts like that and in fact does look much better than doing bilinear.

March 25, 2011 at 7:16 PM

Blogger cbloom said...

Actually that's kind of an interesting test, maybe I'll post that.

March 25, 2011 at 7:26 PM

Blogger cbloom said...

Also it occurs to me that for the case of 3d graphics where we have uv mapping of the texture, you could just shift the uv's.

That is, say you have some height map on a surface and you wish to make a normal map. You could do the "naive gradient" (the [-1,1] filter) which is offset by half a pel, then just shift your uv mapping to compensate.

March 27, 2011 at 10:46 AM

Blogger ryg said...

Sure you can do it, but why would you? The cost of the central difference operator is for all practical purposes identical to forwards/backwards diffs (both for CPU and GPU calculations). And there's a real and nontrivial cost to having two different UV mappings where you used to have one - extra shader instructions, but more importantly, extra complexity. It adds a texture size-dependent offset you need to pass to the shader, so now texture changes might imply constant changes. That kind of dependency is really awkward to have.

March 27, 2011 at 12:42 PM

Blogger cbloom said...

Yeah, indeed.

However, it does give a normal map that's much sharper, for free. In most cases, you don't actually want that sharpness; eg. you would run some kind of blur filter to smooth out the sampling anyway. But in some cases you might.

eg. if you have a heightmap that's like a wire circuit diagram with lots of fine lines and hard steps. Using half-pel offset normals would give you much sharper lines, it's effectively double the resolution.

(BTW this is related to what I call the "sampling fallacy" ; when an artist draws a hard step in a bitmap, they do not mean that they have sampled an infinite resolution image at this sampling step and those are the results, they are actually encoding additional information - eg. they are implying that the hard step exists at higher resolution than they can draw)

March 27, 2011 at 1:08 PM

Blogger ryg said...

Yeah that extra sampling/filtering step is a fundamental issue with the height map to normal map model.

I'm not sure if that's even used that much anymore though. If you bake normal maps from a higher-resolution model, that particular "step ambiguity" is a non-issue - artists can add extra geometry to make edges however sharp they like. And at my old company, the artists started using this baking-style workflow for all normal maps, including stuff like tiled terrain textures. Basically just sculpt your surface structure in Modo/ZBrush then bake a normal map onto a planar mesh. Way more intuitive to work with since the surface structure is explicit instead of implied by the grayscale intensities, and again it's easy to add extra detail where necessary.

Besides, height maps really suck to edit in other ways too. The implicit [0,1] clamping combined with the fact that you're only interested in height deltas not the absolute values makes for a really awkward workflow. Basically you'd need to plan out so you're at a fairly low (or high) value whenever you want to encode a sharp edge. And then you want most other height deltas to be significantly smaller (at least 2x) so the rest of the texture is really low-contrast and hard to edit. It just sucks.

Height maps are a reasonable representation for actual sampled height data where you know the min/max ahead of time and can just normalize stuff to work out, but for manual painting they just suck.

March 27, 2011 at 2:53 PM

Blogger John Costella said...

Sorry, just noticed this thread. A couple of comments:

Thanks for the factorization into 1 1 nearest neighbor upsampling followed by 1 2 1 convolution. I've been looking for a decomposition like that to make it easier to explain. (It's not efficient to compute it like that of course, but conceptually it hits the spot.)

The bicubic and Lanczos upsampling was a single direct 800% upsampling, not three repeated doublings as stated in one comment. And they came straight out of GIMP, so if there's a bug then it's in GIMP. (I will say that I've seen the same artifacts using Photoshop bicubic in the past, so the result didn't surprise me.)

You're right that in principle one could upsample an image using any upsampling method and then apply any of the standard operators. That message needs to be disseminated. But the nice thing about the naive difference operator and the "magic kernel" is that they're about as efficient as you could ask for (a few bit shifts and adds/subtracts and that's it).

Anyhow, nice discussion -- thanks.

May 24, 2011 at 7:17 PM

Blogger Stefan said...

Even with gradient filters the task is not that well-defined. Do you care about gradient magnitude? Rotational accuracy? Rotational invariance? Localisation precision?

I tend to use Simoncelli filters for rotation invariance (Scharr should be similar) and nonlinear filters if I care about localization or magnitude. Another cool trick are "complementary linear bias" gradient filters which make sense in stuff like diffusion (http://dx.doi.org/10.1109/ICPR.2000.903474)

May 25, 2011 at 12:49 PM

You can use some HTML tags, such as <b>, <i>, <a>

This blog does not allow anonymous comments.

Comment moderation has been enabled. All comments must be approved by the blog author.

You will be asked to sign in after submitting your comment.