/camera/imageviewer

To get this branch, use:
bzr branch http://darksoft.org/webbzr/camera/imageviewer

« back to all changes in this revision

Viewing changes to camera.rb

  • Committer: Suren A. Chilingaryan
  • Date: 2011-02-13 01:34:55 UTC
  • Revision ID: csa@dside.dyndns.org-20110213013455-7999955h7v4uf9m8
Initial import

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
require 'socket'
 
2
require 'fileutils'
 
3
 
 
4
require 'RMagick'
 
5
include Magick
 
6
 
 
7
require 'cameralink/cameralink'
 
8
 
 
9
FAST = false
 
10
 
 
11
class Camera < CameraLink::Reader
 
12
    attr_accessor :public
 
13
    attr_accessor :max_width
 
14
    attr_accessor :max_height
 
15
    attr_accessor :width
 
16
    attr_accessor :height
 
17
    attr_accessor :exposure
 
18
    attr_accessor :frame_rate
 
19
    attr_accessor :capture
 
20
    attr_accessor :trigger
 
21
 
 
22
    def initialize()
 
23
        # Getting parameters from camera
 
24
        #@max_width = Integer(get('Window.W.Max'))
 
25
        #@max_height = Integer(get('Window.H.Max'))
 
26
        @max_width, @max_height = 1280, 1024
 
27
        
 
28
        if ((@max_width <= 0) or (@max_height <= 0)) then 
 
29
            raise('Camera communication is failed')
 
30
        end
 
31
 
 
32
        @width, @height = @max_width, @max_height
 
33
        
 
34
        if FAST then
 
35
            @frame_rate = 500
 
36
            @exposure = 2
 
37
            @trigger = 1
 
38
        else
 
39
            set('Window.W', @width)
 
40
            set('Window.H', @height)
 
41
            
 
42
            @trigger = get_integer('Trigger.Source', 0)
 
43
            if (@trigger != 0) && (@trigger != 2) then 
 
44
                @trigger = set('Trigger.Source', 0)
 
45
            end
 
46
 
 
47
            if @trigger > 0 then
 
48
                @frame_rate = nil
 
49
            else
 
50
                @frame_rate = get_integer('FrameRate', 10)
 
51
            end
 
52
            
 
53
            @exposure = Float(get('ExposureTime'))
 
54
        end
 
55
 
 
56
        @display_fps = 25       
 
57
        @display_mode = 0
 
58
#       @trigger = 0
 
59
 
 
60
        @catpure = 1
 
61
 
 
62
        @display_proc = lambda { |w,h,d| }
 
63
        @status_proc = lambda { |t, at_once| }
 
64
        
 
65
        @set_request = Array.new
 
66
        
 
67
        @preallocate = nil
 
68
        
 
69
        FileUtils::mkdir_p("saved_camera_images")
 
70
 
 
71
        super()
 
72
    end
 
73
    
 
74
    def set_procs(status_proc, display_proc)
 
75
        @display_proc = display_proc
 
76
        @status_proc = status_proc
 
77
    end
 
78
    
 
79
 
 
80
    def get(val)
 
81
        s = UNIXSocket.open('/tmp/pfserver.socket')
 
82
        s.print(val)
 
83
        res = s.gets()
 
84
        s.close
 
85
        return res
 
86
    end
 
87
    
 
88
    def get_integer(val, min) 
 
89
        res = get(val)
 
90
        if res =~ /^#(\d+)/ then
 
91
            value = Integer($1);
 
92
        else
 
93
            value = Integer(Float(res));
 
94
        end
 
95
        raise('Camera communication is failed') if value < min 
 
96
        return value
 
97
    end
 
98
 
 
99
    def set(val, value)
 
100
        s = UNIXSocket.open('/tmp/pfserver.socket')
 
101
        s.print(val + ' ' + String(value))
 
102
        res = s.gets()
 
103
        s.close
 
104
        return res
 
105
    end
 
106
 
 
107
    # s.get for some reason is crashing if called from GTK callback
 
108
    def set2(val, value)
 
109
        s = UNIXSocket.open('/tmp/pfserver.socket')
 
