Example #1
0
def compress_thread():
    """thread for compressing images"""
    while True:
        frame_time, im = state.compress_queue.get()
        jpeg = scanner.jpeg_compress(im, int(opts.quality))
        if opts.save:
            state.save_queue.put((frame_time, jpeg, True))
Example #2
0
def transmit_thread():
    '''thread for image transmit to GCS'''
    state = mpstate.camera_state

    tx_count = 0
    skip_count = 0
    bsend = block_xmit.BlockSender(0, state.bandwidth)

    while not state.unload.wait(0.02):
        bsend.tick()
        if state.transmit_queue.empty():
            continue

        (frame_time, regions, im_full, im_640) = state.transmit_queue.get()
        pos = get_plane_position(frame_time)
        latlon_list = log_joe_position(pos, frame_time, regions)

        state.xmit_queue = bsend.sendq_size()
        state.efficiency = bsend.get_efficiency()
        state.bandwidth_used = bsend.get_bandwidth_used()
        state.rtt_estimate = bsend.get_rtt_estimate()

        jpeg = None

        if len(regions) > 0 and bsend.sendq_size() < 2000:
            # send a region message with thumbnails to the ground station
            thumb = cuav_mosaic.CompositeThumbnail(im_full, regions, quality=state.quality, thumb_size=100)
            bsend.set_bandwidth(state.bandwidth)
            bsend.set_packet_loss(state.packet_loss)
            pkt = ThumbPacket(frame_time, regions, thumb, latlon_list, state.frame_loss, state.xmit_queue)

            # send matches with a higher priority
            if state.transmit:
                bsend.send(cPickle.dumps(pkt, cPickle.HIGHEST_PROTOCOL),
                           dest=(state.gcs_address, state.gcs_view_port),
                           priority=1)

        # Base how many images we send on the send queue size
        send_frequency = state.xmit_queue // 3
        if send_frequency == 0 or (tx_count+skip_count) % send_frequency == 0:
            jpeg = scanner.jpeg_compress(im_640, state.quality)

        if jpeg is None:
            skip_count += 1
            continue

        # keep filtered image size
        state.jpeg_size = 0.95 * state.jpeg_size + 0.05 * len(jpeg)
        
        tx_count += 1

        if state.gcs_address is None:
            continue
        bsend.set_packet_loss(state.packet_loss)
        bsend.set_bandwidth(state.bandwidth)
        pkt = ImagePacket(frame_time, jpeg)
        bsend.send(cPickle.dumps(pkt, cPickle.HIGHEST_PROTOCOL),
                   dest=(state.gcs_address, state.gcs_view_port))
Example #3
0
def CompositeThumbnail(img, regions, thumb_size=100, quality=75):
    '''extract a composite thumbnail for the regions of an image

    The composite will consist of N thumbnails side by side

    return it as a compressed jpeg string
    '''
    composite = cv.CreateImage((thumb_size*len(regions), thumb_size),8,3)
    for i in range(len(regions)):
        (x1,y1,x2,y2) = regions[i].tuple()
        midx = (x1+x2)/2
        midy = (y1+y2)/2

        x1 = midx - thumb_size/2
        y1 = midy - thumb_size/2
        thumb = cuav_util.SubImage(img, (x1, y1, thumb_size, thumb_size))
        cv.SetImageROI(composite, (thumb_size*i, 0, thumb_size, thumb_size))
        cv.Copy(thumb, composite)
        cv.ResetImageROI(composite)
    return scanner.jpeg_compress(numpy.ascontiguousarray(cv.GetMat(composite)), quality)
