1 Task Introduction
Fingerprint image processing is an important part of fingerprint
recognition. A fingerprint image usually contains ridge and valley. The
ridge is darker and the valley is brighter. Please use the image processing
method to extract the ridges in the fingerprint image and output a mask.
However, there is a high-resolution fingerprint image acquisition device
that randomly applies a noise during the image acquisition due to the
device itself. You are required to first eliminate this noise through the
knowledge you have learned in class, and then extract the ridge.
The id of images I handled are 17, 18, 19, 20, they are listed as follows:
-
image 17
-
image 18
-
image 19
-
image 20
There are two target results I have to get, which are denoised image and ridge mask image of source image.
2 Methods
There are three steps im my method :
- step1: blur image
- step2: binarize image
- step3: remove holes in image
2.1 blur noise
The fisrt step is to think how to blur the source images with noise. We all know that the method you choose to remove noise depends on the kind of noise. According to my dip experience, I analysised the kind of noise of those four images, they are listed as follows:
- image 17: salt and papper noise
- iamge 18: pepper noise
- image 19: salt noise
- image 20: gaussian noise
The first three images blured easily, but the last image seemed not so easy. After I do gaussian blue and get mask of the last image, I got the this image:
The last image has two kind of noises, which are gaussian noise and salt-papper noise.
After I blured all images, they are show as follows:
- 17 denoised image
- 18 denoised image
- 19 denoised image
- 20 denoised image
2.2 binarize image
Before we want to get the ridge mask image, we have to binarize images with appropriate threshold. By ajusting threshold parameter, I got the following binarized images:
- 17 binary image with threshold value 120
- 18 binary image with threshold value 50
- 19 binary image with threshold value 150
- 20 binary image with threshold value 140
2.3 remove holes
We noticed that there are some tiny white holes in ridges or black holes between ridges. The method I use to remove these two kind of holes is:
- stpe1: find all contours of connected area in image
- step2: get tiny contours
- step3: fill tiny contours which has less than 20 points with black for removing white holes in ridges
- step4: get tiny contours again
- step5: fill tiny contours which has less than 30 points with white for removing black holes between ridges
The final ridge mask image I get are as follows:
- 17 ridge mask image
- 18 ridge mask image
- 19 ridge mask image
- 20 ridge mask image
3 cpp code
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
// remove contours which has less than cmax points
void RemoveSizeContours(vector<vector<Point>> &contours, int cmax = 20, int cmin = 1)
{
vector<vector<Point>>::const_iterator itc = contours.begin();
while (itc != contours.end())
{
if ((itc->size()) < cmin || (itc->size()) > cmax)
{
itc = contours.erase(itc);
}
else ++itc;
}
}
void HandleImages(string save_path, int id, const cv::Mat &src_img, double thresh)
{
imshow("source image" + to_string(id), src_img);
Mat blur_img, bin_img, mask_img;
if (id <= 3)
{
medianBlur(src_img, blur_img, 3);
}
else if (id == 4)
{
medianBlur(src_img, blur_img, 3);
GaussianBlur(blur_img, blur_img, Size(5, 5), 0.4);
}
else
{
cout << "image is is out of range\n";
}
imwrite(save_path + "/result/" + to_string(id + 16) + "_denoised" + ".bmp", blur_img);
// imshow("blured image" + to_string(id), blur_img);
threshold(blur_img, bin_img, thresh, 255, cv::THRESH_BINARY);
imwrite(save_path + "/result/" + to_string(id + 16) + "_binary" + ".bmp", bin_img);
// imshow("binary image"+to_string(id), bin_img);
//remove white holes in ridges
vector<vector<Point>> contours;
findContours(bin_img, contours, cv::RETR_CCOMP, cv::CHAIN_APPROX_NONE, Point(0, 0));
// cout << contours.size() << endl;
RemoveSizeContours(contours);
mask_img = bin_img.clone();
drawContours(mask_img, contours, -1, Scalar(0), cv::FILLED); // -1 means draw all contours
//remove black holes between ridges
findContours(mask_img, contours, cv::RETR_CCOMP, cv::CHAIN_APPROX_NONE, Point(0, 0));
cout << contours.size() << endl;
RemoveSizeContours(contours, 30);
drawContours(mask_img, contours, -1, Scalar(255), cv::FILLED); // -1 means draw all contours
imwrite(save_path + "/result/" + to_string(id + 16) + "_ridge_mask" + ".bmp", mask_img);
imshow("mask image" + to_string(id), mask_img);
}
int main(int argc, char **argv)
{
if (argc != 2)
{
cout << "usage: run_pro1 img_path" << endl;
return 1;
}
//load images
vector<cv::Mat> imgs;
for (int i = 17; i <= 20; ++i)
{
Mat img = cv::imread(string(argv[1]) + "/" + to_string(i) + ".bmp", IMREAD_GRAYSCALE);
imgs.push_back(img);
}
//processing image one by one
string save_path(argv[1]);
HandleImages(save_path, 1, imgs[0], 120);
HandleImages(save_path, 2, imgs[1], 50);
HandleImages(save_path, 3, imgs[2], 150);
HandleImages(save_path, 4, imgs[3], 140);
waitKey(0);
return 0;
}