Class: Naiso::SplitPointDetector

Inherits:
Object
  • Object
show all
Defined in:
lib/naiso/split_point_detector.rb

Overview

분할점 감지기

Instance Method Summary collapse

Constructor Details

#initialize(analyzer, config) ⇒ SplitPointDetector

Returns a new instance of SplitPointDetector.



8
9
10
11
# File 'lib/naiso/split_point_detector.rb', line 8

def initialize(analyzer, config)
  @analyzer = analyzer
  @config = config
end

Instance Method Details

#find_background_transitions(variance_threshold: 5.0, min_uniform_height: 20, color_diff_threshold: 15.0) ⇒ Object

배경색 전환 지점 감지



83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/naiso/split_point_detector.rb', line 83

def find_background_transitions(
  variance_threshold: 5.0,
  min_uniform_height: 20,
  color_diff_threshold: 15.0
)
  img_array = @analyzer.img_array
  variance = @analyzer.variance
  height = @analyzer.height

  transitions = []

  (min_uniform_height...(height - min_uniform_height)).each do |y|
    # 위아래가 모두 단색인지 확인
    above_uniform = variance[(y - min_uniform_height)...y].to_a.all? { |v| v < variance_threshold }
    below_uniform = variance[y...(y + min_uniform_height)].to_a.all? { |v| v < variance_threshold }

    next unless above_uniform && below_uniform

    above_region = img_array[(y - min_uniform_height)...y, true, true]
    below_region = img_array[y...(y + min_uniform_height), true, true]

    above_color = calculate_mean_color(above_region)
    below_color = calculate_mean_color(below_region)

    # RGB 유클리드 거리
    color_diff = Math.sqrt(
      above_color.zip(below_color).map { |a, b| (a - b) ** 2 }.sum
    )

    transitions << y if color_diff > color_diff_threshold
  end

  merge_nearby_points(transitions)
end

#find_best_split_in_range(start_pos, end_pos, margin: 50) ⇒ Object

주어진 범위 내에서 복잡도가 가장 낮은 분할점 찾기



119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/naiso/split_point_detector.rb', line 119

def find_best_split_in_range(start_pos, end_pos, margin: 50)
  search_start = start_pos + margin
  search_end = end_pos - margin

  return (start_pos + end_pos) / 2 if search_start >= search_end

  window_size = 20
  complexity = @analyzer.complexity

  region = complexity[search_start...search_end]
  return search_start + region.min_index if region.size < window_size

  # 이동 평균으로 smoothing
  smoothed = []
  (0...(region.size - window_size)).each do |i|
    smoothed << region[i...(i + window_size)].mean
  end

  best_idx = smoothed.each_with_index.min_by { |v, _| v }[1] + window_size / 2
  search_start + best_idx
end

#find_divider_lines(line_variance_threshold: 3.0, margin_check: 30, margin_variance_threshold: 5.0) ⇒ Object

가로 구분선 감지



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/naiso/split_point_detector.rb', line 48

def find_divider_lines(
  line_variance_threshold: 3.0,
  margin_check: 30,
  margin_variance_threshold: 5.0
)
  img_array = @analyzer.img_array
  variance = @analyzer.variance
  height = @analyzer.height

  dividers = []

  (margin_check...(height - margin_check)).each do |y|
    next if variance[y] > line_variance_threshold

    margin_above = img_array[(y - margin_check)...y, true, true]
    margin_below = img_array[(y + 1)...(y + 1 + margin_check), true, true]

    above_variance = calculate_region_variance(margin_above)
    below_variance = calculate_region_variance(margin_below)

    next if above_variance > margin_variance_threshold
    next if below_variance > margin_variance_threshold

    above_mean = margin_above.cast_to(Numo::DFloat).mean
    below_mean = margin_below.cast_to(Numo::DFloat).mean
    line_mean = img_array[y, true, true].cast_to(Numo::DFloat).mean

    color_diff = (line_mean - (above_mean + below_mean) / 2.0).abs
    dividers << y if color_diff > 10
  end

  merge_nearby_points(dividers)
end

#find_uniform_regionsObject

연속된 단색 영역 찾기



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/naiso/split_point_detector.rb', line 14

def find_uniform_regions
  variance = @analyzer.variance
  threshold = @config.variance_threshold

  regions = []
  in_region = false
  region_start = 0

  @analyzer.height.times do |i|
    uniform = variance[i] < threshold

    if uniform && !in_region
      in_region = true
      region_start = i
    elsif !uniform && in_region
      in_region = false
      if i - region_start >= @config.min_gap_height
        regions << [region_start, i]
      end
    end
  end

  # 마지막까지 단색이면
  if in_region
    region_end = @analyzer.height
    if region_end - region_start >= @config.min_gap_height
      regions << [region_start, region_end]
    end
  end

  regions
end