commit 05e6e36ee38f23d9f48d3b00cfbda596c9d78d1f
parent 02572e33cf820f43a9a0337d3817bc0a46b0bc05
Author: Robin Bäckman <rob@tarina.org>
Date: Fri, 13 Nov 2020 18:15:55 +0200
Merge pull request #1 from rbckman/hq-camera
Hq camera
Diffstat:
4 files changed, 126 insertions(+), 56 deletions(-)
diff --git a/README.md b/README.md
@@ -29,6 +29,7 @@ Hardware
The parts are built around the world by different manufacturers. They've been chosen on the basis of features, quality, openness, availabilty and price. One of the central ideas of the project is to have a camera that could be upgraded or repaired by the fact that you easily just switch a component. The casis of the camera is all 3d printable with a design that has the key element of flipping the lens 180 (gonzo style). Here's the main components:
[Raspberry Pi 3](https://www.raspberrypi.org/products/raspberry-pi-3-model-b/)<br>
+[Raspberry Pi High Quality Camera](https://www.raspberrypi.org/products/raspberry-pi-high-quality-camera/?resellerType=home) or <br>
[Arducam 5 MP OV5647 camera module with CS lens 2718](https://www.ebay.com/itm/OV5647-Camera-Board-w-CS-mount-Lens-for-Raspberry-Pi-3-B-B-2-Model-B-/281212355128?txnId=1913825600018)<br>
[3.5 inch 800x480 TFT Screen](https://www.aliexpress.com/store/product/U-Geek-Raspberry-Pi-3-5-inch-800-480-TFT-Screen-HD-HighSpeed-LCD-Module-3/1954241_32672157641.html)<br>
[USB via vt1620a Sound card](https://www.aliexpress.com/item/Professional-External-USB-Sound-Card-Adapter-Virtual-7-1-Channel-3D-Audio-with-3-5mm-Headset/32588038556.html?spm=2114.01010208.8.8.E8ZKLB)<br>
diff --git a/docs/tarina-manual.md b/docs/tarina-manual.md
@@ -151,6 +151,17 @@ This is a good performance card.
[Aliexpress](https://www.aliexpress.com/item/32676225311.html?spm=a2g0o.productlist.0.0.11ed1b664kPdEf&algo_pvid=d9155fff-7ddc-47bb-9512-f7e686fe69ac&algo_expid=d9155fff-7ddc-47bb-9512-f7e686fe69ac-0&btsid=e2f36205-1c37-47bc-9a94-c006837f0992&ws_ab_test=searchweb0_0,searchweb201602_7,searchweb201603_55)
+Raspberry Pi High Quality Camera (recommended)
+----------------------------------------------
+Price ~60 eur
+
+This is the recommended camera module for Tarina, 12.3 megapixel Sony IMX477 sensor, 7.9mm diagonal image size, and back-illuminated sensor architecture, with adjustable back focus and support for C- and CS-mount lenses.
+
+**Links**
+**Buy**
+[Raspberry pi](https://www.raspberrypi.org/products/raspberry-pi-high-quality-camera/?resellerType=home)
+
+
Arducam 5 MP OV5647 camera module with CS lens
----------------------------------------------
Price ~30 eur
diff --git a/install.sh b/install.sh
@@ -52,9 +52,10 @@ sudo pip3 install omxplayer-wrapper
echo "installing blessed..."
sudo pip3 install blessed
echo "installing rwb27s openflexure microscope fork of picamera with lens shading correction..."
-sudo pip3 --no-cache-dir install https://github.com/rbckman/picamera/archive/master.zip --upgrade
+#sudo pip3 --no-cache-dir install https://github.com/chrisruk/picamera/archive/hq-camera-new-framerates.zip --upgrade
+sudo pip3 install --upgrade picamerax
echo "installing web.py for the tarina webserver..."
-sudo pip3 install web.py==0.40-dev1
+sudo pip3 install web.py==0.61
if grep -q -F '#tarina-rpi-configuration-1.0' /boot/config.txt
then
@@ -122,7 +123,10 @@ then
echo "Debian Buster Alsa config"
cat <<'EOF' > /etc/modprobe.d/alsa-base.conf
#set index value
-options snd_usb_audio index=-2
+options snd-usb-audio index=0
+options snd_bcm2835 index=1
+#reorder
+options snd slots=snd_usb_audio, snd_bcm2835
EOF
else
echo "Debian Stretch Alsa config"
@@ -147,7 +151,7 @@ Conflicts=getty@tty1.service
[Service]
Type=simple
RemainAfterExit=yes
-ExecStart=/usr/bin/python3 /home/pi/tarina/tarina.py
+ExecStart=/usr/bin/python3 /home/pi/tarina/tarina.py default
User=pi
Restart=on-failure
StandardInput=tty-force
diff --git a/tarina.py b/tarina.py
@@ -33,12 +33,13 @@ from PIL import Image
import smbus
import socket
import configparser
+import secrets
#import shlex
from blessed import Terminal
#if buttons are installed
try:
- bus = smbus.SMBus(3) # Rev 2 Pi uses 1
+ bus = smbus.SMBus(11) # Rev 2 Pi uses 1
DEVICE = 0x20 # Device address (A0-A2)
IODIRB = 0x0d # Pin pullups B-side
IODIRA = 0x00 # Pin pullups A-side 0x0c
@@ -153,10 +154,15 @@ def main():
oldtake = take
#TURN OFF WIFI AND TARINA SERVER
- serverstate = 'off'
- wifistate = 'off'
- run_command('sudo iwconfig wlan0 txpower off')
- serverstate = tarinaserver(False)
+ if str(sys.argv[0]) == 'default':
+ serverstate = 'off'
+ wifistate = 'off'
+ run_command('sudo iwconfig wlan0 txpower off')
+ serverstate = tarinaserver(False)
+ else:
+ serverstate = 'off'
+ wifistate = 'on'
+ serverstate = tarinaserver(False)
foldername = filmfolder + filmname + '/' + 'scene' + str(scene).zfill(3) +'/shot' + str(shot).zfill(3) + '/'
filename = 'take' + str(take).zfill(3)
@@ -226,6 +232,7 @@ def main():
camera.stop_preview()
foldername = filmfolder + filmname + '/' + 'scene' + str(scene).zfill(3) +'/shot' + str(shot).zfill(3) + '/'
filename = 'take' + str(take).zfill(3)
+ compileshot(foldername + filename)
playdub(foldername + filename, False, headphoneslevel)
imagename = foldername + filename + '.jpeg'
overlay = displayimage(camera, imagename)
@@ -306,6 +313,11 @@ def main():
filmname = newfilmname
os.makedirs(filmfolder + filmname)
writemessage('Good luck with your film ' + filmname + '!')
+ #make a filmhash
+ print('making filmhash...')
+ filmhash = secrets.token_urlsafe(16)
+ with open(filmfolder + filmname + '.filmhash', 'w') as f:
+ f.write(filmhash)
updatethumb = True
updatemenu = True
scene = 1
@@ -325,13 +337,6 @@ def main():
else:
vumetermessage('')
- #ADELAY
- elif pressed == 'middle' and menu[selected] == 'ADELAY':
- foldername = filmfolder + filmname + '/' + 'scene' + str(scene).zfill(3) +'/shot' + str(shot).zfill(3) + '/'
- filename = 'take' + str(take).zfill(3)
- os.system('cp ' + foldername + filename + '.wav /dev/shm/')
- delayerr = audiodelay(foldername,filename)
-
#YANK(COPY) SHOT
elif event == 'Y' and menu[selected] == 'SHOT:' and recordable == False:
yankedshot = filmfolder + filmname + '/' + 'scene' + str(scene).zfill(3) +'/shot' + str(shot).zfill(3)
@@ -487,7 +492,7 @@ def main():
if os.path.isdir(foldername) == False:
os.makedirs(foldername)
os.system(tarinafolder + '/alsa-utils-1.1.3/aplay/arecord -D hw:0 -f S16_LE -c 1 -r44100 -vv /dev/shm/' + filename + '.wav &')
- camera.start_recording(foldername + filename + '.h264', format='h264', quality=26, bitrate=3000000)
+ camera.start_recording(foldername + filename + '.h264', format='h264', quality=26, bitrate=5000000)
starttime = time.time()
recording = True
elif recording == True and float(time.time() - starttime) > 0.2:
@@ -509,8 +514,9 @@ def main():
vumetermessage('Tarina ' + tarinaversion[:-1] + ' ' + tarinavername[:-1])
thefile = foldername + filename
updatethumb = True
- compileshot(foldername + filename)
- delayerr = audiodelay(foldername,filename)
+ #compileshot(foldername + filename)
+ os.system('cp /dev/shm/' + filename + '.wav ' + foldername + filename + '.wav')
+ #delayerr = audiodelay(foldername,filename)
if beeps > 0:
buzz(300)
#if not in last shot or take then go to it
@@ -777,7 +783,7 @@ def main():
logger.info('okey something has changed')
foldername = filmfolder + filmname + '/' + 'scene' + str(scene).zfill(3) +'/shot' + str(shot).zfill(3) + '/'
filename = 'take' + str(take).zfill(3)
- recordable = not os.path.isfile(foldername + filename + '.mp4')
+ recordable = not os.path.isfile(foldername + filename + '.mp4') and not os.path.isfile(foldername + filename + '.h264')
overlay = removeimage(camera, overlay)
imagename = filmfolder + filmname + '/scene' + str(scene).zfill(3) + '/shot' + str(shot).zfill(3) + '/take' + str(take).zfill(3) + '.jpeg'
overlay = displayimage(camera, imagename)
@@ -938,7 +944,7 @@ def countlast(filmname, filmfolder):
allfiles = []
takes = 0
for a in allfiles:
- if '.mp4' in a:
+ if '.mp4' in a or '.h264' in a:
takes = takes + 1
return scenes, shots, takes
@@ -980,7 +986,7 @@ def counttakes(filmname, filmfolder, scene, shot):
allfiles = []
return takes
for a in allfiles:
- if '.mp4' in a:
+ if '.mp4' in a or '.h264' in a:
takes = takes + 1
return takes
@@ -1134,7 +1140,8 @@ def getfilms(filmfolder):
#-------------Load tarina config---------------
-def getconfig(version):
+def getconfig(camera):
+ version = camera.revision
home = os.path.expanduser('~')
configfile = home + '/.tarina/config.ini'
configdir = os.path.dirname(configfile)
@@ -1159,9 +1166,9 @@ def getconfig(version):
holdbutton = ''
selected = 0
header = 'What revision of ' + version + ' sensor are you using?'
- menu = 'rev.C', 'rev.D'
+ menu = 'rev.C', 'rev.D', 'hq-camera'
while True:
- settings = '', ''
+ settings = '', '', ''
writemenu(menu,settings,selected,header)
pressed, buttonpressed, buttontime, holdbutton, event, keydelay = getbutton(pressed, buttonpressed, buttontime, holdbutton)
if pressed == 'right':
@@ -1350,7 +1357,7 @@ def timelapse(beeps,camera,foldername,filename):
if recording == False and t > between:
if beeps > 0:
buzz(150)
- camera.start_recording(foldername + 'timelapse/' + filename + '_' + str(n).zfill(3) + '.h264', format='h264', quality=26, bitrate=3000000)
+ camera.start_recording(foldername + 'timelapse/' + filename + '_' + str(n).zfill(3) + '.h264', format='h264', quality=26, bitrate=5000000)
if sound == True:
os.system(tarinafolder + '/alsa-utils-1.1.3/aplay/arecord -D hw:0 -f S16_LE -c 1 -r 44100 -vv /dev/shm/' + filename + '_' + str(n).zfill(3) + '.wav &')
files.append(foldername + 'timelapse/' + filename + '_' + str(n).zfill(3))
@@ -1445,7 +1452,7 @@ def remove(filmfolder, filmname, scene, shot, take, sceneshotortake):
elif pressed == 'middle':
if selected == 1:
if sceneshotortake == 'take':
- #os.system('rm ' + foldername + filename + '.h264')
+ os.system('rm ' + foldername + filename + '.h264')
os.system('rm ' + foldername + filename + '.mp4')
os.system('rm ' + foldername + filename + '.wav')
os.system('rm ' + foldername + filename + '.jpeg')
@@ -1489,9 +1496,9 @@ def organize(filmfolder, filmname):
os.system('rm -r ' + filmfolder + filmname + '/' + i + '/' + p)
organized_nr = 1
for s in sorted(takes):
- if '.mp4' in s:
+ if '.mp4' in s or '.h264' in s:
#print(s)
- unorganized_nr = int(s[4:-4])
+ unorganized_nr = int(s[4:7])
if organized_nr == unorganized_nr:
#print('correct')
pass
@@ -1499,6 +1506,7 @@ def organize(filmfolder, filmname):
#print('false, correcting from ' + str(unorganized_nr) + ' to ' + str(organized_nr))
mv = 'mv ' + filmfolder + filmname + '/' + i + '/' + p + '/take' + str(unorganized_nr).zfill(3)
run_command(mv + '.mp4 ' + filmfolder + filmname + '/' + i + '/' + p + '/take' + str(organized_nr).zfill(3) + '.mp4')
+ run_command(mv + '.h264 ' + filmfolder + filmname + '/' + i + '/' + p + '/take' + str(organized_nr).zfill(3) + '.h264')
run_command(mv + '.wav ' + filmfolder + filmname + '/' + i + '/' + p + '/take' + str(organized_nr).zfill(3) + '.wav')
run_command(mv + '.jpeg ' + filmfolder + filmname + '/' + i + '/' + p + '/take' + str(organized_nr).zfill(3) + '.jpeg')
organized_nr += 1
@@ -1610,6 +1618,7 @@ def compileshot(filename):
else:
writemessage('Converting to playable video')
run_command('MP4Box -fps 25 -add ' + filename + '.h264 ' + filename + '.mp4')
+ delayerr = audiodelay(filename)
os.system('rm ' + filename + '.h264')
#run_command('omxplayer --layer 3 ' + filmfolder + '/.rendered/' + filename + '.mp4 &')
#time.sleep(0.8)
@@ -1740,6 +1749,7 @@ def renderscene(filmfolder, filmname, scene):
# Video Hash
for p in filmfiles:
+ compileshot(p)
videohash = videohash + str(int(countsize(p + '.mp4')))
print('Videohash of scene is: ' + videohash)
try:
@@ -1809,6 +1819,7 @@ def renderfilm(filmfolder, filmname, comp):
filmdir = filmfolder + filmname + '/'
for p in filmfiles:
print(p)
+ compileshot(p)
videohash += str(int(countsize(p + '.mp4')))
print('Videohash of film is: ' + videohash)
try:
@@ -2270,11 +2281,11 @@ def viewfilm(filmfolder, filmname):
#--------------Audiodelay--------------------
# make audio file same lenght as video file
-def audiodelay(foldername, filename):
+def audiodelay(filename):
writemessage('Audio syncing..')
- pipe = subprocess.check_output('mediainfo --Inform="Video;%Duration%" ' + foldername + filename + '.mp4', shell=True)
+ pipe = subprocess.check_output('mediainfo --Inform="Video;%Duration%" ' + filename + '.mp4', shell=True)
videolenght = pipe.decode().strip()
- pipe = subprocess.check_output('mediainfo --Inform="Audio;%Duration%" /dev/shm/' + filename + '.wav', shell=True)
+ pipe = subprocess.check_output('mediainfo --Inform="Audio;%Duration%" ' + filename + '.wav', shell=True)
audiolenght = pipe.decode().strip()
#if there is no audio lenght
logger.info('audio is:' + audiolenght)
@@ -2291,9 +2302,9 @@ def audiodelay(foldername, filename):
newaudiolenght = int(audiolenght) - audiosync
logger.info('Audiofile is: ' + str(audiosync) + 'ms longer')
#trim from end and put a 0.01 in- and outfade
- run_command('sox -V0 /dev/shm/' + filename + '.wav ' + foldername + filename + '_temp.wav trim 0 -' + str(int(audiosync)/1000))
- run_command('sox -V0 -G ' + foldername + filename + '_temp.wav ' + foldername + filename + '.wav fade 0.01 0 0.01')
- os.remove(foldername + filename + '_temp.wav')
+ run_command('sox -V0 ' + filename + '.wav ' + filename + '_temp.wav trim 0 -' + str(int(audiosync)/1000))
+ run_command('sox -V0 -G ' + filename + '_temp.wav ' + filename + '.wav fade 0.01 0 0.01')
+ os.remove(filename + '_temp.wav')
#if int(audiosync) > 400:
# writemessage('WARNING!!! VIDEO FRAMES DROPPED!')
# vumetermessage('Consider changing to a faster microsd card.')
@@ -2309,15 +2320,15 @@ def audiodelay(foldername, filename):
# audiosyncms = 1000 + audiosyncms
logger.info('Videofile is: ' + str(audiosync) + 'ms longer')
#make fade
- run_command('sox -V0 -G /dev/shm/' + filename + '.wav ' + foldername + filename + '_temp.wav fade 0.01 0 0.01')
+ run_command('sox -V0 -G ' + filename + '.wav ' + filename + '_temp.wav fade 0.01 0 0.01')
#make delay file
run_command('sox -V0 -n -r 44100 -c 1 /dev/shm/silence.wav trim 0.0 ' + str(int(audiosync)/1000))
#add silence to end
- run_command('sox -V0 /dev/shm/silence.wav ' + foldername + filename + '_temp.wav ' + foldername + filename + '.wav')
- os.remove(foldername + filename + '_temp.wav')
+ run_command('sox -V0 /dev/shm/silence.wav ' + filename + '_temp.wav ' + filename + '.wav')
+ os.remove(filename + '_temp.wav')
os.remove('/dev/shm/silence.wav')
delayerr = 'V' + str(audiosync)
- os.remove('/dev/shm/' + filename + '.wav')
+ #os.remove('/dev/shm/' + filename + '.wav')
return delayerr
#os.system('mv audiosynced.wav ' + filename + '.wav')
#os.system('rm silence.wav')
@@ -2346,6 +2357,7 @@ def copytousb(filmfolder):
buttontime = time.time()
holdbutton = ''
writemessage('Searching for usb storage device, middlebutton to cancel')
+ films = getfilms(filmfolder)
while True:
pressed, buttonpressed, buttontime, holdbutton, event, keydelay = getbutton(pressed, buttonpressed, buttontime, holdbutton)
usbconnected = os.path.ismount('/media/usb0')
@@ -2363,19 +2375,58 @@ def copytousb(filmfolder):
try:
p = subprocess.check_output('stat -f -c %T /media/usb0', shell=True)
filesystem = p.decode()
- writemessage('Copying files...')
- run_command('rsync -avr -P ' + filmfolder + '* /media/usb0/tarinafilms/')
- run_command('sync')
- run_command('pumount /media/usb0')
- writemessage('all files copied successfully!')
- waitforanykey()
- writemessage('You can safely unplug the usb device now')
- time.sleep(2)
- return
+ print('filesystem info: ' + filesystem)
except:
- writemessage('Nope! something wrong with ur drive :(')
+ writemessage('Oh-no! dont know your filesystem')
waitforanykey()
return
+ for filmname in films:
+ #check filmhash
+ filmname = filmname[0]
+ usbpath = '/media/usb0/tarinafilms/'+filmname
+ usbfilmhash = ''
+ filmhash = ''
+ while True:
+ if os.path.exists(usbpath) == False:
+ break
+ try:
+ with open(filmfolder + filmname + '/.filmhash', 'r') as f:
+ filmhash = f.readline().strip()
+ print('filmhash is: ' + filmhash)
+ except:
+ print('no filmhash found!')
+ try:
+ with open(usbpath + '/.filmhash', 'r') as f:
+ usbfilmhash = f.readline().strip()
+ print('usbfilmhash is: ' + usbfilmhash)
+ except:
+ print('no usbfilmhash found!')
+ if usbfilmhash == filmhash:
+ print('same moviefilm found, updating clips...')
+ break
+ else:
+ writemessage('Found a subsequent moviefilm...')
+ print('same film exist with different filmhashes, copying to subsequent film folder')
+ time.sleep(2)
+ usbpath += '_new'
+ try:
+ os.makedirs(usbpath)
+ writemessage('Copying film ' + filmname + '...')
+ except:
+ writemessage('Found existing ' + filmname + ', copying new files... ')
+ try:
+ run_command('rsync -avr -P ' + filmfolder + filmname + '/ ' + usbpath)
+ except:
+ writemessage('couldnt copy film ' + filmname)
+ waitforanykey()
+ return
+ run_command('sync')
+ run_command('pumount /media/usb0')
+ writemessage('all files copied successfully!')
+ waitforanykey()
+ writemessage('You can safely unplug the usb device now')
+ time.sleep(2)
+ return
#-----------Check for the webz---------
@@ -2383,7 +2434,7 @@ def webz_on():
try:
# connect to the host -- tells us if the host is actually
# reachable
- socket.create_connection(("www.google.com", 80))
+ socket.create_connection(("google.com", 80))
return True
except OSError:
pass
@@ -2520,10 +2571,10 @@ def getbutton(lastbutton, buttonpressed, buttontime, holdbutton):
val = term.inkey(timeout=0)
if val.is_sequence:
event = val.name
- print(event)
+ #print(event)
elif val:
event = val
- print(event)
+ #print(event)
else:
event = ''
keydelay = 0.08
@@ -2589,16 +2640,18 @@ def startcamera(lens):
#lensshade = ''
#npzfile = np.load('lenses/' + lens)
#lensshade = npzfile['lens_shading_table']
- table = read_table('lenses/' + lens)
#camera.framerate = 24.999
- v = camera.revision
- camera_model, camera_revision = getconfig(v)
+ camera_model, camera_revision = getconfig(camera)
# v1 = 'ov5647'
# v2 = ?
logger.info("picamera version is: " + camera_model + ' ' + camera_revision)
if camera_model == 'imx219':
+ table = read_table('lenses/' + lens)
+ camera.lens_shading_table = table
camera.framerate = 24.999
if camera_model == 'ov5647':
+ table = read_table('lenses/' + lens)
+ camera.lens_shading_table = table
# Different versions of ov5647 with different clock speeds, need to make a config file
# if there's more frames then the video will be longer when converting it to 25 fps,
# I try to get it as perfect as possible with trial and error.
@@ -2608,12 +2661,13 @@ def startcamera(lens):
# ov5647 Rev D"
if camera_revision == 'rev.D':
camera.framerate = 23.15
+ else:
+ camera.framerate = 24.999
camera.crop = (0, 0, 1.0, 1.0)
camera.video_stabilization = True
camera.led = False
#lens_shading_table = np.zeros(camera._lens_shading_table_shape(), dtype=np.uint8) + 32
#camera.lens_shading_table = lens_shading_table
- camera.lens_shading_table = table
camera.start_preview()
camera.awb_mode = 'auto'
return camera