|
#!/usr/bin/env python |
|
"""max-osc-python.py : demonstration of a service node communicating parameters and data with Max via OSC messaging. |
|
|
|
Copyright (c) 2014-2017, Garth Zeglin. All rights reserved. Provided under the |
|
terms of the BSD 3-clause license. |
|
|
|
This uses txosc and Twisted to send and receive OSC messages. |
|
""" |
|
|
|
|
|
# references: |
|
# https://docs.scipy.org/doc/numpy/ |
|
# https://bitbucket.org/arjan/txosc/wiki/Home |
|
# https://twistedmatrix.com/trac/wiki/Documentation |
|
|
|
# standard Python modules |
|
from __future__ import print_function |
|
import time, argparse, random |
|
|
|
# NumPy system for numeric and matrix computation |
|
import numpy as np |
|
|
|
# Twisted networking framework |
|
import twisted.internet.reactor |
|
import twisted.internet.task |
|
import twisted.internet.protocol |
|
|
|
# TxOSC OpenSoundControl library |
|
import txosc.osc |
|
import txosc.dispatch |
|
import txosc.async |
|
|
|
from PIL import Image, ImageFilter, ImageChops |
|
import numpy as np |
|
import cv2 |
|
import matplotlib.pyplot as plt |
|
|
|
import time |
|
import os.path |
|
|
|
|
|
############ |
|
|
|
#----- Parameters ------ |
|
N_image1 = 5 |
|
N_image2 = np.arange(0, N_image1, 1) # [0,1,2] num of images |
|
N_image3 = np.arange(0, N_image1-1, 1) # [0,1] num of diff |
|
plot = 1 # 1: plot on, 0: plot off |
|
#----------------------- |
|
|
|
|
|
|
|
#---------------------------------------------- |
|
if os.path.exists("./output2.txt"): |
|
print ("output2.txt exists") |
|
if not os.path.exists("./output2.txt"): |
|
print("\n-----------------------------------") |
|
print("image loading....") |
|
img_pixels = [] |
|
for i in N_image2: |
|
str = ("%d" % i) |
|
print("alos_" + str + ".jpg") |
|
img = Image.open("alos_" + str + ".jpg") |
|
|
|
grey_img = img.convert('L') |
|
width, height = grey_img.size |
|
print ("width, height =", width, height) |
|
img_pixels.append(np.array([[grey_img.getpixel((j,m)) for j in range(width)] for m in range(height)])) |
|
#plt.imshow(img_pixels[i]) |
|
#plt.show() |
|
|
|
for i in N_image2: |
|
print("---img", i) |
|
print(img_pixels[i]) |
|
|
|
|
|
|
|
|
|
#---------------------------------------------- |
|
|
|
print("\n-----------------------------------") |
|
print("image subtracting....") |
|
sub = [] |
|
for i in N_image3: |
|
sub.append(img_pixels[i+1] - img_pixels[i]) |
|
|
|
for i in N_image3: |
|
print("---sub", i) |
|
print(sub[i]) |
|
|
|
|
|
|
|
|
|
#---------------------------------------------- |
|
|
|
print("\n-----------------------------------") |
|
print("Finding out significantly changes....") |
|
sub_data2 = [] |
|
sum = [] |
|
ave = [] |
|
N_pixels = height*width |
|
print ("N_pixels =", N_pixels) |
|
print ("width, height =", width, height) |
|
for i in N_image3: |
|
sub_data1 = [] # initialize |
|
print ("subbbbb", i) |
|
sum.append(np.sum(sub[i])) |
|
ave.append(np.average(sub[i])) |
|
for y in range(0,height): |
|
for x in range(0,width): |
|
#print (sub[i][y][x]) |
|
sub_data1.append(sub[i][y][x]) |
|
#print(sub_data1) |
|
sub_data2.append(sub_data1) |
|
|
|
|
|
|
|
|
|
sigma = [] |
|
for i in N_image3: |
|
sigma2 = 0 # initialize |
|
for n in range(0,N_pixels): |
|
sigma2 += np.power(sub_data2[i][n]-ave[i], 2) |
|
sigma.append(np.power(sigma2/N_pixels, 0.5)) |
|
|
|
for i in N_image3: |
|
print ("---sub", i) |
|
print ("sum =", sum[i]) |
|
print ("ave =", ave[i]) |
|
print ("sigma = %.5e" % sigma[i]) |
|
#print (sub_data2[i]) |
|
|
|
|
|
|
|
# brighter (red) |
|
x_b2, y_b2, sub_b2 = [], [], [] |
|
sound_b2, count_b2 = [], [] |
|
max_x_b2, max_y_b2 = [], [] |
|
for i in N_image3: |
|
x_b1 = [] #initialize |
|
y_b1 = [] #initialize |
|
sub_b1 = [] #initialize |
|
sound_b1 = 0 #initialize |
|
count_b1 = 0 #initialize |
|
maxim = 0 |
|
max_x_b1 = 0 |
|
max_y_b1 = 0 |
|
for y in range(0,height): |
|
for x in range(0,width): |
|
if (sub[i][y][x] >= ave[i] + 3*sigma[i]): |
|
if sub[i][y][x] >= maxim: |
|
maxim = sub[i][y][x] |
|
max_x_b1 = x |
|
max_y_b1 = y |
|
x_b1.append(x) |
|
y_b1.append(y) |
|
sub_b1.append(sub[i][y][x]) |
|
sound_b1 += sub[i][y][x] |
|
count_b1 += 1 |
|
x_b2.append(x_b1) |
|
y_b2.append(y_b1) |
|
sub_b2.append(sub_b1) |
|
sound_b2.append(sound_b1) |
|
count_b2.append(count_b1) |
|
max_x_b2.append(max_x_b1) |
|
max_y_b2.append(max_y_b1) |
|
|
|
|
|
#print (max(sub_b2)) |
|
|
|
# darker (blue) |
|
x_d2, y_d2, sub_d2 = [], [], [] |
|
sound_d2, count_d2 = [], [] |
|
max_x_d2, max_y_d2 = [], [] |
|
for i in N_image3: |
|
x_d1 = [] #initialize |
|
y_d1 = [] #initialize |
|
sub_d1 = [] #initialize |
|
sound_d1 = 0 #initialize |
|
count_d1 = 0 #initialize |
|
maxim = 0 |
|
for y in range(0,height): |
|
for x in range(0,width): |
|
if (sub[i][y][x] <= ave[i] - 3*sigma[i]): |
|
if -sub[i][y][x] >= maxim: |
|
maxim = -sub[i][y][x] |
|
max_x_d1 = x |
|
max_y_d1 = y |
|
x_d1.append(x) |
|
y_d1.append(y) |
|
sub_d1.append(sub[i][y][x]) |
|
sound_d1 += - sub[i][y][x] |
|
count_d1 += 1 |
|
x_d2.append(x_d1) |
|
y_d2.append(y_d1) |
|
sub_d2.append(sub_d1) |
|
sound_d2.append(sound_d1) |
|
count_d2.append(count_d1) |
|
max_x_d2.append(max_x_d1) |
|
max_y_d2.append(max_y_d1) |
|
|
|
|
|
#---------------------------------------------- |
|
|
|
f1 = open('output.txt', 'w') |
|
|
|
|
|
# bright |
|
print("\n-----------------------------------") |
|
print("Converting to sounds (1)....") |
|
delta_sound_b = max(sound_b2)-min(sound_b2)+1e-10 # prevent dividing by 0 |
|
print(delta_sound_b) |
|
delta_count_b = max(count_b2)-min(count_b2)+1e-10 |
|
delta_max_x_b = max(max_x_b2)-min(max_x_b2)+1e-10 |
|
delta_max_y_b = max(max_y_b2)-min(max_y_b2)+1e-10 |
|
|
|
Norm_sound_b, Norm_count_b = [], [] |
|
max_x_b, max_y_b = [], [] |
|
for i in N_image3: |
|
Norm_sound_b.append((sound_b2[i] - min(sound_b2))/delta_sound_b) |
|
Norm_count_b.append((count_b2[i] - min(count_b2))/delta_count_b) |
|
max_x_b.append((max_x_b2[i] - min(max_x_b2))/delta_max_x_b) |
|
max_y_b.append((max_y_b2[i] - min(max_y_b2))/delta_max_y_b) |
|
for i in N_image3: |
|
print ("---sub", i) |
|
print ("sound", sound_b2[i]) |
|
print ("count", count_b2[i]) |
|
print ("Normalized sound = %.2f" % Norm_sound_b[i]) |
|
print ("Normalized count = %.2f" % Norm_count_b[i]) |
|
|
|
|
|
|
|
# dark |
|
print("\n-----------------------------------") |
|
print("Converting to sounds (2)....") |
|
delta_sound_d = max(sound_d2)-min(sound_d2)+1e-10 |
|
delta_count_d = max(count_d2)-min(count_d2)+1e-10 |
|
delta_max_x_d = max(max_x_d2)-min(max_x_d2)+1e-10 |
|
delta_max_y_d = max(max_y_d2)-min(max_y_d2)+1e-10 |
|
|
|
Norm_sound_d, Norm_count_d = [], [] |
|
max_x_d, max_y_d = [], [] |
|
for i in N_image3: |
|
Norm_sound_d.append((sound_d2[i] - min(sound_d2))/delta_sound_d) |
|
Norm_count_d.append((count_d2[i] - min(count_d2))/delta_count_d) |
|
max_x_d.append((max_x_d2[i] - min(max_x_d2))/delta_max_x_d) |
|
max_y_d.append((max_y_d2[i] - min(max_y_d2))/delta_max_y_d) |
|
|
|
list = [] |
|
for i in N_image3: |
|
print ("---sub", i) |
|
print ("sound", sound_d2[i]) |
|
print ("count", count_d2[i]) |
|
print ("Normalized sound = %.2f" % Norm_sound_d[i]) |
|
print ("Normalized count = %.2f" % Norm_count_d[i]) |
|
NSB = ("%.3f" % Norm_sound_b[i]) |
|
NCB = ("%.3f" % Norm_count_b[i]) |
|
NSD = ("%.3f" % Norm_sound_d[i]) |
|
NCD = ("%.3f" % Norm_count_d[i]) |
|
#print(NSB, NCB, NSD, NCD) |
|
str = '%.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f\n' % (abs(Norm_sound_b[i]), abs(Norm_count_b[i]), abs(Norm_sound_d[i]), abs(Norm_count_d[i]), max_x_b[i], max_y_b[i], max_x_d[i], max_y_d[i]) |
|
f1.write(str) |
|
|
|
f1.close() |
|
|
|
#----- Plotting ------- |
|
if plot==1: |
|
for i in N_image3: |
|
plt.imshow(sub[i]) |
|
#plt.imshow(img_pixels[i]) |
|
|
|
CB = plt.colorbar() |
|
CB.formatter.set_scientific(True) |
|
CB.formatter.set_powerlimits((0,0)) |
|
CB.update_ticks() |
|
#CB.ax.ticklabel_format(style='sci', scilimits=(0,0)) |
|
CB.set_label('color bar') |
|
|
|
plt.title("Difference") |
|
#plt.xlabel("RA. [pixel]") |
|
#plt.ylabel("DEC. [pixel]") |
|
plt.plot(x_d2[i], y_d2[i], 'bo', markersize=3) |
|
plt.plot(x_b2[i], y_b2[i], 'ro', markersize=3) |
|
#plt.xlim([-0.5,width-0.5]) |
|
plt.show() |
|
#----------------------- |
|
|
|
# print("x_b2, y_b2") |
|
# print(x_b2, y_b2) |
|
# print("x_d2, y_d2") |
|
# print(x_d2, y_d2) |
|
############# |
|
|
|
|
|
#----- Plotting ------- |
|
|
|
|
|
|
|
|
|
arr = np.loadtxt("output.txt", delimiter=" ", dtype="float") |
|
arrT = np.array(arr.T) |
|
print(arr.T) |
|
np.savetxt('output2.txt', arr.T, fmt ='%.3f') |
|
|
|
|
|
|
|
|
|
|
|
base_time = time.time() |
|
|
|
# The associated Max patcher assumes that the Python node sends and receives using the following UDP port numbers: |
|
PYTHON_NODE_RECV_PORT = 12001 |
|
PYTHON_NODE_SEND_PORT = 12000 |
|
|
|
################################################################ |
|
class OscServer(object): |
|
"""The OscServer class holds all the application state: communication ports, |
|
message callback assignments, and dynamic parameters.""" |
|
|
|
def __init__(self, recv_port = PYTHON_NODE_RECV_PORT, send_port = PYTHON_NODE_SEND_PORT, verbose = False): |
|
|
|
self.verbose = verbose |
|
self.recv_portnum = recv_port |
|
self.send_portnum = send_port |
|
self._reactor = None |
|
self._ping_count = 0 |
|
|
|
# set default generator parameters |
|
self._reset_parameters() |
|
return |
|
|
|
def _reset_parameters(self): |
|
self._xfreq = 1 |
|
self._yfreq = 1 |
|
self._xphase = 0.0 |
|
self._yphase = 0.0 |
|
|
|
def listen( self, reactor ): |
|
"""The listen method is called to establish the UDP ports to receive and send OSC messages.""" |
|
self._reactor = reactor |
|
self.receiver = txosc.dispatch.Receiver() |
|
self._server_protocol = txosc.async.DatagramServerProtocol(self.receiver) |
|
self._server_port = reactor.listenUDP(self.recv_portnum, self._server_protocol, maxPacketSize=60000) |
|
if self.verbose: print( "Listening on osc.udp://localhost:%s", self.recv_portnum ) |
|
|
|
self._client_protocol = txosc.async.DatagramClientProtocol() |
|
self._client_port = reactor.listenUDP(0, self._client_protocol, maxPacketSize=60000) |
|
if self.verbose: print( "Ready to send using %s" % self._client_port) |
|
|
|
# Set up the OSC message handling system. As a convention for |
|
# legibility, the message callback methods have msg_ prepended to the |
|
# message, but this is not required. |
|
|
|
# Assign methods to receive messages intended for debugging the system. |
|
self.receiver.addCallback( "/reset", self.msg_reset ) |
|
self.receiver.addCallback( "/quit", self.msg_quit ) |
|
self.receiver.addCallback( "/ping", self.msg_ping ) |
|
|
|
# Assign methods to receive parameter control messages. |
|
self.receiver.addCallback( "/xfreq", self.msg_xfreq) |
|
self.receiver.addCallback( "/yfreq", self.msg_yfreq) |
|
|
|
# Assign methods to receive other event functions. |
|
self.receiver.addCallback( "/nextframe", self.msg_nextframe) |
|
|
|
# Assign a default function to receive any other OSC message. |
|
self.receiver.fallback = self.msg_fallback |
|
|
|
return |
|
|
|
#### Message handlers. ############################################ |
|
|
|
|
|
# Define a default handler for any unmatched message address. |
|
def msg_fallback(self, message, address): |
|
print("Received OSC message with unhandled address '%s' from %s: %s" % (message.address, address, message.getValues())) |
|
return |
|
|
|
def msg_reset( self, message, address): |
|
if self.verbose: print("Receive reset request.") |
|
self._reset_parameters() |
|
return |
|
|
|
def msg_quit( self, message, address): |
|
if self.verbose: print( "Received quit request, shutting down." ) |
|
self._reactor.stop() |
|
|
|
def msg_ping( self, message, address): |
|
if self.verbose: print("Received ping request.") |
|
|
|
# reply to the IP address from which the message was received |
|
send_host = address[0] |
|
|
|
self._ping_count += 1 |
|
self._client_protocol.send( txosc.osc.Message("/pong", self._ping_count), (send_host, self.send_portnum)) |
|
return |
|
|
|
def msg_xfreq( self, message, address): |
|
self._xfreq = message.getValues()[0] |
|
if self.verbose: print("xfreq now %s" % self._xfreq) |
|
return |
|
|
|
def msg_yfreq( self, message, address): |
|
self._yfreq = message.getValues()[0] |
|
if self.verbose: print("yfreq now %s" % self._yfreq) |
|
return |
|
|
|
def msg_nextframe( self, message, address): |
|
#----parameters---- |
|
N_variance = 8 |
|
music_length = 10 #sec |
|
freq = 1 #sec |
|
#------------------ |
|
|
|
if self.verbose: print("Generating next frame.") |
|
|
|
|
|
# create a two-channel trajectory signal as a 2xN array |
|
cols = N_variance |
|
rows = 1 # output each row in order |
|
trajectory = np.ndarray((rows, cols), dtype=np.float32) |
|
|
|
# create index array for calculating functions |
|
#tt = np.linspace(0.0, 1.0, cols, dtype=np.float32) |
|
|
|
data_x = np.loadtxt("output2.txt", comments="#", delimiter=' ') |
|
|
|
# compute two sets of trajectory samples |
|
|
|
#print(data_x) |
|
#for i in range (0,len(data_x[:,0])): |
|
|
|
if (time.time()-base_time) < music_length: |
|
print("num of diff", N_image1-1) |
|
for i in range (0,N_image1-1): |
|
print("\n---", i, "---") |
|
raw = [] |
|
for n in range (0,N_variance): |
|
raw.append(data_x[n,i]) |
|
#print (data_x[n,i]) |
|
print("raw",raw) |
|
trajectory[0,:] = raw |
|
|
|
|
|
# Reformat the trajectory for sending as an OSC message. The txosc Message |
|
# class doesn't recognize numpy values, so the pixel values are |
|
# converted to an ordinary Python list of numbers. The transpose is |
|
# used to re-order the values so each plane is sent in succession. |
|
samples = [float(value) for value in trajectory.flat] |
|
msg = txosc.osc.Message("/trajectory", cols, rows, *samples) |
|
|
|
# send the trajectory back to the source of the request |
|
send_host = address[0] |
|
self._client_protocol.send( msg, (send_host, self.send_portnum)) |
|
time.sleep(freq) |
|
|
|
|
|
print ("time passed", time.time()-base_time) |
|
|
|
|
|
|
|
return |
|
""" |
|
while True: |
|
for i in range (0,N_image1-1): |
|
raw = [] |
|
for n in range (0,N_variance): |
|
raw.append(data_x[n,i]) |
|
print (data_x[n,i]) |
|
#print("raw",raw) |
|
trajectory[0,:] = raw |
|
|
|
|
|
print("Hello") |
|
|
|
# Reformat the trajectory for sending as an OSC message. The txosc Message |
|
# class doesn't recognize numpy values, so the pixel values are |
|
# converted to an ordinary Python list of numbers. The transpose is |
|
# used to re-order the values so each plane is sent in succession. |
|
samples = [float(value) for value in trajectory.flat] |
|
msg = txosc.osc.Message("/trajectory", cols, rows, *samples) |
|
|
|
# send the trajectory back to the source of the request |
|
send_host = address[0] |
|
self._client_protocol.send( msg, (send_host, self.send_portnum)) |
|
print("pushexit") |
|
comand = str(input()) |
|
if comand == "exit": |
|
break |
|
return |
|
""" |
|
|
|
################################################################ |
|
|
|
# Script entry point. |
|
if __name__ == "__main__": |
|
parser = argparse.ArgumentParser( description = """Demonstration of a UDP OSC node which can communicate with Max.""") |
|
parser.add_argument( '--verbose', action='store_true', help = 'Emit debugging output.') |
|
args = parser.parse_args() |
|
|
|
# Set up the txosc UDP port listening for requests. |
|
osc_server = OscServer( verbose=args.verbose ) |
|
osc_server.listen( twisted.internet.reactor ) |
|
|
|
# Start the Twisted event loop. |
|
twisted.internet.reactor.run() |
|
|
|
if args.verbose: print("Event loop exited.") |