Adaptive median, can this be true?

I was looking for an implementation of an adaptive median filter (I found one, by the way), and came across to this pair of images (click on the link to see them):


I do not have Matlab installed to try, but can that be really the filtered result from the noisy image above?

Since the images provided are probably not the original ones, there is no way to really assess it. I tried with the one from the website, converted to 8 bit (since it was RGB), and the script does not provide anything close to what shown.

Thanks for trying it. Yes, it might be the case that these are not the originals. I noted locations where white roundish spots in the result appear from areas that have no corresponding white patch.

Hi @gabriel and @gcardone,

That’s probably the issue.
There’s some additional information in this issue: https://github.com/mortezamg63/Adaptive-Median-Filter/issues/2

With that in hand, I put together an IJ1 macro version of this algorithm, to test it out, and it seems to work quite well for salt-and-pepper noise:


run("Duplicate...", "title=noisy");
for (i = 0; i < 10; i++) {
	run("Salt and Pepper");
	}
	
AdaptiveFilter(13);

function AdaptiveFilter(MaxSizeFilter){
	// adapted from: https://github.com/mortezamg63/Adaptive-Median-Filter
	setBatchMode(true);
	title = getTitle();
	filtered = title + "-filtered";
	copy = title + "-copy";
	
	w = getWidth();
	h = getHeight();
	w2 = w + 2 * MaxSizeFilter;
	h2 = h + 2 * MaxSizeFilter;
	

	run("Duplicate...", "title=&filtered");
	run("Canvas Size...", "width=&w2 height=&h2 position=Center zero");
	run("Duplicate...", "title=&copy");

	//lazy padding
	makeRectangle(MaxSizeFilter, MaxSizeFilter, w, h);
	run("Copy");
	run("Canvas Size...", "width="+(w*3)+" height="+(h*3)+" position=Center zero");						
	for (i = -1; i<2; i++){
		for(j = -1; j<2; j++){
			if(!(i==0 && j==0)){
				makeRectangle(w + w*i , h + h*j, w, h);
				run("Paste");
				if(i!=0) run("Flip Horizontally");
				if(j!=0) run("Flip Vertically");
				}
			}
		}
	run("Canvas Size...", "width=&w2 height=&h2 position=Center zero");

	showStatus("Applying Filter");
	StartPoint = MaxSizeFilter - floor (MaxSizeFilter/2);
	for (i = StartPoint; i < w2 - StartPoint; i++){
		showProgress(i, w2 - MaxSizeFilter);
	    for (j = StartPoint; j < h2 - StartPoint; j++){
	               
	        Computation(3, MaxSizeFilter, i, j, filtered, copy);
		    }
		}
	selectWindow(filtered);
	run("Canvas Size...", "width=&w height=&h position=Center zero");
	setBatchMode(false);
	}


function Computation(FilterSize, MaxFilterSize, i, j, filtered, copy) {
		// adapted from: https://github.com/mortezamg63/Adaptive-Median-Filter   
        justification = floor((FilterSize - 1) / 2);
		selectWindow(copy);
		makeRectangle(i - justification, j - justification, FilterSize, FilterSize);

        Zmin=getValue("Min");
        Zmax=getValue("Max");
        Zmed=getValue("Median");
        Zxy=getPixel(i, j);

        selectWindow(filtered);
        B1=Zxy-Zmin;
        B2=Zxy-Zmax;
        if(B1>0 && B2<0){
            setPixel(i, j, Zxy);
            return;
        	}
        else {
            A1=Zmed-Zmin;
            A2=Zmed-Zmax;
            if(A1>0 && A2<0) {
                setPixel(i, j, Zmed);
                return;
            	}
            else {
                if(FilterSize < MaxFilterSize) {
                    FilterSize = FilterSize + 2;
                    Computation(FilterSize, MaxSizeFilter, i, j, filtered, copy);
                    return;
                	}
                else {
                    setPixel(i, j, Zmed);
                }
            }
        }
	}

Cheers,
Nico

4 Likes

Superb! Thanks for posting the macro.

1 Like