110
        s.print(val + ' ' + String(value))
 
111
        s.close
 
112
    end
 
113
 
 
114
    def open()
 
115
        @running = true
 
116
        @reader_open = false
 
117
        @reader_thread = Thread.new {
 
118
            while @running and not @reader_open
 
119
                sleep 0.0001
 
120
            end
 
121
            
 
122
            geometry = Magick::Geometry.new(@width,@height,nil,nil,Magick::AspectGeometry)
 
123
            
 
124
            if @trigger > 0 then
 
125
                next_display = Time.now
 
126
                next_status = next_display + 1
 
127
                func = :threaded_run
 
128
            else
 
129
                next_status = @frame_rate
 
130
                func = :run
 
131
            end
 
132
 
 
133
            #safe_run(@running) { |id, data|
 
134
            #run(@running) { |id, data|
 
135
            send(func, @running) { |id, data|
 
136
                if ((id < 0) or (not data)) then next; end
 
137
                
 
138
                @lost_frames += id - @current_frame - 1
 
139
 
 
140
                #if (id - @current_frame - 1) > 10
 
141
                #    puts id, id - @current_frame - 1
 
142
                #end
 
143
 
 
144
                @current_frame = id
 
145
                
 
146
                time = Time.now
 
147
                
 
148
                if (case @trigger; when 0: id > next_status; else time > next_status; end) then
 
149
                    if (@frame_rate) then
 
150
                        msg = sprintf("FPS/Expected: %i, FPS/Measured: %i, Dropped Frames: %i", @frame_rate, @frames, @lost_frames)
 
151
                    else
 
152
                        msg = sprintf("FPS/Expected: triggered, FPS/Measured: %i, Dropped Frames: %i", @frames, @lost_frames)
 
153
                    end
 
154
                    
 
155
                    if (@capture) then
 
156
                        msg += sprintf(", Captured: %i (%i MB)", @image_frames.length, @image_frames.length * @width * @height / 1024 / 1024)
 
157
                    end
 
158
                    
 
159
                    @status_proc.call(msg, false)
 
160
                    
 
161
                    while @set_request.length > 0
 
162
                        @set_request.pop.call
 
163
                    end
 
164
                    
 
165
                    @frames = 0
 
166
                    next_status = (@trigger > 0)?(time + 1):(id + @frame_rate - 1)
 
167
                    @lost_frames = 0
 
168
                end
 
169
 
 
170
                if (case @trigger; when 0: ((@display_mode > 0) and (id%@display_mode == 0)); else time > next_display; end) then
 
171
                    @display_proc.call(@width, @height, data)
 
172
                    next_display = (@display_mode>0)?time + (1.0 / @display_fps):time if (@trigger > 0)
 
173
                end
 
174
                
 
175
                if (@capture) then
 
176
                    if (@capture_storage > 0) then
 
177
                        img = Image.from_blob(data) {
 
178
                            self.format = "GRAY"
 
179
                            self.depth = 8
 
180
                            self.size = geometry
 
181
                        }[0]
 
182
                        
 
183
                        @capture_frame += 1
 
184
                        img.write(sprintf("saved_camera_images/%s/PIC%09i.tif", @session, @capture_frame))
 
185
                        img.destroy!
 
186
                    else 
 
187
                        @images.push(String.new(data))
 
188
                    end
 
189
                    
 
190
                    @image_frames.push(id)
 
191
                    
 
192
                    if (time > @stop_capture)
 
193
                        GC.enable if @capture_storage == 0
 
194
 
 
195
                        @capture = false
 
196
                        @capture_session = @session
 
197
                        @capture_width = @width
 
198
                        @capture_height = @height
 
199
                        @stop_action.call()
 
200
                    end
 
201
                end
 
202
 
 
203
                @frames += 1
 
204
            }
 
205
        }
 
206
        super(@width, @height)
 
207
        
 
208
        @frames = 0
 
209
        @lost_frames = 0
 
210
        @current_frame = 0
 
211
        @reader_open = true
 
212
    end
 
213
    
 
214
    def close()
 
215
        stop
 
216
        if @running then
 
217
            @running = false
 
218
            @reader_thread.join
 
