Class: Tabula::ProjectionProfile

Inherits:
Object
  • Object
show all
Defined in:
lib/tabula/algorithms/projection_profile.rb

Overview

Projection profile analysis for detecting table structure. Computes histograms of text element positions to find gaps.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(elements, orientation:, bin_size: 1.0) ⇒ ProjectionProfile

Returns a new instance of ProjectionProfile.

Parameters:

  • elements (Array<Rectangle>) —

    elements to analyze

  • orientation (Symbol) —

    :horizontal or :vertical

  • bin_size (Float) (defaults to: 1.0) —

    size of histogram bins



12
13
14
15
16
17
18
19
20
# File 'lib/tabula/algorithms/projection_profile.rb', line 12

def initialize(elements, orientation:, bin_size: 1.0)
  @orientation = orientation
  @bin_size = bin_size
  @bins = Hash.new(0)
  @min_value = Float::INFINITY
  @max_value = -Float::INFINITY

  compute_profile(elements)
end

Instance Attribute Details

#bins ⇒ Object (readonly)

Returns the value of attribute bins.



7
8
9
# File 'lib/tabula/algorithms/projection_profile.rb', line 7

def bins
  @bins
end

#max_value ⇒ Object (readonly)

Returns the value of attribute max_value.



7
8
9
# File 'lib/tabula/algorithms/projection_profile.rb', line 7

def max_value
  @max_value
end

#min_value ⇒ Object (readonly)

Returns the value of attribute min_value.



7
8
9
# File 'lib/tabula/algorithms/projection_profile.rb', line 7

def min_value
  @min_value
end

Instance Method Details

#[](position) ⇒ Integer

Get value at a specific position

Parameters:

  • position (Float) —

    position to query

Returns:

  • (Integer) —

    count at that position



61
62
63
64
# File 'lib/tabula/algorithms/projection_profile.rb', line 61

def [](position)
  bin = (position / @bin_size).floor
  @bins[bin]
end

#find_gaps(min_gap_size: 3.0) ⇒ Array<Array<Float>>

Find gaps in the projection profile

Parameters:

  • min_gap_size (Float) (defaults to: 3.0) —

    minimum gap size to detect

Returns:

  • (Array<Array<Float>>) —

    array of [start, end] gap ranges



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/tabula/algorithms/projection_profile.rb', line 25

def find_gaps(min_gap_size: 3.0)
  return [] if @bins.empty?

  gaps = []
  gap_start = nil
  last_filled = nil

  (min_bin..max_bin).each do |bin|
    value = @bins[bin]

    if value.positive?
      if gap_start && last_filled
        gap_end = bin * @bin_size
        gap_size = gap_end - gap_start
        gaps << [gap_start, gap_end] if gap_size >= min_gap_size
      end
      gap_start = nil
      last_filled = (bin * @bin_size) + @bin_size
    elsif last_filled && gap_start.nil?
      gap_start = last_filled
    end
  end

  gaps
end

#gap_midpoints(min_gap_size: 3.0) ⇒ Array<Float>

Get midpoints of gaps (useful for column detection)

Parameters:

  • min_gap_size (Float) (defaults to: 3.0) —

    minimum gap size

Returns:

  • (Array<Float>) —

    gap midpoint positions



54
55
56
# File 'lib/tabula/algorithms/projection_profile.rb', line 54

def gap_midpoints(min_gap_size: 3.0)
  find_gaps(min_gap_size: min_gap_size).map { |start, stop| (start + stop) / 2.0 }
end

#in_gap?(position, min_gap_size: 3.0) ⇒ Boolean

Check if a position is in a gap

Parameters:

  • position (Float) —

    position to check

  • min_gap_size (Float) (defaults to: 3.0) —

    minimum gap size

Returns:

  • (Boolean) —

    true if position is in a gap



70
71
72
73
74
# File 'lib/tabula/algorithms/projection_profile.rb', line 70

def in_gap?(position, min_gap_size: 3.0)
  find_gaps(min_gap_size: min_gap_size).any? do |gap_start, gap_end|
    position.between?(gap_start, gap_end)
  end
end