Sep 14, 2011

Translucent window en Processing


Per aconseguir una finestra transparent o translúcida en processing:



Aqui teniu el codi:


//http://java.sun.com/developer/technicalArticles/GUI/translucent_shaped_windows/
import com.sun.awt.AWTUtilities;  // no necessària amb jre7
import java.awt.*;
import javax.swing.JFrame;

JFrame topFrame = null;
PGraphics pg3D;
int framePosX = 800;
int framePosY = 100;
int frameWidth = 300;
int frameHeight = 300;
float opacitatTopFrame = 1.0f;

public void init(){
  frame.removeNotify();
  frame.setUndecorated(true);
  AWTUtilities.setWindowOpaque(frame, false);
  AWTUtilities.setWindowOpacity(frame, 0.0f);  
  //frame.setOpacity(0.0f);  // amb jre7
  frame.setBackground(new Color(0.0f,0.0f,0.0f,0.0f));                
  frame.setVisible(false);
  frame.setLayout( null );
  frame.addNotify();
  
  GraphicsConfiguration translucencyCapableGC;
  translucencyCapableGC = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();

  topFrame = new JFrame(translucencyCapableGC);
  topFrame.setUndecorated(true);
  //topFrame.setOpacity(opacitatTopFrame); // amb jre7
  AWTUtilities.setWindowOpaque(topFrame, false);
  AWTUtilities.setWindowOpacity(topFrame, opacitatTopFrame);    
  topFrame.setAlwaysOnTop(false);
  topFrame.setLocationRelativeTo(null);
  topFrame.setLocation(framePosX, framePosY);
  topFrame.setSize(frameWidth, frameHeight);
  topFrame.setBackground(new Color(0,0,0,0));
  topFrame.setVisible(true);
  topFrame.setTitle( frame == null? "":frame.getTitle() );
  topFrame.setIconImage( frame.getIconImage() );
  topFrame.setLayout( null ); 
  topFrame.addNotify();
  super.init();
  g.format = ARGB;
  g.setPrimary(false);
}


void setup() {
  size(frameWidth, frameHeight);
  colorMode(RGB,255,255,255,255);
  pg3D = createGraphics(frameWidth, frameHeight,P3D);
  pg3D.colorMode(RGB,255,255,255,255);
}


float angle = 0;

void draw() {
  
   background(0,0,255,135);
   fill(0,255,0,55);
   int mX = MouseInfo.getPointerInfo().getLocation().x-framePosX;
   int mY = MouseInfo.getPointerInfo().getLocation().y-framePosY;
   rectMode(CENTER);
   rect(mX, mY,50,50);
   
   pg3D.beginDraw();
     pg3D.background(0,0,0,0);
     pg3D.stroke(0); 
     pg3D.fill(255,0,0,255);
     pg3D.translate(100,100);   pg3D.rotateZ(angle);   pg3D.rotateX(angle);   pg3D.rotateY(angle);
     pg3D.rectMode(CENTER);
     pg3D.rect(0,0,50,50);
   pg3D.endDraw();
   
   image(pg3D,0,0);
   frame.setVisible(false);
   topFrame.add(this);
   
   angle+=0.02;
}

Sep 7, 2011

Jul 21, 2011

Simple controlador d'un 'Stepper' amb Arduino

Amb els xips L293D i 7400 podem fer un cotrolador sumple d'un motor pas a pas.

Funciona bé, però només podem controlar el motor en 'full step', motiu per el qual a velocitats baixes es produeix 'torque ripple' cosa la qual calenta el motor, augmenta el soroll i en el meu cas, fa que algunes parts de la màquina entrin en resonància (cambiaré aquest controlador per un que suporti 'micro stepping').

l'esquema és el següent:



un sencill programa per Arduino que controla el(s) motor(s):

/*
http://www.tigoe.net/pcomp/code/category/arduinowiring/51
http://www.bricogeek.com/shop/upload/datasheets/arduino/Motor_control_v3.0_sch.pdf
http://arduino.cc/en/Tutorial/MotorKnob
*/

class StepperMotor{
  private:
  ;
  public:
    byte motorPin1;
    byte motorPin2;
    byte topePin1;          // Tope -
    byte topePin2;          // Tope +
    int motorSteps;
    int pasosPermm;
    int actualStep;
    int direccio;
    unsigned long stepsLeft;
    boolean running;
    