219
        end
 
220
        super()
 
221
    end
 
222
    
 
223
    def display_fps=(value)
 
224
        @display_fps = value
 
225
        @display_mode = (@frame_rate / value).round if ((@display_mode > 1) and (@frame_rate))
 
226
    end
 
227
    
 
228
    def display_mode=(value)
 
229
        @display_mode = case value 
 
230
            when 0: @frame_rate?((@frame_rate / @display_fps).round):2
 
231
            when 1: 1
 
232
            when 2: 0
 
233
        end
 
234
    end
 
235
    
 
236
    def camera_mode()
 
237
        @trigger
 
238
    end
 
239
    
 
240
    def camera_mode=(value)
 
241
        close
 
242
        
 
243
        @status_proc.call("Changing camera mode...", true)
 
244
        @trigger = value * 2
 
245
        set('Trigger.Source', @trigger)
 
246
        
 
247
        if @trigger > 0 then
 
248
            @frame_rate = nil
 
249
        else
 
250
            @frame_rate = get_integer('FrameRate', 10)
 
251
            @display_mode = (@frame_rate / @display_fps).round if @display_mode > 1
 
252
        end
 
253
 
 
254
        
 
255
        open
 
256
=begin
 
257
        @set_request.push(lambda {
 
258
            trigger = set('Trigger.Source', value * 2)
 
259
            @trigger = Integer(trigger[1..(trigger.length-1)])
 
260
            if @trigger == 0 then
 
261
                @frame_rate = get_integer('FrameRate', 10)
 
262
                @display_mode = (@frame_rate / @display_fps).round if @display_mode > 1
 
263
            else
 
264
                @frame_rate = nil
 
265
            end
 
266
        })
 
267
=end
 
268
    end
 
269
    
 
270
    def exposure=(value)
 
271
        @set_request.push(lambda {
 
272
            @exposure = set('ExposureTime', value)
 
273
            @frame_rate = get_integer('FrameRate', 10) if @trigger == 0
 
274
        })
 
275
    end
 
276
    
 
277
    def set_resolution(res) 
 
278
        close
 
279
        
 
280
        @status_proc.call("Changing resolution...", true)
 
281
        @width, @height = res
 
282
        
 
283
        set('Window.W', @width);
 
284
        set('Window.H', @height);
 
285
        
 
286
        if @trigger == 0 then
 
287
            @frame_rate = get_integer('FrameRate', 10)
 
288
            @display_mode = (@frame_rate / @display_fps).round if @display_mode > 1
 
289
        end
 
290
        
 
291
        open
 
292
    end
 
293
    
 
294
    def start_capture(storage, duration, &stop_action)
 
295
        if storage == 0 and @frame_rate then
 
296
            size = @width * @height * @frame_rate * duration
 
297
            if (100 + 1.02 * size) > $freemem then
 
298
                storage = 1
 
299
            end
 
300
        end
 
301
        
 
302
        @images = (storage>0)?nil:Array.new()
 
303
        @image_frames = Array.new()
 
304
        
 
305
        if storage == 0 then
 
306
            #GC.start may cause frame lose, it somehow prevented by calling it after GUI initialization, but still it is possible
 
307
            GC.start
 
308
        
 
309
            GC.disable
 
310
        end
 
311
        
 
312
        time = Time.now
 
313
        #@session = time.to_i
 
314
        @session = sprintf("%02i%02i%02i_%02i%02i%02i", time.year, time.month, time.day, time.hour, time.min, time.sec)
 
315
        FileUtils::mkdir_p("saved_camera_images/" + @session) if (storage > 0)
 
316
 
 
317
        @stop_capture = Time.now + duration
 
318
        @stop_action = stop_action
 
319
        @capture_storage = storage
 
320
        @capture_frame = 0
 
321
        @capture = true
 
322
        
 
323
        return storage
 
324
    end
 
325
    
 
326
    def stop_capture()
 
327
        @stop_capture = Time.now
 
328
    end
 
329
 
 
330
    def replay()
 
331
        yield(@capture_width, @capture_height, @images?@images:@capture_session, @image_frames)
 
332
    end
 
333
end