venerdì 30 agosto 2013
Compilare librerie Python
Tentando di installare un libreria python mediante il classico comando sulla mia Debian Box
python setup.py install
mi vengono generati una serie di errori. La causa e' che di default non viene installato il pacchetto python-dev indispensabile per la compilazione da sorgenti. tutto si risolve con
apt-get install python-dev
Raspberry in emulazione Qemu
Puntando il browser su questo indirizzo http://sourceforge.net/projects/rpiqemuwindows/ e' possibile ottenere un pacchetto gia' confezionato per emulare Raspberry e sistemi operativi collegati in QEmu
si possono provare altre distribuzioni senza dover formattare SD Card.
La velocita' non e' assolutamente niente di particolare. Curiosamente la distro PiBang non riesce a partire a causa di un errore nella D-Bus connection
Creazione di post automatici su Facebook (4)
Questo riepilogo non è disponibile.
Fai clic qui per visualizzare il post.
Creazione di post automatici su Facebook (3)
Arduino con shield Ethernet e sullo sfondo il post automatico su Facebook |
Visti i precedenti post (1 e 2) adesso si deve configurare l'Arduino come Client Http per chiamare lo script Php che genera post automaticamente mediante l'access_token
La cosa e' piuttosto semplice e viene compiuta dallo sketch sottostante che crea una chiamata HTTP passando i parametri via GET. Il codice si commenta da solo
----------------------------------------
#include <Ethernet.h>
#include <SPI.h>
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte server[] = { 150, 217, 73, XX };
EthernetClient client;
void setup()
{
Ethernet.begin(mac);
Serial.begin(9600);
client.connect(server, 80);
delay(1000);
Serial.println("connecting...");
if (client.connected()) {
Serial.println("connected");
client.println("GET /luca/xxxxxx/example3.php?msg=Arduino_automatico HTTP/1.0");
client.println();
} else {
Serial.println("connection failed");
}
}
void loop()
{
if (client.available()) {
char c = client.read();
Serial.print(c);
}
if (!client.connected()) {
Serial.println();
Serial.println("disconnecting.");
client.stop();
for(;;)
;
}
}
------------------------------------------------------
sul lato server il log di apache mostra la connessione dell'Arduino con il web server
----------------------------
m.xxxxx.unifi.it:80 79.4.7.201 - - [29/Aug/2013:23:01:31 +0200] "GET /luca/xxxxx/example3.php?msg=Arduino_automatico HTTP/1.0" 200 418 "-" "-"sul lato server il log di apache mostra la connessione dell'Arduino con il web server
----------------------------
giovedì 29 agosto 2013
Problema di DNS su Ubuntu Server
E' accaduta una cosa curiosa sul server sul quale effettuo alcune prove tra cui quella di Facebook.
A seguito di una interruzione del corrente il server si e' spento brutalmente ed alla riaccensione erano scomparse le impostazioni del DNS (il file /etc/resolv.conf era vuoto con l'indicazione di non editare a mano)
E' stato necessario ripopolare il file /etc/resolv.conf con la sintassi
A seguito di una interruzione del corrente il server si e' spento brutalmente ed alla riaccensione erano scomparse le impostazioni del DNS (il file /etc/resolv.conf era vuoto con l'indicazione di non editare a mano)
E' stato necessario ripopolare il file /etc/resolv.conf con la sintassi
nameserver xxx.xxx.xxx.xxx
probabilmente le impostazioni del DSN vengono gestite in automatico da qualche programma (vedi questo link) ma su una macchina server mi sembra una scelta quantomeno discutibile
Creazione di post automatici su Facebook (2)
Proseguendo il discorso iniziato con il post precedente adesso si cerca di pubblicare un post senza l'interazione utente utilizzando l'access token
La stringa dell'access token e' quella lunga stringa alfanumerica che viene prodotta come risultato dallo script del post precedente
Per la politica di Facebook attualmente questo metodo funziona solo per 60 giorni perche' gli access token hanno una durata temporale; dopo tale scadenza l'utente deve riloggarsi manualmente ed ottenere un nuovo access token
Questo script di fatto e' una versione semplificata del precedente in cui tutta la fase di autenticazione e' contenuta nell'access token
E' stato leggermente modificato il campo messaggio in modo da renderlo dinamico.
In questo modo se si aggiunge la variale msg alla URL si modifica il testo del messaggio
tipo
http://www.mioserver//script.php?msg=Luca
--------------------------------------------------------------------
<?
require_once '../src/facebook.php';
$appid = '6731359560xxxxxx';
$appsecret = 'dde6cfb07dbb769c7efe949cxxxxxxx';
$msg = $_GET["msg"];
$title = 'Messaggio Automatico Arduino';
$uri = 'http://debiaonoldcomputers.blogspot.com/';
$desc = 'Luca Innocenti.';
$pic = 'https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgluMOnPyTph3iUuLEcHHX8yoUSfMUnM5JlJH4xtJUoNTbZydICSkco_aB1Nc_gZ521xnI_JRptSkThfY7w1-dVLT7_9y5lzyWslzLYnhTQaExMPdr9Z8-Ed73ymkPwQwpnXmKuhfGdJPJ4/s400/Basic-+Facebook+Developers.jpg';
$action_name = 'Action Link in the Footer of the Post';
$action_link = 'http://debiaonoldcomputers.blogspot.com/';
$facebook = new Facebook(array(
'appId' => $appid,
'secret' => $appsecret,
'cookie' => false,
));
$user = $facebook->getUser();
$accessToken = "CAAJkNq2LttoBAJywtmNSbVHqFPubOjYmQ2yyUG4kpibD75BHid9J7xsvif8osSOc4ewgK4aYerrLZBsZCQM5wykRTYVLDkCJXlXYl3gi8WFRQ8U4p4y4ZAXYsdamz6RVdRJZAe4vZA80mWBayuG0qc4IAj2TMDmQXKiv1OrKp8CwKjD6Rz2ZCAqpxxxxxxxx";
$attachment = array(
'access_token' => $accessToken,
'message' => $msg,
'name' => $title,
'link' => $uri,
'description' => $desc,
'picture'=>$pic,
'actions' => json_encode(array('name' => $action_name,'link' => $action_link))
);
$status = $facebook->api("/me/feed", "post", $attachment);
print "Ok";
?>
La stringa dell'access token e' quella lunga stringa alfanumerica che viene prodotta come risultato dallo script del post precedente
Per la politica di Facebook attualmente questo metodo funziona solo per 60 giorni perche' gli access token hanno una durata temporale; dopo tale scadenza l'utente deve riloggarsi manualmente ed ottenere un nuovo access token
Questo script di fatto e' una versione semplificata del precedente in cui tutta la fase di autenticazione e' contenuta nell'access token
E' stato leggermente modificato il campo messaggio in modo da renderlo dinamico.
In questo modo se si aggiunge la variale msg alla URL si modifica il testo del messaggio
tipo
http://www.mioserver//script.php?msg=Luca
--------------------------------------------------------------------
<?
require_once '../src/facebook.php';
$appid = '6731359560xxxxxx';
$appsecret = 'dde6cfb07dbb769c7efe949cxxxxxxx';
$msg = $_GET["msg"];
$title = 'Messaggio Automatico Arduino';
$uri = 'http://debiaonoldcomputers.blogspot.com/';
$desc = 'Luca Innocenti.';
$pic = 'https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgluMOnPyTph3iUuLEcHHX8yoUSfMUnM5JlJH4xtJUoNTbZydICSkco_aB1Nc_gZ521xnI_JRptSkThfY7w1-dVLT7_9y5lzyWslzLYnhTQaExMPdr9Z8-Ed73ymkPwQwpnXmKuhfGdJPJ4/s400/Basic-+Facebook+Developers.jpg';
$action_name = 'Action Link in the Footer of the Post';
$action_link = 'http://debiaonoldcomputers.blogspot.com/';
$facebook = new Facebook(array(
'appId' => $appid,
'secret' => $appsecret,
'cookie' => false,
));
$user = $facebook->getUser();
$accessToken = "CAAJkNq2LttoBAJywtmNSbVHqFPubOjYmQ2yyUG4kpibD75BHid9J7xsvif8osSOc4ewgK4aYerrLZBsZCQM5wykRTYVLDkCJXlXYl3gi8WFRQ8U4p4y4ZAXYsdamz6RVdRJZAe4vZA80mWBayuG0qc4IAj2TMDmQXKiv1OrKp8CwKjD6Rz2ZCAqpxxxxxxxx";
$attachment = array(
'access_token' => $accessToken,
'message' => $msg,
'name' => $title,
'link' => $uri,
'description' => $desc,
'picture'=>$pic,
'actions' => json_encode(array('name' => $action_name,'link' => $action_link))
);
$status = $facebook->api("/me/feed", "post", $attachment);
print "Ok";
?>
mercoledì 28 agosto 2013
Creazione di post automatici su Facebook
Questo post e' relativo ad un tentativo di connettere una Arduino ad un profilo Facebook per pubblicare i dati di un sensore
Esempi di pubblicazione automatica di post su Facebook se ne trovano a decine ma sono quasi tutti inutili perche' relativi ad API e sistemi di autenticazione non piu' in utilizzo presso Facebook
Per prima cosa, come visto in questo post, si deve creare una applicazione Facebook scegliendo stavolta App on Facebook.
Si devono quindi compilare i dati delle informazioni di base, togliere la modalita' SandBox e poi indicare l'indirizzo della directory del server dove sono contenuti gli script Php che contengono l'applicazione (anche qui l'indizzo del server deve essere FQD e deve essere disponibili https)
a questo punto si inizia a lavorare sul lato server copiando l'SDK PHP di Facebook ed aggiungendo il seguente script (ripreso da questo link) nella directory indicata nella schermata precedente
--------------------------------------------------------------
<?php
require_once '../src/facebook.php';
// configuration
$appid = '67313595xxxxxxxx';
$appsecret = 'dde6cfb07dbb769c7efxxxxxxx';
$msg = 'Messaggio';
$title = 'Titolo';
$uri = 'http://www.google.com';
$desc = 'Descrizione';
$pic = 'http://www.testcom/test.png';
$action_name = 'Action Link in the Footer of the Post';
$action_link = 'http://www.nathanbolin.com';
$facebook = new Facebook(array(
'appId' => $appid,
'secret' => $appsecret,
'cookie' => false,
));
$user = $facebook->getUser();
// Contact Facebook and get token
if ($user) {
// you're logged in, and we'll get user acces token for posting on the wall
try {
$accessToken = $facebook->getAccessToken();
if (!empty( $accessToken )) {
$attachment = array(
'access_token' => $accessToken,
'message' => $msg,
'name' => $title,
'link' => $uri,
'description' => $desc,
'picture'=>$pic,
'actions' => json_encode(array('name' => $action_name,'link' => $action_link))
);
$status = $facebook->api("/me/feed", "post", $attachment);
} else {
$status = 'No access token recieved';
}
} catch (FacebookApiException $e) {
error_log($e);
$user = null;
}
} else {
// you're not logged in, the application will try to log in to get a access token
header("Location:{$facebook->getLoginUrl(array('scope' => 'photo_upload,user_status,publish_stream,user_photos,manage_pages'))}");
}
print_r($status);
?>
Esempi di pubblicazione automatica di post su Facebook se ne trovano a decine ma sono quasi tutti inutili perche' relativi ad API e sistemi di autenticazione non piu' in utilizzo presso Facebook
Per prima cosa, come visto in questo post, si deve creare una applicazione Facebook scegliendo stavolta App on Facebook.
Si devono quindi compilare i dati delle informazioni di base, togliere la modalita' SandBox e poi indicare l'indirizzo della directory del server dove sono contenuti gli script Php che contengono l'applicazione (anche qui l'indizzo del server deve essere FQD e deve essere disponibili https)
a questo punto si inizia a lavorare sul lato server copiando l'SDK PHP di Facebook ed aggiungendo il seguente script (ripreso da questo link) nella directory indicata nella schermata precedente
--------------------------------------------------------------
<?php
require_once '../src/facebook.php';
// configuration
$appid = '67313595xxxxxxxx';
$appsecret = 'dde6cfb07dbb769c7efxxxxxxx';
$msg = 'Messaggio';
$title = 'Titolo';
$uri = 'http://www.google.com';
$desc = 'Descrizione';
$pic = 'http://www.testcom/test.png';
$action_name = 'Action Link in the Footer of the Post';
$action_link = 'http://www.nathanbolin.com';
$facebook = new Facebook(array(
'appId' => $appid,
'secret' => $appsecret,
'cookie' => false,
));
$user = $facebook->getUser();
// Contact Facebook and get token
if ($user) {
// you're logged in, and we'll get user acces token for posting on the wall
try {
$accessToken = $facebook->getAccessToken();
if (!empty( $accessToken )) {
$attachment = array(
'access_token' => $accessToken,
'message' => $msg,
'name' => $title,
'link' => $uri,
'description' => $desc,
'picture'=>$pic,
'actions' => json_encode(array('name' => $action_name,'link' => $action_link))
);
$status = $facebook->api("/me/feed", "post", $attachment);
} else {
$status = 'No access token recieved';
}
} catch (FacebookApiException $e) {
error_log($e);
$user = null;
}
} else {
// you're not logged in, the application will try to log in to get a access token
header("Location:{$facebook->getLoginUrl(array('scope' => 'photo_upload,user_status,publish_stream,user_photos,manage_pages'))}");
}
print_r($status);
?>
------------------------------------
Se tutto e' andato a buon fine si avra' come risultato una pagina con scritto l'access token utilizzato (ovvero l'autorizzazione di Facebook) e nel proprio profilo Facebook si avra' il post pubblicato
Il passo successivo sara' utilizzare l'access token per evitare che vi debba essere l'interazione umana per effettuare il login in modo da permettere ad Arduino di pubblicare dati in automatico
martedì 27 agosto 2013
Sostituzione batteria tampone Mac Mini G4
Dopo un po' di tempo il mio vetusto (ma sempre bellissimo Mac Mini G4) ha deciso che la batteria tampone dell'orologio era finita.
La sostituzione e' un esercizio di forza bruta e coraggio
Per prima cosa, rovesciando il Mini, si inserisce una spatola (una spatola per il gesso e' perfetta) nella fessura della base (da evitare il lato posteriore e quello anteriore) e si fa forza fino a far scattare le mollette.
Si procede quindi sul lato anteriore e sull'altro lato
Giunti qui si devono svitare tre viti (cacciavite da orologiaio magnetizzato consigliato) per rimuovere l'unita' ottica e l'hard disk (attenzione: per i modelli con bluetooth e wifi si devono staccare dei cavi), un po' di attenzione al filo del pulsante di accensione nella parte posteriore lato destro
la parte superiore ed inferiore sono collegate da un connettore a pettine sul retro. Sollevare con delicatezza
Si arriva quindi alla batteria CR 2032. Per toglierla il movimento deve essere prima verso il basso e poi verso l'esterno
La sostituzione e' un esercizio di forza bruta e coraggio
Per prima cosa, rovesciando il Mini, si inserisce una spatola (una spatola per il gesso e' perfetta) nella fessura della base (da evitare il lato posteriore e quello anteriore) e si fa forza fino a far scattare le mollette.
Si procede quindi sul lato anteriore e sull'altro lato
Giunti qui si devono svitare tre viti (cacciavite da orologiaio magnetizzato consigliato) per rimuovere l'unita' ottica e l'hard disk (attenzione: per i modelli con bluetooth e wifi si devono staccare dei cavi), un po' di attenzione al filo del pulsante di accensione nella parte posteriore lato destro
la parte superiore ed inferiore sono collegate da un connettore a pettine sul retro. Sollevare con delicatezza
Si arriva quindi alla batteria CR 2032. Per toglierla il movimento deve essere prima verso il basso e poi verso l'esterno
Gestione dispositivi di Android
Visto che oramai e' chiaro che se si perde (o viene rubato il cellulare) ci si trova praticamente in mutande nei confronti di chi ritrova il telefono questa nuova funzione di Android di localizzare il telefono ed eventualmente rimuovere i dati e' fantastica
Di fatto e' necessario che il telefono abbia una scheda che permetta il traffico dati (se e' agganciato WiFi con le mie prove non funziona). Dopo di cio' ci si collega al link
https://www.google.com/android/devicemanager
e si puo' verificare (con ampio margine di errore) dove si trova il telefono, lo si puo' far squillare ed infine si possono cancellare da remoto i dati sensibili
Di fatto e' necessario che il telefono abbia una scheda che permetta il traffico dati (se e' agganciato WiFi con le mie prove non funziona). Dopo di cio' ci si collega al link
https://www.google.com/android/devicemanager
e si puo' verificare (con ampio margine di errore) dove si trova il telefono, lo si puo' far squillare ed infine si possono cancellare da remoto i dati sensibili
Riconoscimento automatico oggetti in OpenCV
Una delle funzioni piu' carine di OpenCV e' quella che permette di individuare oggetti in automatico all'interno di una immagine. Il mio obbiettivo sarebbe quello di determinare la presenza di cartelli stradali.
Per una prova ho preso una normale immagine scattata con la fotocamera del cellulare
Ho cercato quindi di individuare in automatico la posizione del cartello di precedenza
Il programma deriva direttamente dagli esempi di OpenCV
-------------------------------------------------
#include <stdio.h>
#include <iostream>
#include "opencv2/core/core.hpp"
#include "opencv2/features2d/features2d.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/calib3d/calib3d.hpp"
using namespace cv;
void readme();
/** @function main */
int main( int argc, char** argv )
{
if( argc != 3 )
{ readme(); return -1; }
Mat img_object = imread( argv[1], CV_LOAD_IMAGE_GRAYSCALE );
Mat img_scene = imread( argv[2], CV_LOAD_IMAGE_GRAYSCALE );
if( !img_object.data || !img_scene.data )
{ std::cout<< " --(!) Error reading images " << std::endl; return -1; }
//-- Step 1: Detect the keypoints using SURF Detector
int minHessian = 400;
SurfFeatureDetector detector( minHessian );
std::vector<KeyPoint> keypoints_object, keypoints_scene;
detector.detect( img_object, keypoints_object );
detector.detect( img_scene, keypoints_scene );
//-- Step 2: Calculate descriptors (feature vectors)
SurfDescriptorExtractor extractor;
Mat descriptors_object, descriptors_scene;
extractor.compute( img_object, keypoints_object, descriptors_object );
extractor.compute( img_scene, keypoints_scene, descriptors_scene );
//-- Step 3: Matching descriptor vectors using FLANN matcher
FlannBasedMatcher matcher;
std::vector< DMatch > matches;
matcher.match( descriptors_object, descriptors_scene, matches );
double max_dist = 0; double min_dist = 100;
//-- Quick calculation of max and min distances between keypoints
for( int i = 0; i < descriptors_object.rows; i++ )
{ double dist = matches[i].distance;
if( dist < min_dist ) min_dist = dist;
if( dist > max_dist ) max_dist = dist;
}
printf("-- Max dist : %f \n", max_dist );
printf("-- Min dist : %f \n", min_dist );
//-- Draw only "good" matches (i.e. whose distance is less than 3*min_dist )
std::vector< DMatch > good_matches;
for( int i = 0; i < descriptors_object.rows; i++ )
{ if( matches[i].distance < 3*min_dist )
{ good_matches.push_back( matches[i]); }
}
Mat img_matches;
drawMatches( img_object, keypoints_object, img_scene, keypoints_scene,
good_matches, img_matches, Scalar::all(-1), Scalar::all(-1),
vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS );
//-- Localize the object
std::vector<Point2f> obj;
std::vector<Point2f> scene;
for( int i = 0; i < good_matches.size(); i++ )
{
//-- Get the keypoints from the good matches
obj.push_back( keypoints_object[ good_matches[i].queryIdx ].pt );
scene.push_back( keypoints_scene[ good_matches[i].trainIdx ].pt );
}
Mat H = findHomography( obj, scene, CV_RANSAC );
//-- Get the corners from the image_1 ( the object to be "detected" )
std::vector<Point2f> obj_corners(4);
obj_corners[0] = cvPoint(0,0); obj_corners[1] = cvPoint( img_object.cols, 0 );
obj_corners[2] = cvPoint( img_object.cols, img_object.rows ); obj_corners[3] = cvPoint( 0, img_object.rows );
std::vector<Point2f> scene_corners(4);
perspectiveTransform( obj_corners, scene_corners, H);
//-- Draw lines between the corners (the mapped object in the scene - image_2 )
line( img_matches, scene_corners[0] + Point2f( img_object.cols, 0), scene_corners[1] + Point2f( img_object.cols, 0), Scalar(0, 255, 0), 4 );
line( img_matches, scene_corners[1] + Point2f( img_object.cols, 0), scene_corners[2] + Point2f( img_object.cols, 0), Scalar( 0, 255, 0), 4 );
line( img_matches, scene_corners[2] + Point2f( img_object.cols, 0), scene_corners[3] + Point2f( img_object.cols, 0), Scalar( 0, 255, 0), 4 );
line( img_matches, scene_corners[3] + Point2f( img_object.cols, 0), scene_corners[0] + Point2f( img_object.cols, 0), Scalar( 0, 255, 0), 4 );
//-- Show detected matches
imshow( "Good Matches & Object detection", img_matches );
waitKey(0);
return 0;
}
/** @function readme */
void readme()
{ std::cout << " Usage: ./SURF_descriptor <img1> <img2>" << std::endl; }
-------------------------------------------------
per prima cosa ho usato come immagine di training il cartello di precedenza estratto dalla medesima immagine.
Il risultato e' ottimale
a questo punto le cose si complicano. Ho scattato una seconda foto spostandomi di qualche metro per cambiare la prospettiva
Si ha ancora un qualche risultato ma chiaramente basta una piccola modifica per confondere l'algoritmo
Ancora piu' difficile. Invece di tagliare l'immagine ho preso una immagine generica di un cartello di precedenza (da Google Images)
il risultato e' decisamente pessimo
sostanzialmente un esperimento fallito e come al solito "conoscere la risposta aiuta nel risolvere un problema"
Per una prova ho preso una normale immagine scattata con la fotocamera del cellulare
Ho cercato quindi di individuare in automatico la posizione del cartello di precedenza
Il programma deriva direttamente dagli esempi di OpenCV
-------------------------------------------------
#include <stdio.h>
#include <iostream>
#include "opencv2/core/core.hpp"
#include "opencv2/features2d/features2d.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/calib3d/calib3d.hpp"
using namespace cv;
void readme();
/** @function main */
int main( int argc, char** argv )
{
if( argc != 3 )
{ readme(); return -1; }
Mat img_object = imread( argv[1], CV_LOAD_IMAGE_GRAYSCALE );
Mat img_scene = imread( argv[2], CV_LOAD_IMAGE_GRAYSCALE );
if( !img_object.data || !img_scene.data )
{ std::cout<< " --(!) Error reading images " << std::endl; return -1; }
//-- Step 1: Detect the keypoints using SURF Detector
int minHessian = 400;
SurfFeatureDetector detector( minHessian );
std::vector<KeyPoint> keypoints_object, keypoints_scene;
detector.detect( img_object, keypoints_object );
detector.detect( img_scene, keypoints_scene );
//-- Step 2: Calculate descriptors (feature vectors)
SurfDescriptorExtractor extractor;
Mat descriptors_object, descriptors_scene;
extractor.compute( img_object, keypoints_object, descriptors_object );
extractor.compute( img_scene, keypoints_scene, descriptors_scene );
//-- Step 3: Matching descriptor vectors using FLANN matcher
FlannBasedMatcher matcher;
std::vector< DMatch > matches;
matcher.match( descriptors_object, descriptors_scene, matches );
double max_dist = 0; double min_dist = 100;
//-- Quick calculation of max and min distances between keypoints
for( int i = 0; i < descriptors_object.rows; i++ )
{ double dist = matches[i].distance;
if( dist < min_dist ) min_dist = dist;
if( dist > max_dist ) max_dist = dist;
}
printf("-- Max dist : %f \n", max_dist );
printf("-- Min dist : %f \n", min_dist );
//-- Draw only "good" matches (i.e. whose distance is less than 3*min_dist )
std::vector< DMatch > good_matches;
for( int i = 0; i < descriptors_object.rows; i++ )
{ if( matches[i].distance < 3*min_dist )
{ good_matches.push_back( matches[i]); }
}
Mat img_matches;
drawMatches( img_object, keypoints_object, img_scene, keypoints_scene,
good_matches, img_matches, Scalar::all(-1), Scalar::all(-1),
vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS );
//-- Localize the object
std::vector<Point2f> obj;
std::vector<Point2f> scene;
for( int i = 0; i < good_matches.size(); i++ )
{
//-- Get the keypoints from the good matches
obj.push_back( keypoints_object[ good_matches[i].queryIdx ].pt );
scene.push_back( keypoints_scene[ good_matches[i].trainIdx ].pt );
}
Mat H = findHomography( obj, scene, CV_RANSAC );
//-- Get the corners from the image_1 ( the object to be "detected" )
std::vector<Point2f> obj_corners(4);
obj_corners[0] = cvPoint(0,0); obj_corners[1] = cvPoint( img_object.cols, 0 );
obj_corners[2] = cvPoint( img_object.cols, img_object.rows ); obj_corners[3] = cvPoint( 0, img_object.rows );
std::vector<Point2f> scene_corners(4);
perspectiveTransform( obj_corners, scene_corners, H);
//-- Draw lines between the corners (the mapped object in the scene - image_2 )
line( img_matches, scene_corners[0] + Point2f( img_object.cols, 0), scene_corners[1] + Point2f( img_object.cols, 0), Scalar(0, 255, 0), 4 );
line( img_matches, scene_corners[1] + Point2f( img_object.cols, 0), scene_corners[2] + Point2f( img_object.cols, 0), Scalar( 0, 255, 0), 4 );
line( img_matches, scene_corners[2] + Point2f( img_object.cols, 0), scene_corners[3] + Point2f( img_object.cols, 0), Scalar( 0, 255, 0), 4 );
line( img_matches, scene_corners[3] + Point2f( img_object.cols, 0), scene_corners[0] + Point2f( img_object.cols, 0), Scalar( 0, 255, 0), 4 );
//-- Show detected matches
imshow( "Good Matches & Object detection", img_matches );
waitKey(0);
return 0;
}
/** @function readme */
void readme()
{ std::cout << " Usage: ./SURF_descriptor <img1> <img2>" << std::endl; }
-------------------------------------------------
per prima cosa ho usato come immagine di training il cartello di precedenza estratto dalla medesima immagine.
Il risultato e' ottimale
a questo punto le cose si complicano. Ho scattato una seconda foto spostandomi di qualche metro per cambiare la prospettiva
Si ha ancora un qualche risultato ma chiaramente basta una piccola modifica per confondere l'algoritmo
Ancora piu' difficile. Invece di tagliare l'immagine ho preso una immagine generica di un cartello di precedenza (da Google Images)
il risultato e' decisamente pessimo
sostanzialmente un esperimento fallito e come al solito "conoscere la risposta aiuta nel risolvere un problema"
Motion Detection su Raspberry
Per valutare la potenza di calcolo di Raspberry per un eventuale sistema di controllo, ho ricompilato il programma presentato in questo post modificandolo leggermente (non volevo usare il monitor ma solo una connessione di rete via SSH per interagire con la Raspberry) eliminando il namedWindow
Per compilare il programma non ci sono problemi in quanto le libopencv-dev sono disponibili nei repository senza la necessita' di ricompilare da zero le OpenCV
Il sistema ha funzionato bene
anche se in alcuni casi vi sono artefatti
ecco il video completo
Per compilare il programma non ci sono problemi in quanto le libopencv-dev sono disponibili nei repository senza la necessita' di ricompilare da zero le OpenCV
Il sistema ha funzionato bene
anche se in alcuni casi vi sono artefatti
ecco il video completo
Errore stray ‘\342’ in program
copiando un mio sorgente direttamente da questo blog e compilandolo su un'altra macchina e' comparso l'errore
error: stray ‘\342’ in program
ovviamente non si tratta di un errore del programma dato che funziona su un'altra macchina
in realta' nella fase di copia incolla dal browser verso il text editor sono stati copiati dei codici UNICODE e non ASCII per cui, per esempio, quelle che io vedo come virgolette il calcolatore non le vede come tali e blocca la compilazione
error: stray ‘\342’ in program
ovviamente non si tratta di un errore del programma dato che funziona su un'altra macchina
in realta' nella fase di copia incolla dal browser verso il text editor sono stati copiati dei codici UNICODE e non ASCII per cui, per esempio, quelle che io vedo come virgolette il calcolatore non le vede come tali e blocca la compilazione
lunedì 26 agosto 2013
Individuazione di volti con OpenCV
Sempre giocando con OpenCV e' divertente effettuare il riconoscimento automatico dei volti...una operazione di per se complessa si puo' svolgere sostanzialmente in realtime con poca potenza di calcolo
Prendendo l'esempio dei tutorial (con poche modifiche marginali) si puo' ottenere il risultato sottostante (e' stato modificato un parametro rispetto a quelli di default)
per il corretto funzionamento del programma si deve copiare il file haarcascade_frontalface_alt.xml nella directory del programma
---------------------------------------------------------
#include "opencv2/objdetect/objdetect.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
using namespace std;
using namespace cv;
/** Function Headers */
void detectAndDisplay( Mat frame );
/** Global variables */
String face_cascade_name = "haarcascade_frontalface_alt.xml";
CascadeClassifier face_cascade;
string window_name = "Capture - Face detection";
RNG rng(12345);
/** @function main */
int main( int argc, const char** argv )
{
if( !face_cascade.load( face_cascade_name ) ){ printf("--(!)Error loading\n"); return -1; };
Mat img = imread("immagine.jpg", CV_LOAD_IMAGE_UNCHANGED);
detectAndDisplay(img);
waitKey(0);
return 0;
}
void detectAndDisplay(Mat frame)
{
std::vector<Rect> faces;
Mat frame_gray;
cvtColor( frame, frame_gray, CV_BGR2GRAY );
equalizeHist( frame_gray, frame_gray );
//-- Detect faces
face_cascade.detectMultiScale( frame_gray, faces, 1.1, 2, 0|CV_HAAR_SCALE_IMAGE, Size(20, 20) );
for( int i = 0; i < faces.size(); i++ )
{
Point center( faces[i].x + faces[i].width*0.5, faces[i].y + faces[i].height*0.5 );
ellipse( frame, center, Size( faces[i].width*0.5, faces[i].height*0.5), 0, 0, 360, Scalar( 255, 0, 255 ), 4, 8, 0 );
Mat faceROI = frame_gray( faces[i] );
}
imshow( window_name, frame );
vector<int> compression_params;
compression_params.push_back(CV_IMWRITE_JPEG_QUALITY);
compression_params.push_back(98);
bool bSuccess = imwrite("elaborata2.jpg", frame, compression_params);
}
Prendendo l'esempio dei tutorial (con poche modifiche marginali) si puo' ottenere il risultato sottostante (e' stato modificato un parametro rispetto a quelli di default)
per il corretto funzionamento del programma si deve copiare il file haarcascade_frontalface_alt.xml nella directory del programma
---------------------------------------------------------
#include "opencv2/objdetect/objdetect.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
using namespace std;
using namespace cv;
/** Function Headers */
void detectAndDisplay( Mat frame );
/** Global variables */
String face_cascade_name = "haarcascade_frontalface_alt.xml";
CascadeClassifier face_cascade;
string window_name = "Capture - Face detection";
RNG rng(12345);
/** @function main */
int main( int argc, const char** argv )
{
if( !face_cascade.load( face_cascade_name ) ){ printf("--(!)Error loading\n"); return -1; };
Mat img = imread("immagine.jpg", CV_LOAD_IMAGE_UNCHANGED);
detectAndDisplay(img);
waitKey(0);
return 0;
}
void detectAndDisplay(Mat frame)
{
std::vector<Rect> faces;
Mat frame_gray;
cvtColor( frame, frame_gray, CV_BGR2GRAY );
equalizeHist( frame_gray, frame_gray );
//-- Detect faces
face_cascade.detectMultiScale( frame_gray, faces, 1.1, 2, 0|CV_HAAR_SCALE_IMAGE, Size(20, 20) );
for( int i = 0; i < faces.size(); i++ )
{
Point center( faces[i].x + faces[i].width*0.5, faces[i].y + faces[i].height*0.5 );
ellipse( frame, center, Size( faces[i].width*0.5, faces[i].height*0.5), 0, 0, 360, Scalar( 255, 0, 255 ), 4, 8, 0 );
Mat faceROI = frame_gray( faces[i] );
}
imshow( window_name, frame );
vector<int> compression_params;
compression_params.push_back(CV_IMWRITE_JPEG_QUALITY);
compression_params.push_back(98);
bool bSuccess = imwrite("elaborata2.jpg", frame, compression_params);
}
Motion Detection in OpenCV
sempre per fare un po' di esperienza per rendere la Raspberry un sistema di controllo video, un esempio di motion detection con OpenCV ripreso da questo link e leggermente modificato per salvare il video su disco
(il video e' accelerato)
per adesso il programma e' stato testato su un portatile. Presto provero' se Raspberry e' in grado di gestire il flusso dati video ed il relativo calcolo in realtime
--------------------------------------------
#include<opencv2/opencv.hpp>
#include<iostream>
#include<vector>
using namespace std;
int main(int argc, char *argv[])
{
cv::Mat frame;
cv::Mat back;
cv::Mat fore;
cv::VideoCapture cap(0);
cv::BackgroundSubtractorMOG2 bg;
bg.nmixtures = 3;
bg.bShadowDetection = false;
std::vector<std::vector<cv::Point> > contours;
cv::namedWindow("Frame");
double dWidth = cap.get(CV_CAP_PROP_FRAME_WIDTH);
double dHeight = cap.get(CV_CAP_PROP_FRAME_HEIGHT);
cout << "Frame Size = " << dWidth << "x" << dHeight << endl;
Size frameSize(static_cast<int>(dWidth), static_cast<int>(dHeight));
VideoWriter oVideoWriter ("video.avi", CV_FOURCC('M','P','4','2'), 20, frameSize, true);
if ( !oVideoWriter.isOpened() )
{
cout << "ERROR: Failed to write the video" << endl;
return -1;
}
for(;;)
{
cap >> frame;
bg.operator ()(frame,fore);
bg.getBackgroundImage(back);
cv::erode(fore,fore,cv::Mat());
cv::dilate(fore,fore,cv::Mat());
cv::findContours(fore,contours,CV_RETR_EXTERNAL,CV_CHAIN_APPROX_NONE);
cv::drawContours(frame,contours,-1,cv::Scalar(0,0,255),2);
cv::imshow("Frame",frame);
oVideoWriter.write(frame);
if(cv::waitKey(30) >= 0) break;
}
return 0;
}
(il video e' accelerato)
per adesso il programma e' stato testato su un portatile. Presto provero' se Raspberry e' in grado di gestire il flusso dati video ed il relativo calcolo in realtime
--------------------------------------------
#include<opencv2/opencv.hpp>
#include<iostream>
#include<vector>
using namespace std;
int main(int argc, char *argv[])
{
cv::Mat frame;
cv::Mat back;
cv::Mat fore;
cv::VideoCapture cap(0);
cv::BackgroundSubtractorMOG2 bg;
bg.nmixtures = 3;
bg.bShadowDetection = false;
std::vector<std::vector<cv::Point> > contours;
cv::namedWindow("Frame");
double dWidth = cap.get(CV_CAP_PROP_FRAME_WIDTH);
double dHeight = cap.get(CV_CAP_PROP_FRAME_HEIGHT);
cout << "Frame Size = " << dWidth << "x" << dHeight << endl;
Size frameSize(static_cast<int>(dWidth), static_cast<int>(dHeight));
VideoWriter oVideoWriter ("video.avi", CV_FOURCC('M','P','4','2'), 20, frameSize, true);
if ( !oVideoWriter.isOpened() )
{
cout << "ERROR: Failed to write the video" << endl;
return -1;
}
for(;;)
{
cap >> frame;
bg.operator ()(frame,fore);
bg.getBackgroundImage(back);
cv::erode(fore,fore,cv::Mat());
cv::dilate(fore,fore,cv::Mat());
cv::findContours(fore,contours,CV_RETR_EXTERNAL,CV_CHAIN_APPROX_NONE);
cv::drawContours(frame,contours,-1,cv::Scalar(0,0,255),2);
cv::imshow("Frame",frame);
oVideoWriter.write(frame);
if(cv::waitKey(30) >= 0) break;
}
return 0;
}
domenica 25 agosto 2013
Login automatico con GDM3
Per abilitare il login in automatico di un utente con GDM3 si editi il file
/etc/gdm3/daemon.conf
modificando le seguenti righe
-----------------------------------------
# GDM configuration storage
#
# See /usr/share/gdm/gdm.schemas for a list of available options.
[daemon]
# Enabling automatic login
AutomaticLoginEnable = true
AutomaticLogin = luca
------------------------------------------
e riavviando con
dpkg-reconfigure gdm3
/etc/gdm3/daemon.conf
modificando le seguenti righe
-----------------------------------------
# GDM configuration storage
#
# See /usr/share/gdm/gdm.schemas for a list of available options.
[daemon]
# Enabling automatic login
AutomaticLoginEnable = true
AutomaticLogin = luca
------------------------------------------
e riavviando con
dpkg-reconfigure gdm3
OpenCV in C++
Per tentare in futuro di usare il riconoscimento real-time degli oggetti ho convertito lo script in Python visto in questo post in questa versione in C++
si compila, come gia' indicato, mediante
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
#include <sstream>
#include <iomanip>
#include <stdlib.h>
using namespace cv;
using namespace std;
int msleep(unsigned long milisec)
{
struct timespec req={0};
time_t sec=(int)(milisec/1000);
milisec=milisec-(sec*1000);
req.tv_sec=sec;
req.tv_nsec=milisec*1000000L;
while(nanosleep(&req,&req)==-1)
continue;
return 1;
}
int main(int argc, char* argv[])
{
VideoCapture cap(0); // open the video camera no. 0
if (!cap.isOpened()) // if not success, exit program
{
cout << "Cannot open the video file" << endl;
return -1;
}
double dWidth = cap.get(CV_CAP_PROP_FRAME_WIDTH); //get the width of frames of the video
double dHeight = cap.get(CV_CAP_PROP_FRAME_HEIGHT); //get the height of frames of the video
vector<int> compression_params;
compression_params.push_back(CV_IMWRITE_JPEG_QUALITY);
compression_params.push_back(98); /
cout << "Frame size : " << dWidth << " x " << dHeight << endl;
namedWindow("MyVideo",CV_WINDOW_AUTOSIZE); //create a window called "MyVideo"
int i = 0;
while (1)
{
Mat frame;
i++;
bool bSuccess = cap.read(frame);
if (!bSuccess)
{
cout << "Cannot read a frame from video file" << endl;
break;
}
stringstream ss;
ss << std::setfill('0') << std::setw(5) << i;
bool bSuccess2 = imwrite("a_"+ss.str()+".jpg", frame, compression_params);
msleep(1000);
}
return 0;
}
si compila, come gia' indicato, mediante
g++ `pkg-config --cflags --libs opencv` opencv.cpp -o opencv
-------------------------------------------------------------#include "opencv2/highgui/highgui.hpp"
#include <iostream>
#include <sstream>
#include <iomanip>
#include <stdlib.h>
using namespace cv;
using namespace std;
int msleep(unsigned long milisec)
{
struct timespec req={0};
time_t sec=(int)(milisec/1000);
milisec=milisec-(sec*1000);
req.tv_sec=sec;
req.tv_nsec=milisec*1000000L;
while(nanosleep(&req,&req)==-1)
continue;
return 1;
}
int main(int argc, char* argv[])
{
VideoCapture cap(0); // open the video camera no. 0
if (!cap.isOpened()) // if not success, exit program
{
cout << "Cannot open the video file" << endl;
return -1;
}
double dWidth = cap.get(CV_CAP_PROP_FRAME_WIDTH); //get the width of frames of the video
double dHeight = cap.get(CV_CAP_PROP_FRAME_HEIGHT); //get the height of frames of the video
vector<int> compression_params;
compression_params.push_back(CV_IMWRITE_JPEG_QUALITY);
compression_params.push_back(98); /
cout << "Frame size : " << dWidth << " x " << dHeight << endl;
namedWindow("MyVideo",CV_WINDOW_AUTOSIZE); //create a window called "MyVideo"
int i = 0;
while (1)
{
Mat frame;
i++;
bool bSuccess = cap.read(frame);
if (!bSuccess)
{
cout << "Cannot read a frame from video file" << endl;
break;
}
stringstream ss;
ss << std::setfill('0') << std::setw(5) << i;
bool bSuccess2 = imwrite("a_"+ss.str()+".jpg", frame, compression_params);
msleep(1000);
}
return 0;
}
venerdì 23 agosto 2013
Raspberry + Webcam + Python + OpenCV = Camera Car
Riprendendo l'idea precedente (e grazie alla batteria) e' possibile anche fare dei CameraCar
La webcam era posta diretta davanti al volante
in questo caso, data la velocita', avrei dovuto ridurre il tempo di ripresa tra due fotogrammi per rendere il tutto piu' fluido. Sarebbe carino aggiungere un modulo Bluetooth, un GPS bluetooth ed una antenna Wireless per crearsi un piccolo una Google Car
La webcam era posta diretta davanti al volante
in questo caso, data la velocita', avrei dovuto ridurre il tempo di ripresa tra due fotogrammi per rendere il tutto piu' fluido. Sarebbe carino aggiungere un modulo Bluetooth, un GPS bluetooth ed una antenna Wireless per crearsi un piccolo una Google Car
Raspberry + Webcam + Python + OpenCV = tramonto in TimeLapse
Per questo progettino da un giorno ho provato ad usare la Raspberry per catturare dei time lapse
La base hardware e' quella presente in foto ovvero una Raspberry, una batteria esterna da 10000 mAh per essere autonomi dalle prese di corrente ed una comune webcam Logitech C310
La Raspberry e' configurata con un indirizzo statico ed un DHCP server e SSH Server per collegarsi con un portatile ed un cavo cross in modo da poter interagire in caso di necessita' mediante portatile
Per la configurazione software per prima cosa e' necessario installare OpenCV per Python mediante
apt-get install python-opencv
lo script e' il seguente (molto banale)
------------------------------------------
import cv
import time
nome = 0
capture = cv.CaptureFromCAM(0)
while True:
nome = nome + 1
frame = cv.QueryFrame(capture)
indice = ("%04d")%nome
cv.SaveImage("/home/luca/a_"+indice+".jpg",frame)
time.sleep(20)
------------------------------------------
per mandare in esecuzione in automatico lo script e' stato modificato il file /etc/rc.local come segue aggiungendo
python /home/luca/camera.py
una volta ottenute le immagini queste sono state montate in file mpg mediante il comando
ffmpeg -f image2 -i a_%03d.jpg tramonto.mpg
(attenzione che gli indici di ffmpeg devono iniziare da 1. Le immagini sono denominati come a_001.jpg, a_002,jpg ed a seguire)
La base hardware e' quella presente in foto ovvero una Raspberry, una batteria esterna da 10000 mAh per essere autonomi dalle prese di corrente ed una comune webcam Logitech C310
La Raspberry e' configurata con un indirizzo statico ed un DHCP server e SSH Server per collegarsi con un portatile ed un cavo cross in modo da poter interagire in caso di necessita' mediante portatile
Per la configurazione software per prima cosa e' necessario installare OpenCV per Python mediante
apt-get install python-opencv
lo script e' il seguente (molto banale)
------------------------------------------
import cv
import time
nome = 0
capture = cv.CaptureFromCAM(0)
while True:
nome = nome + 1
frame = cv.QueryFrame(capture)
indice = ("%04d")%nome
cv.SaveImage("/home/luca/a_"+indice+".jpg",frame)
time.sleep(20)
------------------------------------------
per mandare in esecuzione in automatico lo script e' stato modificato il file /etc/rc.local come segue aggiungendo
python /home/luca/camera.py
una volta ottenute le immagini queste sono state montate in file mpg mediante il comando
ffmpeg -f image2 -i a_%03d.jpg tramonto.mpg
(attenzione che gli indici di ffmpeg devono iniziare da 1. Le immagini sono denominati come a_001.jpg, a_002,jpg ed a seguire)
giovedì 22 agosto 2013
OpenCV2 con Eclipse in Ubuntu
Update
-------------------------------------
altrimenti in modo piu' semplice e senza installare Eclipse
Per utilizzare la libreria OpenCV in C++ in ambiente Eclipse si deve prima di tutto aver installato Eclipse con il plugin CDT
Successivamente si puo' installare la libreria con il comando
apt-get install libopencv-dev
A questo punto si crea un nuovo progetto C++ dal wizard di Eclipse e si configurano i puntamenti alle directory di include e lib
a questo punto si puo' compilare un semplice esempio che mostra una immagine passata come argomento dalla linea di comando
-------------------------------------------------
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
Mat im;
if (argc == 2) im = imread(argv[1]);
if (im.empty())
{
cout << "Cannot open image!" << endl;
return -1;
}
imshow("image", im);
waitKey(0);
return 0;
}
-------------------------------------
altrimenti in modo piu' semplice e senza installare Eclipse
g++ `pkg-config --cflags --libs opencv` opencv.cpp -o opencv
-------------------------------------
Per utilizzare la libreria OpenCV in C++ in ambiente Eclipse si deve prima di tutto aver installato Eclipse con il plugin CDT
Successivamente si puo' installare la libreria con il comando
apt-get install libopencv-dev
A questo punto si crea un nuovo progetto C++ dal wizard di Eclipse e si configurano i puntamenti alle directory di include e lib
nell'esempio sono riportate sono alcune librerie di base di OpenCV2. Se si usano funzioni avanzate sara' necessario aggiungere le corrispondenti librerie
a questo punto si puo' compilare un semplice esempio che mostra una immagine passata come argomento dalla linea di comando
-------------------------------------------------
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
Mat im;
if (argc == 2) im = imread(argv[1]);
if (im.empty())
{
cout << "Cannot open image!" << endl;
return -1;
}
imshow("image", im);
waitKey(0);
return 0;
}
mercoledì 21 agosto 2013
Pacchetti non aggiornati con apt-get
In alcuni casi facendo
apt-get update
apt-get upgrade
risulta che alcuni pacchetti siano rimasti non aggiornati.Si puo' risolvere con
apt-get dist-upgrade
da fare ovviamente con le dovute accortezze
apt-get update
apt-get upgrade
risulta che alcuni pacchetti siano rimasti non aggiornati.Si puo' risolvere con
apt-get dist-upgrade
da fare ovviamente con le dovute accortezze
Apici inversi in Bash
Riprendendo il precedente post si puo' sostituire l'apice inverso come segue
apt-get install linux-headers-`uname -r`
puo' essere scritto come
apt-get install linux-headers-$(uname -r)
apt-get install linux-headers-`uname -r`
puo' essere scritto come
apt-get install linux-headers-$(uname -r)
martedì 20 agosto 2013
Emulatore Commodore 64 in Debian
Per installare l'emulatore del Commodore 64 e' necessario proecedere come segue
per prima cosa si installa il programma Vice mediante
apt-get install vice
Successivamente e' necessario acquisire le Rom che si possono scaricare da questo link
Si decomprime il file nella directory /usr/lib/vice (permessi di root necessari) e si avra' una sottodirectory per ogni calcolatore emulato. Ricontrollare a questo punto che i permessi siano impostati in modo tale che anche l'utente normale possa leggere i file
per lanciare gli emulatori si digiti
x64 (per Commodore 64)
x128 (per Commodore 128)
xcbm2 (per Commodore CBM-II)
xpet (per Commodore Pet)
xplus4 (per Commodore Plus 4)
xvic (per Commodore VIC 20)
per prima cosa si installa il programma Vice mediante
apt-get install vice
Successivamente e' necessario acquisire le Rom che si possono scaricare da questo link
Si decomprime il file nella directory /usr/lib/vice (permessi di root necessari) e si avra' una sottodirectory per ogni calcolatore emulato. Ricontrollare a questo punto che i permessi siano impostati in modo tale che anche l'utente normale possa leggere i file
per lanciare gli emulatori si digiti
x64 (per Commodore 64)
x128 (per Commodore 128)
xcbm2 (per Commodore CBM-II)
xpet (per Commodore Pet)
xplus4 (per Commodore Plus 4)
xvic (per Commodore VIC 20)
Mandelbrot in Simons Basic (Commodore 64)
Circa 20 anni fa lo facevo sui Commodore 64 reali, registravo sul datasette e per salvare le schermate usavo un VHS....al giorno d'oggi, non avendo piu' l'hardware, non mi rimane che l'emulazione
Attenzione: in modalita' Warp il programma richiede oltre 30 minuti per terminare
----------------------------------------------
10 hires 1,0
12 me = -2.0
14 mi = -1.2
20 de = 0.009375
30 di = 0.012
40 for i = 0 to 199
50 for j = 0 to 319
60 a = me + (j*de)
70 b = mi + (i*di)
80 x=0
90 y=0
100 for k = 1 to 100
110 xn = (x*x)-(y*y)+a
120 yn = (2*x*y)+b
130 t = (xn*xn)+(yn*yn)
135 cl = mod(k,2)
140 if (t>4) then plot j,i,cl
145 if (t>4) then k=101
150 x = xn
160 y = yn
170 next k
180 next j
190 next i
200 pause 5
Attenzione: in modalita' Warp il programma richiede oltre 30 minuti per terminare
----------------------------------------------
10 hires 1,0
12 me = -2.0
14 mi = -1.2
20 de = 0.009375
30 di = 0.012
40 for i = 0 to 199
50 for j = 0 to 319
60 a = me + (j*de)
70 b = mi + (i*di)
80 x=0
90 y=0
100 for k = 1 to 100
110 xn = (x*x)-(y*y)+a
120 yn = (2*x*y)+b
130 t = (xn*xn)+(yn*yn)
135 cl = mod(k,2)
140 if (t>4) then plot j,i,cl
145 if (t>4) then k=101
150 x = xn
160 y = yn
170 next k
180 next j
190 next i
200 pause 5
Installazione di CentOs
Sempre per tornare a RedHat e simili ho provato l'installazione di CentOs, una distribuzione che ricompila i sorgenti di RHEL omettendo tutto quanto soggetto a copyright.
Per rendere le cose piu' interessanti sono partito dal cd di NetInstall piu' che altro per vedere le differenze con il NetInstall di Debian
la prima grande differenza e' che si deve esplicitamente scrivere l'indirizzo della immagine che si vuole utilizzare durante l'installazione via rete. Al contrario di Debian non vengono forniti suggerimenti sui server geograficamente piu' vicini
in seguito l'installazione e' abbastanza standard con la regolazione dell'orologio
ed il download dei pacchetti
al termine dell'installazione ci troveremo con un sistema minimale di shell Linux senza ambiente grafico. Si dovra' quindi configurare anche un utente per le operazioni di tutti i giorni (nell'installazione e' presente solo l'utente root)
I pacchetti si installano con yum che funzione in modo molto simile ad apt-get. Per una lista dettagliata dei comandi relativi a yum si puo' andare a questo link
i pacchetti possono essere installati anche per gruppi.
Di seguito alcuni esempi di cui il primo installa il server X
yum -y groupinstall "Desktop" "Desktop Platform" "X Window System" "Fonts"
yum groupinstall 'Development Tools'
yum -y groupinstall "Graphical Administration Tools"
yum -y groupinstall "Internet Browser"
yum -y groupinstall "General Purpose Desktop"
yum -y groupinstall "Office Suite and Productivity"
yum -y groupinstall "Graphics Creation Tools"
CentOs e' sicuramente veloce ma ci sono alcune cose piuttosto curiose del tipo
Per rendere le cose piu' interessanti sono partito dal cd di NetInstall piu' che altro per vedere le differenze con il NetInstall di Debian
la prima grande differenza e' che si deve esplicitamente scrivere l'indirizzo della immagine che si vuole utilizzare durante l'installazione via rete. Al contrario di Debian non vengono forniti suggerimenti sui server geograficamente piu' vicini
in seguito l'installazione e' abbastanza standard con la regolazione dell'orologio
ed il download dei pacchetti
al termine dell'installazione ci troveremo con un sistema minimale di shell Linux senza ambiente grafico. Si dovra' quindi configurare anche un utente per le operazioni di tutti i giorni (nell'installazione e' presente solo l'utente root)
I pacchetti si installano con yum che funzione in modo molto simile ad apt-get. Per una lista dettagliata dei comandi relativi a yum si puo' andare a questo link
i pacchetti possono essere installati anche per gruppi.
Di seguito alcuni esempi di cui il primo installa il server X
yum -y groupinstall "Desktop" "Desktop Platform" "X Window System" "Fonts"
yum groupinstall 'Development Tools'
yum -y groupinstall "Graphical Administration Tools"
yum -y groupinstall "Internet Browser"
yum -y groupinstall "General Purpose Desktop"
yum -y groupinstall "Office Suite and Productivity"
yum -y groupinstall "Graphics Creation Tools"
CentOs e' sicuramente veloce ma ci sono alcune cose piuttosto curiose del tipo
- Di default viene installato Gnome 2 (nessuna traccia di Gnome3)
- Come alternativa c'e' praticamente solo KDE. Altri WM si possono installare ma non in modo banale
- I repository sono pochi e decisamente meno forniti di Debian
- Il kernel e' ancorato alla versione 2.6
- E' installata ancora la versione 3 delle Qt e per usare la versione 4 viene indicato di ....partire dai sorgenti (evito i commenti)
- come editor c'e' ancora vi e non nano o simili piu' recenti
In conclusione puo' essere un fantastico ambiente server (ho amministrato a lungo una RedHat 7.2 un bel po' di tempo fa) e puo' essere anche una distribuzione con un lunghissimo tempo di supporto ma e' piu' indicata per l'uso Desktop dell'ufficio piuttosto che per l'uso di normale utente che ogni tanto vuole utilizzare qualche programma un po' piu' recente
Flash player su Iceweasel/Debian
Di default Iceweasel (la versione libera di Firefox) in Debian non permette di riprodurre i filmati di Youtube (o simili) per la mancanza del plugin di Flash
per ovviare a questo problema, dopo aver modificato i repository aggiungendo quelli non-free si puo' digitare
apt-get install flashplugin-nonfree
ed in automatico viene scaricato ed installato il plugin direttamente da Macromedia
per ovviare a questo problema, dopo aver modificato i repository aggiungendo quelli non-free si puo' digitare
apt-get install flashplugin-nonfree
ed in automatico viene scaricato ed installato il plugin direttamente da Macromedia
lunedì 19 agosto 2013
Scientific Linux 6.4
Continuando l'esame delle distribuzioni basate su RHEL ho provato Scientific Linux installando come base il Live Cd ed effettuando l'installazione su Hard Disk
A parte il fatto che non ci sono particolari motivi per usare SL al posto di CentOs c'e' da segnalare che su SL 6.4 non si riescono a compilare le estensioni di VirtualBox per cui non si puo' modificare le dimensioni dello schermo
per il resto ha gli stessi pregi e difetti di CentOS.
A parte il fatto che non ci sono particolari motivi per usare SL al posto di CentOs c'e' da segnalare che su SL 6.4 non si riescono a compilare le estensioni di VirtualBox per cui non si puo' modificare le dimensioni dello schermo
per il resto ha gli stessi pregi e difetti di CentOS.
Iscriviti a:
Post (Atom)
Debugger integrato ESP32S3
Aggiornamento In realta' il Jtag USB funziona anche sui moduli cinesi Il problema risiede nell'ID USB della porta Jtag. Nel modulo...
-
In questo post viene indicato come creare uno scatterplot dinamico basato da dati ripresi da un file csv (nel dettaglio il file csv e' c...
-
La scheda ESP32-2432S028R monta un Esp Dev Module con uno schermo TFT a driver ILI9341 di 320x240 pixels 16 bit colore.Il sito di riferiment...
-
Questo post e' a seguito di quanto gia' visto nella precedente prova Lo scopo e' sempre il solito: creare un sistema che permet...