OpenCV C++使用高通滤波和阈值法增强指纹图像

《数字图像处理》冈萨雷斯 第三版中,P179有一个指纹增强的例子;

先用opencv模拟实现:

处理这个指纹图像 ,其污染是很明显的。自动指纹识别的关键一步是增强指纹的脊线并减小污染。使用高通滤波实现;

脊线增强使用脊线包含高频这样一个事实来完成,而高通滤波不会改变高频;另一方面,滤掉了低频,而低频分量对应图像中慢变化的灰度,例如背景和污染。

这样增强就可以同时减少高频外的所有特征来达到,当前情况,高频是感兴趣的特征。

原图像---------------------------------------------------高通滤波后图像------------------------------------------阈值化后图像

                   

先用布特沃斯高通滤波器D0=50,n=4滤波,结果失去了灰度色调,因为直流项被减小为0;最终结果是高通滤波后图像的典型暗色调已成为主流,这样就可以通过附加处理增强感兴趣细节。

一种简单的方法是对结果进行阈值操作,将所有负值设为黑,所有正值设为白。

代码实现:

#include "opencv2/opencv.hpp"

using namespace cv;

//transform to center 中心化
void center_transform( cv::Mat &src )
{
    for(int i=0; i<src.rows; i++){
        float *p = src.ptr<float>(i);
        for(int j=0; j<src.cols; j++){
            p[j] = p[j] * pow(-1, i+j);
        }
    }
}

void zero_to_center(Mat &freq_plane)
{
//    freq_plane = freq_plane(Rect(0, 0, freq_plane.cols & -2, freq_plane.rows & -2));
    //这里为什么&上-2具体查看opencv文档
    //其实是为了把行和列变成偶数 -2的二进制是11111111.......10 最后一位是0
    int cx=freq_plane.cols/2;int cy=freq_plane.rows/2;

//以下的操作是移动图像  (零频移到中心) 与函数center_transform()作用相同,只是一个先处理,一个dft后再变换
    Mat part1_r(freq_plane, Rect(0,0,cx,cy));  //元素坐标表示为(cx,cy)
    Mat part2_r(freq_plane, Rect(cx,0,cx,cy));
    Mat part3_r(freq_plane, Rect(0,cy,cx,cy));
    Mat part4_r(freq_plane, Rect(cx,cy,cx,cy));

    Mat tmp;
    part1_r.copyTo(tmp);  //左上与右下交换位置(实部)
    part4_r.copyTo(part1_r);
    tmp.copyTo(part4_r);

    part2_r.copyTo(tmp);  //右上与左下交换位置(实部)
    part3_r.copyTo(part2_r);
    tmp.copyTo(part3_r);
}

int main(int argc, char * argv[])
{
    const char* filename = argc >=2 ? argv[1] : "zhiwen12.tif";

    Mat image = imread(filename, IMREAD_GRAYSCALE);
    if( image.empty())
        return -1;

    resize( image, image, Size(), 0.25, 0.25);
    imshow("src",image);
    image.convertTo(image,CV_32FC1);


    ///////////////////////////////////////快速傅里叶变换/////////////////////////////////////////////////////
//    int oph = getOptimalDFTSize(image.rows);
//    int opw = getOptimalDFTSize(image.cols);
    int oph = 2*image.rows;
    int opw = 2*image.cols;
    Mat padded;
    copyMakeBorder(image, padded, 0, oph-image.rows, 0, opw-image.cols,
                   BORDER_CONSTANT, Scalar::all(0));
//    center_transform(padded);

    Mat pad_show;
    normalize(padded, pad_show, 1, 0, CV_MINMAX);

    imshow("padded",pad_show);

    Mat temp[] = {padded, Mat::zeros(padded.size(),CV_32FC1)};
    Mat complexI;
    merge(temp, 2, complexI);
    dft(complexI, complexI);    //傅里叶变换

    //显示频谱图
    split(complexI, temp);
    zero_to_center(temp[0]);
    zero_to_center(temp[1]);
    Mat aa;
    magnitude(temp[0], temp[1], aa);
    divide(aa, oph*opw, aa);
    imshow("pu",aa);

    /////////////////////////////////////////////频域滤波///////////////////////////////////////////////////////
    //生成频域滤波核
    Mat butter_sharpen(padded.size(), CV_32FC2);
    float D0 = 50.;
    int n = 4;
    for(int i=0; i<butter_sharpen.rows; i++){
        float *q = butter_sharpen.ptr<float>(i);
        for(int j=0; j<butter_sharpen.cols; j++){
            float d = sqrt(pow(i-oph/2, 2) + pow(j-opw/2, 2));
            q[2*j]   = 1.0/(1 + pow(D0/d, 2* n));
            q[2*j+1] = 1.0/(1 + pow(D0/d, 2*n));
        }
    }

//    Mat tmp[2];
//    split(butter_sharpen, tmp);
//    multiply(temp[0], tmp[0], temp[0]);
//    multiply(temp[1], tmp[0], temp[1]);
    merge(temp, 2, complexI);

    multiply(complexI, butter_sharpen, complexI);
    //傅里叶反变换
    idft(complexI, complexI, CV_DXT_INVERSE);

    Mat dstSharpen[2];
    split(complexI, dstSharpen);
//    magnitude(dstSharpen[0],dstSharpen[1],dstSharpen[0]);  //求幅值(模)
    for(int i=0; i<oph; i++){
        float *q = dstSharpen[0].ptr<float>(i);
        for(int j=0; j<opw; j++){
            q[j] = q[j] * pow(-1, i+j);
        }
    }
    Mat show;
//    divide(dstSharpen[0], dstSharpen[0].cols*dstSharpen[0].rows, show);
    normalize(dstSharpen[0], show, 1, 0, CV_MINMAX);
    show = show(Rect(0,0,image.cols, image.rows));
    imshow("_filter",show);

    threshold(dstSharpen[0], dstSharpen[0], 0, 255, THRESH_BINARY);
    normalize(dstSharpen[0], dstSharpen[0], 0, 1, CV_MINMAX);
    dstSharpen[0] = dstSharpen[0](Rect(0,0,image.cols, image.rows));
    imshow("dstSharpen",dstSharpen[0]);
//    imshow( "dest_finger", dest_finger );
    waitKey(0);

    return 1;
}
 

猜你喜欢

转载自blog.csdn.net/cyf15238622067/article/details/88355225
今日推荐