[PYTHON] Implementation of personally optimized photo frames on Raspberry Pi

Motivation

Let's implement a photo frame with Raspberry Pi. The photo frame on the Raspberry Pi is a worn-out theme, but I was dissatisfied with the conventional one.

After all, careful selection of photos can be a hassle. For example, when displaying a photo sent by a friend or a photo from a camera in a photo frame.

・ If you carefully select and put in, it will be difficult, or the number will be small and you will soon get tired of seeing ・ On the contrary, if you push everything in, mistaken photos will be taken in, and an embarrassing photo will be displayed.

There is a dilemma. To solve this problem, we will create a photo frame that optimizes the display of photos.

When the user likes ・ Skip the photo ・ Reduce the display frequency of the photo ・ Never display the photo again

You can perform the operation. The display frequency adjusted in this way is saved and updated. In other words, the concept is to put all the photos in and adjust them as you use them.

The entire source code is posted at the bottom of the page. qiita.jpg

Preparation

・ Raspberry Pi This time I used the Raspberry Pi 3 model B that I had at home. Any generation is acceptable.

・ 3.5 inch display Used for displaying photos. If I bought about 2000 yen on Amazon, the driver is old and can't be used ... When a driver made by another company is installed, only the screen is displayed, but the touch panel is dead.

specification

If you just want to display photos

fbi image.jpg

It's enough. However, considering the realization of detailed specifications and extensibility such as cooperation with the outside, I will write everything in python this time. OpenCV etc. are major when dealing with images, but this time we will use pygame which is a module for games.

As for this specification (1) Automatically acquire images from DropBox (not implemented) ② Display images in slide show format ③ Use buttons to skip images, reduce the display frequency, never display them, etc. ④ Save and update the adjusted frequency will do. I mainly select pygame for ③.

Automatic image acquisition

making

Image display

In order to display the image, you need to start by creating a window.


import pygame 
from pygame.locals import *
import sys

pygame.init()
screen =pygame.display.set_mode((400,300))  
pygame.mouse.set_visible(False)
pygame.display.set_caption("Photo")

Initialize with pygame.init () and Specify the screen size with display.set_mode (). (It will be full screen by inserting FULL SCREEN as an argument, but it seems better not to do it during debugging because it will be difficult to finish if there is a bug in full screen.)

It's awkward to have the mouse cursor as a photo frame, so delete it with pygame.mouse.set_visible (False).


img =pygame.image.load("file.jpg ")
img = pygame.transform.scale(img1,(400,300))
rectimg = img.get_rect()
screen.fill((0,0,0))
screen.blit(img,rect_img)
pygame.display.update()

