PythonからArduinoにシリアル通信でデータを送る
Pythonからシリアル通信でArduinoにデータを送り、LEDの明るさを制御する。 Arduinoには、D13とGRDにLEDを接続する。
Pythonでのシリアル通信には、pySerialライブラリが必要。
$ pip install pyserial
以下、コード。 PythonからArduinoに数値を送るときは、chr()で変換する。
Arduino
int v = 0;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
pinMode(13, OUTPUT);
}
void loop() {
// put your main code here, to run repeatedly:
if(Serial.available() > 0){
v = Serial.read();
}
int ms = map(v, 0, 255, 0, 10);
digitalWrite(13, HIGH);
delay(10 - ms);
digitalWrite(13, LOW);
delay(ms);
}
Python
#! -*- coding: utf-8 -*-
import serial
import time
ser = serial.Serial('/dev/tty.usbmodem1411', 9600)
v = 0
vc = 1
while True:
v += vc
if v > 255:
v = 0
print v
ser.write(chr(v))
time.sleep(0.02)
Museで取得した脳波に基づき,ArduinoでLEDを光らせる
脳波ヘッドバンドのMuseで脳波から集中度を所得し,その値をProcessingでArduinoに送ってLEDの明るさを変化させる. MuseはPCとBluetooth接続し,ターミナルから以下のコマンドを実行する.
$ muse-io --device Muse-XXXX --osc osc.udp://localhost:5000
LEDはArduinoのGRDとD13に接続する.
Processing
/**
*
* Before running this program,you need to launch
* MuseIO by below command in your terminal.
*
* $ muse-io --device Muse-XXXX --osc osc.udp://localhost:5000
*/
import processing.serial.*;
import oscP5.*;
OscP5 oscP5;
Serial serial;
float concentration = 0;
void setup(){
size(300, 300);
noStroke();
fill(255, 20, 147);
oscP5 = new OscP5(this, 5000);
serial = new Serial(this, "/dev/tty.usbmodem1411", 9600);
}
void draw(){
background(64);
float radious = map(concentration, 0, 1, 50, 300);
ellipse(width/2, height/2, radious, radious);
println(concentration);
serial.write(int(map(concentration, 0, 1, 0, 255)));
}
void oscEvent(OscMessage msg){
if(msg.checkAddrPattern("/muse/elements/experimental/concentration")){
concentration = msg.get(0).floatValue();
}
}
Arduino
int v = 0;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
pinMode(13, OUTPUT);
}
void loop() {
// put your main code here, to run repeatedly:
if(Serial.available() > 0){
v = Serial.read();
}
int ms = map(v, 0, 255, 0, 10);
digitalWrite(13, HIGH);
delay(ms);
digitalWrite(13, LOW);
delay(10 - ms);
}
Arduino/signal_from_muse_to_arduino_via_processing at master · aa-debdeb/Arduino
シリアル通信でProcessingからArduinoに信号を送る
Processingでマウスのx座標を取得して,その値をシリアル通信でArduinoに送り,LEDの明るさとして表示する. ArduinoのGRDとD13にLEDを接続する.
Processing
import processing.serial.*;
Serial serial;
void setup(){
size(500,200);
stroke(128);
strokeWeight(1);
serial = new Serial(this, "/dev/tty.usbmodem1411", 9600);
}
void draw(){
background(255);
line(mouseX, 0, mouseX, height);
serial.write(int(map(mouseX, 0, width, 0, 255)));
}
Arduino
int v = 0;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
pinMode(13, OUTPUT);
}
void loop() {
// put your main code here, to run repeatedly:
if(Serial.available() > 0){
v = Serial.read();
}
int ms = map(v, 0, 255, 0, 10);
digitalWrite(13, HIGH);
delay(10 - ms);
digitalWrite(13, LOW);
delay(ms);
}
Arduino/signal_from_processing_to_arduino at master · aa-debdeb/Arduino
シリアル通信でArduinoからProcessingに信号を送る
シリアル通信でArduinoに接続した可変抵抗器の値をProcessingに送り,Processing上で円の大きさとして可視化する. 可変抵抗器はGRDと5V,A0に接続する.
Processing
import processing.serial.*;
Serial serial;
float diameter = 0;
void setup(){
size(300, 300);
noStroke();
fill(255, 20, 147);
serial = new Serial(this, "/dev/tty.usbmodem1411", 9600);
}
void draw(){
background(64);
ellipse(width/2, height/2, diameter, diameter);
}
void serialEvent(Serial p){
int v = p.read();
diameter = map(v, 0, 255, 50, 300);
println(v, diameter);
}
Arduino
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
}
void loop() {
// put your main code here, to run repeatedly:
Serial.write(map(analogRead(A0), 0, 1023, 0, 255));
}
Arduino/signal_from_arduino_to_processing at master · aa-debdeb/Arduino
Arduinoで可変抵抗器により圧電スピーカーの音の高さを制御する
Arduinoで可変抵抗器により,圧電スピーカーから出力する音の高さを制御する.可変抵抗器の左右をGRDと5Vに,真ん中をA0に接続する.スピーカーはGRDとD12に接続する.
#define DX 12
void mtone(int dx, int hz, unsigned long tm){
unsigned long t = millis();
unsigned long ns = (long)500000 / hz;
while(millis() - t < tm){
digitalWrite(dx, HIGH);
delayMicroseconds(ns);
digitalWrite(dx, LOW);
delayMicroseconds(ns);
}
}
void setup() {
// put your setup code here, to run once:
pinMode(DX, OUTPUT);
}
void loop(){
float hz = map(analogRead(A0), 0, 1023, 0, 8000);
mtone(DX, hz, 50);
}
Museで取得した脳波データをProcessingで可視化する
Museという瞑想用の脳波計がある. MUSE ™ | Meditation Made Easy
このMuseはiOS,Android用のSDKが公開されている他,MacやWindows向けにResearch Toolsが提供されている. Muse: the brain sensing headband Developer Portal
今回は,Mac用のResearch Toolsを用いて,脳波データをProcessingで可視化するプログラムを作成した. プログラムを走らせる前に,PCとMuseをBluetoothで繋いで,ターミナルから以下のコマンドでMuseIOを実行する必要がある.
muse-io --device Muse-XXXX --osc osc.udp://localhost:5000
基本的には,OSC(Open Sound Control)プロトコルが使えるプログラミング言語なら,どれでもデータを扱えるよう.
/**
* Muse Visualizer
*
* @author aa_debdeb
* @date 2015/12/21
*
* Before running this program,you need to launch
* MuseIO by below command in your terminal.
*
* $ muse-io --device Muse-XXXX --osc osc.udp://localhost:5000
*
*/
import oscP5.*;
OscP5 oscP5;
color bgColor = color(32);
color baseColor = color(128);
color[] chColor = {color(0, 139, 139), color(50, 205, 50), color(255, 140, 0), color(199, 21, 133)};
ArrayList[] rawEEG;
float[] accelerometer;
float[][] rawFFT;
float[] lowFreqAbs;
float[] deltaAbs;
float[] thetaAbs;
float[] alphaAbs;
float[] betaAbs;
float[] gammaAbs;
int blink;
int jawClench;
float concentration;
float mellow;
void setup(){
size(800, 600);
smooth();
frameRate(60);
textSize(10);
textAlign(CENTER);
oscP5 = new OscP5(this, 5000);
rawEEG = new ArrayList[4];
for(int i = 0; i < 4; i++){
rawEEG[i] = new ArrayList();
for(int j = 0; j < 300; j++){
rawEEG[i].add(1600.0);
}
}
accelerometer = new float[3];
rawFFT = new float[4][129];
lowFreqAbs = new float[4];
deltaAbs = new float[4];
thetaAbs = new float[4];
alphaAbs = new float[4];
betaAbs = new float[4];
gammaAbs = new float[4];
blink = 0;
jawClench = 0;
concentration = 0.0;
mellow = 0.0;
}
void draw(){
background(bgColor);
noFill();
stroke(chColor[0]);
drawRawEEG(rawEEG[0], 25, 25, 362.5, 50);
stroke(chColor[1]);
drawRawEEG(rawEEG[1], 412.5, 25, 362.5, 50);
stroke(chColor[2]);
drawRawEEG(rawEEG[2], 25, 175, 362.5, 50);
stroke(chColor[3]);
drawRawEEG(rawEEG[3], 412.5, 175, 362.5, 50);
noStroke();
fill(chColor[0]);
drawRawFFT(rawFFT[0], 25, 100, 362.5, 50);
fill(chColor[1]);
drawRawFFT(rawFFT[1], 412.5, 100, 362.5, 50);
fill(chColor[2]);
drawRawFFT(rawFFT[2], 25, 250, 362.5, 50);
fill(chColor[3]);
drawRawFFT(rawFFT[3], 412.5, 250, 362.5, 50);
drawAbsBandPower(lowFreqAbs, 25, 350, 115, 100);
drawAbsBandPower(deltaAbs, 152, 350, 115, 100);
drawAbsBandPower(thetaAbs, 279, 350, 115, 100);
drawAbsBandPower(alphaAbs, 406, 350, 115, 100);
drawAbsBandPower(betaAbs, 533, 350, 115, 100);
drawAbsBandPower(gammaAbs, 660, 350, 115, 100);
fill(baseColor);
text("low freqs(1~8Hz)", 25, 340, 115, 100);
text("delta(1~4Hz)", 152, 340, 115, 100);
text("theta(5~8Hz)", 279, 340, 115, 100);
text("alpha(9~13Hz)", 406, 340, 115, 100);
text("beta(12~30Hz)", 533, 340, 115, 100);
text("gamma(30~50Hz)", 660, 340, 115, 100);
fill(baseColor);
text("blink", 0, 470, 200, 100);
text("jaw clench", 200, 470, 200, 100);
text("concentration", 400, 470, 200, 100);
text("mellow", 600, 470, 200, 100);
drawMuscleMovement(blink, 100, 530, 50);
drawMuscleMovement(jawClench, 300, 530, 50);
drawExperimental(concentration, 500, 530, 50);
drawExperimental(mellow, 700, 530, 50);
}
void drawRawEEG(ArrayList data, float x, float y, float w, float h){
pushMatrix();
translate(x, y);
beginShape();
for(int i = 0; i < data.size(); i++){
vertex(map(i, 0, data.size(), 0, w), map(data.get(i), 0, 1682.815, h, 0));
}
endShape();
popMatrix();
}
void drawRawFFT(float[] data, float x, float y, float w, float h){
pushMatrix();
translate(x, y);
float binW = w / data.length;
for(int i = 0; i < data.length; i++){
float binH = map(data[i], -40.0, 20.0, 0, h);
rect(i * binW, h - binH, binW, binH);
}
popMatrix();
}
void drawAbsBandPower(float[] data, float x, float y, float w, float h){
pushMatrix();
translate(x, y);
float binW = w / data.length;
for(int i = 0; i < data.length; i++){
fill(chColor[i]);
float binH = map(data[i], -2.5, 2.5, 0, h);
rect(i * binW, h - binH, binW, binH);
}
popMatrix();
}
void drawMuscleMovement(int data, float x, float y, float radious){
float diameter = data == 1 ? radious * 2 * 0.8 : radious * 2 * 0.2;
ellipse(x, y, diameter, diameter);
}
void drawExperimental(float data, float x, float y, float radious){
float diameter = radious * 2 * data;
ellipse(x, y, diameter, diameter);
}
void oscEvent(OscMessage msg){
if(msg.checkAddrPattern("/muse/eeg")){
for(int i = 0; i < 4; i++){
rawEEG[i].remove(0);
rawEEG[i].add(msg.get(i).floatValue());
}
}
if(msg.checkAddrPattern("/muse/elements/raw_fft0")){
for(int j = 0; j < 129; j++){
rawFFT[0][j] = msg.get(j).floatValue();
}
}
if(msg.checkAddrPattern("/muse/elements/raw_fft1")){
for(int j = 0; j < 129; j++){
rawFFT[1][j] = msg.get(j).floatValue();
}
}
if(msg.checkAddrPattern("/muse/elements/raw_fft2")){
for(int j = 0; j < 129; j++){
rawFFT[2][j] = msg.get(j).floatValue();
}
}
if(msg.checkAddrPattern("/muse/elements/raw_fft3")){
for(int j = 0; j < 129; j++){
rawFFT[3][j] = msg.get(j).floatValue();
}
}
if(msg.checkAddrPattern("/muse/elements/low_freqs_absolute")){
for(int i = 0; i < 4; i++){
lowFreqAbs[i] = msg.get(i).floatValue();
}
}
if(msg.checkAddrPattern("/muse/elements/low_freqs_absolute")){
for(int i = 0; i < 4; i++){
lowFreqAbs[i] = msg.get(i).floatValue();
}
}
if(msg.checkAddrPattern("/muse/elements/delta_absolute")){
for(int i = 0; i < 4; i++){
deltaAbs[i] = msg.get(i).floatValue();
}
}
if(msg.checkAddrPattern("/muse/elements/theta_absolute")){
for(int i = 0; i < 4; i++){
thetaAbs[i] = msg.get(i).floatValue();
}
}
if(msg.checkAddrPattern("/muse/elements/alpha_absolute")){
for(int i = 0; i < 4; i++){
alphaAbs[i] = msg.get(i).floatValue();
}
}
if(msg.checkAddrPattern("/muse/elements/beta_absolute")){
for(int i = 0; i < 4; i++){
betaAbs[i] = msg.get(i).floatValue();
}
}
if(msg.checkAddrPattern("/muse/elements/gamma_absolute")){
for(int i = 0; i < 4; i++){
gammaAbs[i] = msg.get(i).floatValue();
}
}
if(msg.checkAddrPattern("/muse/elements/blink")){
blink = msg.get(0).intValue();
}
if(msg.checkAddrPattern("/muse/elements/jaw_clench")){
jawClench = msg.get(0).intValue();
}
if(msg.checkAddrPattern("/muse/elements/experimental/concentration")){
concentration = msg.get(0).floatValue();
}
if(msg.checkAddrPattern("/muse/elements/experimental/mellow")){
mellow = msg.get(0).floatValue();
}
}
参考
OpenCVで特徴点をもとに画像をボロノイ分割・ドロネー分割する
この前に,ランダムに選んだ母点をもとに画像をボロノイ分割,ドロネー分割して,モザイク画像を生成した.
今回は,母点の粗密がいい感じになることを期待して,画像の特徴点をもとに分割する. それぞれの特徴検出器のパラメータ設定は適当.
固有値に基づく特徴点検出
特徴点
ボロノイ図
ドロネー分割
Harris検出器に基づく特徴点検出
特徴点
ボロノイ図
ドロネー分割
FAST検出器に基づく特徴点検出
特徴点
ボロノイ図
ドロネー分割
Star検出器に基づく特徴点検出
特徴点
ボロノイ図
ドロネー分割
SIFT検出器に基づく特徴点検出
特徴点
ボロノイ図
ドロネー分割
SURF検出器に基づく特徴点検出
特徴点
ボロノイ図
ドロネー分割
MSER検出器に基づく特徴点検出
特徴点
ボロノイ図
ドロネー分割
ORB検出器に基づく特徴点検出
特徴点
ボロノイ図
ドロネー分割
FAST検出器+Gridアダプタ に基づく特徴点検出
特徴点
ボロノイ図
ドロネー分割
FAST検出器+Pyramidアダプタ に基づく特徴点検出
特徴点
ボロノイ図
ドロネー分割
main.cpp
#include
#include "opencv2/opencv.hpp"
#include "opencv2/nonfree/nonfree.hpp"
int main(int argc, const char * argv[]) {
cv::Mat img = cv::imread("lena.jpg", 1);
if(img.empty()) return -1;
cv::Mat gray_img;
cv::cvtColor(img, gray_img, CV_BGR2GRAY);
cv::normalize(gray_img, gray_img, 0, 255, cv::NORM_MINMAX);
std::vector keypoints;
std::vector::iterator itk;
cv::GoodFeaturesToTrackDetector detector(1600, 0.01, 5, 3); // 固有値に基づく特徴点検出
// cv::GoodFeaturesToTrackDetector detector(1600, 0.01, 5, 3, true); // Harris検出器に基づく特徴点検出
// cv::FastFeatureDetector detector(25, false); // FAST検出器に基づく特徴点検出
// cv::StarFeatureDetector detector(16, 5); // Star検出器に基づく特徴点検出
// cv::SiftFeatureDetector detector(0.001, 3.0); // SIFT検出器に基づく特徴点検出
// cv::SurfFeatureDetector detector(100); // SURF検出器に基づく特徴点検出
// cv::MserFeatureDetector detector; // MSER検出器に基づく特徴点検出
// cv::OrbFeatureDetector detector(1500); // ORB検出器に基づく特徴点検出
// cv::GridAdaptedFeatureDetector detector(new cv::FastFeatureDetector(10), 5000, 5, 5); // FAST検出器+Gridアダプタ に基づく特徴点検出
// cv::PyramidAdaptedFeatureDetector detector(new cv::FastFeatureDetector(10), 3); // FAST検出器+Pyramidアダプタ に基づく特徴点検出
detector.detect(img, keypoints);
cv::Mat feature_img = img.clone();
cv::Subdiv2D subdiv;
subdiv.initDelaunay(cv::Rect(0, 0, img.rows, img.cols));
std::vector points;
for(itk = keypoints.begin(); itk!=keypoints.end(); ++itk) {
cv::circle(feature_img, itk->pt, 5, cv::Scalar(184, 210, 0), 1, CV_AA);
points.push_back(itk->pt);
}
points.push_back(cv::Point2f(0, 0));
points.push_back(cv::Point2f(img.rows - 1, 0));
points.push_back(cv::Point2f(0, img.cols - 1));
points.push_back(cv::Point2f(img.rows - 1, img.cols - 1));
subdiv.insert(points);
// ボロノイモザイクの作成
std::vector idx;
std::vector> facetLists;
std::vector facetCenters;
subdiv.getVoronoiFacetList(idx, facetLists, facetCenters);
cv::Mat voronoi_img = cv::Mat::zeros(img.rows, img.cols, CV_8UC3);
for(auto facetList = facetLists.begin(); facetList != facetLists.end(); facetList++){
cv::Point *vertices = new cv::Point[facetList->size()];
cv::Vec3f polyColor = cv::Vec3f(0, 0, 0);
int polyColorNum = 0;
for(int i = 0; i < facetList->size(); i++){
cv::Point vertex = facetList->at(i);
vertices[i] = vertex;
if(0 <= vertex.x && vertex.x < img.rows && 0 <= vertex.y && vertex.y < img.cols){
polyColor += img.at(vertex.y, vertex.x);
polyColorNum++;
}
}
polyColor /= float(polyColorNum);
cv::fillConvexPoly(voronoi_img, vertices, int(facetList->size()), cv::Scalar(polyColor[0], polyColor[1], polyColor[2]), CV_AA);
delete[] vertices;
}
// ドロネーモザイクの作成
std::vector triangles;
subdiv.getTriangleList(triangles);
cv::Mat dalaunay_img = cv::Mat::zeros(img.rows, img.cols, CV_8UC3);
for(auto it = triangles.begin(); it != triangles.end(); it++)
{
cv::Vec6f &vec = *it;
cv::Point vertices[3];
vertices[0] = cv::Point(vec[0], vec[1]);
vertices[1] = cv::Point(vec[2], vec[3]);
vertices[2] = cv::Point(vec[4], vec[5]);
cv::Vec3f polyColor = cv::Vec3f(0, 0, 0);
polyColor += img.at(vertices[0].y, vertices[0].x);
polyColor += img.at(vertices[1].y, vertices[1].x);
polyColor += img.at(vertices[2].y, vertices[2].x);
polyColor /= float(3);
cv::fillConvexPoly(dalaunay_img, vertices, 3, cv::Scalar(polyColor[0], polyColor[1], polyColor[2]), CV_AA);
}
cv::imshow("feature", feature_img);
cv::imshow("voronoi", voronoi_img);
cv::imshow("dalaunay", dalaunay_img);
cv::waitKey(0);
}
OpenCV/dalaunay_feature at master · aa-debdeb/OpenCV