Пример #1
0
class ImageLoader:
    def __init__(self):
        datapin = 10
        clockpin = 11

        if is_running_on_pi:
            self.strip = Adafruit_DotStar(0, datapin, clockpin, 18500000)
        else:
            self.strip = None

    def load_to_circular_buffer(self, path):
        if not is_running_on_pi:
            return

        img = Image.open(path).convert("RGB")
        pixels = img.load()
        width = img.size[0]
        height = img.size[1]

        circular_image = CircularImage(height, width)

        bytess = img.tobytes()

        for x in range(width):
            offset = x * 3
            multiplier = width * 3
            self.strip.prepareBuffer(circular_image.get_sample(x), bytess,
                                     offset, multiplier, False)

        for x in range(width):
            offset = x * 3
            multiplier = width * 3
            self.strip.prepareBuffer(circular_image.get_sample(x + width),
                                     bytess, offset, multiplier, True)

        circular_image.reverse()

        img.close()

        return circular_image

    @staticmethod
    def black():
        black = bytearray(144 * 4)
        for x in range(len(black)):
            if x % 4 == 0:
                black[x] = 0xFF
            else:
                black[x] = 0

        return black
Пример #2
0
class PovFan:
    def __init__(self):
        datapin = 10
        clockpin = 11

        self.column = None
        self.width = 0
        self.sequence = []
        self.cur_column = 0

        self.images_folder = ""

        self.next_buffer_index = 0
        self.last_push = 0
        self.image_start_time = 0

        if is_running_on_pi:
            self.strip = Adafruit_DotStar(0, datapin, clockpin, 18500000)
        else:
            self.strip = None

    def add_image(self, image_path, reverse):
        if is_running_on_pi == False:
            # print "add_image"
            return
        img = Image.open(image_path).convert("RGB")
        pixels = img.load()
        width = img.size[0]
        height = img.size[1]

        if (height < STRIP_LENGTH):
            assert ("trying to load image too small")

        column = [0 for x in range(width)]
        for x in range(width):
            column[x] = bytearray(STRIP_LENGTH * 4)

        bytess = img.tobytes()

        for x in range(width):
            offset = x * 3
            multiplier = width * 3
            self.strip.prepareBuffer(column[x], bytess, offset, multiplier,
                                     reverse)

        self.sequence.append(column)
        self.width = width

        img.close()

    def disabled_animation():
        pass

    def clear_fan():
        pass

    def loading_animation():
        pass

    #TODO: set sequence length
    def load_sequence(self, sequence_path, fan_id, seq_size=-1):
        if is_running_on_pi == False:
            # print "load_sequence: ", sequence_path, fan_id
            return
        start = time.time()
        path = os.path.join(self.images_folder, 'incoming_images',
                            sequence_path, "fan_" + str(fan_id))
        files = sorted(glob.glob(os.path.join(path, "*.png")))

        for i in range(len(files)):
            print "loading image ", i
            self.add_image(files[i], i % 2)

        print "loading took ", time.time() - start

    def transition_image(self, next_image):
        for i in range(len(self.column)):
            self.strip.pushBuffer(self.column[i], next_image[i],
                                  self.next_buffer_index)
        self.next_buffer_index = self.next_buffer_index + 1
        if self.next_buffer_index / 2 > len(next_image[i]):
            self.next_buffer_index = 0
            print "restart buffer loop"

    def next_image(self, magnet_synced=False):
        # check if image have been looping for enough time
        if time.time() - self.image_start_time > 15:
            self.next_buffer_index = 0
            self.image_start_time = time.time()
            self.cur_column = (self.cur_column + 1) % len(self.sequence)
            print "next image is ", self.cur_column

        self.transition_image(self.sequence[self.cur_column])

    def no_magnet_callback(self, timing):
        timing["lapse_time"] = timing["no_magnet_lapse_time"]
        timing["last_update"] = time.time()
        timing["lapses"] = timing["lapses"] + 1
        timing["need_swap"] = 0
        if timing["lapses"] % 10 == 0:
            print "MAGNET SENSOR INACTIVE! FALLBACK ESTIMATING SPEED"
            print "lapse ", timing["lapses"], " refresh count: ", timing[
                "refresh_count"]
            print "lapse time", timing["lapse_time"]
            timing["refresh_count"] = 0

    def play(self, length):
        if len(self.sequence) == 0:
            print "No sequence loaded! Cancel play"
            return

        if is_running_on_pi == False:
            return

        self.strip.begin()

        end_time = length + time.time()
        PIXELS_IN_CIRCLE = 2 * self.width
        self.column = []
        for i in range(len(self.sequence[self.cur_column])):
            r = bytearray(STRIP_LENGTH * 4)
            r[:] = self.sequence[0][i]
            self.column.append(r)

        self.cur_column = 0

        self.image_start_time = time.time()

        timing = {
            "lapse_time": 0.18,  # time to complete lapse
            "last_update": time.time(),  # last frame time
            "lapses": 0,  # number of whole rotations (or every magnet on)
            "refresh_count": 0,  # number of columns showed
            "need_swap": 0,  # track for estimating mid-lapse image swap
            "max_lapse_time": 0.33,  # max time allowed before force swap
            "use_magnet": True,
            "no_magnet_lapse_time": 0.2
        }

        print "playing sequence for ", length, "seconds"
        if is_running_on_pi:

            def sync_magnet(counter):
                a = timing

                def magnet_cbk(m):
                    if not timing["use_magnet"]:
                        return

                    timing["lapse_time"] = m.estimated_rpm()
                    timing["last_update"] = time.time()
                    timing["lapses"] = timing["lapses"] + 1
                    timing["need_swap"] = 0
                    if timing["lapses"] % 10 == 0:
                        # print "lapse ", timing["lapses"], " refresh count: ", timing["refresh_count"]
                        # print "lapse time", timing["lapse_time"]
                        timing["refresh_count"] = 0

                return magnet_cbk

            magnet = MagnetButton(16)
            magnet.when_magnet = sync_magnet(timing)
            magnet.set_timeout(timing["max_lapse_time"])

            while end_time > timing["last_update"]:
                timing["use_magnet"] = not (magnet.is_not_responding())

                if not timing["use_magnet"]:
                    if time.time(
                    ) > timing["last_update"] + timing["no_magnet_lapse_time"]:
                        self.no_magnet_callback(timing)

                if timing["need_swap"] == 0:
                    self.next_image()
                    timing["need_swap"] = 1

                c = int(PIXELS_IN_CIRCLE *
                        (time.time() - timing["last_update"]) /
                        timing["lapse_time"])

                # TODO: make this cleaner...
                if c >= (self.width):
                    if timing["need_swap"] == 1:
                        self.next_image()
                        timing["need_swap"] = 2

                    ## if overflowing since lapse is longer now
                    c = c % self.width

                self.strip.show(self.column[c])
                timing["refresh_count"] = timing["refresh_count"] + 1
                time.sleep(0.0001)

            magnet.close()

        else:
            while end_time > timing["last_update"]:
                timing["last_update"] = time.time()

        self.strip.clear()
        self.strip.close()

    def stop(self):
        self.strip.clear()
        self.strip.close()
