Keyboard scanner (raspistill spawn and kill, camera effect flag changer)
Code: Select all
# Key scanner for vOICe on Raspberry PI
# This script scans the keyboard for input
# If a valid keypress is detected, it kills the currently running raspistill process
# The keypress is interpreted, from one of four categories:
# exposure mode, AWB mode (light type), image effect, and metering mode
# The keypress will cycle through the possible type within the mode and then wrap back to the first
# additional keys will be defined for other relevant flags as the project progresses
# The raspistill launch string is then built incorporating the latest flag change
# It launches raspistill as a timelapse with a lapse duration of 300ms, and a timeout of five minutes
# It writes the captured files to the ramdrive for the vOICe process to grab from
# Then it returns to looking for a keypress
import subprocess #used for starting and kill raspistill process
import curses #used for keyboard scanning
import os #used to see if a file exists
from os import walk #used for smart renaming
from time import sleep #Lets the process suspend to reduce CPU load.
stdscr = curses.initscr() #set curses to terminal screen
curses.cbreak() #engage keyscanning mode. This WILL NOT WORK in IDLE you have to launch from a terminal
stdscr.keypad(1) #allows use of keypad
x = 1 # just a random variable
#all the string components will have a leading space to make concatenation easier
width = ' -w 176' #image width
height = ' -h 64' #image height
time_lapse = ' -tl 300' #timelapse in milliseconds
time = ' -t 1200000' #length of time for timelapse = 15 minutes or 1200 seconds or 300000 ms
colour_effect = ' -cfx 128:128' #Makes the image monochrome implement this once other things are working
preview = ' -p 100,100,176,64' # preview windows for use in debugging, remove for production
path = ' -o /dev/shm/picture%04d.jpg' #output is to the 16mb ramdrive built into raspbian this saves SD card writes and latency
exposure_list = [' off',' auto',' night',' nightpreview',' backlight',' spotlight',' sports',' snow',' beach',' verylong',' fixedfps',' antishake',' fireworks']
awb_list = [' off',' auto',' sun',' cloud',' shade',' tungsten',' fluorescent',' incandescent',' flash',' horizon']
image_effect_list = [' none',' negative',' solarise',' sketch',' denoise',' oilpaint',' hatch',' gpen',' pastel',' watercolour',' film',' blur',' saturation',' colourswap',' washedout',' posterise',' colourpoint',' colourbalance',' cartoon']
metering_method_list = [' average',' spot',' backlit',' matrix']
exposure_pos = 1 #Set exposure to auto
awb_pos = 1 #set AWB to auto
image_effect_pos = 0 #set image effect to none
metering_method_pos = 0 #set metering method to average
exposure = exposure_list[1] # set to auto
awb = awb_list[2] #set to auto
image_effect = image_effect_list[0]
metering_method = metering_method_list[0]
raspistill_execute = raspistill_execute = "sudo raspistill"+ width + height + colour_effect + time_lapse + time + preview+ path + exposure + awb + image_effect + metering_method #concatenate the string, set the execute string to default values
renamestring = ''
mypath = '/dev/shm/'
# roi = ['roi 0,0,1,1','roi 0.5,0.5,0.25,0.25'] # I believe this will act as a digital zoom by using less of the sensor
key = '' #set initial keypress value to blank
def KillRaspistillProcess():
subprocess.call(["sudo", "pkill", "raspistill"], shell=False) # subprocess allows for the kill command to go through and come back to keyscanning
return()
def LaunchNewRaspistill():
global exposure
global metering_method
global awb
global image_effect
exposure = " -ex" + exposure_list[exposure_pos]
awb = " -awb" + awb_list[awb_pos]
image_effect = " -ifx" + image_effect_list[image_effect_pos]
metering_method = " -mm" + metering_method_list[metering_method_pos]
raspistill_execute = "sudo raspistill"+ width + height + colour_effect + time_lapse + time + preview+ path + exposure + awb + image_effect + metering_method#concatenate the string
#print (raspistill_execute)#print the string for debug purposes
#execute the string with shell = true
subprocess.Popen([raspistill_execute], shell=True) #take the current launch string and execute the timelapse using raspistill
return()
def CycleExposure():
global exposure_pos
exposure_pos = exposure_pos + 1 # increase the current exposure element position in the list
if exposure_pos == 13: # There are 12 exposure elements in the list. If this is exceeded, we must return to position 0
exposure_pos = 0 # return to position 0 is list length has been exceeded
else:
exposure_pos = exposure_pos # if the list length has not been exceeded, proceed with the current setting
exposure = " -ex" + exposure_list[exposure_pos] #Setting exposure for string building
#print ("cycle exposure")
return()
def CycleAWB():
global awb_pos
awb_pos = awb_pos +1
if awb_pos == 10: #see CycleExposure() for comments
awb_pos = 0
else:
awb_pos = awb_pos
awb = " -awb" + awb_list[awb_pos]
#print("cycle awb")
return()
def CycleImageEffect():
global image_effect_pos
image_effect_pos = image_effect_pos + 1
if image_effect_pos == 19:
image_effect_pos = 0
else:
image_effect_pos = image_effect_pos
image_effect = " -ifx" + image_effect_list[image_effect_pos] # more preset for string
#print ("cycle image effect")
return()
def CycleMeteringMethod():
global metering_method_pos
metering_method_pos = metering_method_pos + 1
if metering_method_pos == 4:
metering_method_pos = 0
else:
metering_method_pos = metering_method_pos
metering_method = " -mm" + metering_method_list[metering_method_pos] # more preset for string
#print ("cycle metering method")
return()
# Main keyscanning loop
while key != ord('q'):
curses.halfdelay(10);
key=stdscr.getch()
stdscr.addch(20,25,key)
stdscr.refresh()
f = []
for (dirpath, dirnames, filenames) in walk(mypath):
f.extend(filenames)
break
try:
renamestring = "cp /dev/shm/" + f[1] + " /dev/shm/picture0001.jpg"
except:
pass
try:
print (renamestring)
except:
pass
try:
subprocess.Popen([renamestring], shell=True) #copy recent existing file to picture0001.jpg
except:
pass
sleep (0.1) # sleep 100ms
if key == ord('1'):
KillRaspistillProcess()
CycleExposure()
LaunchNewRaspistill()
elif key == ord('2'):
KillRaspistillProcess()
CycleAWB()
LaunchNewRaspistill()
elif key == ord('3'):
KillRaspistillProcess()
CycleImageEffect()
LaunchNewRaspistill()
elif key == ord('4'):
KillRaspistillProcess()
CycleMeteringMethod()
LaunchNewRaspistill()
else:
x=x+1
curses.endwin()
Code: Select all
/* C program for soundscape generation. (C) P.B.L. Meijer 1996 */
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
#include <math.h>
#include <stdio.h>
const char* FNAME="h01.wav"; /* User-defined parameters */
const int N=64; /* Resolution, i.e., # rows and columns */
const int FL=500; /* Lowest frequency (Hz) in soundscape */
const int FH=5000; /* Highest frequency (Hz) */
const int FS=44100; /* Sample frequency (Hz) */
const double T=1.05; /* Image to sound conversion time (s) */
// non-const, so they can get toggled at startup
int D=1; /* Linear|Exponential=0|1 distribution */
int HIFI=1; /* 8-bit|16-bit=0|1 sound quality */
int STEREO=1; /* Mono|Stereo=0|1 sound selection */
int DELAY=1; /* Nodelay|Delay=0|1 model (STEREO=1) */
int FADE=1; /* Relative fade Yes|No=0|1 (STEREO=1) */
int DIFFR=1; /* Diffraction Yes|No=0|1 (STEREO=1) */
int BSPL=1; /* Rectangular|B-spline=0|1 time window */
const int BW=0; /* 16|2-level=0|1 grey format in *P[] */
#define C_ALLOC(number, type) ((type *) calloc((number),sizeof(type)) )
const double TwoPi=6.283185307179586476925287;
int playSound( char *filename ) {
char command[256]; int status;
/* create command to execute */
sprintf( command, "aplay -i %s", filename ); /* play sound */ status = system( command );
return status;
// return PlaySound(filename,0,SND_FILENAME);
}
FILE *fp; unsigned long ir=0L, ia=9301L, ic=49297L, im=233280L;
void wi(unsigned int i) { int b1,b0; b0=i%256; b1=(i-b0)/256; fputc(b0,fp); fputc(b1,fp); }
void wl(long l) { unsigned int i1,i0; i0=l%65536L; i1=(l-i0)/65536L; wi(i0); wi(i1); }
double rnd(void){ ir = (ir*ia+ic) % im; return ir / (1.0*im); }
int main(int argc, char *argv[])
{
int cam_id = 0; // 1st available opencv camera
// override flags from cmdline : prog.exe [cam_id] [linear] [nodelay], etc. args can be in any order
for ( int a=1; a<argc; a++ )
{
if ( ! strcmp(argv[a],"linear") ) { D = 0; }
else if ( ! strcmp(argv[a],"nohifi") ) { HIFI = 0; }
else if ( ! strcmp(argv[a],"nostereo") ) { STEREO = 0; }
else if ( ! strcmp(argv[a],"nodelay") ) { DELAY = 0; }
else if ( ! strcmp(argv[a],"nofade") ) { FADE = 0; }
else if ( ! strcmp(argv[a],"nodiffr") ) { DIFFR = 0; }
else if ( ! strcmp(argv[a],"nobspl") ) { BSPL = 0; }
else cam_id = atoi(argv[a]);
}
//beginning of main function
//start of opencv variables
VideoCapture cap; //handle camera capture
Mat gray,frame; //image matrices
//end of opencv variables
//variables for soundscape generation (initialization)
int i, j, d=D, ss;
long k=0L, l, ns=2L*(long)(0.5*FS*T), m=ns/N;
double **A, a, t, dt=1.0/FS, *w, *phi0, s, y, yp, z, tau1, tau2, x, theta,
scale=0.5/sqrt(double(N)), q, q2, r, sl, sr, tl, tr, yl, ypl, yr, ypr,
zl, zr, hrtf, hrtfl, hrtfr, v=340.0, /* v = speed of sound (m/s) */
hs=0.20; /* hs = characteristic acoustical size of head (m) */
w = C_ALLOC(N, double);
phi0 = C_ALLOC(N, double);
A = C_ALLOC(N, double *);
for (i=0; i<N; i++) A[i] = C_ALLOC(N, double); /* N x N pixel matrix */
//end of variables for soundscape generation (initialization)
/* Set lin|exp (0|1) frequency distribution and random initial phase */
if (d) for (i=0; i<N; i++) w[i] = TwoPi * FL * pow(1.0* FH/FL,1.0*i/(N-1));
else for (i=0; i<N; i++) w[i] = TwoPi * FL + TwoPi * (FH-FL) *i/(N-1) ;
for (i=0; i<N; i++) phi0[i] = TwoPi * rnd();
//end of frequency randomization
/*start video capture and image downsampling for feeding into matrix contained in variable A*/
// device ids
//converting to a file based capturing system
bool ok = true;
//create a main while loop that handles keyboard input
while(ok)
{//start of keyboard while loop
//take the image to sonify
/*takePiImage();*/
//read image file from disk for sonification
getframe:
frame=imread("/dev/shm/picture0001.jpg",CV_LOAD_IMAGE_UNCHANGED);
//save image after height and width reduction to disk
//imwrite("h01Shrunk.jpg",frame);
if ( frame.empty() )
{
//fprintf(stderr,"No image.");
usleep(50);
goto getframe;
return 1;
}
//temp overwrite frame with image for testing
//frame=imread("lineflat.jpg",CV_LOAD_IMAGE_COLOR);
//reduce to gray scale
Mat tmp;
cvtColor(frame,tmp,CV_BGR2GRAY);
//actually resize to NxN
if ( frame.rows != N )
resize( tmp, gray, Size(N,N) );
else
gray=tmp;
//save grayscale image to disk for debugging
//imwrite("h01Gray.jpg",gray);
//feed data into matrix overwriting the hard coded image
for(int rws=0;rws<N;rws++)
{//start of matrix population for loop for rows
for(int cols=0;cols<N;cols++)
{//start of matrix population for loop for columns
double mVal=gray.at<uchar>(rws,cols)/16;
A[rws][cols]=mVal;
}//end of matrix population for loop for columns
}//end of matrix population for loop for rows
/*end video capture and image downsampling for feeding into matrix contained in variable A*/
// moved this into the loop, so you can toggle flags
long sso=HIFI?0L:128L, ssm=HIFI?32768L:128L;
int HIST = (1+HIFI)*(1+STEREO);
/* Write 8/16-bit mono/stereo .wav file, using rectangular time window */
fp = fopen(FNAME,"wb"); fprintf(fp,"RIFF"); wl(ns*HIST+36L);
fprintf(fp,"WAVEfmt "); wl(16L); wi(1); wi(STEREO?2:1); wl(0L+FS);
wl(0L+FS*HIST); wi(HIST); wi(HIFI?16:8); fprintf(fp,"data"); wl(ns*HIST);
tau1 = 0.5 / w[N-1]; tau2 = 0.25 * tau1*tau1;
y = yl = yr = z = zl = zr = 0.0;
/* Not optimized for speed */
while (k < ns && !STEREO) {
if (BSPL) { q = 1.0 * (k%m)/(m-1); q2 = 0.5*q*q; }
j = k / m; if (j>N-1) j=N-1; s = 0.0; t = k * dt;
if (k < ns/(5*N)) s = (2.0*rnd()-1.0) / scale; /* "click" */
else for (i=0; i<N; i++) {
if (BSPL) { /* Quadratic B-spline for smooth C1 time window */
if (j==0) a = (1.0-q2)*A[i][j]+q2*A[i][j+1];
else if (j==N-1) a = (q2-q+0.5)*A[i][j-1]+(0.5+q-q2)*A[i][j];
else a = (q2-q+0.5)*A[i][j-1]+(0.5+q-q*q)*A[i][j]+q2*A[i][j+1];
}
else a = A[i][j];
s += a * sin(w[i] * t + phi0[i]);
}
yp = y; y = tau1/dt + tau2/(dt*dt);
y = (s + y * yp + tau2/dt * z) / (1.0 + y); z = (y - yp) / dt;
l = sso + 0.5 + scale * ssm * y; /* y = 2nd order filtered s */
if (l >= sso-1+ssm) l = sso-1+ssm; if (l < sso-ssm) l = sso-ssm;
ss = (unsigned int) l;
if (HIFI) wi(ss); else fputc(ss,fp);
k++;
}
while (k < ns && STEREO) {
if (BSPL) { q = 1.0 * (k%m)/(m-1); q2 = 0.5*q*q; }
j = k / m; if (j>N-1) j=N-1;
r = 1.0 * k/(ns-1); /* Binaural attenuation/delay parameter */
theta = (r-0.5) * TwoPi/3; x = 0.5 * hs * (theta + sin(theta));
tl = tr = k * dt; if (DELAY) tr += x / v; /* Time delay model */
x = fabs(x); sl = sr = 0.0; hrtfl = hrtfr = 1.0;
for (i=0; i<N; i++) {
if (DIFFR) {
/* First order frequency-dependent azimuth diffraction model */
if (TwoPi*v/w[i] > x) hrtf = 1.0; else hrtf = TwoPi*v/(x*w[i]);
if (theta < 0.0) { hrtfl = 1.0; hrtfr = hrtf; }
else { hrtfl = hrtf; hrtfr = 1.0; }
}
if (FADE) {
/* Simple frequency-independent relative fade model */
hrtfl *= (1.0-0.7*r);
hrtfr *= (0.3+0.7*r);
}
if (BSPL) {
if (j==0) a = (1.0-q2)*A[i][j]+q2*A[i][j+1];
else if (j==N-1) a = (q2-q+0.5)*A[i][j-1]+(0.5+q-q2)*A[i][j];
else a = (q2-q+0.5)*A[i][j-1]+(0.5+q-q*q)*A[i][j]+q2*A[i][j+1];
}
else a = A[i][j];
sl += hrtfl * a * sin(w[i] * tl + phi0[i]);
sr += hrtfr * a * sin(w[i] * tr + phi0[i]);
}
if (k < ns/(5*N)) sl = (2.0*rnd()-1.0) / scale; /* Left "click" */
if (tl < 0.0) sl = 0.0;
if (tr < 0.0) sr = 0.0;
ypl = yl; yl = tau1/dt + tau2/(dt*dt);
yl = (sl + yl * ypl + tau2/dt * zl) / (1.0 + yl); zl = (yl - ypl) / dt;
ypr = yr; yr = tau1/dt + tau2/(dt*dt);
yr = (sr + yr * ypr + tau2/dt * zr) / (1.0 + yr); zr = (yr - ypr) / dt;
l = sso + 0.5 + scale * ssm * yl;
if (l >= sso-1+ssm) l = sso-1+ssm; if (l < sso-ssm) l = sso-ssm;
ss = (unsigned int) l;
if (HIFI) wi(ss); else fputc(ss,fp); /* Left channel */
l = sso + 0.5 + scale * ssm * yr;
if (l >= sso-1+ssm) l = sso-1+ssm; if (l < sso-ssm) l = sso-ssm;
ss = (unsigned int) l;
if (HIFI) wi(ss); else fputc(ss,fp); /* Right channel */
k++;
}
fclose(fp);
//play the soundscape using aplay
system ("sudo rm /dev/shm/*.*"); //delete files in directory to ensure latest frame the python script will rename the latest frame that is generated while the sound plays
int pps=playSound("h01.wav");
int rFile=remove("h01.jpg");
rFile=remove("h01.wav");
k=0; //reset the sample count to allow while loop to execute
}//end of keyboard while loop
printf("normal exit. \n");
return(0);
}//end of main function
every now and then an incomplete jpeg is accessed by the C program, but it doesn't have a major effect.
The time between frames is still 5-7 seconds.
I am going to investigate some speedup things mentioned earlier in the next little while to see what can happen.