    StepperMotor(byte lmotorPin1, byte lmotorPin2, byte ltopePin1, byte ltopePin2, int lmotorSteps, int lpasosPermm){
      motorPin1 = lmotorPin1;
      motorPin2 = lmotorPin2;
      topePin1 = ltopePin1;        // Tope -
      topePin2 = ltopePin2;        // Tope +      
      motorSteps = lmotorSteps;  // Steps per volta. NO Usat
      pasosPermm = lpasosPermm;
      actualStep = 0;
      running = false;
      
      pinMode(motorPin1,OUTPUT);
      pinMode(motorPin2,OUTPUT);
      pinMode(topePin1,INPUT);
      pinMode(topePin2,INPUT);    
    }
    
    void run(float lmm, int ldireccio){
      direccio = ldireccio;
      stepsLeft = lmm * (float)pasosPermm;
      running = true;
    }
    
    void playStep(){
      if(stepsLeft > 0 && pucAvansar(direccio)){
        switch (actualStep) {
          case 0: digitalWrite(motorPin1, LOW);  digitalWrite(motorPin2, HIGH);  break;  // 01
          case 1: digitalWrite(motorPin2, HIGH); digitalWrite(motorPin1, HIGH);  break;  // 11
          case 2: digitalWrite(motorPin1, HIGH); digitalWrite(motorPin2, LOW);   break;  // 10
          case 3: digitalWrite(motorPin2, LOW);  digitalWrite(motorPin1, LOW);   break;  // 00
        }
        actualStep += direccio;
        if(actualStep < 0) actualStep = 3; else if(actualStep > 3) actualStep = 0;
        stepsLeft--;
        if(stepsLeft == 0) running = false;
      }
    }
    
    boolean pucAvansar(int direccio){  // Retorna false si no es pot avançar en la dirreció actual
      switch (direccio){
        case -1:
          if(digitalRead(topePin1)) {running =false; return(false);} else return(true);
        case 1:
          if(digitalRead(topePin2)) {running =false; return(false);} else return(true);
      }
    }
    
    void goHome(){
      direccio = -1;
      while(pucAvansar(direccio)){
        switch (actualStep) {
          case 0: digitalWrite(motorPin1, LOW);  digitalWrite(motorPin2, HIGH);  break;  // 01
          case 1: digitalWrite(motorPin1, HIGH); digitalWrite(motorPin2, HIGH);  break;  // 11
          case 2: digitalWrite(motorPin1, HIGH); digitalWrite(motorPin2, LOW);   break;  // 10
          case 3: digitalWrite(motorPin1, LOW);  digitalWrite(motorPin2, LOW);   break;  // 00
        }
        actualStep += direccio;
        if(actualStep < 0) actualStep = 3; else if(actualStep > 3) actualStep = 0;
        delayMicroseconds(1300);
      }
    }
};





#include <flexitimer2.h> //http://arduino.cc/playground/Main/FlexiTimer2

const int nombreMotors = 3;
StepperMotor motors[nombreMotors] = {StepperMotor( 6,  7, 14, 15, 200,201)
                                    ,StepperMotor( 8,  9, 16, 17, 200,201)
                                    ,StepperMotor(10, 11, 18, 19, 200,201)};

void setup() {
  Serial.begin(115200); // Initialize the Serial port:
  
 // allMotorsHome();
  FlexiTimer2::set(3, 1.0/2000, driveSteppers);  // equivalent a delayMicroseconds(1500);
  FlexiTimer2::start();
}


void loop() {
  char eix = '  ';
  int mm;

  mm = procesaComandaSerie(&eix);
  if(mm !=0){
    switch(eix){
      case 'x':  case 'X':
        motors[0].run(abs(mm), mm/abs(mm)); break;
      case 'y': case 'Y':
        motors[1].run(abs(mm), mm/abs(mm)); break;
      case 'z': case 'Z':
        motors[2].run(abs(mm), mm/abs(mm)); break;
    }
  }
}


void allMotorsHome(){
  
  for(int i = 0; i < nombreMotors; i++){
    motors[i].goHome();
  }
}


void driveSteppers(){
  for(int i = 0; i < nombreMotors; i++){
    motors[i].playStep();
  }
}


   


int procesaComandaSerie(char *eix){
  String comanda = "";
  int retorn = 0;
  
  comanda = getSerialCommand();
  if(comanda.length()>0){
    Serial.println("#"+comanda+"#");
    *eix = comanda.charAt(0);
    Serial.println(*eix);
    comanda = comanda.substring(1);
    retorn = strToInt(comanda);
  }
  return(retorn);
}

