Linux в кармане — на службе у фотографа

    Так получилось, что фотография, это мой основной профессиональный вид деятельности, а программирование — хобби, которое иногда позволяет размять мозг. Кроме непосредственно разминки для мозга, программирование помогает и в работе. Например, писал полезные штуки, такие как это или это, или это.

    Недавно поставил себе задачу, как бы еще порадовать своих клиентов. Вспомнил многочисленные просьбы клиентов на свадебную съемку: «Как хорошо было бы, если бы на банкете вы смогли показать коротенькое слайдшоу из фотографий, которые отсняли за день». На эти просьбы приходилось отказывать, по нескольким причинам: лень таскать с собой ноутбук для сборки слайдшоу, нет времени на отбор пары десятков снимков из сотен, из raw опять же нужно конвертировать, и самое главное — на это все нужно время, которого нет.

    Это рассказ, о том, как мне удалось сделать для себя инструмент, который с минимальным моим участием и минимальным дополнительным весом в рюкзаке, помогает сделать красивые слайдшоу. И конечно же рассказ о python, ffmpeg и linux на android.

    Неожиданный выбор железа


    Первая проблема — это лишний вес. Мне нужен был полноценный linux на достаточно приличном железе. Изначально мой выбор пал на Orange PI PC, о котором я услышал на гигтаймсе. Железка была заказана и доставлена. Мне казалось, это то что нужно — 4 ядра по 1.5 ггц, 1 гб оперативной памяти и полноценные USB. Но на деле, лишний раз убедился, что без нормальной поддержки, все «клоны raspberry», ничего не стоят. Очень глючные образы OS, постоянно отваливающиеся ядра под нагрузкой, проблема с работой библиотек, чтоб, например подключить lcd дисплей.
    И самое главная проблема, это неожиданный killed, при свободных 800 мб оперативки, на участке кода типа:
    from PIL import Image
    img=Image.new('RGB',(6000,4000)) #на деле мне нужно было не создавать, а открывать фотографии
    img.rotate()
    

    Причем тоже самое прекрасно работало на нетбуке с 1гб оперативке без свопа, а так же на Raspberry PI первом. И уж тем более, и речи не могло быть, чтоб делать тоже самое, но на 4-х ядрах одновременно.

    Решение пришло неожиданно, когда я взял в руки смартфон, чтоб прочитать пришедшее сообщение:
    А в кармане то постоянно лежит железка с 2.2 ггц 4-х ядерным процессором, 2гб оперативном памяти + USB-otg имеется (Nexus 5). Осталось найти способ полноценного запуска Linux окружения. После отбрасывания различных вариантов с перепрошивкой (хотелось пользоваться им полноценно и как смартфоном), выход был найден — Linux Deploy. Если кратко, Linux Deploy запускает полноценное linux окружение в chroot'e (подробнее о программе можно почитать в блоге у нашего соотечественника — разработчика), и самое главное для меня — монтировать произвольный каталог из fs android в свое окружение. Без этого, не была бы возможна работа с картридером SD карт памяти, воткнутым в OTG разъем.

    Отбор фотографий


    Слайдшоу из сотен фотографий, заняло бы пару часов времени. Нужен был способ легко и быстро отобрать 20-40 фотографий. Пролистывать даже 100 фотографий со смартфона — то еще удовольствие, а количество может доходить к вечеру до тысячи (дубли с серийной съемки, брак, пристрелочные фото, репортаж и пр.)
    Взглянув на фотоаппарат, вспомнил про кнопку, которой никогда не пользовался — спасительницей оказалась кнопка «rate», которая присваивает рейтинг фотографии:



    Колесом прокрутки справа достаточно быстро пролистываются снимки, и на нужном нажимается кнопка «rate». Так как ты уже знаешь, что удачного за сегодня отснял, на все уходит не больше пары минут. Остается заставить программу найти и выбрать те снимки, которым присвоен хоть какой нибудь рейтинг.

    Так как рейтинг попадает в exif, понадобится замечательный пакет exiftool (sudo apt-get install libimage-exiftool-perl) и wrapper к нему для python. А дальше все просто:

    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()
    


    Следующий этап достаточно тривиален — копирование нужных фотографий во временный каталог и резайс в несколько потоков для дальнейшей работы. Единственное, на чем бы хотел заострить внимание, это raw, в который я снимаю. Конвертацией занимается утилита dcraw (хотя это не полноценная конвертация, а лишь выдергивание вшитой jpg в raw файл, но в данном случае, это более чем достаточно.

    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()) # и записываем в нужное место.
    


    Сделай мне красиво!



    На предыдущем этапе можно было бы остановиться, взяв фотографии и пустив их как слайдшоу на ноутбуке диджея, подключенного к проектору, но хочется, чтоб все это выглядело красиво.
    На помощь приходит такая замечательная вещь, как ffmpeg (avconv). Я не любитель каких либо ярких спецэффектов, мне достаточно легкой динамики, в виде zoom'a фотографии и «crossfade» перехода между слайдами. Скажу сразу, несмотря на огромные возможности ffmpeg, это сделать у меня не получилось. Например, фильтр zoompan, выдавал ужасное качество и дрожащую картинку. После недели, проведенные за чтением мануалов и форумов, решено было сделать это «в лоб»:

    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()
    


    Ах да, я что то там говорил про ядра процессора. Хотелось бы распаралеллить этот процесс, чтоб были заняты все ядра. В python это делается очень очень просто:
    from multiprocessing import Pool
    s=len(glob.glob('input_temp/*.jpg')) #берем количество фотографий 
    pool = Pool()
    pool.map(processImage, xrange(s)) # и отдаем их воркерам, количество которых будет равно количеству ядер процессора
    pool.close()
    pool.join()
    


    В итоге мы имеем множество отрезков mjpeg видео, которые нужно соединить воедино, вставив музыку.
    Погуглив, не нашел лучшего способа, как сначала напрямую соединить видео, используя cat:
    cat 00.mjpg 01.mjpg ..... > out.mjpg
    

    Осталось только переконвертировать его в нужный формат, добавив музыку:
    avconv -threads 4 -framerate 25 -i out.mjpg  -i  audio.mp3  -shortest -y  -r 25  -preset veryfast out.mp4
    


    Чтобы не возиться каждый раз в консоли, а нужно было выбирать музыкальный трек, вписывать название для слайдшоу (для первого кадра) и пр, поднял простой web сервер, который стартует при запуске Linux Deploy. Я использовал простенький фреймворк bottle. Выглядит это вот так:



    Итого


    2-3 минуты отбор фотографий, запуск Linux Deploy, localhost в браузере, пару секунд на то, чтоб вписать title и нажать на СТАРТ. Далее 10-15 минут работы смартфона, и видео готово:



    Таким же способом можно делать не только слайдшоу из фотографий, но и склеивать видео: пометить нужные отрывки в камере кнопкой rate и склеить их потом ffmpeg'ом.

    И небольшой анонс

    Если эта тема окажется интересной, я сделаю еще несколько публикаций. Например, на очереди статья, как сделать вот такую милую и функциональную фотобудку:
    Поделиться публикацией
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама
    Комментарии 75
    • +6
      Здорово! Действительно очень элегантное решение!

      А не планируете опубликовать исходники? Понятно, что в статье ключевые моменты освещены, но хотелось бы, так сказать, «комплект»… Чтобы сразу начать эксперименты.

      Еще небольшое замечание. Возможно это уже у меня проф.деформация, но мне лично очень мешает, что при переходе фотография в начале стоит на месте (во время микса), и только потом начинает двигаться. Это очень легко поправить, но я думаю будет заметно приятнее.

      На счет новых статей — было бы здорово! Про фото-будку — очень интересно. Подписался.
      • 0
        мне лично очень мешает, что при переходе фотография в начале стоит на месте (во время микса), и только потом начинает двигаться

        Тоже об это глаз каждый раз спотыкался, неплохо бы начинать движение сразу.
        • +1
          Подтверждаю, дискомфортно.

          Хорошо будет сделать так, как вы сказали, плюс замедлить скорость зума. Такой быстрый ни к чему, достаточно чтобы в кадре ощущалось лёгкое движение. Можно ещё прикрутить рандомно, чтобы не в центр каждый раз зумилось, а в произвольную рандомную точку, или пойти дальше и алгоритмом распознавания лиц находить центр зуммирования.

          Ах, да, можно ещё виньетирование, помимо зума сделать рандомный/осмысленный сдвиг кадра и всё такое прочее, чтобы «дороже смотрелось». Но это уже advanced-уровень. :)
          • +1
            Вместо распознавания лиц, можно делать зуммирование «умным кропом», он дешевле распознавания лиц и даёт хорошие результаты на фотографиях разного типа, в т.ч. и без лиц.
            Пример работы смарткропа
            image
        • +4
          Вот крайне интересно читать о том, как программирование помогает «обычным людям» в решии их повседневных задач. Хоть цифровая фотография и крайне тесна связана с IT, но большинство фотографов кроме как ФШ да ЛР ничего и не умеют, и даже винду переставить не могут, а тут человек пишет не такое уж и простое ПО для себя. Круто. Автор молодец!!!
          • +1
            большинство фотографов кроме как ФШ да ЛР ничего и не умеют, и даже винду переставить не могут


            Умения переустановить винду — это самое важное умение для фотографа, да. :)
            • 0
              Нет, это говорит об общей компьютерной грамотности, это лишь яркий показатель
              • +1
                Переустановка винды в наше время это настолько простой процесс, что показателем компьютерной грамотности не является. Воткнул диск, да два-три раза нажал «далее». Даже установка какой-нибудь убунты — тоже не показатель грамотности.
                А вот запуск линукса на телефоне и дальнейший запуск там самописной программы — это показатель.
                • 0
                  Так в том то и дело
                  Воткнул диск, да два-три раза нажал «далее»
                  а большинство не могут. Это как раз показатель низкой компьютерной грамотности, о чём я и говорил изначально.
                  • 0
                    Могут, просто боятся. Или не хотят.
                    Но при этом могут быть хорошими фотографами, дизайнерами, бухгалтерами или даже программистами.
            • 0
              Самое главное умение фотографа на пк (помимо обработки фото) либо делать backup, либо Raid, второе умение — восстанавливать уделенные фото…
              • 0
                либо делать backup, либо Raid
                Резервная копия не заменяет RAID-массив и наоборот.
                • +1
                  не всегда важен способ главное, чтобы был дубль. Но грамотное приятнее безграмотного. Согласен с Вами.
                  • 0
                    Так вот RAID как раз «дублей» и не обеспечивает. От удаленных и испорченных файлов не спасёт.
                    • 0
                      RAID — 1 например спасет от испорченных файлов, либо убийством одного из дисков. От удаления Да — не спасет, но удаление, чаще всего — осознанный шаг
                    • 0
                      Удалив файл с массива, Вы удалите и «дубль». Тот же файл останется в резервной копии. Почувствуйте разницу.
                • +1
                  Да у меня скорее нетипичный случай )
                  Программировать начал раньше чем фотографировать. В одно время встал выбор, в какую сторону двигаться дальше — приглашали работать программистом в достаточно хорошую компанию, но выбрал фотографию.
                  По мелочи тоже здорово помогает. Например, как то надоело ждать, как любимый резайсер фотографий делает все в один поток, написал свой )
                  • 0
                    Работал в студии, где у каждого фотографа была своя, очень некислая рабочая станция, предоставленная фирмой, но всё что касается софта, лежало на плечах фотографов/художников/верстальщиков и их познания в сфере тонкого тюнинга софта и железа меня поражали.
                  • +1
                    В общем, если убрать код, то процесс выглядит так:

                    1) На экране фотоаппарата отбираете фото
                    2) Карту памяти подключаете к телефону, из отмеченных фото выдергиваете джпеги
                    3) Через веб-интерфейс для вашей программы указываете параметры конвертирования, ждёте
                    4) На выходе — видеофайл со слайдшоу.

                    Так?
                    • +1
                      Да, все именно так!
                      • 0
                        А в чем фишка снимать в RAW, а потом дергать оттуда превью джипег?
                        • 0
                          Чтобы не расходовать место на джпеги, например.
                          • 0
                            Слайдшоу в день съемки, это вторично. Главное все же, это фотографии. Для гарантированного результата, нужны raw.
                            Вытащить jpeg из raw — простая и быстрая операция. Если бы её не было, то быстрее и проще не стало бы, так как остаётся все остальное.
                      • +3
                        Круто, спасибо. Программирование действительно во многих случаях помогает. Я вот Python и OpenCV начал учить. Удивительно, но офигенно полезно для врача-исследователя в лаборатории.
                        • +3
                          Вот я бы послушал на эту тему, пилите пост :)
                          • +2

                            Вот первые робкие шаги) Пока обучаю видеть метки. С python и OpenCV никогда раньше не стлакивался. Пока идет довольно легко. Хотя меня вымораживает неопределенность в типе переменной. Хрен ти что может храниться. То ли контейнер с массивом какой-то фигни, то ли кадр, то ли Boolean. очень легко запутаться и налажать, если переменные плохо названы. Возможно я чего-то не понимаю пока. До этого немного C ковырял.
                            • 0
                              ИМХО было ошибкой одеть рубашку того же цвета, как и метки. Или так и было задумано? :)
                              • 0
                                Вообще ошибся) но это самое начало. Только сегментация. Я потом ещё фильтры крутил, erode/dilate, определение координат и прочее.
                                • 0
                                  Радует глаз когда специалисты нетехнических специальностей так глубоко копают :)
                                  В штатах это давно норма, когда какой-нибудь бизнес-аналитик пишет свой аналитический софт под конкретные задачи и инструмент тут не важен, видел на Excel таких монстров, что возникал вопрос «и кто тут программист». Мне также приносили задачки типа «Я тут в Access накидал базу, давай сделаем нормальный сетевой вариант?», я открываю это «накидал», и понимаю что это месяцы работы, а приносит это далеко не программист. Важно, что только человек, глубоко знакомый с предметной областью, понимает все тонкости того, что нужно автоматизировать.
                                  Думаю что скоро к тому придём, что на уровне школы программирование будет преподаваться на уровне иностранных языков.
                                  • 0
                                    Спасибо) в итоге, правда, код наполовину из комментариев, чтобы не забыть и все время явно изобретаю велосипед. Хотя работает, да. И не хватает математики и базовых универсальных алгоритмов. Сейчас думаю, как корректнее определить центроид четырёхугольника при наличии координат вершин. Среднее арифметическое (x,y) странно выглядит.
                                    • 0
                                      А в чём собственно проблема? Считаем центроиды четырёх треугольников, проводим к ним линии из противоположных вершин, ищем точки пересечения. Или проблема это именно алгоритмически и эффективно реализовать?
                                      • 0
                                        Проблема алгоритмически. Я до сих пор не привыкну к манипуляции массивами точек. Трудно) Вот пока наброски кода. Примитивненько, но мне еще надо учиться:

                                        Код
                                        # The distance between green marks shuold be at least 4a, where "a" is the width of the square.
                                        # It's easier to draw the area around the central point between them.
                                        
                                        import cv2
                                        import numpy as np
                                        
                                        cap = cv2.VideoCapture(0)
                                        
                                        def nothing(x):
                                            pass
                                        
                                        cv2.namedWindow('mask')
                                        
                                        # Create sliders for range adjusting
                                        cv2.createTrackbar('Hue_low', 'mask', 40, 255, nothing)
                                        cv2.createTrackbar('Hue_high', 'mask', 76, 255, nothing)
                                        cv2.createTrackbar('Saturation_low', 'mask', 81, 255, nothing)
                                        cv2.createTrackbar('Saturation_high', 'mask', 255, 255, nothing)
                                        
                                        while True:
                                            # flashing the counter
                                            centrIndex = 0
                                            # init list
                                            centroidListX = []
                                            centroidListY = []
                                        
                                            # Take each frame
                                            _, frame = cap.read()
                                        
                                            # Convert BGR to HSV
                                            hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
                                        
                                            # Get current slider position
                                            Hue_low = cv2.getTrackbarPos('Hue_low', 'mask')
                                            Hue_high = cv2.getTrackbarPos('Hue_high', 'mask')
                                            Sat_low = cv2.getTrackbarPos('Saturation_low', 'mask')
                                            Sat_high = cv2.getTrackbarPos('Saturation_high', 'mask')
                                        
                                            # define range of green color in HSV
                                            lower_green = np.array([Hue_low, Sat_low, 40])
                                            upper_green = np.array([Hue_high, Sat_high, 250])
                                        
                                            # Threshold the HSV image to get only blue colors
                                            mask = cv2.inRange(hsv, lower_green, upper_green)
                                        
                                            #Erode disabled to speedup. Works nice without it.
                                            mask = cv2.erode(mask, None, iterations = 1)
                                            mask = cv2.dilate(mask, None, iterations = 1)
                                        
                                            # Bitwise-AND mask and original image
                                            image_result = cv2.bitwise_and(frame, frame, mask=mask)
                                        
                                            # Detecting edges
                                            image_mask_blur = cv2.medianBlur(mask, 3)
                                            image_canny = cv2.Canny(image_mask_blur, 30, 150)
                                        
                                            # Closing gaps
                                            kernel_canny = cv2.getStructuringElement(cv2.MORPH_RECT, (7, 7))
                                            image_canny_closed = cv2.morphologyEx(image_canny, cv2.MORPH_CLOSE, kernel_canny)
                                        
                                            # Finding contours
                                            (cnts, _) = cv2.findContours(image_canny_closed.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
                                        
                                            for c in cnts:
                                        
                                                # approximate the contour
                                                peri = cv2.arcLength(c, True)
                                                approx = cv2.approxPolyDP(c, 0.03 * peri, True)
                                                # get the bounding box with it's coordinates and aspect ratio
                                                (x,y,w,h) = cv2.boundingRect(approx)
                                                aspectRatio = w / float(h)
                                        
                                                # initialize bool variables
                                                boolRectangle = False
                                                boolPeri = False
                                                boolAspect = False
                                        
                                                if len(approx) >= 4 and len(approx) <= 6:
                                                    boolRectangle = True
                                                if peri >= 50:
                                                    boolPeri = True
                                                if aspectRatio > 0.9 and aspectRatio < 1.1:
                                                    boolAspect = True
                                        
                                                if boolRectangle and boolPeri and boolAspect:
                                                    cv2.rectangle(frame,(x,y),(x+w,y+h),(255,0,0),2)
                                        
                                                    # get centroid of rectangle
                                                    centroidX = x + w/2
                                                    centroidY = y + h/2
                                                    centroidListX.append(centroidX)
                                                    centroidListY.append(centroidY)
                                        
                                                    cv2.circle(frame, (centroidListX[centrIndex], centroidListY[centrIndex]), 1,(0,0,255),3)
                                                    centrIndex += 1
                                        
                                                    if centrIndex == 4:
                                                        centroidMainX = 0
                                                        centroidMainY = 0
                                                        for loopIndex in range(0, 3):
                                                            centroidMainX = centroidMainX + centroidListX[loopIndex]
                                                            centroidMainY = centroidMainY + centroidListY[loopIndex]
                                                        centroidMainX = centroidMainX/4
                                                        centroidMainY = centroidMainY/4
                                                        cv2.circle(frame, (centroidMainX, centroidMainY), 5, (0, 0, 255),3)
                                                        cv2.rectangle(frame, (centroidMainX - int(peri),centroidMainY + int(peri)), (centroidMainX + int(peri), centroidMainY - int(peri)), (0,255,255), 2)
                                                cv2.imshow('frame', frame)
                                        
                                            # Visualization
                                            cv2.imshow('mask', image_result)
                                            #cv2.imshow('canny_closed', image_canny_closed)
                                            #cv2.imshow('canny', image_canny)
                                            k = cv2.waitKey(5) & 0xFF
                                            if k == 27:
                                                break
                                        
                                        cv2.destroyAllWindows()
                                        
                                        

                              • 0
                                • 0
                                  Посмотрю. но я пока на 2.7. Сейчас Ubuntu 14.04 на работе, не хочу сильно ворошить систему вручную. Перейду на 16.04 — обновлюсь.
                            • +2
                              Очень приятная штука, когда благодаря программирования, у тебя развязываются руки )
                            • +1
                              я может быть напишу глупость, но почему нельзя было сделать то же самое силами самого андроида?
                              • 0
                                Привычные инструменты, отсутствие необходимости мусорить в системе, легкий перенос с места на место…

                                • 0
                                  Каким образом? Есть софт, который что то может делать по отдельности, но много ручной работы.
                                  Приличных программ для создания слайдшоу, например, не нашёл. Все пытаются сделать его квадратным для инстаграма. А уж чтоб сохранить только снимки с рейтингами, да ещё из raw пакетно, никто не умеет.
                                  • +1
                                    Написать код с такой же функциональностью на Java, наверняка там множество готовых библиотек для изображений и видео
                                    • +1
                                      Думаю, проблем написать на Java нет, но рассказ не об этом.
                                      У меня «одноразовое» решения для личного пользования. Сделал максимально быстрым для себя способом.
                                      • 0
                                        Да, я про это и спрашивал, тем более, что опыт программирования у автора есть. Заодно мог бы и продавать продукт, наверняка бы нашлась бы целевая аудитория.
                                  • +3
                                    Игорь, наблюдаю за вашим python-творчеством еще с времен Симбиан и s40 — ваши статьи всегда интересны, пишите еще. Смотря на ваши работы в программировании, вспоминаются слова Advice from an Old Programmer из Learn Python The Hard Way
                                    ...Programming as a profession is only moderately interesting. It can be a good job, but you could make about the same money and be happier running a fast food joint. You're much better off using code as your secret weapon in another profession.
                                    • +1
                                      Symbian, хорошие были времена. У меня был смартфон, но не было компьютера и я тогда читал Россума (book ods) и писал скрипты прямо на смартфоне, с экраном 174х208, сейчас с трудом себе это представляю. Может и мои работы вам знакомы — MP3Editor, MBM Tool, AIF Tool, GIF Tool. Мы с Игорем тогда общались на димонвидео, можно сказать вместе работали.
                                      • 0
                                        Да да, это было трудное, но веселое «детство») Спасибо за то, что сподвиг вообще начать заниматься программированием )
                                        • 0
                                          MBM Tool помню — ресурсы менял на своей старенькой Nokia N76, благодаря чему все одногрупники несли свои телефоны на починить и настроить мне. Спасибо вам за нее.
                                      • 0
                                        Сразу несколько вопросов:
                                        1. Сколько уходит зарядки у вашего смартфона на 1 описанный вами цикл.
                                        2. А если кто нибудь вам позвонит в момент рендера?
                                        3. Не виснет, не глючит? Прямо все без нареканий?
                                        • 0
                                          В момент, когда задействованы 4 ядра на все 100, да, глючит и лагает, на звонок ответить затруднительно. Но это длится минут 10. Да и в это время не до звонков — на съёмках же )
                                          По поводу заряда, не замерял, но не думаю что уйдёт заряда больше чем за 15-20 минут работы какой нибудь требовательной игрушки.
                                        • 0
                                          Очень круто!

                                          Только думаю, что все действительно можно соединить в одном полноценном приложении. И что-то мне подсказывает, что такие проги уже есть)

                                          Вот крайне интересно читать о том, как программирование помогает «обычным людям» в решии их повседневных задач.
                                          +1 решение проблем — это самый кайф в нашем деле!
                                          • 0
                                            Уж очень специфичная штука, чтоб такое приложение уже было ) даже на PC готового нет. По отдельности — пожалуйста, но вот все вместе нет.
                                            • 0
                                              А у вас не было мысли запилить такое приложение? Мне кажется, среди фотографов было бы весьма востребованным.
                                              • 0
                                                Тут проблема — кроме питона, мне всегда было лень что то новое изучать (за исключением немного c++ для микроконтроллеров), а распространять приложение в виде скриптов для Linux deploy среди не айтишников, которые почти все на iOS — бесполезно )
                                          • 0
                                            Супер! Делитесь своим опытом, у вас прекрасно получается!!! Спасибо за столько интересный рассказ! Не думали оформить все либой и где-нибудь распространять за не бесплатно?
                                            • 0
                                              Спасибо. Нет, не думал. Программирование это хобби, основной доход другой.
                                              Единственное, что, сделал коммерческий заказ на доработку софтины для коллеги, который занимается видео. Все тоже самое, но половину функционала не понадобилось, так как видео нужно склеивать напрямую, без какой либо обработки.
                                            • 0
                                              Замечательное решение и отличная статья. Частенько вот сталкивался с мнением, де никак фотографу под Linux работать не удастся, мол фотошопа нет и тому подобное. А оно вон как получается, отличная автоматизация рабочего процесса.
                                              • 0
                                                Да, но без Windows, если занимаешься коммерческой съемкой, действительно очень сложно. Как раз таки из за фотошопе и тому подобное. Аналоги есть, но до коммерческого применения не дотягивают. С удовольствием поучаствовал бы, например, в работе над dark table, но не хватает времени (
                                                • 0
                                                  Мне RawTherapee нравится. Правда фотки больше научного характера. Камера микроскопа, макрофотографии образцов со штатива…
                                                  • 0
                                                    Я не буду говорить про цвет, профили камер и объективов, это все субъективно.
                                                    Когда ты целыми днями работаешь с программой, любой косяк интерфейса или тормоза очень и очень мешают.
                                                    Пару фотографий обработать можно, но вот когда их сотни и тысячи (
                                                    • 0
                                                      Lightroom удобнее, согласен. Но у меня большая часть работы в Linux идёт.
                                                • +1
                                                  Это всё же не работа фотографа получилась, а работа программиста.
                                                  О пригодности линукса для фотографа оно не говорит.
                                                  • +1
                                                    О пригодности линукса для фотографа говорит использование линукса фотографом.
                                                    • 0
                                                      То есть если фотограф на линукс-машине только лазит по интернету — это тоже считается «использованием линукса фотографом»?

                                                      • 0
                                                        Нет. Это значит, если фотограф использует линукс для работы с фотографией.
                                                        • +2
                                                          В описываемом случае — не фотограф, а программист.
                                                • +1
                                                  Вы молодец! Ограничения всегда порождают продуманные и интересные решения.
                                                  • 0
                                                    Например, на очереди статья, как сделать вот такую милую и функциональную фотобудку

                                                    Можно карманный принтер к фотоаппарату синей изолентой примотать, дешево и сердито!
                                                    • 0
                                                      Шикарный пост!

                                                      У вас так понимаю Canon с карточками формата Compact Flash? Это к телефону картридер еще нужно подключать?
                                                      • +1
                                                        Голосую за статью про фотобудку!
                                                        • 0
                                                          exiftool можно заменить на pyexiv2, больше возможностей и код проще
                                                          • 0
                                                            Спасибо, посмотрю на него еще раз — когда то у меня с ним не срослось, не помню почему.
                                                            Pillow кстати тоже может читать exif, но почему то не все теги и не всегда )
                                                            from PIL import Image,ExifTags
                                                            img=Image.open(PATH_TO_IMAGE)
                                                            exif=dict((ExifTags.TAGS[k], v) for k, v in img._getexif().items() if k in ExifTags.TAGS)
                                                            
                                                            • 0
                                                              Да у меня на c++ тоже с exiv2 не срослось, но там видимо отсутствие опыта с самим c++, а как на python попробовал, завелось и заработало на ура сразу же
                                                          • 0
                                                            Да, отличное решение с Linux Deploy! Сразу возникают мысли, как еще можно это использовать. Ведь в кармане у каждого лежит приличный компьютер да еще всегда подключенный к интернет. Можно и веб сервер с интернет магазином на нем развернуть. Хостинг открыть.
                                                            Даже биткоины можно потихоньку майнить :)
                                                            • 0
                                                              Аха, а через час-два бежать искать розетку )
                                                              А вот использовать старенькие смартфоны или планшеты, которые валяются дома — почему нет.
                                                            • +1
                                                              Круто, мощность смартфонов, о которой много говорится, реально используется в деле.

                                                              Объединять видео файлы можно так (https://trac.ffmpeg.org/wiki/Concatenate)

                                                              ffmpeg -i "concat:input1.mpg|input2.mpg|input3.mpg" -c copy output.mpg
                                                              • 0
                                                                С mpg было проще через cat сделать. И наверняка быстрее, не знаю, что ffmpeg там с этим делает внутри )
                                                                • +1
                                                                  ffmpeg внутри делает то же самое — копирует видеопотоки. Скорость по идее та же. Разница только в том, что заголовок с параметрами файла он поставит только один — в начале файла.
                                                                  Я таким способом объединяю MTS файлы с видеокамеры — она их ограничивает в 2ГБ размером.

                                                              Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.