Lisp HUG Maillist Archive

Artifacts when drawing scaled bitmaps (via gp:draw-image)

Hi LispWorkers,

I am scaling images derived via gp:make-image-from-port in the following manner:

(capi:with-geometry pane
  (gp:with-graphics-scale (pane (/ capi:%width% iw) (/ capi:%height% ih))
    (gp:draw-image pane image 0 0)))

where iw and ih are the image width and height, respectively. This works nicely
when I want to scale the image up, but if I resize down a grid of vertical and
horizontal black lines appears. This seems to relate to the fact that internally
CAPI images are bitmaps. I get the same effect if the image is derived from an
external .bmp file, but with .png, .gif, .tiff or .jpg everything rescales
perfectly.

The images themselves are highly granular (spectrograms, actually), and this
seems to be a significant factor - larger areas of pure color are unaffected.
Also I don't think this has anything to do with compression, as I have tested
with uncompressed .tiff files and they work fine. Whether the bitmap is paletted
or true color also seems to be irrelevant.

Since I'm deriving my images from CAPI ports I'm stuck with bitmaps - so if
anyone can offer a possible solution, or even just a clue as to why this
happens, I would be most grateful.

Best wishes and compliments of the season,
Chris



RE: Artifacts when drawing scaled bitmaps (via gp:draw-image)

Unfortunately my previous two attempts to post in this thread seem to have failed - they had images attached, and were possibly too big (320kb??)...

Anyway, I'm pretty convinced the effect I'm seeing is a Moire pattern:

http://en.wikipedia.org/wiki/Moire

Instead of continuing to bang my head against a Google-shaped wall in the search for an answer I have opted for a different strategy: using .png images. I can generate these by passing .png data to the :data initarg of a new gp:external-image (as in "/examples/capi/buttons/buttons.lisp"), compressing the data to .png format using Salza2. The only problem then is that scaling a .png upwards results in blurring, which I can't guarantee won't be excessive.

I would still prefer to use bitmaps, however, so huge thanks in advance to anyone who has even the faintest suggestion of a possible solution or explanation for this issue..

Best,
Chris


> To: lisp-hug@lispworks.com
> From: relativeflux@hotmail.co.uk
> Subject: Artifacts when drawing scaled bitmaps (via gp:draw-image)
> Date: Thu, 30 Dec 2010 22:58:01 +0000
>
>
> Hi LispWorkers,
>
> I am scaling images derived via gp:make-image-from-port in the following manner:
>
> (capi:with-geometry pane
> (gp:with-graphics-scale (pane (/ capi:%width% iw) (/ capi:%height% ih))
> (gp:draw-image pane image 0 0)))
>
> where iw and ih are the image width and height, respectively. This works nicely
> when I want to scale the image up, but if I resize down a grid of vertical and
> horizontal black lines appears. This seems to relate to the fact that internally
> CAPI images are bitmaps. I get the same effect if the image is derived from an
> external .bmp file, but with .png, .gif, .tiff or .jpg everything rescales
> perfectly.
>
> The images themselves are highly granular (spectrograms, actually), and this
> seems to be a significant factor - larger areas of pure color are unaffected.
> Also I don't think this has anything to do with compression, as I have tested
> with uncompressed .tiff files and they work fine. Whether the bitmap is paletted
> or true color also seems to be irrelevant.
>
> Since I'm deriving my images from CAPI ports I'm stuck with bitmaps - so if
> anyone can offer a possible solution, or even just a clue as to why this
> happens, I would be most grateful.
>
> Best wishes and compliments of the season,
> Chris
>
>

RE: Artifacts when drawing scaled bitmaps (via gp:draw-image)

Many thanks, David, for taking the time to reply, one which (as ever) has proven highly informative and stimulating.

I am going to investigate the method you suggest, although on the face of it it seems that it would likely be more expensive than my application's core analysis engine. I was hoping to implement 'live resize' for my spectrograms, as I have with my waveform display, but that seems unfeasible given the amount of computation likely to be required with this method. But I will take a look at it nonetheless, and do some experimentation.

Many thanks again, and best wishes,
Chris


CC: lisp-hug@lispworks.com
From: dbm@refined-audiometrics.com
Subject: Re: Artifacts when drawing scaled bitmaps (via gp:draw-image)
Date: Tue, 4 Jan 2011 02:10:49 -0700
To: relativeflux@hotmail.co.uk

Hello Chris,

The problem you are seeing is no doubt due to the manner in which Windows resamples the large image for shrinking. There are so many different ways to do this - some good, some not so good. I don't know the details for how Windows accomplishes this.

But in order to get a decent shrunken representation, you need to low-pass filter the image before resampling. If you don't do this, you end up with aliasing artifacts. And that's what you are seeing as Moire patterns.

The way to do low-pass filtering depends hugely on how much shrinkage you are trying to accomplish. It could be as simple as a (1 2 1) x (1 2 1)  [ matrix outer-product ] kernel, convolved over the image. Or it could be a very elaborate 2-D FFT filtering.

However you do it, this will take some serious compute cycles, and that's probably why Windows opts for the cheapest possible method. And obviously, their method introduces aliasing because they either didn't low-pass filter the image, or their filter is too crude.

Once the image is properly low-pass filtered, then the usual way to shrink the image is to create the destination bitmap and for every pixel in that bitmap compute the corresponding location in the larger bitmap and take its (low-pass filtered) pixel value as the value to plant in the smaller bitmap. This also takes some serious computing power, especially if you are animating 2-D images.