Example #4
0
def transmit_thread():
    '''thread for image transmit to GCS'''
    state = mpstate.camera_state

    tx_count = 0
    skip_count = 0
    bsend = block_xmit.BlockSender(0,
                                   bandwidth=state.settings.bandwidth,
                                   debug=False)
    state.bsocket = MavSocket(mpstate.mav_master[0])
    state.bsend2 = block_xmit.BlockSender(mss=96,
                                          sock=state.bsocket,
                                          dest_ip='mavlink',
                                          dest_port=0,
                                          backlog=5,
                                          debug=False)
    state.bsend2.set_bandwidth(state.settings.bandwidth2)

    while not state.unload.wait(0.02):
        bsend.tick(packet_count=1000, max_queue=state.settings.maxqueue1)
        state.bsend2.tick(packet_count=1000,
                          max_queue=state.settings.maxqueue2)
        check_commands()
        if state.transmit_queue.empty():
            continue

        (frame_time, regions, im_full, im_640) = state.transmit_queue.get()
        if state.settings.roll_stabilised:
            roll = 0
        else:
            roll = None
        pos = get_plane_position(frame_time, roll=roll)

        # this adds the latlon field to the regions
        log_joe_position(pos, frame_time, regions)

        # filter out any regions outside the boundary
        if state.boundary_polygon:
            regions = cuav_region.filter_boundary(regions,
                                                  state.boundary_polygon, pos)
            regions = cuav_region.filter_regions(
                im_full, regions, min_score=state.settings.minscore)

        state.xmit_queue = bsend.sendq_size()
        state.xmit_queue2 = state.bsend2.sendq_size()
        state.efficiency = bsend.get_efficiency()
        state.bandwidth_used = bsend.get_bandwidth_used()
        state.rtt_estimate = bsend.get_rtt_estimate()

        jpeg = None

        if len(regions) > 0:
            lowscore = 0
            highscore = 0
            for r in regions:
                lowscore = min(lowscore, r.score)
                highscore = max(highscore, r.score)

            if state.settings.transmit:
                # send a region message with thumbnails to the ground station
                thumb = None
                if state.settings.send1:
                    thumb = cuav_mosaic.CompositeThumbnail(
                        cv.GetImage(cv.fromarray(im_full)),
                        regions,
                        quality=state.settings.quality,
                        thumb_size=state.settings.thumbsize)
                    pkt = ThumbPacket(frame_time, regions, thumb,
                                      state.frame_loss, state.xmit_queue, pos)

                    buf = cPickle.dumps(pkt, cPickle.HIGHEST_PROTOCOL)
                    bsend.set_bandwidth(state.settings.bandwidth)
                    bsend.set_packet_loss(state.settings.packet_loss)
                    bsend.send(buf,
                               dest=(state.settings.gcs_address,
                                     state.settings.gcs_view_port),
                               priority=1)
                # also send thumbnails via 900MHz telemetry
                if state.settings.send2 and highscore >= state.settings.minscore2:
                    if thumb is None or lowscore < state.settings.minscore2:
                        # remove some of the regions
                        regions = cuav_region.filter_regions(
                            im_full,
                            regions,
                            min_score=state.settings.minscore2)
                        thumb = cuav_mosaic.CompositeThumbnail(
                            cv.GetImage(cv.fromarray(im_full)),
                            regions,
                            quality=state.settings.quality,
                            thumb_size=state.settings.thumbsize)
                        pkt = ThumbPacket(frame_time, regions, thumb,
                                          state.frame_loss, state.xmit_queue,
                                          pos)

                        buf = cPickle.dumps(pkt, cPickle.HIGHEST_PROTOCOL)
                    state.bsend2.set_bandwidth(state.settings.bandwidth2)
                    state.bsend2.send(buf, priority=highscore)

        # Base how many images we send on the send queue size
        send_frequency = state.xmit_queue // 3
        if send_frequency == 0 or (tx_count +
                                   skip_count) % send_frequency == 0:
            jpeg = scanner.jpeg_compress(im_640, state.settings.quality)

        if jpeg is None:
            skip_count += 1
            continue

        # keep filtered image size
        state.jpeg_size = 0.95 * state.jpeg_size + 0.05 * len(jpeg)

        tx_count += 1

        if state.settings.gcs_address is None:
            continue
        bsend.set_packet_loss(state.settings.packet_loss)
        bsend.set_bandwidth(state.settings.bandwidth)
        pkt = ImagePacket(frame_time, jpeg, state.xmit_queue, pos)
        str = cPickle.dumps(pkt, cPickle.HIGHEST_PROTOCOL)
        bsend.send(str,
                   dest=(state.settings.gcs_address,
                         state.settings.gcs_view_port))
