Median filter: Difference between revisions

Content added Content deleted
(Added BBC BASIC)
(Updated and improved D entry (but currently it's grayscale only))
Line 300: Line 300:
=={{header|D}}==
=={{header|D}}==


This uses structures defined on [[Basic bitmap storage]] problem page.
This uses modules of the [[Bitmap]] and [[Grayscale image]] Tasks.


The implementation uses algorithm described in [http://nomis80.org/ctmf.html Median Filtering in Constant Time]
The implementation uses algorithm described in [http://nomis80.org/ctmf.html Median Filtering in Constant Time]
paper with some slight differences, that shouldn't have impact on complexity.
paper with some slight differences, that shouldn't have impact on complexity.


Currently this code works only on greyscale images.
Unfortunatelly because Bitmap's structure overloaded opIndex operator (as defined in [[Basic bitmap storage]]), doesn't return reference
<lang d>import grayscale_image;
(since you can't return a reference in D 1.0, but this handy feature is present in D 2.0), calculations
are made directly on underlying data buffer, good side of that is this is probably faster.


Image!Color medianFilter(uint radius=10, Color)(in Image!Color img)
<lang D>ubyte median(uint[] cummulative, int no) {
pure nothrow if (radius > 0) {
int localSum;
foreach (k, v; cummulative)
alias Hist = uint[256];
if (v) {
localSum += v;
if (localSum > no / 2)
return k;
}
return 0;
}


static ubyte median(uint no)(in ref Hist cumulative) pure nothrow {
RgbBitmap filterChannel(int Radius = 10)(RgbBitmap rgb, uint idx) {
size_t localSum = 0;
auto res = RgbBitmap(rgb.width, rgb.height);
foreach (immutable ubyte k, immutable v; cumulative)
res.data = rgb.data.dup;
int edge = 2*Radius + 1, rsqr = edge*edge;
if (v) {
localSum += v;
alias uint[256] Hist;
if (localSum > no / 2)
Hist H;
return k;
Hist[] hCol;
}
return 0;
}


// Copy image borders in the result image.
static assert ( Radius >= 1 );
auto result = new Image!Color(img.nx, img.ny);
foreach (immutable y; 0 .. img.ny)
foreach (immutable x; 0 .. img.nx)
if (x < radius || x > img.nx - radius ||
y < radius || y > img.ny - radius)
result[x, y] = img[x, y];


hCol.length = rgb.width;
enum edge = 2 * radius + 1;
auto hCol = new Hist[img.nx];
// create histogram columns
for (int i = 0; i < edge - 1; i++)
for (int j = 0; j < rgb.width; j++)
hCol[j][ rgb.data[i*rgb.width + j].value[idx] ]++;


// Create histogram columns.
for (int i = Radius; i < rgb.height - Radius; i++) {
foreach (immutable y; 0 .. edge - 1)
// add to each histogram column lower pixel
for (int j = 0; j < rgb.width; j++) {
foreach (immutable x, ref hx; hCol)
hCol[j][ rgb.data[(i + Radius)*rgb.width + j].value[idx] ]++;
hx[img[x, y]]++;

}
foreach (immutable y; radius .. img.ny - radius) {
// Add to each histogram column lower pixel.
foreach (immutable x, ref hx; hCol)
hx[img[x, y + radius]]++;


// calculate main Histogram using first edge-1 columns
// Calculate main Histogram using first edge-1 columns.
H[] = 0;
Hist H;
for (int x = 0; x < edge - 1; x++)
foreach (immutable x; 0 .. edge - 1)
foreach(k,v; hCol[x]) if (v)
foreach (immutable k, immutable v; hCol[x])
if (v)
H[k] += v;
H[k] += v;


for (int j = Radius; j < rgb.width - Radius; j++) {
foreach (immutable x; radius .. img.nx - radius) {
// add right-most column
// Add right-most column.
foreach (k, v; hCol[j + Radius]) if (v)
foreach (immutable k, immutable v; hCol[x + radius])
if (v)
H[k] += v;
H[k] += v;


res.data[i*res.width + j].value[idx] = median(H, rsqr);
result[x, y] = Color(median!(edge ^^ 2)(H));


// drop left-most column
// Drop left-most column.
foreach (k, v; hCol[j - Radius]) if (v)
foreach (immutable k, immutable v; hCol[x - radius])
H[k] -= v;
if (v)
H[k] -= v;
}
}


// substract the upper pixels
// Substract the upper pixels.
for (int j = 0; j < rgb.width; j++)
foreach (immutable x, ref hx; hCol)
hCol[j][ rgb.data[(i - Radius)*rgb.width + j].value[idx] ]--;
hx[img[x, y - radius]]--;
}
}


return res;
return result;
}

version (median_filter_main) {
void main() { // Demo.
loadPGM!Gray(null, "lena.pgm")
.medianFilter!10()
.savePGM("lena_median_r10.pgm");
}
}</lang>
}</lang>
Compile with -version=median_filter_main to run the demo.

Sample usage:
<lang D>alias filterChannel!(10) median10;
auto inFile = new P6Image(new FileConduit("input.ppm"));

auto c1 = inFile.bitmap;
auto c2 = median10(c1, 0); // red
auto c3 = median10(c2, 1); // green
auto c4 = median10(c3, 2); // blue

// this requires constructor defined in [[Write ppm file]]
auto outFile = new P6Image(c4, inFile.maxVal);
write (outFile);</lang>



=={{header|GDL}}==
=={{header|GDL}}==