Jul 26, 2015

Denoise filters: Median

Gauss and Mean filters required a good knowledge of mathematics to understand its background. Median filter is very similar to both of them, but it based in a more logical approach than a mathematical one.
The Median filter read all pixels in the scan window and put all of them in an array:
27 0 172 87 108 251 12 151 198

Then, sort the array:

0 12 27 87 108 151 172 198 251

And finally, takes the value in the middle, 108 in this case, and write the pixel in the output image. The same process is done for each channel. This is the code for the Mean filter:
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    Q_UNUSED(a)

    QImage inImage("lena.png");
    inImage = inImage.convertToFormat(QImage::Format_RGB32);
    QImage outImage(inImage.size(), inImage.format());

    // Here we configure the denoise parameters.
    int radius = 3;

    // Add noise to the image
    qsrand(QTime::currentTime().msec());

    for (int i = 0; i < 100000; i++) {
        inImage.setPixel(qrand() % inImage.width(),
                         qrand() % inImage.height(),
                         qRgb(qrand() % 256,
                              qrand() % 256,
                              qrand() % 256));
    }

    Buffer image(inImage);
    Buffer buffer;

    QElapsedTimer timer;
    timer.start();

    for (int y = 0; y < inImage.height(); y++) {
        QRgb *oLine = (QRgb *) outImage.scanLine(y);
        int yp = qMax(y - radius, 0);
        int kh = qMin(y + radius, inImage.height() - 1) - yp + 1;

        for (int x = 0; x < inImage.width(); x++) {
            int xp = qMax(x - radius, 0);
            int kw = qMin(x + radius, inImage.width() - 1) - xp + 1;

            // Adjust the buffer to the number of pixels we want to sort.
            buffer.resize(kw, kh);

            // Copy all pixels in scan window to the buffer.
            for (int j = 0; j < kh; j++) {
                QVector<const quint8 *> pixel = image.constPixel(xp, yp + j);
                buffer.copy(j, pixel);
            }

            // Sort the buffer.
            buffer.sort();

            // Select the pixel in the middle of the buffer.
            QVector<quint8> pixel = buffer[buffer.size / 2];

            oLine[x] = qRgb(pixel[0], pixel[1], pixel[2]);
        }
    }

    qDebug() << timer.elapsed();
    outImage.save("median.png");

    return EXIT_SUCCESS;
}

The full source code is in my github.

For an input image with a noise of 100k:



the result for a scan window of $r=3$ is this:



In this image you can compare the quality of the Gauss, Mean and Median filters for a noise of 100k, $r=3$, $\sigma=1000$ for Gauss and $\sigma=1$ for Mean:

No comments:

Post a Comment