Example #5
0
def transmit_thread():
    '''thread for image transmit to GCS'''
    state = mpstate.camera_state

    tx_count = 0
    skip_count = 0
    bsend = block_xmit.BlockSender(0, state.settings.bandwidth, debug=False)
    state.bsocket = MavSocket(mpstate.mav_master[0])
    state.bsend2 = block_xmit.BlockSender(mss=96, sock=state.bsocket, dest_ip='mavlink', dest_port=0, backlog=5, debug=False)
    state.bsend2.set_bandwidth(state.settings.bandwidth2)

    while not state.unload.wait(0.02):
        bsend.tick(packet_count=1000, max_queue=state.settings.maxqueue1)
        state.bsend2.tick(packet_count=1000, max_queue=state.settings.maxqueue2)
        check_commands()
        if state.transmit_queue.empty():
            continue

        (frame_time, regions, im_full, im_640) = state.transmit_queue.get()
        if state.settings.roll_stabilised:
            roll=0
        else:
            roll=None
        pos = get_plane_position(frame_time, roll=roll)

        # this adds the latlon field to the regions
        log_joe_position(pos, frame_time, regions)

        # filter out any regions outside the boundary
        if state.boundary_polygon:
            regions = cuav_region.filter_boundary(regions, state.boundary_polygon, pos)

        state.xmit_queue = bsend.sendq_size()
        state.xmit_queue2 = state.bsend2.sendq_size()
        state.efficiency = bsend.get_efficiency()
        state.bandwidth_used = bsend.get_bandwidth_used()
        state.rtt_estimate = bsend.get_rtt_estimate()

        jpeg = None

        if len(regions) > 0:
            lowscore = 0
            highscore = 0
            for r in regions:
                lowscore = min(lowscore, r.score)
                highscore = max(highscore, r.score)
                
            if state.settings.transmit:
                # send a region message with thumbnails to the ground station
                thumb = None
                if state.settings.send1:
                    thumb = cuav_mosaic.CompositeThumbnail(cv.GetImage(cv.fromarray(im_full)),
                                                           regions, quality=state.settings.quality, thumb_size=state.settings.thumbsize)
                    pkt = ThumbPacket(frame_time, regions, thumb, state.frame_loss, state.xmit_queue, pos)

                    buf = cPickle.dumps(pkt, cPickle.HIGHEST_PROTOCOL)
                    bsend.set_bandwidth(state.settings.bandwidth)
                    bsend.set_packet_loss(state.settings.packet_loss)
                    bsend.send(buf,
                               dest=(state.settings.gcs_address, state.settings.gcs_view_port),
                               priority=1)
                # also send thumbnails via 900MHz telemetry
                if state.settings.send2 and highscore >= state.settings.minscore2:
                    if thumb is None or lowscore < state.settings.minscore2:
                        # remove some of the regions
                        regions = cuav_region.filter_regions(im_full, regions, min_score=state.settings.minscore2)
                        thumb = cuav_mosaic.CompositeThumbnail(cv.GetImage(cv.fromarray(im_full)),
                                                               regions, quality=state.settings.quality, thumb_size=state.settings.thumbsize)
                        pkt = ThumbPacket(frame_time, regions, thumb, state.frame_loss, state.xmit_queue, pos)

                        buf = cPickle.dumps(pkt, cPickle.HIGHEST_PROTOCOL)
                    state.bsend2.set_bandwidth(state.settings.bandwidth2)
                    state.bsend2.send(buf, priority=highscore)

        # Base how many images we send on the send queue size
        send_frequency = state.xmit_queue // 3
        if send_frequency == 0 or (tx_count+skip_count) % send_frequency == 0:
            jpeg = scanner.jpeg_compress(im_640, state.settings.quality)

        if jpeg is None:
            skip_count += 1
            continue

        # keep filtered image size
        state.jpeg_size = 0.95 * state.jpeg_size + 0.05 * len(jpeg)
        
        tx_count += 1

        if state.settings.gcs_address is None:
            continue
        bsend.set_packet_loss(state.settings.packet_loss)
        bsend.set_bandwidth(state.settings.bandwidth)
        pkt = ImagePacket(frame_time, jpeg, state.xmit_queue, pos)
        str = cPickle.dumps(pkt, cPickle.HIGHEST_PROTOCOL)
        bsend.send(str,
                   dest=(state.settings.gcs_address, state.settings.gcs_view_port))
Example #6
0
        continue
    scanner.debayer(im, im_640)
    regions = scanner.scan(im_640)
    if len(regions) > 0:
        print("Found %u regions" % len(regions))
        for r in regions:
            (minx, miny, maxx, maxy) = r
            print(minx, miny, maxx, maxy)

    mat = cv.fromarray(im_640)
    for (x1, y1, x2, y2) in regions:
        cv.Rectangle(mat, (x1, y1), (x2, y2), (255, 0, 0), 1)
    im_marked = numpy.ascontiguousarray(mat)

    # compress using neon-accelerated compressor, and write to a file
    jpeg = scanner.jpeg_compress(im_marked, 30)
    jfile = open("tmp/i%u.jpg" % i, "w")
    jfile.write(jpeg)
    jfile.close()

    cv.ShowImage("Viewer", im_marked)
    i += 1

    if i % 10 == 0:
        tdiff = time.time() - tstart
        print("%.1f fps" % (10 / tdiff))
        tstart = time.time()

    key = cv.WaitKey(1)
    if key == -1:
        continue