See just about any Astronomical journal over the past two decades for numerous articles on this process. At least that's where I learned to do it. No doubt a decent text on image processing would tell you the same things...

Cheers,

Dr. David McClain
Chief Technical Officer
Refined Audiometrics Laboratory
4391 N. Camino Ferreo
Tucson, AZ  85750

email: dbm@refined-audiometrics.com
phone: 1.520.390.3995
web: http://refined-audiometrics.com



On Jan 4, 2011, at 00:18, Christopher Melen wrote:

Unfortunately my previous two attempts to post in this thread seem to have failed - they had images attached, and were possibly too big (320kb??)...

Anyway, I'm pretty convinced the effect I'm seeing is a Moire pattern:

http://en.wikipedia.org/wiki/Moire

Instead of continuing to bang my head against a Google-shaped wall in the search for an answer I have opted for a different strategy: using .png images. I can generate these by passing .png data to the :data initarg of a new gp:external-image (as in "/examples/capi/buttons/buttons.lisp"), compressing the data to .png format using Salza2. The only problem then is that scaling a .png upwards results in blurring, which I can't guarantee won't be excessive.

I would still prefer to use bitmaps, however, so huge thanks in advance to anyone who has even the faintest suggestion of a possible solution or explanation for this issue.

Best,
Chris


> To: lisp-hug@lispworks.com
> From: relativeflux@hotmail.co.uk
> Subject: Artifacts when drawing scaled bitmaps (via gp:draw-image)
> Date: Thu, 30 Dec 2010 22:58:01 +0000
> 
> 
> Hi LispWorkers,
> 
> I am scaling images derived via gp:make-image-from-port in the following manner:
> 
> (capi:with-geometry pane
> (gp:with-graphics-scale (pane (/ capi:%width% iw) (/ capi:%height% ih))
> (gp:draw-image pane image 0 0)))
> 
> where iw and ih are the image width and height, respectively. This works nicely
> when I want to scale the image up, but if I resize down a grid of vertical and
> horizontal black lines appears. This seems to relate to the fact that internally
> CAPI images are bitmaps. I get the same effect if the image is derived from an
> external .bmp file, but with ..png, .gif, .tiff or .jpg everything rescales
> perfectly.
> 
> The images themselves are highly granular (spectrograms, actually), and this
> seems to be a significant factor - larger areas of pure color are unaffected.
> Also I don't think this has anything to do with compression, as I have tested
> with uncompressed .tiff files and they work fine. Whether the bitmap is paletted
> or true color also seems to be irrelevant.
> 
> Since I'm deriving my images from CAPI ports I'm stuck with bitmaps - so if
> anyone can offer a possible solution, or even just a clue as to why this
> happens, I would be most grateful.
> 
> Best wishes and compliments of the season,
> Chris
> 
> 

RE: Artifacts when drawing scaled bitmaps (via gp:draw-image)

Hello again David,

Inspired by your last post I've been doing some research into this (actually rather fascinating) topic, and came across a nice little library called FreeImage (http://freeimage.sourceforge.net/). Its rescaling function offers a range of filter options (box, bicubic, Catmull-Rom, etc.), and I've been experimenting with it through the FLI. My initial tests have given some very pleasing results, and I'm confident that I can satisfactorily resolve this issue now. Many thanks again, David, for your helpful suggestions.

Of course I'm doing all this via an external library (actually C++), but it might be something I'd want to implement myself. So if you don't mind me asking, do you do this kind of thing entirely in Lisp or go through the FLI?

Regards,
Chris


CC: lisp-hug@lispworks.com
From: dbm@refined-audiometrics.com
Subject: Re: Artifacts when drawing scaled bitmaps (via gp:draw-image)
Date: Thu, 6 Jan 2011 11:04:43 -0700
To: relativeflux@hotmail.co.uk

Hello Chris,

I didn't mean to scare you off... As with so much of computer graphics, most of what you see is "smoke and mirrors". If you can carefully restrict the range of variations you wish to see, you could easily come up with a fast, inexpensive, method for shrinking images. For example, 2:1 or 3:1. The difficulties mostly arise from having to be open to all possible scalings.

But, for example, if you restricted the shrinkage to a factor of 3, then you can easily compute the low-pass filtered image as a fast convolution with a 1-2-1 kernel:

#2A((1 2 1) (2 4 2) (1 2 1))

And since you will be resampling every 3rd pixel in both rows and columns, you really only need to take every destination pixel, find which exact pixel in the source corresponds to it, then perform the convolution sum over the source pixels under the kernel centered at that source pixel, and record that sum as your new destination pixel. You might want to rescale the filtered value to account for the summation growth. Depends on what your pixels represent.

For color images, you need to do this for every color plane.

By restricting the options we are able to arrive at a very cheap, fast, solution.

The full-blown solution, for arbitrary shrinkage factors is more involved. It probably requires a 2-D FFT for low-pass filtering, taking care of edge effects since the FFT is a circular convolution, and then using bilinear interpolation in the destination to source mappings to decide what value to use in the destination bitmap.


Dr. David McClain
Chief Technical Officer
Refined Audiometrics Laboratory
4391 N. Camino Ferreo
Tucson, AZ  85750

email: dbm@refined-audiometrics.com
phone: 1.520.390.3995
web: http://refined-audiometrics.com

Updated at: 2020-12-10 08:38 UTC