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 |
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) { |
|||
⚫ | |||
alias Hist = uint[256]; |
|||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
static ubyte median(uint no)(in ref Hist cumulative) pure nothrow { |
|||
RgbBitmap filterChannel(int Radius = 10)(RgbBitmap rgb, uint idx) { |
|||
⚫ | |||
auto res = RgbBitmap(rgb.width, rgb.height); |
|||
foreach (immutable ubyte k, immutable v; cumulative) |
|||
res.data = rgb.data.dup; |
|||
if (v) { |
|||
⚫ | |||
alias uint[256] Hist; |
|||
⚫ | |||
Hist H; |
|||
⚫ | |||
Hist[] hCol; |
|||
⚫ | |||
⚫ | |||
⚫ | |||
// 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]; |
|||
enum edge = 2 * radius + 1; |
|||
auto hCol = new Hist[img.nx]; |
|||
⚫ | |||
⚫ | |||
for (int j = 0; j < rgb.width; j++) |
|||
hCol[j][ rgb.data[i*rgb.width + j].value[idx] ]++; |
|||
⚫ | |||
for (int i = Radius; i < rgb.height - Radius; i++) { |
|||
⚫ | |||
⚫ | |||
foreach (immutable x, ref hx; hCol) |
|||
hx[img[x, y]]++; |
|||
⚫ | |||
foreach (immutable y; radius .. img.ny - radius) { |
|||
⚫ | |||
foreach (immutable x, ref hx; hCol) |
|||
hx[img[x, y + radius]]++; |
|||
// |
// Calculate main Histogram using first edge-1 columns. |
||
H |
Hist H; |
||
foreach (immutable x; 0 .. edge - 1) |
|||
foreach(k,v; hCol[x] |
foreach (immutable k, immutable v; hCol[x]) |
||
⚫ | |||
H[k] += v; |
H[k] += v; |
||
foreach (immutable x; radius .. img.nx - radius) { |
|||
// |
// Add right-most column. |
||
foreach (k, v; hCol[ |
foreach (immutable k, immutable v; hCol[x + radius]) |
||
if (v) |
|||
H[k] += v; |
H[k] += v; |
||
result[x, y] = Color(median!(edge ^^ 2)(H)); |
|||
// |
// Drop left-most column. |
||
foreach (k, v; hCol[ |
foreach (immutable k, immutable v; hCol[x - radius]) |
||
if (v) |
|||
H[k] -= v; |
|||
} |
} |
||
// |
// Substract the upper pixels. |
||
foreach (immutable x, ref hx; hCol) |
|||
hx[img[x, y - radius]]--; |
|||
} |
} |
||
return |
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}}== |