📜 ⬆️ ⬇️

Linux in your pocket - in the service of the photographer

It so happened that photography is my main professional activity, and programming is a hobby that sometimes allows us to stretch the brain. In addition to directly warming up for the brain, programming helps in work. For example, wrote useful things, such as this or this , or this .

Recently I set myself a task, how to please my clients. He recalled the numerous requests from customers for the wedding shooting: “How good it would be if at a banquet you could show a short slideshow of photos that were shot in a day.” These requests had to be refused, for several reasons: too lazy to carry a laptop to assemble a slideshow with them, there is no time to select a couple of dozens of shots from hundreds, again you need to convert from raw, and most importantly - all this takes time, which is not.

This is a story about how I managed to make a tool for myself that, with my minimum participation and minimal additional weight in my backpack, helps to make beautiful slideshows. And of course the story about python, ffmpeg and linux on android.

Unexpected iron selection


The first problem is overweight. I needed a full linux on a fairly decent hardware. Initially, my choice fell on the Orange PI PC, which I heard about on gigtimes . The piece of iron was ordered and delivered. It seemed to me that this is what you need - 4 cores of 1.5 GHz each, 1 GB of RAM and full USB. But in fact, once again convinced that without normal support, all the “raspberry clones” are worth nothing. Very buggy OS images, constantly falling off kernels under load, a problem with the work of libraries, for example, to connect an lcd display.
And the main problem is the unexpected killed, with a free 800 MB of RAM, in the area of ​​the type code:
from PIL import Image img=Image.new('RGB',(6000,4000)) #      ,    img.rotate() 

And the same thing worked perfectly on a netbook with 1GB of RAM without a swap, as well as on the first Raspberry PI. And even more so, there could be no talk to do the same, but on 4 cores at the same time.
')
The solution came unexpectedly when I picked up a smartphone to read the message that came:
And in the pocket there is always a piece of iron with a 2.2 GHz 4-core processor, 2GB of RAM + USB-otg is available (Nexus 5). It remains to find a way to fully launch the Linux environment. After discarding various options with a flashing (I wanted to use it fully and as a smartphone), the solution was found - Linux Deploy . In short, Linux Deploy launches a full-fledged linux environment in chroot (more information about the program can be found on the blog of our compatriot developer), and the most important thing for me is to mount an arbitrary directory from fs android to my environment. Without this, it would not be possible to work with an SD card reader inserted into the OTG connector.

Photo selection


A slideshow of hundreds of photos would take a couple of hours to complete. We needed a way to quickly and easily select 20-40 photos. Scrolling through even 100 photos from a smartphone is still a pleasure, and the number can reach up to a thousand in the evening (duplicates from serial shooting, marriage, sighting photos, a report, etc.)
Looking at the camera, I remembered the button I never used - the “rate” button was the savior, which assigns a photo rating:



The scroll wheel on the right quickly scrolls images, and the rate button is pressed on the desired one. Since you already know that you successfully shot today, it takes no more than a couple of minutes. It remains to force the program to find and select those images that have been assigned at least some rating.

Since the rating gets into exif, you need a wonderful exiftool package (sudo apt-get install libimage-exiftool-perl) and a wrapper for it for python. And then everything is simple:

 import os import exiftool all_files=[] """     SD  """ for directory, dirnames, filenames in os.walk(PATH_TO_SD_ROOT): for name in filenames: f=os.path.join(directory, name) if f.lower().endswith('.cr2') or f.lower().endswith('.jpg'): #    jpg  raw  all_files.append(f) tool=exiftool.ExifTool() tool.start() # exiftool #         result=tool.get_tags_batch(['XMP:Rating'],all_files) rated_files=[] for x in result: if x['XMP:Rating']>0: rated_files.append(x['SourceFile']) #        rated_files.sort() 


The next stage is quite trivial - copying the necessary photos into a temporary directory and re-recording in several streams for further work. The only thing I would like to focus on is raw, which I shoot. Conversion is handled by the dcraw utility (although this is not a full conversion, but only pulling out jpg embedded into a raw file, but in this case, it is more than enough.

 import subprocess for n,x in enumerate(self.rated_files): dcraw_opts = ["dcraw", "-e", "-c", x] # -e -   jpg, -     stdout dcraw_proc = subprocess.Popen(dcraw_opts, stdout=subprocess.PIPE) image = StringIO.StringIO(dcraw_proc.communicate()[0]) #    stdout image.seek(0) open('input/%02d.jpg'%(n),'wb').write(image.read()) #     . 


Make me beautiful!



At the previous stage, one could stop by taking photos and launching them as a slideshow on a DJ's laptop connected to the projector, but I want it all to look beautiful.
Such a wonderful thing as ffmpeg (avconv) comes to the rescue. I am not a fan of any bright special effects, I have a rather light dynamic, in the form of a zoom photo and a crossfade transition between slides. I will say right away, despite the enormous possibilities of ffmpeg, I did not succeed. For example, a zoompan filter, gave a terrible quality and a shaky picture. After a week spent reading manuals and forums, it was decided to do it "in the forehead":

 def processImage(numb): img=Image.open('input_temp/%02d.jpg'%numb) #    #   crossfade   ,    ,   try:next_img=Image.open('input_temp/%02d.jpg'%(numb+1)).resize((1280,720),Image.ANTIALIAS) except:next_img=Image.new('RGB',(1280,720),'black') #       ,  ffmpeg   stdin  #        p = subprocess.Popen(['avconv', '-y', '-f', 'image2pipe', '-vcodec', 'mjpeg', '-r', '25', '-i', '-', '-vcodec', 'mjpeg','-q:v', '3' , '-r', '25', 'output/%02d.mjpg'%(numb)], stdin=subprocess.PIPE) # 100   25 /c - 4     for x in xrange(100): #            16:9 n=img.crop((int(float(x)*16.0/9.0),x,int(1920.0-float(x)*16.0/9.0),1080-x)) #       n=n.resize((1280,720),Image.ANTIALIAS) #   ,  ""   if x>75: n=Image.blend(n,next_img,float(x-75)/25) #   ffmpeg' n.save(p.stdin,'JPEG') p.stdin.close() p.wait() 


Oh yeah, I said something about the processor cores. I would like to parallel this process so that all cores are busy. In python, this is done very very simply:
 from multiprocessing import Pool s=len(glob.glob('input_temp/*.jpg')) #   pool = Pool() pool.map(processImage, xrange(s)) #    ,        pool.close() pool.join() 


As a result, we have a lot of mjpeg video segments that need to be put together by inserting music.
Googling, did not find a better way how to first directly connect the video using cat:
 cat 00.mjpg 01.mjpg ..... > out.mjpg 

It remains only to convert it to the desired format by adding music:
 avconv -threads 4 -framerate 25 -i out.mjpg -i audio.mp3 -shortest -y -r 25 -preset veryfast out.mp4 


In order not to mess around each time in the console, but it was necessary to choose a music track, enter a name for the slideshow (for the first frame), etc., raised a simple web server that starts when Linux Deploy starts. I used a simple framework bottle. It looks like this:



Total


2-3 minutes selection of photos, launch Linux Deploy, localhost in the browser, a couple of seconds to enter the title and click on START. Next, 10-15 minutes of the smartphone, and the video is ready:



In the same way, you can make not only a slideshow from photos, but also glue together the video: mark the necessary passages in the camera with the rate button and then glue them together with ffmpeg.

And a small announcement

If this topic turns out to be interesting, I will make some more publications. For example, next in line is an article on how to make such a nice and functional photo booth:

Source: https://habr.com/ru/post/275595/


All Articles