Example #7
0
def process(args):
    """process a set of files"""

    global slipmap, mosaic
    scan_count = 0
    files = []
    for a in args:
        if os.path.isdir(a):
            files.extend(glob.glob(os.path.join(a, "*.pgm")))
        else:
            files.append(a)
    files.sort()
    num_files = len(files)
    print ("num_files=%u" % num_files)
    region_count = 0
    joes = []

    if opts.mavlog:
        mpos = mav_position.MavInterpolator(gps_lag=opts.gps_lag)
        mpos.set_logfile(opts.mavlog)
    else:
        mpos = None

    if opts.boundary:
        boundary = cuav_util.polygon_load(opts.boundary)
    else:
        boundary = None

    if opts.mosaic:
        slipmap = mp_slipmap.MPSlipMap(service="GoogleSat", elevation=True, title="Map")
        icon = slipmap.icon("planetracker.png")
        slipmap.add_object(
            mp_slipmap.SlipIcon("plane", (0, 0), icon, layer=3, rotation=0, follow=True, trail=mp_slipmap.SlipTrail())
        )
        C_params = cam_params.CameraParams(lens=opts.lens)
        path = os.path.join(
            os.path.dirname(os.path.realpath(__file__)), "..", "..", "cuav", "data", "chameleon1_arecont0.json"
        )
        C_params.load(path)
        mosaic = cuav_mosaic.Mosaic(slipmap, C=C_params)
        if boundary is not None:
            mosaic.set_boundary(boundary)

    if opts.joe:
        joes = cuav_util.polygon_load(opts.joe)
        if boundary:
            for i in range(len(joes)):
                joe = joes[i]
                if cuav_util.polygon_outside(joe, boundary):
                    print ("Error: joe outside boundary", joe)
                    return
                icon = slipmap.icon("flag.png")
                slipmap.add_object(mp_slipmap.SlipIcon("joe%u" % i, (joe[0], joe[1]), icon, layer=4))

    joelog = cuav_joe.JoeLog("joe.log")

    if opts.view:
        viewer = mp_image.MPImage(title="Image")

    for f in files:
        frame_time = cuav_util.parse_frame_time(f)
        if mpos:
            try:
                if opts.roll_stabilised:
                    roll = 0
                else:
                    roll = None
                pos = mpos.position(frame_time, opts.max_deltat, roll=roll)
                slipmap.set_position("plane", (pos.lat, pos.lon), rotation=pos.yaw)
            except mav_position.MavInterpolatorException as e:
                print e
                pos = None
        else:
            pos = None

        # check for any events from the map
        if opts.mosaic:
            slipmap.check_events()
            mosaic.check_events()

        if f.endswith(".pgm"):
            pgm = cuav_util.PGM(f)
            im = pgm.array
            if pgm.eightbit:
                im_8bit = im
            else:
                im_8bit = numpy.zeros((960, 1280, 1), dtype="uint8")
                if opts.gamma != 0:
                    scanner.gamma_correct(im, im_8bit, opts.gamma)
                else:
                    scanner.reduce_depth(im, im_8bit)
            im_full = numpy.zeros((960, 1280, 3), dtype="uint8")
            scanner.debayer_full(im_8bit, im_full)
            im_640 = numpy.zeros((480, 640, 3), dtype="uint8")
            scanner.downsample(im_full, im_640)
        else:
            im_full = cv.LoadImage(f)
            im_640 = cv.CreateImage((640, 480), 8, 3)
            cv.Resize(im_full, im_640)
            im_640 = numpy.ascontiguousarray(cv.GetMat(im_640))
            im_full = numpy.ascontiguousarray(cv.GetMat(im_full))

        count = 0
        total_time = 0
        img_scan = im_640

        t0 = time.time()
        for i in range(opts.repeat):
            if opts.fullres:
                regions = scanner.scan_full(im_full)
            else:
                regions = scanner.scan(img_scan)
            count += 1
        regions = cuav_region.RegionsConvert(regions)
        t1 = time.time()

        if opts.filter:
            regions = cuav_region.filter_regions(im_full, regions, frame_time=frame_time, min_score=opts.minscore)

        scan_count += 1

        # optionally link all the images with joe into a separate directory
        # for faster re-running of the test with just joe images
        if pos and opts.linkjoe and len(regions) > 0:
            cuav_util.mkdir_p(opts.linkjoe)
            if not cuav_util.polygon_outside((pos.lat, pos.lon), boundary):
                joepath = os.path.join(opts.linkjoe, os.path.basename(f))
                if os.path.exists(joepath):
                    os.unlink(joepath)
                os.symlink(f, joepath)

        if pos and len(regions) > 0:
            joelog.add_regions(frame_time, regions, pos, f, width=1280, height=960, altitude=opts.altitude)

            if boundary:
                regions = cuav_region.filter_boundary(regions, boundary, pos)

        region_count += len(regions)

        if opts.mosaic and len(regions) > 0:
            composite = cuav_mosaic.CompositeThumbnail(
                cv.GetImage(cv.fromarray(im_full)), regions, quality=opts.quality
            )
            chameleon.save_file("composite.jpg", composite)
            thumbs = cuav_mosaic.ExtractThumbs(cv.LoadImage("composite.jpg"), len(regions))
            mosaic.add_regions(regions, thumbs, f, pos)

        if opts.compress:
            jpeg = scanner.jpeg_compress(im_full, opts.quality)
            jpeg_filename = f[:-4] + ".jpg"
            if os.path.exists(jpeg_filename):
                print ("jpeg %s already exists" % jpeg_filename)
                continue
            chameleon.save_file(jpeg_filename, jpeg)

        if opts.view:
            if opts.fullres:
                img_view = im_full
            else:
                img_view = img_scan
            mat = cv.fromarray(img_view)
            for r in regions:
                (x1, y1, x2, y2) = r.tuple()
                if opts.fullres:
                    x1 *= 2
                    y1 *= 2
                    x2 *= 2
                    y2 *= 2
                cv.Rectangle(mat, (max(x1 - 2, 0), max(y1 - 2, 0)), (x2 + 2, y2 + 2), (255, 0, 0), 2)
            cv.CvtColor(mat, mat, cv.CV_BGR2RGB)
            viewer.set_image(mat)

        total_time += t1 - t0
        print ("%s scan %.1f fps  %u regions [%u/%u]" % (f, count / total_time, region_count, scan_count, num_files))
