How to blur background?

The MagickWand interface is a new high-level C API interface to ImageMagick core methods. We discourage the use of the core methods and encourage the use of this API instead. Post MagickWand questions, bug reports, and suggestions to this forum.
Post Reply
pulsar
Posts: 6
Joined: 2015-03-18T11:21:35-07:00
Authentication code: 6789

How to blur background?

Post by pulsar »

Hello,

I am writing a C program to process my astrophotography images. I got the basics of Magick Wand programming (reading/writing the image; manipulation with pixel brightness values), but now I am lost trying to do a more advanced task. I wonder if anyone could point me in the right direction?

Specifically, I designate certain pixels in the input image as "noisy" (basically, the least bright ones), and the rest are "signal" (a small fraction of all pixels). I want to leave the "signal" pixels as is, and to apply a (Gaussian) blur to the noisy pixels, ignoring the "signal" pixels. This should bring faint details out of noise. At the end I want to combine the blurred noisy pixels with the signal pixels.

I have image wand, image_wand_out, with iterator_out being its pixel iterator. The image doesn't have alpha/matte/mask objects. I have a double loop over x,y coordinates, where I'm using PixelGetNextIteratorRow and PixelGetMagickColor to get and process r, g, b pixel values.

From what I read I will likely need to use MagickSetImageMask, and to apply both ReadPixelMask and WritePixelMask, but I can't figure out how to proceed.

I'd appreciate any help with this!
snibgo
Posts: 12159
Joined: 2010-01-23T23:01:33-07:00
Authentication code: 1151
Location: England, UK

Re: How to blur background?

Post by snibgo »

What version of IM are you using? I guess it is V7.something.
pulsar wrote:At the end I want to combine the blurred noisy pixels with the signal pixels.
I think this is the key problem to be solved. How do you want to combine them? I can think of two obvious methods:

(a) Use a mask, which could be white where you have a signal and black where you don't. Then you simply composite the input image over the blurred noise, with the mask image.

(b) If you have a "signal" image that is black were this is no signal, and non-black where there is a signal, the brigter of this and the blurred background is the required output.

Option (a) seems most appropriate. I'll assume you can make that mask.

Next question: How do you want to blur the noise? If you simply blur the entire input image, the lighter signal pixels will bleed lightness out into the noise. I don't know if a read-mask solves this problem. If it does, great. If not, you can replace the signal pixels with "invented noise" before blurring. One method for this is is to make them transparent, and fill them with one of the methods shown on my "Filling holes" page.

But the obvious hole-filler method is blurFill, and you want to blur anyway. So you can simply make your signal pixels transparent, and do your blurring. The holes may not be completely filled but that doesn't matter as they will be replaced by signal pixels.
snibgo's IM pages: im.snibgo.com
pulsar
Posts: 6
Joined: 2015-03-18T11:21:35-07:00
Authentication code: 6789

Re: How to blur background?

Post by pulsar »

Thanks for the quick reply!

I am only familiar with v6.x, so that's what I'm currently using. (I just compiled a 6.8 version with Q32 quantum range for this project.)

I found a command line (not C API) IM example solving the same problem (blurring background); there they just made the fg pixels transparent (effectively applying a read mask to them; but I think they also applied a write mask to the same pixels in a separate process); after blurring they simply made the fg pixels non-transparent again, which effectively combined bg and fg in the way I want to do - use bg pixels everywhere where there are no fg pixels. I just want to implement this using Magick Wand.

Here is the link:

http://www.imagemagick.org/Usage/masking/#read_mask
pulsar
Posts: 6
Joined: 2015-03-18T11:21:35-07:00
Authentication code: 6789

Re: How to blur background?

Post by pulsar »

I just went through the description of all Wand functions, and now have more specific questions.

1) Is Alpha manipulations all I need to achieve my goal? (So I don't need masks, channels, matte etc.). Specifically, if I create an alpha channel for my image, set my "signal" pixels to alpha=0 (fully transparent), and then apply MagickGaussianBlurImage to the image wand - will it take the transparency into account, and only blur the background pixels based on their brightness (and ignore the signal pixels)? Ain other words, will I achieve "ReadMask" this way? I think I don't care much about WriteMask at this point, as I will put back the original signal pixel values at the end.

2) After the above, I think I just need to remove the alpha channel, and put back the original (unmodified) values of my signal pixels.

So I'm thinking about something like this:

image_wand_out = CloneMagickWand(image_wand_in);
MagickSetImageAlphaChannel (image_wand_out, ActivateAlphaChannel);
iterator_out = NewPixelIterator(image_wand_out);
for (y=0; y < (long) MagickGetImageHeight(image_wand_out); y++)
{
pixels_out=PixelGetNextIteratorRow(iterator_out,&width);
if ((pixels_out == (PixelWand **) NULL))
break;
for (x=0; x < (long) width; x++)
{
if (signal)
PixelSetAlpha(pixels_out[x], 0.0);
else
PixelSetAlpha(pixels_out[x], 1.0);
}
(void) PixelSyncIterator(iterator_out);
}
iterator_out = DestroyPixelIterator(iterator_out);
MagickGaussianBlurImage(image_wand_out, radius, sigma);
MagickSetImageAlphaChannel(image_wand_out, DeactivateAlphaChannel);

I guess now that I wrote it down I might as well test it...
pulsar
Posts: 6
Joined: 2015-03-18T11:21:35-07:00
Authentication code: 6789

Re: How to blur background?

Post by pulsar »

Hmm, it looks like I can't even add the alpha channel to my image wand. I tried this:

image_wand_out = CloneMagickWand(image_wand_in);
MagickSetImageAlphaChannel(image_wand_out,ActivateAlphaChannel);
MagickSetImageAlphaChannel(image_wand_out,OpaqueAlphaChannel);

without trying to destroy the alpha channel at the end. The image it creates is a plain sRGB, no alpha channel present. And when I'm trying to blur it in my code, it blurs everything (signal and noise), so it doesn't see (or doesn't care) the alpha setting.

What am I doing wrong?

EDIT: I found the problem (using a debugger). In my code I first used PixelSetAlpha(pixels_out[x], alpha), and then later on did PixelSetMagickColor(pixels_out[x],&pixel_out). I could see in the debugger that PixelSetAlpha correctly modifies the pixel opacity, but executing PixelSetMagickColor sets it back to zero. The solution was not to use PixelSetAlpha, and instead set the pixel_out.opacity value directly, before PixelSetMagickColor. That fixed the problem - I now get proper transparency for the pixels I want.
Post Reply