motion-capture 1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.md +47 -0
- data/lib/motion-capture.rb +8 -0
- data/lib/project/motion-capture.rb +193 -0
- data/lib/project/views/overlay_view.rb +112 -0
- metadata +62 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 098882fee3cdac39ac683f6add7df21009187b01
|
4
|
+
data.tar.gz: 95a133286c70f6bab31ce7410056046df6ed2231
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1957c4720f94d8fb3aaf998535a6865fa2b98d37daed7469703920f21167b15b64a029607644345c350d9477584cff1a2524707d76f08997b9e3496411bc06ce
|
7
|
+
data.tar.gz: ec63205dae5efc7e59eecbdc569f07b91c99c862dd47952446c5964bdb1ea18e733b19c789d5dbc9a0ac5bd02c72ed2b997cb3bd222f499949964b1feb219e25
|
data/README.md
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
# motion-capture
|
2
|
+
|
3
|
+
Camera support for custom camera controllers
|
4
|
+
|
5
|
+
## Usage
|
6
|
+
|
7
|
+
motion_capture = Motion::Capture.new
|
8
|
+
motion_capture = Motion::Capture.new(device: :front) # specify camera
|
9
|
+
|
10
|
+
preview = motion_capture.capture_preview_view(frame: view.bounds)
|
11
|
+
view.addSubview(preview) # UIView containing AVCaptureVideoPreviewLayer
|
12
|
+
|
13
|
+
motion_capture.toggle_camera # Switch between front/rear cameras
|
14
|
+
motion_capture.toggle_flash # Switch bettwen flash on/off
|
15
|
+
|
16
|
+
motion_capture.turn_flash_on
|
17
|
+
motion_capture.turn_flash_off
|
18
|
+
|
19
|
+
motion_capture.use_camera(:default)
|
20
|
+
motion_capture.use_camera(:front)
|
21
|
+
motion_capture.use_camera(:rear)
|
22
|
+
|
23
|
+
motion_capture.capture do |image|
|
24
|
+
# Use UIImage
|
25
|
+
end
|
26
|
+
|
27
|
+
## Setup
|
28
|
+
|
29
|
+
Add this line to your application's Gemfile:
|
30
|
+
|
31
|
+
gem 'motion-capture'
|
32
|
+
|
33
|
+
And then execute:
|
34
|
+
|
35
|
+
$ bundle
|
36
|
+
|
37
|
+
Or install it yourself as:
|
38
|
+
|
39
|
+
$ gem install motion-capture
|
40
|
+
|
41
|
+
## Contributing
|
42
|
+
|
43
|
+
1. Fork it
|
44
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
45
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
46
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
47
|
+
5. Create new Pull Request
|
@@ -0,0 +1,8 @@
|
|
1
|
+
unless defined?(Motion::Project::Config)
|
2
|
+
raise "This file must be required within a RubyMotion project Rakefile."
|
3
|
+
end
|
4
|
+
|
5
|
+
lib_dir_path = File.dirname(File.expand_path(__FILE__))
|
6
|
+
Motion::Project::App.setup do |app|
|
7
|
+
app.files.unshift(Dir.glob(File.join(lib_dir_path, "project/**/*.rb")))
|
8
|
+
end
|
@@ -0,0 +1,193 @@
|
|
1
|
+
class Motion
|
2
|
+
class Capture
|
3
|
+
DEFAULT_OPTIONS = { device: :default }
|
4
|
+
|
5
|
+
attr_accessor :options, :device
|
6
|
+
|
7
|
+
def initialize(options = {})
|
8
|
+
self.options = options.merge(DEFAULT_OPTIONS)
|
9
|
+
end
|
10
|
+
|
11
|
+
def start!
|
12
|
+
use_camera(options[:device])
|
13
|
+
|
14
|
+
add_ouput(still_image_output)
|
15
|
+
end
|
16
|
+
|
17
|
+
def capture(&block)
|
18
|
+
still_image_connection = still_image_output.connections.first
|
19
|
+
|
20
|
+
still_image_output.captureStillImageAsynchronouslyFromConnection(still_image_connection, completionHandler: lambda { |image_data_sample_buffer, error|
|
21
|
+
if image_data_sample_buffer
|
22
|
+
image_data = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(image_data_sample_buffer)
|
23
|
+
|
24
|
+
image = UIImage.alloc.initWithData(image_data)
|
25
|
+
|
26
|
+
block.call(image)
|
27
|
+
else
|
28
|
+
p "Error capturing image: #{error[0].description}"
|
29
|
+
end
|
30
|
+
})
|
31
|
+
end
|
32
|
+
|
33
|
+
def capture_preview_view(options)
|
34
|
+
@_capture_preview_view ||= begin
|
35
|
+
start!
|
36
|
+
|
37
|
+
UIView.alloc.initWithFrame(options.fetch(:frame, CGRectZero)).tap do |view|
|
38
|
+
view.backgroundColor = UIColor.whiteColor
|
39
|
+
|
40
|
+
view.layer.addSublayer(preview_layer_for_view(view))
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def use_camera(camera)
|
46
|
+
device = camera_devices[camera]
|
47
|
+
|
48
|
+
error = Pointer.new(:object)
|
49
|
+
|
50
|
+
self.device = device
|
51
|
+
input = AVCaptureDeviceInput.deviceInputWithDevice(device, error: error)
|
52
|
+
|
53
|
+
if input
|
54
|
+
set_input(input)
|
55
|
+
else
|
56
|
+
p error[0].description
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def toggle_camera
|
61
|
+
if using_rear_camera?
|
62
|
+
use_camera(:front)
|
63
|
+
else
|
64
|
+
use_camera(:rear)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def toggle_flash
|
69
|
+
if device && device.hasFlash
|
70
|
+
error = Pointer.new(:object)
|
71
|
+
if device.lockForConfiguration(error)
|
72
|
+
if flash_on?
|
73
|
+
turn_flash_off
|
74
|
+
else
|
75
|
+
turn_flash_on
|
76
|
+
end
|
77
|
+
|
78
|
+
device.unlockForConfiguration
|
79
|
+
else
|
80
|
+
p error[0].description
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
def set_input(input)
|
88
|
+
remove_inputs
|
89
|
+
|
90
|
+
add_input(input)
|
91
|
+
end
|
92
|
+
|
93
|
+
def set_output(output)
|
94
|
+
remove_outputs
|
95
|
+
|
96
|
+
add_output(output)
|
97
|
+
end
|
98
|
+
|
99
|
+
def remove_inputs
|
100
|
+
session.inputs.each do |input|
|
101
|
+
remove_input(input)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def remove_outputs
|
106
|
+
session.outputs.each do |output|
|
107
|
+
remove_output(output)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def remove_input(input)
|
112
|
+
session.removeInput(input)
|
113
|
+
end
|
114
|
+
|
115
|
+
def remove_output(output)
|
116
|
+
session.removeOutput(output)
|
117
|
+
end
|
118
|
+
|
119
|
+
def add_input(input)
|
120
|
+
session.addInput(input)
|
121
|
+
end
|
122
|
+
|
123
|
+
def add_ouput(output)
|
124
|
+
session.addOutput(output)
|
125
|
+
end
|
126
|
+
|
127
|
+
def default_camera
|
128
|
+
AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)
|
129
|
+
end
|
130
|
+
|
131
|
+
def rear_camera
|
132
|
+
capture_devices.select { |device| device.position == camera_position_mapping[:rear] }.first
|
133
|
+
end
|
134
|
+
|
135
|
+
def front_camera
|
136
|
+
capture_devices.select { |device| device.position == camera_position_mapping[:front] }.first
|
137
|
+
end
|
138
|
+
|
139
|
+
def using_rear_camera?
|
140
|
+
device.position == AVCaptureDevicePositionBack
|
141
|
+
end
|
142
|
+
|
143
|
+
def camera_position_mapping
|
144
|
+
{ rear: AVCaptureDevicePositionBack, front: AVCaptureDevicePositionFront }
|
145
|
+
end
|
146
|
+
|
147
|
+
def camera_devices
|
148
|
+
{ default: default_camera, rear: rear_camera, front: front_camera }
|
149
|
+
end
|
150
|
+
|
151
|
+
def capture_devices
|
152
|
+
@_capture_devices ||= AVCaptureDevice.devicesWithMediaType(AVMediaTypeVideo)
|
153
|
+
end
|
154
|
+
|
155
|
+
def preview_layer_for_view(view)
|
156
|
+
AVCaptureVideoPreviewLayer.layerWithSession(session).tap do |layer|
|
157
|
+
layer_bounds = view.layer.bounds
|
158
|
+
|
159
|
+
layer.bounds = layer_bounds
|
160
|
+
layer.position = CGPointMake(CGRectGetMidX(layer_bounds), CGRectGetMidY(layer_bounds))
|
161
|
+
layer.videoGravity = AVLayerVideoGravityResizeAspectFill
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def flash_on?
|
166
|
+
device.flashMode == AVCaptureFlashModeOn
|
167
|
+
end
|
168
|
+
|
169
|
+
def turn_flash_on
|
170
|
+
device.flashMode = AVCaptureFlashModeOn
|
171
|
+
end
|
172
|
+
|
173
|
+
def turn_flash_off
|
174
|
+
device.flashMode = AVCaptureFlashModeOff
|
175
|
+
end
|
176
|
+
|
177
|
+
def session
|
178
|
+
@_session ||= AVCaptureSession.alloc.init.tap do |session|
|
179
|
+
session.sessionPreset = AVCaptureSessionPresetMedium
|
180
|
+
|
181
|
+
session.startRunning
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
def still_image_output
|
186
|
+
@_still_image_output ||= AVCaptureStillImageOutput.alloc.init.tap do |output|
|
187
|
+
settings = { 'AVVideoCodeKey' => AVVideoCodecJPEG }
|
188
|
+
|
189
|
+
output.setOutputSettings(settings)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
class GridOverlayView < UIView
|
2
|
+
DEFAULTS = { stroke_color: UIColor.grayColor,
|
3
|
+
stroke_width: 1.0,
|
4
|
+
x_lines: 3,
|
5
|
+
y_lines: 3 }
|
6
|
+
|
7
|
+
attr_accessor :x_interval, :y_interval
|
8
|
+
attr_reader :stroke_color, :stroke_width
|
9
|
+
|
10
|
+
def initWithFrame(frame)
|
11
|
+
super.tap do |view|
|
12
|
+
view.backgroundColor = UIColor.clearColor
|
13
|
+
|
14
|
+
self.x_lines = DEFAULTS[:x_lines]
|
15
|
+
self.y_lines = DEFAULTS[:y_lines]
|
16
|
+
self.stroke_color = DEFAULTS[:stroke_color]
|
17
|
+
self.stroke_width = DEFAULTS[:stroke_width]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def hidden?
|
22
|
+
stroke_color == UIColor.clearColor
|
23
|
+
end
|
24
|
+
|
25
|
+
def toggle
|
26
|
+
if hidden?
|
27
|
+
show
|
28
|
+
else
|
29
|
+
hide
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def show
|
34
|
+
self.stroke_color = @original_color
|
35
|
+
|
36
|
+
setNeedsDisplay
|
37
|
+
end
|
38
|
+
|
39
|
+
def hide
|
40
|
+
unless hidden?
|
41
|
+
@original_color = stroke_color
|
42
|
+
|
43
|
+
self.stroke_color = UIColor.clearColor
|
44
|
+
|
45
|
+
setNeedsDisplay
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def x_lines=(lines)
|
50
|
+
self.x_interval = frame.size.width / lines
|
51
|
+
|
52
|
+
setNeedsDisplay
|
53
|
+
end
|
54
|
+
|
55
|
+
def y_lines=(lines)
|
56
|
+
self.y_interval = frame.size.height / lines
|
57
|
+
|
58
|
+
setNeedsDisplay
|
59
|
+
end
|
60
|
+
|
61
|
+
def stroke_width=(width)
|
62
|
+
@stroke_width = width
|
63
|
+
|
64
|
+
setNeedsDisplay
|
65
|
+
end
|
66
|
+
|
67
|
+
def stroke_color=(color)
|
68
|
+
@stroke_color = color
|
69
|
+
|
70
|
+
setNeedsDisplay
|
71
|
+
end
|
72
|
+
|
73
|
+
def setup_drawing
|
74
|
+
CGContextSetStrokeColorWithColor(context, stroke_color.CGColor)
|
75
|
+
|
76
|
+
CGContextSetLineWidth(context, stroke_width)
|
77
|
+
end
|
78
|
+
|
79
|
+
def drawRect(rect)
|
80
|
+
super
|
81
|
+
|
82
|
+
setup_drawing
|
83
|
+
draw_vertical_lines
|
84
|
+
draw_horizontal_lines
|
85
|
+
|
86
|
+
fill_path
|
87
|
+
end
|
88
|
+
|
89
|
+
def fill_path
|
90
|
+
CGContextStrokePath(context)
|
91
|
+
end
|
92
|
+
|
93
|
+
def draw_horizontal_lines
|
94
|
+
draw_line([0, y_interval], [size.width, y_interval])
|
95
|
+
draw_line([0, y_interval * 2], [size.width, y_interval * 2])
|
96
|
+
end
|
97
|
+
|
98
|
+
def draw_vertical_lines
|
99
|
+
draw_line([x_interval, 0], [x_interval, size.height])
|
100
|
+
draw_line([x_interval * 2, 0], [x_interval * 2.0, size.height])
|
101
|
+
end
|
102
|
+
|
103
|
+
def draw_line(start_point, end_point)
|
104
|
+
CGContextMoveToPoint(context, start_point[0], start_point[1])
|
105
|
+
|
106
|
+
CGContextAddLineToPoint(context, end_point[0], end_point[1])
|
107
|
+
end
|
108
|
+
|
109
|
+
def context
|
110
|
+
@_context ||= UIGraphicsGetCurrentContext()
|
111
|
+
end
|
112
|
+
end
|
metadata
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: motion-capture
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '1.0'
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Devon Blandin
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-07-08 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rake
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
description: AVFoundation wrapper to support custom camera controllers
|
28
|
+
email:
|
29
|
+
- dblandin@gmail.com
|
30
|
+
executables: []
|
31
|
+
extensions: []
|
32
|
+
extra_rdoc_files: []
|
33
|
+
files:
|
34
|
+
- README.md
|
35
|
+
- lib/motion-capture.rb
|
36
|
+
- lib/project/motion-capture.rb
|
37
|
+
- lib/project/views/overlay_view.rb
|
38
|
+
homepage: https://github.com/dblandin/motion-capture
|
39
|
+
licenses:
|
40
|
+
- MIT
|
41
|
+
metadata: {}
|
42
|
+
post_install_message:
|
43
|
+
rdoc_options: []
|
44
|
+
require_paths:
|
45
|
+
- lib
|
46
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
47
|
+
requirements:
|
48
|
+
- - '>='
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: '0'
|
51
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - '>='
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
56
|
+
requirements: []
|
57
|
+
rubyforge_project:
|
58
|
+
rubygems_version: 2.0.0
|
59
|
+
signing_key:
|
60
|
+
specification_version: 4
|
61
|
+
summary: AVFoundation wrapper to support custom camera controllers
|
62
|
+
test_files: []
|