Skip to content

Commit 5b12a9a

Browse files
author
Olivier Burri
committed
updates de-striping example with an advanced version.
1 parent dc1db2b commit 5b12a9a

File tree

1 file changed

+179
-9
lines changed

1 file changed

+179
-9
lines changed

Week-04/De-Striping.ijm

+179-9
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,201 @@
22
* Fourier Stripe Filtering
33
* ----------------------------------------------
44
*
5-
* This short macro shows the destriping procedure presented in the course slides from 4.3.2
5+
* This macro shows an advanced version of the destriping procedure presented in the course slides from 4.3.2
66
*
7-
* Due to the simple nature of this code, no copyright is applicable
7+
* The procedure has 3 steps
8+
* 1. Detect the angle of the stripes by checking the mean radial intensity in teh Fourier domain
9+
* 2. Create a mask that we can use in Fourier to 'hide' the frequencies around the detected angle
10+
* 3. Apply the mask using the Process>FFT>Custom Filter
11+
*
12+
* NOTE that the stripes are detected in fourier by finding the radius with teh highest mean instansity.
13+
* If the original signal has a strong directionality, this method might fail.
814
*
915
* Code created for Image Processing and Analysis For Life Scientists MOOC on EdX
1016
* https://www.edx.org/course/image-processing-and-analysis-for-life-scientists
1117
*
12-
* 2018 - Olivier Burri, EPFL - SV - BIOP
18+
*
19+
* 2018 - CC-BY Olivier Burri, EPFL - SV - BIOP
1320
* https://biop.epfl.ch
21+
*
1422
*/
15-
run("Close All");
1623

17-
waitForUser("Please Open 'image_with_stripes.tif' and 'Stripe_Filter.tif'");
24+
thickness = 25;
25+
start_radius_px = 10;
26+
27+
28+
roiManager("reset");
29+
// Make sure that the image is opened, or ask the user to open it.
30+
if( !isOpen("image_with_stripes.tif") ) {
31+
run("Close All");
32+
waitForUser("Please Open 'image_with_stripes.tif'");
33+
}
1834

1935
selectImage("image_with_stripes.tif");
36+
close("\\Others");
2037

2138
// Make a copy and apply the stripe filter in Fourier
22-
run("Duplicate...", "title=[Destriped Image]");
39+
run("Duplicate...", " ");
40+
rename("Destriped Image");
41+
run("FFT");
42+
rename("Original Fourier Transform");
43+
waitForUser("Notice the bright almost vertical line on the Fourier image.\nThis is mostly due to the contribution of the stripes.");
2344

24-
// We just run the custom filter on the stiped image
25-
run("Custom Filter...", "filter=Stripe_Filter.tif");
45+
angle = locateAngle();
46+
makeCenteredLine(angle, thickness); // For showing if the computed angles was useful, we display it with a custom function
47+
48+
waitForUser("The angle was determined to be "+angle+" degrees\nWe will now create the Fourier Mask");
49+
50+
// If we know the angle, we can produce a mask in Fourier to hide these frequencies
51+
52+
// We can build a line that
53+
// 1. Goes through the center of the image
54+
// 2. is at 'angle' degrees from the horizontal.
55+
// 3. is 'cut' in the center, to avoid removing interesting low variations
56+
buildCenteredLines(angle, start_radius_px, thickness);
2657

58+
// From these lines, we can build a Fourier mask to use in our image
59+
makeFourierMask();
60+
waitForUser("This is the resulting Fourier Mask.\nYou can look at the code to see how it was created");
61+
62+
// Pick up the name of the fourier mask
63+
filter_name = getTitle();
64+
65+
66+
// We just run the custom filter on the stiped image
67+
selectImage("Destriped Image");
68+
run("Custom Filter...", "filter=["+filter_name+"]");
69+
run("FFT");
70+
rename("Destriped Fourier Transform");
2771
// We can check the difference between the two images to see what was removed
2872
imageCalculator("Subtract create 32-bit", "Destriped Image","image_with_stripes.tif");
2973

3074
rename("Difference between the striped and destriped images");
3175

32-
run("Tile");
76+
run("Tile");
77+
78+
waitForUser("See how a simple line mask in Fourier can efectively remove artifacts from the image.");
79+
80+
waitForUser("You can try it yourself on the original striped image\nand using the 'Stripe Mask.tif' image\nOpen both images and use\nProcess>FFT>Custom FIlter...");
81+
82+
function makeFourierMask() {
83+
// Let's create a Fourier mask
84+
getDimensions(width, height, channels, slices, frames);
85+
newImage("Fourier Mask", "32-bit", width, height, 1);
86+
setForegroundColor(255,255,255);
87+
88+
// We fill the two thick lines in the image and slighly blurr them to avoid edge effects
89+
roiManager("Fill");
90+
91+
run("Invert");
92+
run("Gaussian Blur...", "sigma=5");
93+
94+
95+
}
96+
97+
/*
98+
* locateAngle will make lines from the center of the Fourier image on the two upper quadrants of the image
99+
* It will compute the line profile and extract the mean value along that line and store it in an array
100+
* We will then compute, based on the mean values the highest value and find its corresponding angle
101+
*
102+
*/
103+
function locateAngle() {
104+
steps=1000;
105+
run("Duplicate...", "title=[Angle Detection]");
106+
// Slight blur to remove noise
107+
run("Smooth");
108+
getDimensions(width, height, channels, slices, frames);
109+
r = width/2;
110+
angles = newArray(steps);
111+
intensities = newArray(steps);
112+
angle = 0;
113+
current_mean = 0;
114+
115+
// Break down the upper two quadrants in small steps and loop through each one
116+
for(i=0;i<steps; i++) {
117+
// Get angle in radians
118+
a = i*PI/steps;
119+
120+
// Compute first point for the line
121+
p1x = r*cos(a) + r;
122+
p1y = -r*sin(a) + r;
123+
124+
// Second point is mirrored
125+
p2x = -r*cos(a) + r;
126+
p2y = r*sin(a) + r;
127+
128+
// Make a line and extract its intensity profile
129+
makeLine(p1x, p1y, p2x, p2y,3);
130+
line_profile = getProfile();
131+
132+
// Get the mean intensity along that line
133+
Array.getStatistics(line_profile, line_min, line_max, line_mean, line_stdDev);
134+
135+
// Save the mean intensity
136+
intensities[i] = line_mean;
137+
138+
// Get the current angle in degrees
139+
angles[i] = a/(2*PI)*360;
140+
}
141+
142+
// Close the temporary image we duplicated
143+
close();
144+
// see https://imagej.net/ij/developer/macro/functions.html#Array.findMaxima
145+
indexes = Array.findMaxima(intensities, 2, 2);
146+
highest_value = indexes[0];
147+
return angles[highest_value];
148+
}
149+
150+
/*
151+
* This is just a convenience function to draw a centered line at an angle to visualisation
152+
*/
153+
function makeCenteredLine(angle, thickness) {
154+
angle_radians = angle / 360 * 2*PI;
155+
width = getWidth();
156+
r = sqrt(2)*width/2;
157+
158+
// first point
159+
p1x = r*cos(angle_radians) + width/2;
160+
p1y = -r*sin(angle_radians) + width/2;
161+
162+
// Second point is mirrored
163+
p2x = -r*cos(angle_radians) + width/2;
164+
p2y = r*sin(angle_radians) + width/2;
165+
166+
makeLine(p1x, p1y, p2x, p2y, thickness);
167+
}
168+
169+
/*
170+
* This function will make a line centered on the image
171+
*/
172+
function buildCenteredLines(angle, start_radius, thickness) {
173+
174+
// Get the dimensions of the image
175+
getDimensions(width, height, channels, slices, frames);
176+
177+
// Assuming the image is square, the longest distance to an edge is at the corner
178+
r = sqrt(2)*width/2;
179+
angle_radians = angle / 360 * 2*PI;
180+
// Compute first point for the line
181+
p1x = start_radius*cos(angle_radians) + width/2;
182+
p1y = -start_radius*sin(angle_radians) + width/2;
183+
184+
// Second point is mirrored
185+
p2x = r*cos(angle_radians) + width/2;
186+
p2y = -r*sin(angle_radians) + width/2;
187+
188+
makeLine(p1x, p1y, p2x, p2y, thickness);
189+
190+
// This command allows us to have two lines instead of one, you can ignore it for now. It will be covered in Week 6
191+
roiManager("add");
192+
193+
p1x = -start_radius*cos(angle_radians) + width/2;
194+
p1y = start_radius*sin(angle_radians) + width/2;
195+
196+
// Second point is mirrored
197+
p2x = -r*cos(angle_radians) + width/2;
198+
p2y = r*sin(angle_radians) + width/2;
199+
200+
makeLine(p1x, p1y, p2x, p2y, thickness);
201+
roiManager("add");
202+
}

0 commit comments

Comments
 (0)