Example #8
0
def transmit_thread():
    '''thread for image transmit to GCS'''
    state = mpstate.camera_state

    tx_count = 0
    skip_count = 0
    bsend = block_xmit.BlockSender(0, state.bandwidth)

    while not state.unload.wait(0.02):
        bsend.tick()
        if state.transmit_queue.empty():
            continue

        (frame_time, regions, im_full, im_640) = state.transmit_queue.get()
        pos = get_plane_position(frame_time)
        latlon_list = log_joe_position(pos, frame_time, regions)

        state.xmit_queue = bsend.sendq_size()
        state.efficiency = bsend.get_efficiency()
        state.bandwidth_used = bsend.get_bandwidth_used()
        state.rtt_estimate = bsend.get_rtt_estimate()

        jpeg = None

        if len(regions) > 0 and bsend.sendq_size() < 2000:
            # send a region message with thumbnails to the ground station
            thumb = cuav_mosaic.CompositeThumbnail(im_full,
                                                   regions,
                                                   quality=state.quality,
                                                   thumb_size=100)
            bsend.set_bandwidth(state.bandwidth)
            bsend.set_packet_loss(state.packet_loss)
            pkt = ThumbPacket(frame_time, regions, thumb, latlon_list,
                              state.frame_loss, state.xmit_queue)

            # send matches with a higher priority
            bsend.send(cPickle.dumps(pkt, cPickle.HIGHEST_PROTOCOL),
                       dest=(state.gcs_address, state.gcs_view_port),
                       priority=1)

        # Base how many images we send on the send queue size
        send_frequency = state.xmit_queue // 3
        if send_frequency == 0 or (tx_count +
                                   skip_count) % send_frequency == 0:
            jpeg = scanner.jpeg_compress(im_640, state.quality)

        if jpeg is None:
            skip_count += 1
            continue

        # keep filtered image size
        state.jpeg_size = 0.95 * state.jpeg_size + 0.05 * len(jpeg)

        tx_count += 1

        if state.gcs_address is None:
            continue
        bsend.set_packet_loss(state.packet_loss)
        bsend.set_bandwidth(state.bandwidth)
        pkt = ImagePacket(frame_time, jpeg)
        bsend.send(cPickle.dumps(pkt, cPickle.HIGHEST_PROTOCOL),
                   dest=(state.gcs_address, state.gcs_view_port))
