opencvfilteringbiometricsimage-enhancement

palm veins enhancement with OpenCV


I'm trying to implement in OpenCV an algorithm to bring out the details of a palm vein pattern. I've based myself on a paper called "A Contactless Biometric System Using Palm Print and Palm Vein Features" that I've found on the Internet. The part I'm interested in is the chapter 3.2 Pre-processing. The steps involved are shown there.

I'd like to do the implementation using OpenCV but until now I'm stuck hard. Especially they use a Laplacian filter on the response of a low-pass filter to isolate the principal veins but my result gets very noisy, no matter the parameters I try!

Any help would be greatly appreciated!


Solution

  • Ok finally I've figured out by myself how to do it. Here is my code :

    #include <opencv2/core/core.hpp>
    #include <opencv2/highgui/highgui.hpp>
    #include <opencv2/imgproc/imgproc.hpp>
    
    #define THRESHOLD 150
    #define BRIGHT 0.7
    #define DARK 0.2
    
    using namespace std;
    using namespace cv;
    
    int main()
    {
    
        // Read source image in grayscale mode
        Mat img = imread("roi.png", CV_LOAD_IMAGE_GRAYSCALE);
    
        // Apply ??? algorithm from https://stackoverflow.com/a/14874992/2501769
        Mat enhanced, float_gray, blur, num, den;
        img.convertTo(float_gray, CV_32F, 1.0/255.0);
        cv::GaussianBlur(float_gray, blur, Size(0,0), 10);
        num = float_gray - blur;
        cv::GaussianBlur(num.mul(num), blur, Size(0,0), 20);
        cv::pow(blur, 0.5, den);
        enhanced = num / den;
        cv::normalize(enhanced, enhanced, 0.0, 255.0, NORM_MINMAX, -1);
        enhanced.convertTo(enhanced, CV_8UC1);
    
        // Low-pass filter
        Mat gaussian;
        cv::GaussianBlur(enhanced, gaussian, Size(0,0), 3);
    
        // High-pass filter on computed low-pass image
        Mat laplace;
        Laplacian(gaussian, laplace, CV_32F, 19);
        double lapmin, lapmax;
        minMaxLoc(laplace, &lapmin, &lapmax);
        double scale = 127/ max(-lapmin, lapmax);
        laplace.convertTo(laplace, CV_8U, scale, 128);
    
        // Thresholding using empirical value of 150 to create a vein mask
        Mat mask;
        cv::threshold(laplace, mask, THRESHOLD, 255, CV_THRESH_BINARY);
    
        // Clean-up the mask using open morphological operation
        morphologyEx(mask,mask,cv::MORPH_OPEN,
            getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(5,5)));
    
        // Connect the neighboring areas using close morphological operation
        Mat connected;
        morphologyEx(mask,mask,cv::MORPH_CLOSE,
            getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(11,11)));
    
        // Blurry the mask for a smoother enhancement
        cv::GaussianBlur(mask, mask, Size(15,15), 0);
    
        // Blurry a little bit the image as well to remove noise
        cv::GaussianBlur(enhanced, enhanced, Size(3,3), 0);
    
        // The mask is used to amplify the veins
        Mat result(enhanced);
        ushort new_pixel;
        double coeff;
        for(int i=0;i<mask.rows;i++){
            for(int j=0;j<mask.cols;j++){
                coeff = (1.0-(mask.at<uchar>(i,j)/255.0))*BRIGHT + (1-DARK);
                new_pixel = coeff * enhanced.at<uchar>(i,j);
                result.at<uchar>(i,j) = (new_pixel>255) ? 255 : new_pixel;
            }
        }
    
        // Show results
        imshow("frame", img);
        waitKey();
    
        imshow("frame", result);
        waitKey();
    
        return 0;
    }
    

    So the main steps of the paper are followed here. For some parts I've inspired myself on code I've found. It's the case for the first processing I apply that I've found here. Also for the High-pass filter (laplacian) I've inspired myself on the code given in OpenCV 2 Computer Vision Application Programming Cookbook.

    Finally I've done some little improvements by allowing to modify the brightness of the background and the darkness of the veins (see defines BRIGHT and DARK). I've also decided to blur a bit the mask to have a more "natural" enhancement.


    Here the results (Source / Paper result / My result) :

    The source image The paper result My result