Ask Your Question

Revision history [back]

Blockwise PCA & Sobel seem to be way off for ridge angle detection

As a forewarning, complete hobbyist here. I'm attempting to enhance the capture of fingerprints via camera. I'm performing the following steps:

  1. Image normalization using equalizeHist
  2. Blockwise Sobel for edge detection
  3. Angle extraction using phase
  4. Average of angles within the block

I then draw these angles out but they appear to vary wildly. I also tried another method using blockwise PCA, but also have a similar result. Here is the resulting image:

image description

and here is my code so far:

#!/usr/bin/env python3
import cv2
import numpy as np
import math

def draw_angle(img, center, angle, length=10):
  line_start_x = int(center[0] + length * math.cos(angle))
  line_end_x   = int(center[0] - length * math.cos(angle))

  line_start_y = int(center[1] + length * math.sin(angle))
  line_end_y   = int(center[1] - length * math.sin(angle))

  cv2.line(img, (line_start_x, line_start_y), (line_end_x, line_end_y), (255, 255, 0), 1)


def process_sobel(img, block_size=16):
  rows, cols = img.shape

  # Apply a histogram to clarify ridges
  hist = cv2.equalizeHist(img)
  histc = cv2.cvtColor(hist, cv2.COLOR_GRAY2RGB)

  x = 0
  y = 0

  while y < rows - block_size:
    y2 = y + block_size

    while x < cols - block_size:
      x2 = x + block_size

      block_grax_x = cv2.Sobel(hist[y:y2, x:x2], cv2.CV_32F, 1, 0, ksize=3, scale=1, delta=0, borderType=cv2.BORDER_DEFAULT)
      block_grax_y = cv2.Sobel(hist[y:y2, x:x2], cv2.CV_32F, 0, 1, ksize=3, scale=1, delta=0, borderType=cv2.BORDER_DEFAULT)

      angles = cv2.phase(block_grax_x, block_grax_y)

      angle = math.degrees(np.average(angles))

      center = (int(x + block_size / 2), int(y + block_size / 2))

      draw_angle(histc, center, angle)

      cv2.rectangle(histc, (x, y), (x2, y2), (0, 0, 0), 1)

      x = x2

    y = y2
    x = 0

  return histc

def process_pca(img, block_size=16):
  rows, cols = img.shape

  # Apply a histogram to clarify ridges
  hist = cv2.equalizeHist(img)
  histc = cv2.cvtColor(hist, cv2.COLOR_GRAY2RGB)

  x = 0
  y = 0

  while y < rows - block_size:
    y2 = y + block_size

    while x < cols - block_size:
      x2 = x + block_size

      block = hist[y:y2, x:x2]

      _, eigvec, _ = cv2.PCACompute2(block, mean=None)

      angle = math.atan2(eigvec[0, 1], eigvec[0, 0])

      center = (int(x + block_size / 2), int(y + block_size / 2))

      draw_angle(histc, center, angle)

      cv2.rectangle(histc, (x, y), (x2, y2), (0, 0, 0), 1)

      x = x2

    y = y2
    x = 0

  return histc


img = cv2.imread('fingerprint2.jpg', 0)
img = process_sobel(img, 16)

cv2.imwrite('result.png', img)

I'm not too sure where I'm going wrong, it feels like I'm misunderstanding something with the operations I'm doing. Although some of the blocks appear to be spot on. I've also tried larger block sizes. All advice would be welcomed at this point.