各种光线下的阈值面部图像

时间:2013-12-11 21:32:57

标签: android opencv image-processing signal-processing

我想问一些与二值化有关的想法/学习材料。我正在尝试创建检测人类情感的系统。我能够获得眉毛,眼睛,鼻子,嘴巴等区域,但随后又进入另一个阶段 - >处理...

我的照片是在不同的地方/时间/天气条件下拍摄的。在二值化期间存在问题,具有相同的阈值,一个图像是完全黑色的,其他图像看起来很好并且提供了我想要的信息。

我想问你的是:
1)如果知道如何将所有图像置于同一亮度水平?
2)如何在图像上创建阈值和亮度之间的依赖关系?

我现在尝试的是将图像标准化...但是没有效果,也许我做错了。我正在使用OpenCV(用于Android)

Core.normalize(cleanFaceMatGRAY, cleanFaceMatGRAY,0, 255, Core.NORM_MINMAX, CvType.CV_8U);

编辑:

我尝试过自适应阈值,OTSU - 它们对我没用。我在Android中使用CLAHE时遇到问题,但我设法实现了Niblack算法。

Core.normalize(cleanFaceMatGRAY, cleanFaceMatGRAY,0, 255, Core.NORM_MINMAX, CvType.CV_8U);
nibelBlackTresholding(cleanFaceMatGRAY, -0.2);  

private void nibelBlackTresholding(Mat image, double parameter) {
    Mat meanPowered = image.clone();
    Core.multiply(image, image, meanPowered);

    Scalar mean = Core.mean(image);
    Scalar stdmean = Core.mean(meanPowered);

    double tresholdValue = mean.val[0] + parameter * stdmean.val[0];

    int totalRows = image.rows();
    int totalCols = image.cols();

    for (int cols=0; cols < totalCols; cols++) {
        for (int rows=0; rows < totalRows; rows++) {
            if (image.get(rows, cols)[0] > tresholdValue) {
                image.put(rows, cols, 255);
            } else {
                image.put(rows, cols, 0);
            }
        }
    }
}

结果非常好,但对于某些图像仍然不够。我粘贴链接cuz图像很大,我不想拍太多屏幕:

例如,这个是非常好的阈值:
https://dl.dropboxusercontent.com/u/108321090/a1.png https://dl.dropboxusercontent.com/u/108321090/a.png

但是坏光有时会产生阴影,这会产生这种效果: https://dl.dropboxusercontent.com/u/108321090/b1.png https://dl.dropboxusercontent.com/u/108321090/b.png

您是否有任何想法可以帮助我改善具有高光差(阴影)的图像的阈值?

EDIT2:

我发现我之前的算法以错误的方式实现。 Std以错误的方式计算。在Niblack中,阈值均值是本地值而非全局值。我根据此参考http://arxiv.org/ftp/arxiv/papers/1201/1201.5227.pdf

修复了它
private void niblackThresholding2(Mat image, double parameter, int window) {

    int totalRows = image.rows();
    int totalCols = image.cols();
    int offset = (window-1)/2;

    double tresholdValue = 0;

    double localMean = 0;
    double meanDeviation = 0;

    for (int y=offset+1; y<totalCols-offset; y++) {
        for (int x=offset+1; x<totalRows-offset; x++) {
            localMean = calculateLocalMean(x, y, image, window);
            meanDeviation = image.get(y, x)[0] - localMean;
            tresholdValue = localMean*(1 + parameter * ( (meanDeviation/(1 - meanDeviation)) - 1 ));
            Log.d("QWERTY","TRESHOLD " +tresholdValue);
            if (image.get(y, x)[0] > tresholdValue) {
                image.put(y, x, 255);
            } else {
                image.put(y, x, 0);
            }
        }
    }
}

private double calculateLocalMean(int x, int y, Mat image, int window) {
    int offset = (window-1)/2;

    Mat tempMat;
    Rect tempRect = new Rect();
    Point leftTop, bottomRight;

    leftTop = new Point(x - (offset + 1), y - (offset + 1));
    bottomRight = new Point(x + offset, y + offset);
    tempRect = new Rect(leftTop, bottomRight);
    tempMat = new Mat(image, tempRect);

    return Core.mean(tempMat).val[0];
}

7x7窗口的结果和参考k参数中提出的= 0.34:我仍然无法摆脱脸上的阴影。
https://dl.dropboxusercontent.com/u/108321090/b2.png
https://dl.dropboxusercontent.com/u/108321090/b1.png