Пример #3
0
class PovFan:
    def __init__(self):
        datapin    = 10
        clockpin   = 11

        self.column = None
        self.width = 0
        self.sequence = []
        self.cur_column = 0

        self.images_folder = ""

        if is_running_on_pi:
            self.strip = Adafruit_DotStar(0, datapin, clockpin, 18500000)            
        else:
            self.strip = None

    def add_image(self, image1_path, image2_path):
        if not is_running_on_pi:
            # print "add_image"
            return

        img1       = Image.open(image1_path).convert("RGB")
        pixels1    = img1.load()
        width     = img1.size[0]
        height    = img1.size[1]

        img2       = Image.open(image2_path).convert("RGB")
        pixels2    = img2.load()

        if (height < STRIP_LENGTH):
            assert("trying to load image too small")


        column = [0 for x in range(width*2)]
        for x in range(width*2):
            column[x] = bytearray(STRIP_LENGTH * 4)

        bytess = img1.tobytes()

        for x in range(width):                        
            offset = x * 3
            multiplier = width * 3
            self.strip.prepareBuffer(column[x], bytess, offset, multiplier, False)
        
        bytess = img2.tobytes()

        for x in range(width):                        
            offset = x * 3
            multiplier = width * 3
            self.strip.prepareBuffer(column[x+width], bytess, offset, multiplier, True)
            
        column.reverse()
        self.sequence.append(column)
        self.width = width*2

        img1.close()
        img2.close()

    def disabled_animation(): pass
    
    def clear_fan(): pass

    def loading_animation(): pass

    #TODO: set sequence length
    def load_sequence(self, sequence_path, fan_id, seq_size = -1):
        if is_running_on_pi == False:
            # print "load_sequence: ", sequence_path, fan_id
            return
        start = time.time()
        path = os.path.join(self.images_folder, 'incoming_images', sequence_path, "fan_"+str(fan_id))
        files = sorted( glob.glob( os.path.join(path, "*.png") ))
        
        for i in range(len(files)):
            print "load images ", i, i+1
            if i%2 == 0 and i+1 < len(files):
                self.add_image(files[i], files[i+1])

        print "loading took ", time.time() - start

    def next_image(self, magnet_synced=False):
        self.cur_column = (self.cur_column + 1) % len(self.sequence)
        
        # Make sure that is on even numbered image when hitting magnet
        if magnet_synced and self.cur_column % 2 == 1:
            self.cur_column = (self.cur_column + 1) % len(self.sequence)
            
        self.column = self.sequence[self.cur_column]
        # print "showing frame #",self.cur_column

    def no_magnet_callback(self, timing):
        timing["lapse_time"] = timing["no_magnet_lapse_time"]
        timing["last_update"] = time.time()
        timing["lapses"] = timing["lapses"] + 1
        timing["need_swap"] = 0
        if timing["lapses"] % 10 == 0:
            print "MAGNET SENSOR INACTIVE! FALLBACK ESTIMATING SPEED"
            print "lapse ", timing["lapses"], " refresh count: ", timing["refresh_count"]
            print "lapse time", timing["lapse_time"]
            timing["refresh_count"] = 0

    def play(self, length):        
        if len(self.sequence) == 0:
            print "No sequence loaded! Cancel play"
            return
        
        if is_running_on_pi == False:            
            return

        self.strip.begin()

        end_time = length + time.time()
        PIXELS_IN_CIRCLE = self.width
        angle_offset_pixels = (int) (PHYSICAL_ANGLE_OFFSET * 360.0 / PIXELS_IN_CIRCLE)
        print "offsting image by " + str(angle_offset_pixels) 

        self.column = self.sequence[self.cur_column]        

        timing = {
            "lapse_time": 0.18,             # time to complete lapse
            "last_update": time.time(),     # last frame time
            "lapses": 0,                    # number of whole rotations (or every magnet on)
            "refresh_count": 0,             # number of columns showed
            "need_swap": 0,                 # track for estimating mid-lapse image swap
            "max_lapse_time": 0.33,          # max time allowed before force swap
            "use_magnet": True,
            "no_magnet_lapse_time": 0.2
            }

        print "playing sequence for ", length, "seconds"
        if is_running_on_pi:
            def sync_magnet(counter):
                a = timing

                def magnet_cbk(m):                                                    
                    if not timing["use_magnet"]: 
                        return
                    
                    timing["lapse_time"] = m.estimated_rpm()
                    timing["last_update"] = time.time()
                    timing["lapses"] = timing["lapses"] + 1
                    timing["need_swap"] = 0
                    if timing["lapses"] % 10 == 0:
                        print "lapse ", timing["lapses"], " refresh count: ", timing["refresh_count"]
                        print "lapse time", timing["lapse_time"]
                        timing["refresh_count"] = 0
                return magnet_cbk

            magnet = MagnetButton(16)
            magnet.when_magnet = sync_magnet(timing)
            magnet.set_timeout(timing["max_lapse_time"])

            while end_time > timing["last_update"]:
                timing["use_magnet"] = not (magnet.is_not_responding())

                if not timing["use_magnet"]:
                    if time.time() > timing["last_update"] + timing["no_magnet_lapse_time"]:
                        self.no_magnet_callback(timing)
            
                if timing["need_swap"] == 0:
                    self.next_image()
                    timing["need_swap"] = 1

                ## Angle_offset_pixels is a temp solutions .... need to fix in actual image
                c = angle_offset_pixels + int(PIXELS_IN_CIRCLE * (time.time() - timing["last_update"]) / timing["lapse_time"])

                # TODO: make this cleaner...
                if c >= (self.width):
                    # if timing["need_swap"] == 1:
                    #     self.next_image()
                    #     timing["need_swap"] = 2

                    ## if overflowing since lapse is longer now
                    c = c % self.width                    

                self.strip.show(self.column[c])
                timing["refresh_count"] = timing["refresh_count"] + 1      
                time.sleep(0.0001) 
                

            magnet.close()

        else:
            while end_time > timing["last_update"]:
                timing["last_update"] = time.time()
        
        
        
        self.strip.show(bytearray(STRIP_LENGTH * 4))
        
        self.strip.close()

    def stop(self):
        self.strip.clear()
        self.strip.close()