String getSerialCommand(){
  String retorn="";
  char llegit;
     
  if(Serial.available()){
    llegit = Serial.read();
    while (llegit != 32){      
      if(Serial.available()){
        retorn += llegit;
        llegit = Serial.read();        
      }
    }
  }
  return(retorn);
}


int strToInt(String sNum){
  int retorn = 0;
  int pes = 1;
  
  for(int n=sNum.length()-1; n>=0; n--){
    if(sNum.charAt(n) == '-'){
      retorn *= -1;
    }else{
      retorn += (byte(sNum.charAt(n))-48)*pes;
      pes *= 10;
    }
  }
  Serial.println(retorn);
  return(retorn);
}

aques petit programa acepta comandes des de la consola sèrie de la forma 'x100 y-20 z300 ' (els espais son imprescindibles) que fa avançar 100mm en X -20mm en Y i 300mm en Z. donada les caractrística de la màquina (en el meu cas 'pasosPermm = 201' pasos per mm).

Jul 6, 2011

Projecte de la meva CNC

Aquest es el meu projecte de màquina CNC.



El model està fet amb Autodesk 123D (després d'haver patit multiples penjades i fins i tot la pèrdua d'un fitxer. espero que en futures Beta o en la verssió definitiva arreclin aquests problemes).

De moment tinc fets els controladors dels motors pas a pas i l'eix X i funcionen. Com a controlador uso una Arduino Uno convencional.



El següent pas serà l'eix Y, el Z i el software (tinc previst usar el 'ReplicatorG').

Quan funcionin els eixos Y i Z publicaré tota la documentació (ara mateix tinc dubtes fonamentats de que tal com els he dissenyat funcionin, però bé ja ho corregiré).

Mira la Nova verssió

Jun 27, 2011

Autdesk 123D, free 3D CAD

Autodesk 123D és un fantastic, simple i gratuit programa de disseny 3D. Segueix l'enllaç:

Exemple de peça creat en 5 minuts:


No és tant potent com Blender ni incorpora els refinaments de Meshlab, però el interface és extremament simple, intuitiu i precis (es nota que es d'Autodesk).

Pot exportar a format STL.

Apr 29, 2011

Fantastic i divertit exemple en Processing



Segueix l'enllaç:

Geotagging photos




En geoetiquetar les fotografies, magatzamem en la informació EXIF de cada fotografia les coordenades geogràfiques del lloc on es va fer la foto (s'ha acabat allò de, on caram varem fer aquesta foto).

Des del 2009 jo geoetiqueto totes les meves fotografies.

Actualment uso el i-gotU GT-600 (Pàgina oficial de i-gotU) de 37 g de pès.


El podeu comprar, per exemple a PIXmania per uns 60€  (busqueu i-gotu).

Aquest aparell funciona enregistrant les coodenades GPS i l'hora cada 30s (aquest interval es configurable). L'unic que hem de fer per geoetiquetar les fotografies es executar el software del i-gotU que simplement enparella les fotografies amb les coodenades GPS donada la hora en que es va fer la fotografia.

Amb aquest GPS jo he magatzemat les dades de una setmana sense problemes (Aquest es l'avantatge de la desconnexió automàtica quan no et mous).


Finalment la parella ideal per organitzar les fotografies geoetiquetades (per mi) es el Google Picasa.








Apr 14, 2011

BarCode reading and writing with Processing



Mira aquest enllaç, però si el compiles tu, tindràs una verssió mes actualitzada.


// http://code.google.com/p/zxing/wiki/GettingStarted
// http://blog.makezine.com/archive/2011/03/codebox-use-qr-codes-in-processing.html
// http://code.google.com/p/zxing/wiki/DeveloperNotes
// http://zxing.org/w/docs/javadoc/index.html
// http://code.google.com/p/zxing/source/browse/trunk#trunk%2Fcore%2Fsrc
// http://zxing.org/w/docs/javadoc/com/google/zxing/client/j2se/package-frame.html
// http://code.google.com/p/zxing/source/browse/trunk#trunk%2Fjavase%2Fsrc%2Fcom%2Fgoogle%2Fzxing%2Fclient%2Fj2se
// http://code.google.com/p/zxing/source/browse/trunk/android/src/com/google/zxing/client/android/encode/QRCodeEncoder.java




import com.google.zxing.*;
import java.awt.image.BufferedImage;


int SIZE = 400;


//com.google.zxing.Writer writer = new com.google.zxing.qrcode.QRCodeWriter(); 
//http://zxing.org/w/docs/javadoc/index.html
//com.google.zxing.Reader reader = new com.google.zxing.qrcode.QRCodeReader();
MultiFormatWriter writer = new MultiFormatWriter();
MultiFormatReader reader = new MultiFormatReader();
BitMatrix QRBitMatrix = new BitMatrix(SIZE, SIZE);
BarcodeFormat format = BarcodeFormat.QR_CODE;
// QR_CODE
// DATA_MATRIX
// UPC_E
// UPC_A
// EAN_8
// EAN_13
// CODE_128
// CODE_39       ATENCIÓ    Només Numèric
// ITF






void setup(){
size(SIZE, SIZE);


PImage img = new PImage(SIZE, SIZE);
String codi = "Hola";//println(codi.length());


img = codificaBarCcode(codi, format, SIZE, SIZE);


image(img, 0, 0);
img.save(savePath("data\\QR.jpg"));


println(decodificaBarCode(img));
}






PImage codificaBarCcode(String codi, BarcodeFormat format, int ample, int alt){
color negre = color(0), blanc = color(255);
PImage img = new PImage(ample, alt);
Hashtable hints = new Hashtable(1);
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");

try {
QRBitMatrix = writer.encode(codi, format, ample, alt, hints);
} catch (Exception e) {println(e.toString());}

int width = QRBitMatrix.getWidth();
int height = QRBitMatrix.getHeight();

for (int y = 0; y < height; y++) {
int offset = y * width;
for (int x = 0; x < width; x++) {
if(QRBitMatrix.get(x, y)) img.set(x, y, negre); else img.set(x, y, blanc);
}
}
return(img);
}




String decodificaBarCode(PImage img){
String retorn = "";
Result result = null;

try {
LuminanceSource source = new BufferedImageLuminanceSource((BufferedImage)img.getImage());
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
result = reader.decode(bitmap);
retorn = result.getText();
if (retorn != null) {
//println(result.getText());
ResultPoint[] points = result.getResultPoints();

for (int i = 0; i < points.length; i++) {
fill(#ff8c00);
ellipse(points[i].getX(), points[i].getY(), 20,20);
}
}
} catch (Exception e) {println(e.toString());}

return(retorn);
}

Mar 18, 2011

Kinect's OpenNi Wrapper for Processing

SimpleOpenNI és una llibreria per Processing que permet usar la Kinect des de Processing.
Segueix l'enllaç:

Aquest programa (que es la modificació d'un dels exemples de SimpleOpenNI), es un prototipus per scanejar en color una imatge en 3D .


import processing.opengl.*;

import SimpleOpenNI.*;

SimpleOpenNI context;
float z =0.3f;
float ox = radians(180);
float oy = radians(0);

float rotx = radians(180), roty = radians(0), rotz = 0, incX = 0, incY = 0, incZ = 0;
final float RATE = 0.01; // Velocitat de rotació
int despX=14, despY=56; //24, 48 -22 +56
float VE=0.001;
PImage rgbTrans = new PImage(640,480);


void setup(){
size(1024,768,OPENGL);
context = new SimpleOpenNI(this);

context.setMirror(false);
context.enableDepth();
context.enableRGB();

smooth();
perspective(95, float(width)/float(height), 10, 150000);
//context.update();
}



void draw(){
int[] depthMap = context.depthMap();
int steps = 2; // to speed up the drawing, draw every third point
int index;
int i;
float x1,x2,x3,x4,y1,y2,y3,y4,z1,z2,z3,z4;

PVector realWorldPoint, projectivePoint = new PVector();

background(0,0,0); translate(width/2, height/2, 0); rotateX(rotx); rotateY(roty); scale(z);
translate(0,0,-1000); // set the rotation center of the scene 1000 infront of the camera
println(frameRate);

context.update();
rgbTrans.copy(context.rgbImage(),
                       despX,despY, context.rgbImage().width, context.rgbImage().height,
                               0,        0, context.rgbImage().width, context.rgbImage().height);

for(int y=0;y < context.depthHeight()-steps;y+=steps){
for(int x=0;x < context.depthWidth()-steps;x+=steps) {
beginShape(QUADS);
index = x + y * context.depthWidth();
if(depthMap[index] > 0){
fill(rgbTrans.pixels[index]); noStroke();

i = index; realWorldPoint = context.depthMapRealWorld()[i];
x1 = realWorldPoint.x; y1 = realWorldPoint.y; z1 = realWorldPoint.z;

i = index+steps; realWorldPoint = context.depthMapRealWorld()[i];
x2 = realWorldPoint.x; y2 = realWorldPoint.y; z2 = realWorldPoint.z;

i = x+steps + (y+steps) * context.depthWidth(); realWorldPoint = context.depthMapRealWorld()[i];
x3 = realWorldPoint.x; y3 = realWorldPoint.y; z3 = realWorldPoint.z;

i = x + (y+steps) * context.depthWidth(); realWorldPoint = context.depthMapRealWorld()[i];
x4 = realWorldPoint.x; y4 = realWorldPoint.y; z4 = realWorldPoint.z;

if(z1 >0 && z2 >0 && z3 >0 && z4 >0){
vertex(x1,y1,z1); vertex(x2,y2,z2); vertex(x3,y3,z3); vertex(x4,y4,z4);
}
// realWorldPoint = context.depthMapRealWorld()[index];
////context.convertRealWorldToProjective(realWorldPoint,projectivePoint);
////stroke(context.rgbImage().pixels[(int)(projectivePoint.x + projectivePoint.y * context.depthWidth())]);
// stroke(rgbTrans.pixels[index]);
// point(realWorldPoint.x,realWorldPoint.y,realWorldPoint.z); // make realworld z negative, in the 3d
//drawing coordsystem +z points in the direction of the eye
}
endShape(CLOSE);
}
}
}


void mouseDragged() {
if(mouseButton == LEFT){
incX = (mouseY-pmouseY) * RATE;
incY = (mouseX-pmouseX) * RATE;
rotx -= incX;
roty -= incY;
}else{
incX = (mouseY-pmouseY) * RATE*100;
incY = (mouseX-pmouseX) * RATE*100;
despX +=incY;
despY +=incX;
println(despX+" "+despY);
}
}


void keyPressed(){
switch(keyCode) {
case UP:
z += VE;
break;
case DOWN:
z -= VE;
break;
}
}

Mar 5, 2011

Us de punters en Processing

En el següent exemple simulo l'us de punters en processing.
Per fer-ho he declarat la clse Boolean.
A més a més el codi també és un exemple del us del threading en Processing.

//http://wiki.processing.org/w/Threading




Boolean pinta = new Boolean(false);


void setup() {
  setValueAfterMs(pinta, true, 2000);
  setValueAfterMs(pinta, false, 3000);
  setValueAfterMs(pinta, true, 4000);
  setValueAfterMs(pinta, false, 5000);
  setValueAfterMs(pinta, true, 6000);
  setValueAfterMs(pinta, false, 7000);
}


void draw() {
  print(pinta.valor);
}


ArrayList StacksetValueAfterMsClass = new ArrayList();
int usedArrayListElements = 0;

void setValueAfterMs(Boolean lVarDest, boolean lValor, int lWait){
  int index = StacksetValueAfterMsClass.size();

  StacksetValueAfterMsClass.add(new setValueAfterMsClass(lVarDest, lValor, lWait));
  ((setValueAfterMsClass)StacksetValueAfterMsClass.get(index)).start();
}


class Boolean{
  boolean valor;

  Boolean(boolean lValor){
    valor = lValor;
  }
}


class setValueAfterMsClass extends Thread {
  boolean running; // Is the thread running? Yes or no?
  int wait; // How many milliseconds should we wait in between executions?
  Boolean varDest;
  boolean valor;

  // Constructor, create the thread // It is not running by default
  setValueAfterMsClass (Boolean lVarDest, boolean lValor, int lWait) {
    usedArrayListElements++;
    varDest = lVarDest;
    valor = lValor;
    wait = lWait;
    running = false;
  }

  void start () { // Overriding "start()"
    if(!running){
      running = true; // Set running equal to true
      super.start();
    }
  }

  void run () { // We must implement run, this gets triggered by start()
    while (running) {
      try {
        sleep((long)(wait));
        varDest.valor = valor;
        quit();
      } catch (Exception e) {
      }
    }
  }

  void quit() { // Our method that quits the thread

    running = false; // Setting running to false ends the loop in run()
    interrupt(); // IUn case the thread is waiting. . .
    usedArrayListElements--;
    if(usedArrayListElements == 0){ // Destrueix l'ArrayList
      for(int j = StacksetValueAfterMsClass.size()-1 ; j >= 0 ; j--){
        StacksetValueAfterMsClass.remove(j);
      }
    }
  }
}// end class

Feb 10, 2011

Comandament pel Televisor amb Kinect

Kinect + OpenNi + Osceleton + Processing + Arduino + Windows


1- Primer de tot hem de instal·lar els driver i el paquet SDK de OpenNI. Per fer-ho segueix el següent enllaç:
compte amb el pas 4, seria millor que seguir el pas 4 suggerit aquí:

2- Baixa i descomprimeix OSCeleton-1.0_win32.zip al següent enllaç:

3 - Per usar Osceleton a Processing segueix el següent enllaç:

4 - Per usa Arduino com a comandament infraroig del televisor segueix l'enllaç:

5 - Finalment per usar-ho, executa Osceleton, executa el codi el codi Arduino i finalment el codi Processing.
Recorda que cal posar-te en posició 'Croisant' per que Osceleton et reconegui.
Per cert et recomano que iniciis Oceleton amb els paràmetres '-w -r' que mostra la càmera infraroja en imatge no especular (-h es ajuda).

6- El codi Arduino i Processing a continuació:

Codi Arduino:
/*
* IRremote: IRsendDemo - demonstrates sending IR codes with IRsend
* An IR LED must be connected to Arduino PWM pin 3.
* Version 0.1 July, 2009
* Thans to Ken Shirriff for IR code
* http://arcfn.com
*/
// http://www.benryves.com/products/sonyir
// http://www.arcfn.com/search/label/ir
// http://lirc.sourceforge.net/remotes/sony/RM-ED035
// http://www.arcfn.com/2010/03/understanding-sony-ir-remote-codes-lirc.html

#include

IRsend irsend;
unsigned long irCommand;
byte command;

void setup() {
  Serial.begin(115200);
}


void loop() {
  if (Serial.available() >=6) {
    if(Serial.read()==0xFF && Serial.read()==0xFE && Serial.read()==0xFD && Serial.read()==0xFC){
      command = Serial.read();
      Serial.flush();

      switch(command){
        case 1:
          irCommand = 0x30; break; // Send AV1 Command
       case 2:
         irCommand = 0x250; break; // Send TV Command
      }

      for (int i = 0; i < 4; i++) {
        irsend.sendSony(irCommand, 12);
       delay(40);
      }
      delay(100);
    }
  }
}


Codi Processing:

Canvieu el mètode 'draw()' de l'exemple 'Stickmanetic' del conjunt d'exemples d'Oscelleton que podeu descarregar aquí:

import processing.serial.*;

Serial port;

void draw() {
  for (Skeleton s: skels.values()) {
    if((s.rHandCoords[1] < s.headCoords[1]) && (s.lHandCoords[1] > s.headCoords[1])){ // si la ma dreta es per sobre del cap
      port.write(0xFF); port.write(0xFE); port.write(0xFD); port.write(0xFC); port.write((byte)1);
    }else if((s.rHandCoords[1] < s.headCoords[1]) && (s.lHandCoords[1] < s.headCoords[1])){
      port.write(0xFF); port.write(0xFE); port.write(0xFD); port.write(0xFC); port.write((byte)2);
    }
  } 
}

i afageix la següent línia al mètode 'setup()':
port = new Serial(this, Serial.list()[0], 115200);

Dec 24, 2010

Photosynth

Photosynth. Una virgueria 3D.



o bé Segueix l'enllaç:

Dec 15, 2010

Problema amb WMP12. Baixa Qualitat de imatge en fer 'Play To' Sony Bravia

Un dels avantatges de Windows Media Player 12, es la posibilitat de ordenar a un dispositiu DLNA (en el meu cas un Televisor Bravia) que reprodueixi determinat medi.

En la configuració per defecte del WMP12 i amb el meu televisor, quan feia 'Play To' d'un fitxer de video en format .wmv o be .mp4 la qualitat era molt baixa. Per el cotrari, en reproduir aquest mateix fitxer des del menú del televisor, la qualitat era correcta.

El problema és que WMP12 i el televisor no es posen d'acord en quins formats pot reproduir el televisor, i per tant WMP12 fa un transcoding dels fitxers (i sempre a pitxor qualitat).

En espera que Sony actualitzi el firmware (si es que ho fa) vaig trobar aquest article:


In order to workaround the problem, you have to modify some registry key (I would make a back-up or something because I do not know if this will have any side effects). However, this will -remove completely the capability of your WIn7 machine to transcode to MP3. Here is what you need to do:

- Type regedit in an elevated command prompt or in the search box in your Start menu. By doing that you get to the Windows registry

- navigate in that tree to the following path: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Media Player NSS\3.0\Transcode

- remove the MP3 entry.

- reboot your machine and give it another try to your scenario.

These steps will remove the MP3 transcoding capability from Win7 DMS. Unless you put the keys back, your machine will never transcode to MP3 again. If your device now prefers WMA (cause we transcode WAV to WMA also), do the same thing for the WMA key. I hope this will help you. Let me know if it does not. It worked on my side...


En el meu cas, he modificat les claus que fan referència als formats de video. I JA FUNCIONA!!

Malgrat tot encara tinc um problema amb el pre-buffer d'audio ...  El tema DLNA encara està una mica verd.

Dec 1, 2010

Problemes amb la Time Capsule i Windows 7

Revisat el 17-12-2010. amb la verssió 7.5.2 ja han corregit el roblema que hi havia amb la 7.4.2


En conectar una Time Capsule a Windows 7, era imposible utilitzar-la des de l'administrador de fitxers.
El problema és la verssió 7.4.2 del firmware. Per tant he instal·lat la verssió 7.3.2 que si que funciona.
Per fer-ho:
  Carrega la utilitat AirPort (preferiblement des de OSX)
  Selecciona la TimeCapsule i prem 'Configuració Manual'
  Al menú 'Estació Base' selecciona 'Carregar Firmware'
  Finalment selecciona la verssió 7.3.2
i Problema resolt.

Nov 16, 2010

IR Shutter for Canon EOS 400D with Arduino

Per fer un disparador infraroig per la canon EOS 400D muntem aquest circuit amb arduino:


i carreguem el seguent programa:

/*

Arduino sketch for simulating a Canon RC-1 IR remote control
http://controlyourcamera.blogspot.com/
Huge thanks go to http://www.doc-diy.net/photo/rc-1_hacked/index.php for figuring out the IR code.
*/


const int irLED = 10;
const int statusLED = 13;
const int pushBUTTON = 3;

void setup() {
  pinMode(irLED, OUTPUT);
  pinMode(statusLED, OUTPUT);
  pinMode(pushBUTTON, INPUT);
}

void loop() {
  if (digitalRead(pushBUTTON) == HIGH) {
    digitalWrite(statusLED, HIGH);
    ShuttCanon();
    delay(10);
    digitalWrite(statusLED, LOW);
  }
}

void ShuttCanon() {                     // When the camera is in BULB mode,
  for(int i=0; i<16; i++) {              //        the first call to ShutCanon() opens the shutter
    digitalWrite(irLED, HIGH);      //       and a scond one closes the shutter
    delayMicroseconds(11);          // delay de 15 us (11 més el temps d'execució)
    digitalWrite(irLED, LOW);
    delayMicroseconds(11);
  }

/*






*/
  delayMicroseconds(7330);      // 7330 fa la foto inmediatament. 5360 fa la foto amb un delay de 2 s
  for(int i=0; i<16; i++) {           //           i en alguns models começa el video recording
    digitalWrite(irLED, HIGH);
    delayMicroseconds(11);
    digitalWrite(irLED, LOW);
    delayMicroseconds(11);
  }
}


Quan premem el pulsador es dispara la càmera. És important notar que si la càmera es en modus 'BULB', la primera crida a la funció ShuttCanon obre l'obturador i la segona el tanca (cosa la qual pot esser especialment útil).

Home Made Shutter for Canon EOS 400D

Nov 9, 2010

Capacitive sensing w/ Arduino

Aquest és el meu sensor capacitiu pensat per nesurar la humitta del terra (i per aquest motiu és estanc):




Nov 2, 2010

Focs Artificials


Fes Click amb el mouse

Oct 25, 2010

Oct 21, 2010

HDR, High Dynamic Range

En una fotografia amb gran contrasto de llum, la imatge final (si no la tractem) ha d'esser un compromís entre les zones clares i les fosques.
Afortunadament moltes càmeres actuals ens permeten fer fotografies amb contrast intel·ligent, però si volem un control més acurat del resultat podem usar la següent tècnica:

Programem la càmera de tal manera que automàticament ens faci 3 fotografies, la primera seria la 'correcta' la següent
 -2EV i la tercera +2EV (mireu-vos el manual de la vostra càmera, si és porfesional o prouser, segur que  trobeu com fer-ho i si no ho podeu fer a mà).

Així doncs, tenim 3 fotografies una 'correcta' un altre 'clara' i un altre 'fosca'. La fotografia ideal seria una composició de les 3. De la 'correcta' agafem les mitges llums, de la 'clara' les penombres i de la 'fosca' les zones d'alta lluminositat.

Finalment, per obtenir la foto ideal, usem internet on, gràcies a la feina de genis altruistes, trobem eines com el següent programa: EnfuseGUI.

Properament publicaré exemples. De moment podeu veure aquest de HDR a Wikipedia


A la Canon EOS 400D/Rebel XT podem canviar aquest ajust al menú AEB (Exp. Sec. en castellà) i si a més posem la càmera en modus ràfega (Continuous shooting), quan premem el disparador tindrem una ràfega de 3 (i només 3) fotografies cada una exposada tal com hem definit al menú AEB.

Informació Exif de les fotografies

Usant el programa ExifTool podem consultar i modifica la informació Exif de les fotografies.
Per usar-lo, només cal reneombrar el fitxer '.exe' amb els paràmetres que volguem. Per exemple:
  si renombrem el fitxer ExifTool.exe a:

      ExifTool(-k).exe                       Presenta les instruccions de funcionament
      ExifTool(-a -u -g1 -k).exe       Presenta totes les etiquetes Exif del fitxer
      ExifTool(-all= -k).exe              Esborrem totes les etiquetes Exif del fitxer

Un cop renombrat el ExifTool, arrosseguem amb el mouse les fotografies sobre l'executable (en Windows, en altres sistemes operatius ho desconec), i ens presentarà una finestra DOS amb el resultat (amb altres paràmetres podem fer que escrigui el resultat sobre un fitxer de text).

Una aplicació especialment útil (sobre tot si en l'arxiu hi tenim fotografies de diferents càmeres), és renombrar les fotografies amb la data de creació:

     exiftool "-FileName<createdate" %y%m%d_%h%m%s%%-c.%%e="" -d="" dir
         Rename all images in "dir" according to the CreateDate date and
         time, adding a copy number with leading '-' if the file already
         exists ("%-c"), and preserving the original file extension (%e).
         Note the extra '%' necessary to escape the filename codes (%c and
         %e) in the date format string.

Cal notar que el format aaaa-mm-dd hh:mm:ss és a més ideal per endreçar alfabèticament els fitxers
(Si el format fos dd-mm-aaaa, les primeres fotografies serien les del dia 1 de qualsevol mes i any).

Oct 20, 2010

Fotografia del Guggenheim de Bilbo

A vegades hi ha fotografies vulgars que et donen sorpreses. La original és del 2008, i 2 any i escaig després, revisant l'arxiu fotogràfic de Picassa va sortir això (i ja posats en vaig revisar altres).



Prova de Adobe Lightroom 3.2

Detall del fons original del blog al 200%:



Després de tractar-lo amb una demo de Adobe Lightroom 3.2
Ajustant l'enfocament i la reducció de soroll


Realment és una passada

Modificació de la plantilla del blog al Blogger de Google

Aquesta es la meva modificació de la plantilla del blog:

Primer cal fer una còpia de seguretat del blog:
      Disseny - Modifica l'HTML - Baixar la plantilla completa

A Disseny de la plantilla - Avançat - CSS, he afegit:

.tabs-inner .widget ul            {                                                  background: rgba(   0,   0,  0,    0);         }
.tabs-inner .widget li a          { border: rgba(   0,   0,   0, 0.3)  solid 1px;    background: rgba( 255, 150,  50, 0.2);         }
.tabs-inner .widget li.selected a { border: rgba(   0,   0,   0, 0.5)  solid 1px;    background: rgba( 255, 150,  50, 0.4);         }
.tabs-inner .widget li a:hover    { border: rgba(   0,   0,   0, 0.6)  solid 1px;    background: rgba( 255, 150,  50, 0.6);         }
.post           {                                                font-size: 80%;                                                       }
.post-header    {                                                font-size: 90%;                                                       }
.post-outer     { border: rgba(   0,    0,    0, 0.5) solid 1px; border-radius: 7px; background: rgba(   0,   0,   0, 0.5);         }
.sidebar        { border: rgba(   0,    0,    0,   0) solid 5px; border-radius: 7px; background: rgba(   0,   0,   0, 0.6);         }
.widget ul      {                                                                    background: rgba(   0,   0,   0, 0.1);         }
.widget-content   {                                              font-size: 90%;                                                    }
.content-outer  {                                                                    background: rgba(   0,   0,   0, 0.7);         }
'.fauxcolumn-inner {                                                                  background: rgba(   0,   0,   0, 0.3);         }
'.body-fauxcolumns {                                                                  background: rgba(   0,   0,   0, 0.3);         }
'.date-header {font-size: 120%; background: rgba(100, 1000, 1000, 0.4); text-align: center; max-width: 15%;  border:solid 20px rgba(100, 1000, 1000, 0.3); border-radius: 20px; 'height: 50px;}

Les 3 darreres línies estan comentades i per tant no s'apliquen.
i el resultat és:
Abans


Després