This is the depiction part of the image. You can load one image with ʻimage.load. Specify the RGB background color with screen.fill. This time it is black. Paste the image with screen.blit and update and display the screen with the last display.update () `. The image can be displayed by the above operation. Now let's implement a slide show.

Slideshow implementation

What is a slide show? ・ Measure time ・ Load and display new images after a lapse of time

That is the process. Therefore, save the time when the image is displayed.


start_time = pygame.time.get_ticks()

And while turning the while (1) loop,

time_since_start = pygame.time.get_ticks() - start_time
if time_since_start>10000:
     break 

It can be realized by. You can get the time with pygame.time.get_ticks () and the unit is ms, so in this example it will switch every 10 seconds. (Actually, the photo loading time is added.)

Image skip function

Allows you to switch without waiting 10 seconds. Specifically, it is a function to display the next image when the button is pressed. Since there was no easy physical button this time, I will connect a keyboard and use it.

Also, the function to end it cannot be done as it is. Therefore, when ESC is pressed, the program will be terminated.

for event in pygame.event.get():
     if event.type == KEYDOWN:
          if event.key == K_ESCAPE:
               pygame.quit()  
               sys.exit()
          if event.key == K_z:
               flugloop = False

First, the event that occurred is fetched in a loop, and if it is a key press, the process is executed. K_ESCAPE is the ESC key and K_z is the z key. In this way, you can implement the behavior when any key is pressed with K_a etc.

If it is the ESC key, it will be terminated immediately in the if statement, if the z key is pressed, the skip flag will be set and the next image will be moved to.

Change the display frequency of images

Now that you have a slideshow, you can add processing for photos that you want to display less frequently or that you don't want to see again. In [Display image](#Display image), the path was specified and read. The read part is weighted and randomly changed.

photonum = list(range(1,len(w)+1))
filenum = random.choices(photonum,weight)
filename = str(filenum[0]) + ".jpg "
pygame.image.load(filename)

Name the image in advance with 1.jpg, 2.jpg, etc. Here, the second line random.choices is the function to select by weighting random. photonum is a list containing 1 to the number of sheets Weight contains the weight of each image as an integer value. By passing these two to random.choices, it will select from photonum according to its weight. Then the selected image file is loaded.

All you have to do is operate this weight.

This time, save weight in a text file separated by line breaks. In addition, the initial value of the weight is an integer value of 10.

data = open('data.txt')
weight =[]
for line in data:
   weight.append(int(line))
data.close()

This will read the weights line by line from data.txt and store them in weight.

Now, using the KEYDOWN that came out earlier,

if event.key == K_x:
     flugloop =False
     weight[filenum-1] = 0

If so, the weight will be 0 when x is pressed, and the photo will never be displayed again. Decrementing in the same way will reduce the frequency with which the photo is displayed.

Well, this list will of course be lost when finished. So let's save it by writing to data.txt. Add to the behavior of the ESC key.

if event.key == K_ESCAPE
     f = open("data.txt",'w')
     for i in weight:
          f.write(str(i))
          f.write("\n")         
     f.close()
     pygame.quit()  
     sys.exit()

By doing this, the settings will be inherited the next time you start up.

Whole source code

Sample code

#photo.py

import pygame
from pygame.locals import *
import sys
import random

def get_image(w=[]):
    photonum = list(range(1,len(w)+1)) 
    filenum = random.choices(photonum,w)  #Randomly extract images
    filename = str(filenum[0]) + ".jpg "
    return pygame.image.load(filename).convert_alpha(),filenum[0]  #The return value is the image and its ID


def main():

    
    data = open('data.txt')  #Load weighting
    weight =[]
    for line in data:
        weight.append(int(line))
   
    data.close()

    while(1):#Display one image
        pygame.init()
        screen =pygame.display.set_mode((400,300),FULLSCREEN)  
        pygame.mouse.set_visible(0)
        pygame.display.set_caption("test")
        x=get_image(weight)
        img1 = x[0]
        filenum = x[1]
        img2 = pygame.transform.scale(img1,(400,300))
        rect_img2 = img2.get_rect()
        screen.fill((0,0,0))
        screen.blit(img2,rect_img2)  #Image display
        pygame.display.update()   #Screen update
        start_time = pygame.time.get_ticks()  #Start time measurement
        flugloop = True

        
        while(1):  #Loop to accept operations
            time_since_start = pygame.time.get_ticks() - start_time  #Time measurement
            if time_since_start>10000:  #Break after 10 seconds,To the next image display
                break
            if flugloop ==False:  #Break if flagged,To the next image display
                break

            for event in pygame.event.get():  #Reception of operation
                if event.type == QUIT:
                    pygame.quit()
                    sys.exit()
            
                if event.type == KEYDOWN:
                    if event.key == K_ESCAPE:  #When esc is pressed
                        f = open("data.txt",'w')  #Save display frequency
                        for i in weight:
                            f.write(str(i))
                            f.write("\n")
                                    
                        f.close()
                        pygame.quit()  #The end of the program
                        sys.exit()
                    if event.key == K_SPACE: #When the space key is pressed, reduce the weight and move to the next image
                        flugloop = False
                        if weight[filenum-1] >3:
                            weight[filenum-1] -=1
                    
                    if event.key == K_x:   #When the x key is pressed, the weight is set to 0 and never displayed again.
                        flugloop =False
                        weight[filenum-1] = 0
                    
                    if event.key == K_z:
                        flugloop =False
                        
main() 
   

Future expandability

Implementation of automatic photo addition from DropBox. Installation of physical buttons. If you use a webcam to increase the weight of the photos you pay close attention to and display them well, it will be easier to adjust the weight of the display frequency.

Recommended Posts