Skip to content

Instantly share code, notes, and snippets.

@ultraist
Created June 18, 2011 05:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ultraist/1032841 to your computer and use it in GitHub Desktop.
Save ultraist/1032841 to your computer and use it in GitHub Desktop.
opencv-haar-classifer XML translater
sum = 0.0;
<% node[:feature][:rects].each do |rect| %>
xs = x + Math.round(<%= rect[0] %> * scale);
ys = y + Math.round(<%= rect[1] %> * scale);
w = Math.round(<%= rect[2] %> * scale);
h = Math.round(<%= rect[3] %> * scale);
<% if (node[:feature][:tilted]) %>
sum += sumtf(integral_tilted, xs, ys, w, h) * <%= rect[4] %> * s2h_inv;
<% else %>;
sum += sumf(integral, xs, ys, w, h) * <%= rect[4] %> * s2_inv;
<% end %>
<% end %>
if (sum < <%= sprintf("%E", node[:threshold]) %> * variance_norm_factor ) {
<% if node[:left_val] %>
p += <%= sprintf("%E", node[:left_val]) %>;
<% else %>
<%= tree_exec(c, nodes, nodes[node[:left_node]])%>
<% end %>
} else {
<% if node[:right_val] %>
p += <%= sprintf("%E", node[:right_val]) %>;
<% else %>
<%= tree_exec(c, nodes, nodes[node[:right_node]])%>
<% end %>
}
# haargen.rb -l javascript -i haarcascade_frontalface_alt.xml > frontalface_alt.js
require 'rubygems'
require 'rexml/document'
require 'optparse'
require 'json'
require 'erb'
$lang = "javascript"
def parse_rect(node)
rect = node.text.strip.split(/\s+/)
(0 ... 4).each do |i|
rect[i] = rect[i].to_i
end
rect[4] = rect[4].to_f
rect
end
def parse_tree_node(node)
tree_node = {}
tree_node[:threshold] = node.elements["threshold"].text.to_f
if (node.elements["left_val"])
tree_node[:left_val] = node.elements["left_val"].text.to_f
elsif (node.elements["left_node"])
tree_node[:left_node] = node.elements["left_node"].text.to_i
end
if (node.elements["right_val"])
tree_node[:right_val] = node.elements["right_val"].text.to_f
elsif (node.elements["right_node"])
tree_node[:right_node] = node.elements["right_node"].text.to_i
end
tree_node[:feature] = {}
tree_node[:feature][:rects] = []
node.elements.each("feature/rects/_") do |rect|
tree_node[:feature][:rects] << parse_rect(rect)
end
tree_node[:feature][:tilted] = node.elements["feature/tilted"].text.to_i == 1 ? true : false;
tree_node
end
def parse_tree(node)
tree = []
node.elements.each("_") do |child|
tree << parse_tree_node(child)
end
tree
end
def parse_stages(node)
stage = {}
stage[:threshold] = node.elements["stage_threshold"].text.to_f
stage[:parent] = node.elements["parent"].text.to_i
stage[:next] = node.elements["next"].text.to_i
stage[:trees] = []
node.elements.each("trees/_") do |tree|
stage[:trees] << parse_tree(tree)
end
stage
end
def parse_opencv_haar_classifier(filename)
classifier = {}
file = File.new(filename)
doc = REXML::Document.new file
classifier[:size] = doc.elements["opencv_storage/*/size"].text.split(' ').map{|v| v.to_i}
classifier[:name] = doc.elements["opencv_storage/*"].name
classifier[:stages] = []
doc.elements.each("opencv_storage/*/stages/_") do |stage|
classifier[:stages] << parse_stages(stage)
end
classifier
end
def exec_erb(filename, outer_binding)
erb = ERB.new(File.read(filename))
erb.filename = filename
erb.result(outer_binding)
end
def tree_exec(c, nodes, node)
exec_erb(File.join($lang, "_tree.erb"), binding)
end
def u(x)
x < 0 ? 2 ** 32 : x;
end
def fix(c)
scale = 1.0
width = (c[:size][0] - 2) * scale
height = (c[:size][1] - 2) * scale
weight_scale = 1.0 / (width * height);
c[:extend] = false
c[:stages].each do |stage|
stage[:trees].each do |tree|
tree.each do |node|
rects = node[:feature][:rects]
sum0 = 0.0
area0 = 0.0
rects.each_index do |k|
tr = {};
tr[:x] = (rects[k][0] * scale).round
tr[:width] = (rects[k][2] * scale).round
tr[:y] = (rects[k][1] * scale).round
tr[:height] = (rects[k][3] * scale).round
correction_ratio = weight_scale
if (node[:feature][:tilted])
correction_ratio *= 0.5
c[:extend] = true
end
rects[k][4] = rects[k][4] * correction_ratio;
if( k == 0 )
area0 = tr[:width] * tr[:height]
else
sum0 += rects[k][4] * tr[:width] * tr[:height]
end
end
rects[0][4] = -sum0.to_f / area0.to_f
end
end
end
end
def main
file = nil
opt = OptionParser.new
opt.on('-l LANGUAGE', ["javascript", "glsl"]) do |l|
if (l)
$lang = l
end
end
opt.on('-i XML') do |d|
file = d
end
argv = opt.parse(ARGV)
unless (file)
warn opt.to_s
exit
end
c = parse_opencv_haar_classifier(file)
fix(c)
puts exec_erb(File.join($lang, "main.erb"), binding)
end
main
var nvjs = nvjs || {};
nvjs.ext = nvjs.ext || {};
nvjs.ext.haar_classifier = nvjs.ext.haar_classifier || {};
nvjs.ext.haar_classifier["<%= c[:name] %>"] = nvjs.ext.haar_classifier["<%= c[:name] %>"] || {};
nvjs.ext.haar_classifier["<%= c[:name] %>"].size = <%= "{width:#{c[:size][0]}, height:#{c[:size][1]}}" %>;
nvjs.ext.haar_classifier["<%= c[:name] %>"].extend = <%= c[:extend] %>;
nvjs.ext.haar_classifier["<%= c[:name] %>"].predict =
function(integral, integral_tilted, x, y,
scale, variance_norm_factor)
{
var sumf = function(integral, x, y, w, h) {
return nvjs.ip.integral_v(integral, x, y, x + w, y + h);
};
var sumtf = function(t, x, y, w, h) {
return (t.v[(y * t.cols) + x]
- t.v[((y + h) * t.cols) + (x - h)]
- t.v[((y + w) * t.cols) + (x + w)]
+ t.v[((y + w + h) * t.cols) + (x + w - h)]);
};
var ys, xs, w, h;
var sum, p;
var s2_inv = 1.0 / (scale * scale);
var s2h_inv = 1.0 / (scale * scale * 0.5);
<% c[:stages].each do |stage| %>;
p = 0.0;
<% stage[:trees].each do |tree| %>;
<%= tree_exec(c, tree, tree[0]) %>
<% end %>
if (p < <%= sprintf("%E", stage[:threshold]) %>) {
return false;
}
<% end %>
return true;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment