# Masking an image with an annulus

I have an image where I would like to do 2 things:

a) Put a disk of radius r on an specific $\{x,y\}$ position on the image such as the result is the original image within the disk and black color outside.

My attempt was this, but the resulting image within the disk looks different

 i = Import["http://exampledata.wolfram.com/coneflower.jpg"]
DiskRec[x_, y_, rr_] := Graphics@Disk[{x, y}, rr];
HighlightImage[i, DiskRec[45, 40, 30], Method -> "Brightness"];
ImageSubtract[i,HighlightImage[i, DiskRec[45, 40, 30], Method -> "Brightness"]]


b)Then, I would like to draw a black circle within the previous one, with a smaller.

Thanks in advance, Juan.

• I'm not sure I fully understand what you're asking, but does this do what you're after? HighlightImage[i, {DiskRec[45, 40, 30], {Black, EdgeForm[Thick], Opacity[1], DiskRec[45, 40, 30]}}, {"Darken", .5}] – Chip Hurst Apr 25 '18 at 21:36
• In the first part, it seems you want to create a circular mask, doesn’t it? However, reading the second one, it seems rather you want an annular mask. Look around here to find similar questions... – José Antonio Díaz Navas Apr 25 '18 at 21:47

## 3 Answers

Get the image:

i = Import["http://exampledata.wolfram.com/coneflower.jpg"];


Define regions for: the whole image, the window disk, the black dot disk:

imRegion = Rectangle[{0, 0}, ImageDimensions[i]]
disk1 = Disk[{80, 60}, 40];
disk2 = Disk[{80, 60}, 10];


Window by changing everything in imRegion but not in disk1 Black:

windowed = ImageApply[{0, 0, 0} &, i, Masking -> RegionDifference[imRegion, disk1]]


Dot by changing everything in disk2 to Black:

dotted = ImageApply[{0, 0, 0} &, windowed, Masking -> disk2]


Done knowing what result you want before starting, we can just skip to defining your region of interest as an Annulus:

roi = Annulus[{80, 60}, {10, 40}];
viewRoI = ImageApply[{0, 0, 0} &, i, Masking -> RegionDifference[imRegion, roi]]


This returns the same as the dotted version of windowed, so I won't add another image.

EDIT:

There was a request to move away from using Region, because so much of Region support is new (and not implemented in old versions).

We can use ImageApplyIndexed to achieve this effect as long as we keep the "Regions" of interest simple enough that it is easy to test if a coordinate pair lies in the region.

Our Version 10 - robust method looks like this:

Define an image:

i = RandomImage[1, {150, 113}, ColorSpace -> "RGB"];


Define some parameters to characterize the disks:

{d1Center, d1Radius} = {{50, 80}, 40};
{d2Center, d2Radius} = {{50, 80}, 10};


- Note that because of how ImageApplyIndexed feeds pixel coordinates, the center here is specified as {"row from top", "column from left"}.

Now we turn all pixels not in disk 1 Black:

windowed = ImageApplyIndexed[If[EuclideanDistance[#2, d1Center] > d1Radius, {0, 0, 0}, #1] &, i]


And then turn just the pixels in disk2 Black:

dotted = ImageApplyIndexed[If[EuclideanDistance[#2, d2Center] > d2Radius, #1, {0, 0, 0}] &, windowed]

• Well, I am working on a 10 version, and it does not recognize ´RegionDifference´ as an option for Masking. – Juan Manuel Gomba Apr 26 '18 at 12:41
• I have edited to accommodate back to version 10. The second answer is a bit narrower in applicability because you've got to have a way to test if a pixel lies in your RoI, but that is easy for disks. – kjosborne Apr 26 '18 at 15:46
• Thanks, it looks exactly what I was looking for, now for an old version. – Juan Manuel Gomba Apr 26 '18 at 16:04

We can define a general mask based on Annulus[]. Then Rasterize the Graphics, resize it, padd it, and locate in any position in the image to be masked:

mask[img_, pos_, rin_, size_] := ImagePad[ImageResize[
ColorNegate@
Rasterize@
Graphics[Annulus[{0, 0}, {rin, 1}],
PlotRangePadding -> 0], {size}], {{pos[[2]] - size/2,
img[[1]] - (pos[[2]] + size/2)}, {img[[2]] - (pos[[1]] + size/2),
pos[[1]] - size/2}}]


As an example the mask resulting is:

m = mask[ImageDimensions[i], {50, 50}, 0.2, 50]


and applied to the image provided:

ImageMultiply[i, m]


Another example:

i = Import[
"C:\\Users\\Public\\Pictures\\Sample Pictures\\Penguins.jpg"]


m = mask[ImageDimensions[i], {500, 500}, 0.5, 500];
ImageMultiply[i, m]


Further improvement would consist in taking into account that the annulus will always be inside the image dimensions.

## EDIT

When Annulus is not available, this also works:

mask[img_, pos_, rin_, size_] := ImagePad[ImageResize[
ColorNegate@Rasterize@
Graphics[{Disk[], White, Disk[{0, 0}, rin]},
PlotRangePadding -> 0], {size}], {{pos[[2]] - size/2,
img[[1]] - (pos[[2]] + size/2)}, {img[[2]] - (pos[[1]] + size/2),
pos[[1]] - size/2}}]

• Version 10 does not have the Annulus command. Is it possible to do the same without Annulus? I tried this, but is not possible to be employed in place of Annulus DiscretizeRegion[ RegionDifference[Disk[{0, 0}, 200], Disk[{0, 40}, 100]]] – Juan Manuel Gomba Apr 26 '18 at 12:47
• @JuanManuelGomba see my edit. No need to use RegionPlot... – José Antonio Díaz Navas Apr 26 '18 at 16:26
• Thanks José, the use of Disk seems to work well when the radius of the inner disk is smaller than the outer one. I observe some distortion of the mask. – Juan Manuel Gomba Apr 26 '18 at 16:32

thanks to your input I was able to find an answer for my old version.

 i = Import["http://exampledata.wolfram.com/coneflower.jpg"];

dim = ImageDimensions[i];

R[x_, y_, rin_] := RegionPlot[RegionDifference[Disk[{0, 0}, Max[dim]],Disk[{x, y}, rin]], Frame -> False, PlotStyle -> {Black, Opacity[1]}]

mask[img_, pos_, size_, x_, y_, rin_] :=ImagePad[ImageResize[ColorNegate@Rasterize@Graphics[R[x, y, rin],  PlotRangePadding -> 0], {size}], {{pos[[2]] - size/2,img[[1]] - (pos[[2]] + size/2)}, {img[[2]] - (pos[[1]] + size/2),pos[[1]] - size/2}}]

Manipulate[{R[xx, yy, rre],m = mask[dim, {dim[[2]] - a, b}, rre, xx, yy, rr],multi = ImageMultiply[i, m]},{a, 1, dim[[2]], 1}, {b, 1, dim[[1]], 1}, {rre, 1, dim[[1]], 1}, {xx,1,dim[[2]], 1}, {yy, 1, dim[[1]], 1}, {rr, 1, dim[[1]], 1}]