Example #9
0
def process(filename):
  '''process one file'''
  pgm = cuav_util.PGM(filename)
  img_full_grey = pgm.array

  im_full = numpy.zeros((960,1280,3),dtype='uint8')
  im_640 = numpy.zeros((480,640,3),dtype='uint8')

  t0 = time.time()
  for i in range(opts.repeat):
    scanner.debayer(img_full_grey, im_640)
  t1 = time.time()
  print('debayer: %.1f fps' % (opts.repeat/(t1-t0)))

  t0 = time.time()
  for i in range(opts.repeat):
    scanner.debayer_full(img_full_grey, im_full)
  t1 = time.time()
  print('debayer_full: %.1f fps' % (opts.repeat/(t1-t0)))

  t0 = time.time()
  im_full2 = cv.CreateImage((1280,960),8,3)
  img_full_grey2 = cv.GetImage(cv.fromarray(img_full_grey)) 
  for i in range(opts.repeat):
      cv.CvtColor(img_full_grey2, im_full2, cv.CV_BayerBG2BGR)
  t1 = time.time()
  print('debayer_cv_full: %.1f fps' % (opts.repeat/(t1-t0)))

  t0 = time.time()
  for i in range(opts.repeat):
      img = cv.GetImage(cv.fromarray(im_full))
      cv.CvtColor(img, img, cv.CV_RGB2HSV)
  t1 = time.time()
  print('RGB2HSV_full: %.1f fps' % (opts.repeat/(t1-t0)))

  t0 = time.time()
  for i in range(opts.repeat):
      img = cv.GetImage(cv.fromarray(im_640))
      cv.CvtColor(img, img, cv.CV_RGB2HSV)
  t1 = time.time()
  print('RGB2HSV_640: %.1f fps' % (opts.repeat/(t1-t0)))

  t0 = time.time()
  for i in range(opts.repeat):
      thumb = numpy.empty((100,100,3),dtype='uint8')
      scanner.rect_extract(im_full, thumb, 120, 125)
  t1 = time.time()
  print('rect_extract: %.1f fps' % (opts.repeat/(t1-t0)))

  t0 = time.time()
  for i in range(opts.repeat):
      thumb = cuav_util.SubImage(cv.GetImage(cv.fromarray(im_full)), (120,125,100,100))
  t1 = time.time()
  print('SubImage: %.1f fps' % (opts.repeat/(t1-t0)))


  t0 = time.time()
  for i in range(opts.repeat):
    scanner.downsample(im_full, im_640)
  t1 = time.time()
  print('downsample: %.1f fps' % (opts.repeat/(t1-t0)))

  t0 = time.time()
  for i in range(opts.repeat):
    scanner.scan(im_640)
  t1 = time.time()
  print('scan: %.1f fps' % (opts.repeat/(t1-t0)))

  for quality in [30, 40, 50, 60, 70, 80, 90, 95]:
    t0 = time.time()
    for i in range(opts.repeat):
      jpeg = cPickle.dumps(ImagePacket(time.time(), scanner.jpeg_compress(im_full, quality)),
                           protocol=cPickle.HIGHEST_PROTOCOL)
    t1 = time.time()
    print('jpeg full quality %u: %.1f fps  %u bytes' % (quality, opts.repeat/(t1-t0), len(bytes(jpeg))))

  for quality in [30, 40, 50, 60, 70, 80, 90, 95]:
    t0 = time.time()
    for i in range(opts.repeat):
      jpeg = cPickle.dumps(ImagePacket(time.time(), scanner.jpeg_compress(im_640, quality)),
                           protocol=cPickle.HIGHEST_PROTOCOL)
    t1 = time.time()
    print('jpeg 640 quality %u: %.1f fps  %u bytes' % (quality, opts.repeat/(t1-t0), len(bytes(jpeg))))

  for thumb_size in [10, 20, 40, 60, 80, 100]:
    thumb = numpy.zeros((thumb_size,thumb_size,3),dtype='uint8')
    t0 = time.time()
    for i in range(opts.repeat):
      scanner.rect_extract(im_full, thumb, 0, 0)
      jpeg = cPickle.dumps(ImagePacket(time.time(), scanner.jpeg_compress(thumb, 85)),
                           protocol=cPickle.HIGHEST_PROTOCOL)
    t1 = time.time()
    print('thumb %u quality 85: %.1f fps  %u bytes' % (thumb_size, opts.repeat/(t1-t0), len(bytes(jpeg))))