Full Code of rtshadow/biometrics for AI

master 6ed6d7348f88 cached
13 files
24.3 KB
7.6k tokens
39 symbols
1 requests
Download .txt
Repository: rtshadow/biometrics
Branch: master
Commit: 6ed6d7348f88
Files: 13
Total size: 24.3 KB

Directory structure:
gitextract_uyx_0b11/

├── README.md
├── crossing_number.py
├── frequency.py
├── gabor.py
├── hough.py
├── normalization.py
├── orientation.py
├── poincare.py
├── segmentation.py
├── sobel.py
├── sobel_showcase.py
├── thining.py
└── utils.py

================================================
FILE CONTENTS
================================================

================================================
FILE: README.md
================================================
# Fingerprint recognition algorithms

Active development year: 2012

## Summary
Some implementations of fingerprint recognition algorithms developed for Biometric Methods course at University of Wrocław, Poland.

## Usage

### Prerequisites
* python 2.7
* python imaging library (PIL)

### How to use it
Simply do ```python filename.py --help``` to figure out how to execute ```filename``` algorithm

## Algorithms

### Poincaré Index
Finds singular points on fingerprint. 

How it works (more detailed description [here](http://books.google.pl/books?id=1Wpx25D8qOwC&lpg=PA120&ots=9wRY0Rosb7&dq=poincare%20index%20fingerprint&hl=pl&pg=PA120#v=onepage&q=poincare%20index%20fingerprint&f=false)):
* divide image into blocks of ```block_size```
* for each block: 
    * calculate orientation of the fingerprint ridge in that block (i.e. what is the rigde slope / angle between a ridge and horizon)
    * sum up the differences of angles (orientations) of the surrounding blocks
    * there are 4 cases:
        * sum is 180 (+- tolerance) - loop found
        * sum is -180 (+- tolerance) - delta found
        * sum is 360 (+- tolerance) - whorl found

The python script will mark the singularities with circles:
* red for loop
* green for delta
* blue for whorl
      
Example: ```python poincare.py images/ppf1.png 16 1 --smooth```

Images:
* Original 

![fingerprint](https://raw.github.com/rtshadow/biometrics/master/images/ppf1.png)

* With singular points marked by algorithm: 

![poincare](https://raw.github.com/rtshadow/biometrics/master/images/ppf1_poincare.gif)

Note: algorithm marked singular points not only inside fingerprint itself, but on its edges and even outside. This is a result of usage of non-preprocessed image - if the image was enhanced (better contrast, background removed), then only singular points inside fingerprint would be marked.

### Thinning (skeletonization)

How it [works] (http://bme.med.upatras.gr/improc/Morphological%20operators.htm#Thining)

Example: ```python thining.py images/ppf1_enhanced.gif --save```

Images:
* Before

![before](https://raw.github.com/rtshadow/biometrics/master/images/ppf1_enhanced.gif)

* After:

![after](https://raw.github.com/rtshadow/biometrics/master/images/ppf1_enhanced_thinned.gif)

### Minutiae recognition (crossing number method)
Crossing number methods is a really simple way to detect ridge endings and ridge bifurcations.

First, you'll need thinned (skeleton) image (refer to previous section how to get it). Then the crossing number algorithm will look at 3x3 pixel blocks:
* if middle pixel is black (represents ridge):
    * if pixel on boundary are crossed with the ridge once, then we've found ridge ending
    * if pixel on boundary are crossed with the ridge three times, then we've found ridge bifurcation
    
Example: ```python crossing_number.py images/ppf1_enhanced_thinned.gif --save```

![minutiae](https://raw.github.com/rtshadow/biometrics/master/images/ppf1_enhanced_thinned_minutiae.gif)


================================================
FILE: crossing_number.py
================================================
# Metody biometryczne
# Przemyslaw Pastuszka

from PIL import Image, ImageDraw
import utils
import argparse
import math
import os

cells = [(-1, -1), (-1, 0), (-1, 1), (0, 1), (1, 1), (1, 0), (1, -1), (0, -1), (-1, -1)]

def minutiae_at(pixels, i, j):
    values = [pixels[i + k][j + l] for k, l in cells]

    crossings = 0
    for k in range(0, 8):
        crossings += abs(values[k] - values[k + 1])
    crossings /= 2

    if pixels[i][j] == 1:
        if crossings == 1:
            return "ending"
        if crossings == 3:
            return "bifurcation"
    return "none"

def calculate_minutiaes(im):
    pixels = utils.load_image(im)
    utils.apply_to_each_pixel(pixels, lambda x: 0.0 if x > 10 else 1.0)

    (x, y) = im.size
    result = im.convert("RGB")

    draw = ImageDraw.Draw(result)

    colors = {"ending" : (150, 0, 0), "bifurcation" : (0, 150, 0)}

    ellipse_size = 2
    for i in range(1, x - 1):
        for j in range(1, y - 1):
            minutiae = minutiae_at(pixels, i, j)
            if minutiae != "none":
                draw.ellipse([(i - ellipse_size, j - ellipse_size), (i + ellipse_size, j + ellipse_size)], outline = colors[minutiae])

    del draw

    return result

parser = argparse.ArgumentParser(description="Minutiae detection using crossing number method")
parser.add_argument("image", nargs=1, help = "Skeleton image")
parser.add_argument("--save", action='store_true', help = "Save result image as src_minutiae.gif")
args = parser.parse_args()

im = Image.open(args.image[0])
im = im.convert("L")  # covert to grayscale

result = calculate_minutiaes(im)
result.show()

if args.save:
    base_image_name = os.path.splitext(os.path.basename(args.image[0]))[0]
    result.save(base_image_name + "_minutiae.gif", "GIF")


================================================
FILE: frequency.py
================================================
# Metody biometryczne
# Przemyslaw Pastuszka

from PIL import Image, ImageDraw
import utils
import argparse
import math


def points_on_line(line, W):
    im = Image.new("L", (W, 3 * W), 100)
    draw = ImageDraw.Draw(im)
    draw.line([(0, line(0) + W), (W, line(W) + W)], fill=10)
    im_load = im.load()

    points = []
    for x in range(0, W):
        for y in range(0, 3 * W):
            if im_load[x, y] == 10:
               points.append((x, y - W))

    del draw
    del im

    dist = lambda (x, y): (x - W / 2) ** 2 + (y - W / 2) ** 2

    return sorted(points, cmp = lambda x, y: dist(x) < dist(y))[:W]

def vec_and_step(tang, W):
    (begin, end) = utils.get_line_ends(0, 0, W, tang)
    (x_vec, y_vec) = (end[0] - begin[0], end[1] - begin[1])
    length = math.hypot(x_vec, y_vec)
    (x_norm, y_norm) = (x_vec / length, y_vec / length)
    step = length / W

    return (x_norm, y_norm, step)

def block_frequency(i, j, W, angle, im_load):
    tang = math.tan(angle)
    ortho_tang = -1 / tang

    (x_norm, y_norm, step) = vec_and_step(tang, W)
    (x_corner, y_corner) = (0 if x_norm >= 0 else W, 0 if y_norm >= 0 else W)

    grey_levels = []

    for k in range(0, W):
        line = lambda x: (x - x_norm * k * step - x_corner) * ortho_tang + y_norm * k * step + y_corner
        points = points_on_line(line, W)
        level = 0
        for point in points:
            level += im_load[point[0] + i * W, point[1] + j * W]
        grey_levels.append(level)

    treshold = 100
    upward = False
    last_level = 0
    last_bottom = 0
    count = 0.0
    spaces = len(grey_levels)
    for level in grey_levels:
        if level < last_bottom:
            last_bottom = level
        if upward and level < last_level:
            upward = False
            if last_bottom + treshold < last_level:
                count += 1
                last_bottom = last_level
        if level > last_level:
            upward = True
        last_level = level

    return count / spaces if spaces > 0 else 0

def freq(im, W, angles):
    (x, y) = im.size
    im_load = im.load()
    freqs = [[0] for i in range(0, x / W)]

    for i in range(1, x / W - 1):
        for j in range(1, y / W - 1):
            freq = block_frequency(i, j, W, angles[i][j], im_load)
            freqs[i].append(freq)
        freqs[i].append(0)

    freqs[0] = freqs[-1] = [0 for i in range(0, y / W)]

    return freqs

def freq_img(im, W, angles):
    (x, y) = im.size
    freqs = freq(im, W, angles)
    freq_img = im.copy()

    for i in range(1, x / W - 1):
        for j in range(1, y / W - 1):
            box = (i * W, j * W, min(i * W + W, x), min(j * W + W, y))
            freq_img.paste(freqs[i][j] * 255.0 * 1.2, box)

    return freq_img

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Image frequency")
    parser.add_argument("image", nargs=1, help = "Path to image")
    parser.add_argument("block_size", nargs=1, help = "Block size")
    parser.add_argument('--smooth', "-s", action='store_true', help = "Use Gauss for smoothing")
    args = parser.parse_args()

    im = Image.open(args.image[0])
    im = im.convert("L")  # covert to grayscale
    im.show()

    W = int(args.block_size[0])

    f = lambda x, y: 2 * x * y
    g = lambda x, y: x ** 2 - y ** 2

    angles = utils.calculate_angles(im, W, f, g)
    if args.smooth:
        angles = utils.smooth_angles(angles)

    freq_img = freq_img(im, W, angles)
    freq_img.show()


================================================
FILE: gabor.py
================================================
# Metody biometryczne
# Przemyslaw Pastuszka

from PIL import Image, ImageDraw
import utils
import argparse
import math
import frequency
import os

def gabor_kernel(W, angle, freq):
    cos = math.cos(angle)
    sin = math.sin(angle)

    yangle = lambda x, y: x * cos + y * sin
    xangle = lambda x, y: -x * sin + y * cos

    xsigma = ysigma = 4

    return utils.kernel_from_function(W, lambda x, y:
        math.exp(-(
            (xangle(x, y) ** 2) / (xsigma ** 2) +
            (yangle(x, y) ** 2) / (ysigma ** 2)) / 2) *
        math.cos(2 * math.pi * freq * xangle(x, y)))

def gabor(im, W, angles):
    (x, y) = im.size
    im_load = im.load()

    freqs = frequency.freq(im, W, angles)
    print "computing local ridge frequency done"

    gauss = utils.gauss_kernel(3)
    utils.apply_kernel(freqs, gauss)

    for i in range(1, x / W - 1):
        for j in range(1, y / W - 1):
            kernel = gabor_kernel(W, angles[i][j], freqs[i][j])
            for k in range(0, W):
                for l in range(0, W):
                    im_load[i * W + k, j * W + l] = utils.apply_kernel_at(
                        lambda x, y: im_load[x, y],
                        kernel,
                        i * W + k,
                        j * W + l)

    return im

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Gabor filter applied")
    parser.add_argument("image", nargs=1, help = "Path to image")
    parser.add_argument("block_size", nargs=1, help = "Block size")
    parser.add_argument("--save", action='store_true', help = "Save result image as src_image_enhanced.gif")
    args = parser.parse_args()

    im = Image.open(args.image[0])
    im = im.convert("L")  # covert to grayscale
    im.show()

    W = int(args.block_size[0])

    f = lambda x, y: 2 * x * y
    g = lambda x, y: x ** 2 - y ** 2

    angles = utils.calculate_angles(im, W, f, g)
    print "calculating orientation done"

    angles = utils.smooth_angles(angles)
    print "smoothing angles done"

    result = gabor(im, W, angles)
    result.show()

    if args.save:
        base_image_name = os.path.splitext(os.path.basename(args.image[0]))[0]
        im.save(base_image_name + "_enhanced.gif", "GIF")


================================================
FILE: hough.py
================================================
# Metody biometryczne
# Przemyslaw Pastuszka

from PIL import Image, ImageDraw
import utils
import argparse
import math


def get_hough_image(im):
    (x, y) = im.size
    x *= 1.0
    y *= 1.0

    im_load = im.load()

    result = Image.new("RGBA", im.size, 0)
    draw = ImageDraw.Draw(result)

    for i in range(0, im.size[0]):
        for j in range(0, im.size[1]):
            if im_load[i, j] > 220:
                line = lambda t: (t, (-(i / x - 0.5) * (t / x) + (j / y - 0.5)) * x)
                draw.line([line(0), line(x)], fill=(50, 0, 0, 10))

    return result


if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Hough transform")
    parser.add_argument("image", nargs=1, help = "Path to image")
    args = parser.parse_args()

    im = Image.open(args.image[0])
    im = im.convert("L")  # covert to grayscale
    im.show()

    hough_img = get_hough_image(im)
    hough_img.show()


================================================
FILE: normalization.py
================================================
# Metody biometryczne
# Przemyslaw Pastuszka

from PIL import Image, ImageStat
import argparse
from math import sqrt

# x - pixel value
# v0 - desired variance
# v - actual image variance
# m - actual image mean
# m0 - desired mean
def normalize_pixel(x, v0, v, m, m0):
    dev_coeff = sqrt((v0 * ((x - m)**2)) / v)
    if x > m:
        return m0 + dev_coeff
    return m0 - dev_coeff

def normalize(im, m0, v0):
    stat = ImageStat.Stat(im)
    m = stat.mean[0]
    v = stat.stddev[0] ** 2

    return im.point(lambda x: normalize_pixel(x, v0, v, m, m0))  # normalize each pixel

parser = argparse.ArgumentParser(description="Image normalization")
parser.add_argument("image", nargs=1, help = "Path to image")
parser.add_argument("mean", nargs=1, help = "desired mean")
parser.add_argument("variance", nargs=1, help = "desired variance (squared stdev)")
args = parser.parse_args()

im = Image.open(args.image[0])
im = im.convert("L")  # covert to grayscale

im.show()

normalizedIm = normalize(im, float(args.mean[0]), float(args.variance[0]))
normalizedIm.show()


================================================
FILE: orientation.py
================================================
# Metody biometryczne
# Przemyslaw Pastuszka

from PIL import Image, ImageDraw
import utils
import argparse

parser = argparse.ArgumentParser(description="Rao's and Chinese algorithms")
parser.add_argument("image", nargs=1, help = "Path to image")
parser.add_argument("block_size", nargs=1, help = "Block size")
parser.add_argument('--smooth', "-s", action='store_true', help = "Use Gauss for smoothing")
parser.add_argument('--chinese', "-c", action='store_true', help = "Use Chinese alg. instead of Rao's")
args = parser.parse_args()

im = Image.open(args.image[0])
im = im.convert("L")  # covert to grayscale

W = int(args.block_size[0])

f = lambda x, y: 2 * x * y
g = lambda x, y: x ** 2 - y ** 2

if args.chinese:
    normalizator = 255.0
    f = lambda x, y: 2 * x * y / (normalizator ** 2)
    g = lambda x, y: ((x ** 2) * (y ** 2)) / (normalizator ** 4)

angles = utils.calculate_angles(im, W, f, g)
utils.draw_lines(im, angles, W).show()

if args.smooth:
    smoothed_angles = utils.smooth_angles(angles)
    utils.draw_lines(im, smoothed_angles, W).show()


================================================
FILE: poincare.py
================================================
# Metody biometryczne
# Przemyslaw Pastuszka

from PIL import Image, ImageDraw
import utils
import argparse
import math
import os

signum = lambda x: -1 if x < 0 else 1

cells = [(-1, -1), (-1, 0), (-1, 1), (0, 1), (1, 1), (1, 0), (1, -1), (0, -1), (-1, -1)]

def get_angle(left, right):
    angle = left - right
    if abs(angle) > 180:
        angle = -1 * signum(angle) * (360 - abs(angle))
    return angle

def poincare_index_at(i, j, angles, tolerance):
    deg_angles = [math.degrees(angles[i - k][j - l]) % 180 for k, l in cells]
    index = 0
    for k in range(0, 8):
        if abs(get_angle(deg_angles[k], deg_angles[k + 1])) > 90:
            deg_angles[k + 1] += 180
        index += get_angle(deg_angles[k], deg_angles[k + 1])

    if 180 - tolerance <= index and index <= 180 + tolerance:
        return "loop"
    if -180 - tolerance <= index and index <= -180 + tolerance:
        return "delta"
    if 360 - tolerance <= index and index <= 360 + tolerance:
        return "whorl"
    return "none"

def calculate_singularities(im, angles, tolerance, W):
    (x, y) = im.size
    result = im.convert("RGB")

    draw = ImageDraw.Draw(result)

    colors = {"loop" : (150, 0, 0), "delta" : (0, 150, 0), "whorl": (0, 0, 150)}

    for i in range(1, len(angles) - 1):
        for j in range(1, len(angles[i]) - 1):
            singularity = poincare_index_at(i, j, angles, tolerance)
            if singularity != "none":
                draw.ellipse([(i * W, j * W), ((i + 1) * W, (j + 1) * W)], outline = colors[singularity])

    del draw

    return result

parser = argparse.ArgumentParser(description="Singularities with Poincare index")
parser.add_argument("image", nargs=1, help = "Path to image")
parser.add_argument("block_size", nargs=1, help = "Block size")
parser.add_argument("tolerance", nargs=1, help = "Tolerance for Poincare index")
parser.add_argument('--smooth', "-s", action='store_true', help = "Use Gauss for smoothing")
parser.add_argument("--save", action='store_true', help = "Save result image as src_poincare.gif")
args = parser.parse_args()

im = Image.open(args.image[0])
im = im.convert("L")  # covert to grayscale

W = int(args.block_size[0])

f = lambda x, y: 2 * x * y
g = lambda x, y: x ** 2 - y ** 2

angles = utils.calculate_angles(im, W, f, g)
if args.smooth:
    angles = utils.smooth_angles(angles)

result = calculate_singularities(im, angles, int(args.tolerance[0]), W)
result.show()

if args.save:
    base_image_name = os.path.splitext(os.path.basename(args.image[0]))[0]
    result.save(base_image_name + "_poincare.gif", "GIF")


================================================
FILE: segmentation.py
================================================
# Metody biometryczne
# Przemyslaw Pastuszka

from PIL import Image, ImageStat
import argparse
from math import sqrt

def distance(x, y, W):
    return 1 + sqrt((x - W) ** 2 + (y - W) ** 2)

def create_segmented_and_variance_images(im, W, threshold):
    (x, y) = im.size
    variance_image = im.copy()
    segmented_image = im.copy()
    for i in range(0, x, W):
        for j in range(0, y, W):
            box = (i, j, min(i + W, x), min(j + W, y))
            block_stddev = ImageStat.Stat(im.crop(box)).stddev[0]
            variance_image.paste(block_stddev, box)
            if block_stddev < threshold:
                segmented_image.paste(0, box)  # make block black if rejected
    return (segmented_image, variance_image)

parser = argparse.ArgumentParser(description="Image segmentation")
parser.add_argument("image", nargs=1, help = "Path to image")
parser.add_argument("block_size", nargs=1, help = "Block size")
parser.add_argument("threshold", nargs=1, help = "Treshold on stddev for accepting / rejecting blocks")
args = parser.parse_args()

im = Image.open(args.image[0])
im = im.convert("L")  # covert to grayscale

im.show()

(segmented, variance) = create_segmented_and_variance_images(im, int(args.block_size[0]), int(args.threshold[0]))
segmented.show()
variance.show()


================================================
FILE: sobel.py
================================================
# Metody biometryczne
# Przemyslaw Pastuszka

from PIL import Image, ImageFilter
from math import sqrt
import utils

sobelOperator = [[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]]

def merge_images(a, b, f):
    result = a.copy()
    result_load = result.load()
    a_load = a.load()
    b_load = b.load()

    (x, y) = a.size
    for i in range(0, x):
        for j in range(0, y):
            result_load[i, j] = f(a_load[i, j], b_load[i, j])

    return result

def partial_sobels(im):
    ySobel = im.filter(ImageFilter.Kernel((3, 3), utils.flatten(sobelOperator), 1))
    xSobel = im.filter(ImageFilter.Kernel((3, 3), utils.flatten(utils.transpose(sobelOperator)), 1))
    return (xSobel, ySobel)

def full_sobels(im):
    (xSobel, ySobel) = partial_sobels(im)
    sobel = merge_images(xSobel, ySobel, lambda x, y: sqrt(x**2 + y**2))
    return (xSobel, ySobel, sobel)


================================================
FILE: sobel_showcase.py
================================================
# Metody biometryczne
# Przemyslaw Pastuszka

import sobel
import argparse
from PIL import Image

parser = argparse.ArgumentParser(description="Sobel filter")
parser.add_argument("image", nargs=1, help = "Path to image")
parser.add_argument('--showX', "-x", action='store_true', help = "Show Sobel filter for X coordinate")
parser.add_argument('--showY', "-y", action='store_true', help = "Show Sobel filter for Y coordinate")
args = parser.parse_args()

im = Image.open(args.image[0])
im = im.convert("L")  # covert to grayscale

(xSobel, ySobel, fullSobel) = sobel.full_sobels(im)

if args.showX:
    xSobel.show()
if args.showY:
    ySobel.show()
fullSobel.show()


================================================
FILE: thining.py
================================================
# Metody biometryczne
# Przemyslaw Pastuszka

from PIL import Image, ImageDraw
import utils
import argparse
import math
import os
from utils import flatten, transpose

usage = False

def apply_structure(pixels, structure, result):
    global usage
    usage = False

    def choose(old, new):
        global usage
        if new == result:
            usage = True
            return 0.0
        return old

    utils.apply_kernel_with_f(pixels, structure, choose)

    return usage

def apply_all_structures(pixels, structures):
    usage = False
    for structure in structures:
        usage |= apply_structure(pixels, structure, utils.flatten(structure).count(1))

    return usage

def make_thin(im):
    loaded = utils.load_image(im)
    utils.apply_to_each_pixel(loaded, lambda x: 0.0 if x > 10 else 1.0)
    print "loading phase done"

    t1 = [[1, 1, 1], [0, 1, 0], [0.1, 0.1, 0.1]]
    t2 = utils.transpose(t1)
    t3 = reverse(t1)
    t4 = utils.transpose(t3)
    t5 = [[0, 1, 0], [0.1, 1, 1], [0.1, 0.1, 0]]
    t7 = utils.transpose(t5)
    t6 = reverse(t7)
    t8 = reverse(t5)

    thinners = [t1, t2, t3, t4, t5, t6, t7]

    usage = True
    while(usage):
        usage = apply_all_structures(loaded, thinners)
        print "single thining phase done"

    print "thining done"

    utils.apply_to_each_pixel(loaded, lambda x: 255.0 * (1 - x))
    utils.load_pixels(im, loaded)
    im.show()

def reverse(ls):
    cpy = ls[:]
    cpy.reverse()
    return cpy

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Image thining")
    parser.add_argument("image", nargs=1, help = "Path to image")
    parser.add_argument("--save", action='store_true', help = "Save result image as src_image_thinned.gif")
    args = parser.parse_args()

    im = Image.open(args.image[0])
    im = im.convert("L")  # covert to grayscale
    im.show()

    make_thin(im)

    if args.save:
        base_image_name = os.path.splitext(os.path.basename(args.image[0]))[0]
        im.save(base_image_name + "_thinned.gif", "GIF")


================================================
FILE: utils.py
================================================
# Metody biometryczne
# Przemyslaw Pastuszka

from PIL import Image, ImageDraw
import math
import sobel
import copy

def apply_kernel_at(get_value, kernel, i, j):
    kernel_size = len(kernel)
    result = 0
    for k in range(0, kernel_size):
        for l in range(0, kernel_size):
            pixel = get_value(i + k - kernel_size / 2, j + l - kernel_size / 2)
            result += pixel * kernel[k][l]
    return result

def apply_to_each_pixel(pixels, f):
    for i in range(0, len(pixels)):
        for j in range(0, len(pixels[i])):
            pixels[i][j] = f(pixels[i][j])

def calculate_angles(im, W, f, g):
    (x, y) = im.size
    im_load = im.load()
    get_pixel = lambda x, y: im_load[x, y]

    ySobel = sobel.sobelOperator
    xSobel = transpose(sobel.sobelOperator)

    result = [[] for i in range(1, x, W)]

    for i in range(1, x, W):
        for j in range(1, y, W):
            nominator = 0
            denominator = 0
            for k in range(i, min(i + W , x - 1)):
                for l in range(j, min(j + W, y - 1)):
                    Gx = apply_kernel_at(get_pixel, xSobel, k, l)
                    Gy = apply_kernel_at(get_pixel, ySobel, k, l)
                    nominator += f(Gx, Gy)
                    denominator += g(Gx, Gy)
            angle = (math.pi + math.atan2(nominator, denominator)) / 2
            result[(i - 1) / W].append(angle)

    return result

def flatten(ls):
    return reduce(lambda x, y: x + y, ls, [])

def transpose(ls):
    return map(list, zip(*ls))

def gauss(x, y):
    ssigma = 1.0
    return (1 / (2 * math.pi * ssigma)) * math.exp(-(x * x + y * y) / (2 * ssigma))

def kernel_from_function(size, f):
    kernel = [[] for i in range(0, size)]
    for i in range(0, size):
        for j in range(0, size):
            kernel[i].append(f(i - size / 2, j - size / 2))
    return kernel

def gauss_kernel(size):
    return kernel_from_function(size, gauss)

def apply_kernel(pixels, kernel):
    apply_kernel_with_f(pixels, kernel, lambda old, new: new)

def apply_kernel_with_f(pixels, kernel, f):
    size = len(kernel)
    for i in range(size / 2, len(pixels) - size / 2):
        for j in range(size / 2, len(pixels[i]) - size / 2):
            pixels[i][j] = f(pixels[i][j], apply_kernel_at(lambda x, y: pixels[x][y], kernel, i, j))

def smooth_angles(angles):
    cos_angles = copy.deepcopy(angles)
    sin_angles = copy.deepcopy(angles)
    apply_to_each_pixel(cos_angles, lambda x: math.cos(2 * x))
    apply_to_each_pixel(sin_angles, lambda x: math.sin(2 * x))

    kernel = gauss_kernel(5)
    apply_kernel(cos_angles, kernel)
    apply_kernel(sin_angles, kernel)

    for i in range(0, len(cos_angles)):
        for j in range(0, len(cos_angles[i])):
            cos_angles[i][j] = (math.atan2(sin_angles[i][j], cos_angles[i][j])) / 2

    return cos_angles

def load_image(im):
    (x, y) = im.size
    im_load = im.load()

    result = []
    for i in range(0, x):
        result.append([])
        for j in range(0, y):
            result[i].append(im_load[i, j])

    return result

def load_pixels(im, pixels):
    (x, y) = im.size
    im_load = im.load()

    for i in range(0, x):
        for j in range(0, y):
            im_load[i, j] = pixels[i][j]

def get_line_ends(i, j, W, tang):
    if -1 <= tang and tang <= 1:
        begin = (i, (-W/2) * tang + j + W/2)
        end = (i + W, (W/2) * tang + j + W/2)
    else:
        begin = (i + W/2 + W/(2 * tang), j + W/2)
        end = (i + W/2 - W/(2 * tang), j - W/2)
    return (begin, end)

def draw_lines(im, angles, W):
    (x, y) = im.size
    result = im.convert("RGB")

    draw = ImageDraw.Draw(result)

    for i in range(1, x, W):
        for j in range(1, y, W):
            tang = math.tan(angles[(i - 1) / W][(j - 1) / W])

            (begin, end) = get_line_ends(i, j, W, tang)
            draw.line([begin, end], fill=150)

    del draw

    return result
Download .txt
gitextract_uyx_0b11/

├── README.md
├── crossing_number.py
├── frequency.py
├── gabor.py
├── hough.py
├── normalization.py
├── orientation.py
├── poincare.py
├── segmentation.py
├── sobel.py
├── sobel_showcase.py
├── thining.py
└── utils.py
Download .txt
SYMBOL INDEX (39 symbols across 10 files)

FILE: crossing_number.py
  function minutiae_at (line 12) | def minutiae_at(pixels, i, j):
  function calculate_minutiaes (line 27) | def calculate_minutiaes(im):

FILE: frequency.py
  function points_on_line (line 10) | def points_on_line(line, W):
  function vec_and_step (line 29) | def vec_and_step(tang, W):
  function block_frequency (line 38) | def block_frequency(i, j, W, angle, im_load):
  function freq (line 75) | def freq(im, W, angles):
  function freq_img (line 90) | def freq_img(im, W, angles):

FILE: gabor.py
  function gabor_kernel (line 11) | def gabor_kernel(W, angle, freq):
  function gabor (line 26) | def gabor(im, W, angles):

FILE: hough.py
  function get_hough_image (line 10) | def get_hough_image(im):

FILE: normalization.py
  function normalize_pixel (line 13) | def normalize_pixel(x, v0, v, m, m0):
  function normalize (line 19) | def normalize(im, m0, v0):

FILE: poincare.py
  function get_angle (line 14) | def get_angle(left, right):
  function poincare_index_at (line 20) | def poincare_index_at(i, j, angles, tolerance):
  function calculate_singularities (line 36) | def calculate_singularities(im, angles, tolerance, W):

FILE: segmentation.py
  function distance (line 8) | def distance(x, y, W):
  function create_segmented_and_variance_images (line 11) | def create_segmented_and_variance_images(im, W, threshold):

FILE: sobel.py
  function merge_images (line 10) | def merge_images(a, b, f):
  function partial_sobels (line 23) | def partial_sobels(im):
  function full_sobels (line 28) | def full_sobels(im):

FILE: thining.py
  function apply_structure (line 13) | def apply_structure(pixels, structure, result):
  function apply_all_structures (line 28) | def apply_all_structures(pixels, structures):
  function make_thin (line 35) | def make_thin(im):
  function reverse (line 62) | def reverse(ls):

FILE: utils.py
  function apply_kernel_at (line 9) | def apply_kernel_at(get_value, kernel, i, j):
  function apply_to_each_pixel (line 18) | def apply_to_each_pixel(pixels, f):
  function calculate_angles (line 23) | def calculate_angles(im, W, f, g):
  function flatten (line 48) | def flatten(ls):
  function transpose (line 51) | def transpose(ls):
  function gauss (line 54) | def gauss(x, y):
  function kernel_from_function (line 58) | def kernel_from_function(size, f):
  function gauss_kernel (line 65) | def gauss_kernel(size):
  function apply_kernel (line 68) | def apply_kernel(pixels, kernel):
  function apply_kernel_with_f (line 71) | def apply_kernel_with_f(pixels, kernel, f):
  function smooth_angles (line 77) | def smooth_angles(angles):
  function load_image (line 93) | def load_image(im):
  function load_pixels (line 105) | def load_pixels(im, pixels):
  function get_line_ends (line 113) | def get_line_ends(i, j, W, tang):
  function draw_lines (line 122) | def draw_lines(im, angles, W):
Condensed preview — 13 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (26K chars).
[
  {
    "path": "README.md",
    "chars": 2990,
    "preview": "# Fingerprint recognition algorithms\n\nActive development year: 2012\n\n## Summary\nSome implementations of fingerprint reco"
  },
  {
    "path": "crossing_number.py",
    "chars": 1770,
    "preview": "# Metody biometryczne\n# Przemyslaw Pastuszka\n\nfrom PIL import Image, ImageDraw\nimport utils\nimport argparse\nimport math\n"
  },
  {
    "path": "frequency.py",
    "chars": 3476,
    "preview": "# Metody biometryczne\n# Przemyslaw Pastuszka\n\nfrom PIL import Image, ImageDraw\nimport utils\nimport argparse\nimport math\n"
  },
  {
    "path": "gabor.py",
    "chars": 2223,
    "preview": "# Metody biometryczne\n# Przemyslaw Pastuszka\n\nfrom PIL import Image, ImageDraw\nimport utils\nimport argparse\nimport math\n"
  },
  {
    "path": "hough.py",
    "chars": 929,
    "preview": "# Metody biometryczne\n# Przemyslaw Pastuszka\n\nfrom PIL import Image, ImageDraw\nimport utils\nimport argparse\nimport math\n"
  },
  {
    "path": "normalization.py",
    "chars": 1067,
    "preview": "# Metody biometryczne\n# Przemyslaw Pastuszka\n\nfrom PIL import Image, ImageStat\nimport argparse\nfrom math import sqrt\n\n# "
  },
  {
    "path": "orientation.py",
    "chars": 1067,
    "preview": "# Metody biometryczne\n# Przemyslaw Pastuszka\n\nfrom PIL import Image, ImageDraw\nimport utils\nimport argparse\n\nparser = ar"
  },
  {
    "path": "poincare.py",
    "chars": 2589,
    "preview": "# Metody biometryczne\n# Przemyslaw Pastuszka\n\nfrom PIL import Image, ImageDraw\nimport utils\nimport argparse\nimport math\n"
  },
  {
    "path": "segmentation.py",
    "chars": 1294,
    "preview": "# Metody biometryczne\n# Przemyslaw Pastuszka\n\nfrom PIL import Image, ImageStat\nimport argparse\nfrom math import sqrt\n\nde"
  },
  {
    "path": "sobel.py",
    "chars": 864,
    "preview": "# Metody biometryczne\n# Przemyslaw Pastuszka\n\nfrom PIL import Image, ImageFilter\nfrom math import sqrt\nimport utils\n\nsob"
  },
  {
    "path": "sobel_showcase.py",
    "chars": 667,
    "preview": "# Metody biometryczne\n# Przemyslaw Pastuszka\n\nimport sobel\nimport argparse\nfrom PIL import Image\n\nparser = argparse.Argu"
  },
  {
    "path": "thining.py",
    "chars": 2048,
    "preview": "# Metody biometryczne\n# Przemyslaw Pastuszka\n\nfrom PIL import Image, ImageDraw\nimport utils\nimport argparse\nimport math\n"
  },
  {
    "path": "utils.py",
    "chars": 3913,
    "preview": "# Metody biometryczne\n# Przemyslaw Pastuszka\n\nfrom PIL import Image, ImageDraw\nimport math\nimport sobel\nimport copy\n\ndef"
  }
]

About this extraction

This page contains the full source code of the rtshadow/biometrics GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 13 files (24.3 KB), approximately 7.6k tokens, and a symbol index with 39 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!