11/14/2010

OpenCV et Python sur MacOSX

Je viens d'installer l'application Picasa de Google pour gérer toutes mes photos de vacances sur mon MacBook. J'ai été tout simplement bluffé par la fonction qui permet de reconnaître les visages sur les photos et les classer... J'ai cherché un peu de documentation sur le fonctionnement... mais Google n'est pas vraiment la société la plus ouverte qui soit...
En cherchant un peu plus, j'ai fini par trouver : opencv et ça tombe plutôt bien, opencv s'intègre très bien avec Python.
Pour installer Opencv sur votre ordinateur Apple préféré, il suffit d'avoir MacPort et de lancer la commande suivante :
sudo port install opencv

11/13/2010

Lucene et Jython

Au début, je souhaitais seulement tester un peu la technologie LUCENE : vous savez ce projet de la fondation APACHE, qui vous permet d'utiliser la même technologie que les grands moteurs de recherche sur Internet.  Je me suis dis que la meilleure solution était d'utiliser une bibliothèque python... comme pylucene... mais après 1H sur le site à regarder comment j'allais pouvoir faire fonctionner ce machin, je me suis dit : il faut laisser à JAVA ce qui appartient à JAVA... mais je ne voulais pas pour autant quitter le monde des pythoniens... ça tombe bien, d'autres personnes ont déjà fait ce chemin et ont créé un interpréteur python, qui fonctionne au dessus d'une JVM (Java Virtual Machine) et qui permet d'utiliser les bibliothèques JAVA : JYTHON.


Bon, il faut le dire, la documentation LUCENE est pas vraiment des plus explicite et il n'y a pas tant de code qui traine sur Internet... Bon, après une journée à me familiariser avec JYTHON et une autre à me familiariser avec LUCENE, j'ai fini par écrire un "indexer" :

import sys

# Add jars to classpath
jars = ["./lucene-core-3.0.2.jar"]

for jar in jars:
    sys.path.append(jar)

from org.apache.lucene.analysis.standard import *
from org.apache.lucene.index import *
from org.apache.lucene.store import *
from org.apache.lucene.util import *
from org.apache.lucene.document import Document, Field 


from java.io import File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Date;

import glob
import os

def listdirectory2file(path):
    l = glob.glob(path+"/*")
    for i in l:
        if os.path.isdir(i):
                print "Directory :"+i
                print listdirectory2file(i)
        else:
                print i
                indexfile(i)

def indexfile(filename):
    global writer
    f = open(filename, 'r')
    content = f.read()
    doc = Document () 
    doc.add(Field("name", filename, Field.Store.YES,Field.Index.ANALYZED))
    doc.add(Field("content", content, Field.Store.YES,Field.Index.ANALYZED))
    writer.addDocument(doc)

path = './toindex'
INDEX_DIR = File("index")

analyzer  = StandardAnalyzer(Version.LUCENE_CURRENT)

writer = IndexWriter(FSDirectory.open(INDEX_DIR),analyzer, 1, IndexWriter.MaxFieldLength.LIMITED)

listdirectory2file(path)



#writer.DocCount()
writer.optimize()
writer.close()

et un système de recherche :


import sys

# Add jars to classpath
jars = ["./lucene-core-3.0.2.jar"]

for jar in jars:
    sys.path.append(jar)


from org.apache.lucene.analysis.standard import *
from org.apache.lucene.index import *
from org.apache.lucene.store import *
from org.apache.lucene.util import *
from org.apache.lucene.document import Document, Field 
from org.apache.lucene.search import IndexSearcher, TopScoreDocCollector
from org.apache.lucene.queryParser import QueryParser

from java.io import File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Date;

querystring = "test"
path = './toindex'
INDEX_DIR = File("index")
hitsPerPage = 10


analyzer  = StandardAnalyzer(Version.LUCENE_CURRENT)
searcher = IndexSearcher(SimpleFSDirectory(INDEX_DIR))
query = QueryParser(Version.LUCENE_CURRENT, "content", analyzer).parse(querystring)

hits = searcher.search(query,hitsPerPage)


for hit in hits.scoreDocs:
    print "====="
    print hit.score, hit.doc, hit.toString()
    doc = searcher.doc(hit.doc)
    print doc.get("name").encode("utf-8")

Bon si vous êtes un peu familier avec le python, ce code ne devrait pas trop vous dérouter. Pour le reste, vous aurez noter la présence du fichier "lucene-core-3.0.2.jar" là où je lance mes commandes :
jython createindex.py
et
jython queryindex.py

Amusez-vous bien et n'hésitez pas à me poser des questions si vous rencontrez des difficultés.

5/19/2010

Gource et Dokuwiki : en couleur

ça y est suite aux différentes demandes, je viens d'ajouter la coloration de la représentation Gource. Vous pouvez donc télécharger la nouvelle version.

#!/bin/python

"""
This program parse logs of a dokuwiki
and tranform them for gource (a log viewer)
http://code.google.com/p/gource/

developped by WolverineX02
site : http://wolverinex02.blogspot.com

"""
import glob
import os.path
import getopt
import sys
import re

WHITE = "11FFAA"
GREEN = "00F000"
vector = (1,10,100)
start_page_name = "start"

def RGBToHTMLColor(rgb_tuple):
    """ convert an (R, G, B) tuple to #RRGGBB """
    hexcolor = '#%02x%02x%02x' % rgb_tuple
    # that's it! '%02x' means zero-padded, 2-digit hex values
    return hexcolor

def HTMLColorToRGB(colorstring):
    """ convert #RRGGBB to an (R, G, B) tuple """
    colorstring = colorstring.strip()
    if colorstring[0] == '#': colorstring = colorstring[1:]
    if len(colorstring) != 6:
        raise ValueError, "input #%s is not in #RRGGBB format" % colorstring
    r, g, b = colorstring[:2], colorstring[2:4], colorstring[4:]
    r, g, b = [int(n, 16) for n in (r, g, b)]
    return (r, g, b)

def colormodify(colorstring):
    rgb_tuple = HTMLColorToRGB(colorstring)
    r, g, b = (rgb_tuple[0]+vector[0]) % 255,(rgb_tuple[1]+vector[1]) % 255,(rgb_tuple[2]+vector[2]) % 255
    return RGBToHTMLColor((r, g, b))

def listdirectory(path,color):
    l = glob.glob(path+"/*")
    for i in l:
        if os.path.isdir(i):
                listdirectory(i,colormodify(color))
        else:
                readfile(i,color)

def listdirectory2(path):
    """list all the files like *.changes,
       read them and output them in gource's log syntax
    """
    for root, dirs, files in os.walk(path):
        for i in files:
            if  (re.search('\.changes$', i)):
                fichier = os.path.join(root, i)
                readfile(fichier,GREEN)

def readfile(fichier,color):
    """read the file and output for each line of this
       file a log line for Gource
    """

    myfile = open(fichier, 'r')
    for line in myfile.readlines():
        mots = line.split('\t')
        if len(mots)>=6:
            resultat = mots[0] + "|"
            if mots[4] == '':
                mots[4]  = 'Anonymous'
            resultat += mots[4] + "|"
            resultat += translate(mots[2]) + "|"
            resultat += mots[3].replace(':', '/')
            if mots[3].rfind(start_page_name) == len(mots[3])-len(start_page_name):
                resultat += "|" + color
            else:
                resultat += "|" + colormodify(color)
            print resultat
    myfile.close()


def translate(mot):
    """translate the dokuwiki vocabulary to the gource one
       C (also cc and sc from discussion plugin) ->A
       E (also ec from discussion plugin) -> M
       D (also dc and hc from discssion plugin) -> D
       other -> M
    """
    if mot.upper == "C" or mot == 'cc' or mot == 'sc':
        return "A"
    elif mot.upper == "E" or mot == 'ec':
        return "M"
    elif mot.upper == "D" or mot == 'dc' or mot == 'hc':
        return "D"
    else:
        return "M"

def main(argv):
    """principal function
    """
    try:
        opts, args = getopt.getopt(argv, "hd:", ["help", "dokuwiki="])
    except getopt.GetoptError:
        usage()
        sys.exit(2)
    for opt, arg in opts:
        if opt in ("-h","--help"):
            usage()
            sys.exit()
        elif opt in ("-d","--dokuwiki"):
            print listdirectory(arg,WHITE)


def usage():
    """this function will display how to use this script
    """
    print "This script will output change logs of a dokuwiki"
    print "in a friendly way for gource"
    print "how to use it :"
    print "python gourcedoku.py -d ~/Sites/MyDokuwiki/ | sort > dokusort.log"
    print "and then :"
    print "gource --log-format custom dokusort.log --stop-position 1.0 \ "
    print "--stop-on-idle --file-idle-time 10000000"
    print "---"
    print "-h : help "
    print "-d : meta directory of your dokuwiki"

if __name__ == "__main__":
    main(sys.argv[1:])

5/15/2010

Gource et Dokuwiki : la video

La vidéo :



obtenue avec la ligne de commande suivante :
gource --log-format custom dokusort.log --stop-position 1.0 --stop-on-idle --file-idle-time 10000000 --output-ppm-stream - | ffmpeg -y -b 3000K -r 60 -f image2pipe -vcodec ppm -i - -vcodec mpeg4 gource.mp4
C'est un peu long mais ça marche super bien ;-)

Emulsion de Wasabi

Nous avions goûté cette préparation dans un très bon resto...
En devinant les ingrédients qui pouvaient s'y trouver... nous sommes parvenus à recréer une recette d' Emulsion au Wasabi bien sympa et très simple à réaliser :-)



En voici la recette :
- Liste des ingrédients :
  • 1 càs de wasabi (en tube et non en poudre)
  • 1 càs de sauce soja
  • le jus d'un demi citron
  • 200 ml de crème fleurette
- Préparation : Diluer le wasabi dans la sauce soja. Ajouter le jus de citron, la crème fleurette et battez le tout jusqu'à obtention d'une émulsion bien ferme.



Suggestion :
Vous pouvez la servir à l'apéritif avec des gressins, en accompagnement d'un sashimi de saumon.

Bonne dégustation !

Gource et Dokuwiki

J'ai découvert comme tout un chacun les superbes vidéos de Gource permettant de faire une représentation des modifications faites sur un système de gestion de version comme GIT ou SVN. Je me suis alors rappelé que mon wiki préféré (DOKUWIKI) est lui aussi un système de gestion de version comme un autre... Il suffit en effet de soulever le capot et d'aller regarder dans l'arborescence des dossiers pour y trouver le dossier "data/meta" dans lequel les fichiers "*.changes" renferment justement les informations recherchées. Par exemple, le fichier "systemes_visualisation.changes" ressemble à :
1263135717 ::1 C informatique:systemes_visualisation Wolverine créée
1263135988 ::1 E informatique:systemes_visualisation Wolverine
1263136423 ::1 E informatique:systemes_visualisation Wolverine

Explication :
  1. Le première colonne est un Unix Timestamp,
  2. la deuxième est l'adresse IP (je suis en localhost ;-) ),
  3. la troisième l'action réalisée (C pour créée, E pour éditée,...),
  4. la quatrième est claire, la cinquième est l'identifiant de la personne ayant modifié la page
  5. et enfin la dernière colonne est le petit texte que vous pouvez remplir quand vous modifiez une page...
Que faire de tout ça pour le faire lire à Gource, rien de plus simple, il suffit de transformer cette arborescence en un fichier de log compréhensible par Gource. Pour ce faire, j'ai développé un petit script python, nommé gourcedoku.py :
#!/bin/python

"""
This program parse logs of a dokuwiki
and tranform them for gource (a log viewer)
http://code.google.com/p/gource/

developped by WolverineX02
site : http://wolverinex02.blogspot.com

"""

import os.path
import getopt
import sys
import re



def listdirectory2(path):
"""list all the files like *.changes,
read them and output them in gource's log syntax
"""
for root, dirs, files in os.walk(path):
for i in files:
if (re.search('\.changes$', i)):
fichier = os.path.join(root, i)
myfile = open(fichier, 'r')
for line in myfile.readlines():
mots = line.split()
if len(mots)>=5:
resultat = mots[0] + "|"
resultat += mots[4] + "|"
resultat += translate(mots[2]) + "|"
resultat += fichier
print resultat
elif len(mots)==4:
resultat = mots[0] + "|Anonymous|"
resultat += translate(mots[2]) + "|"
resultat += fichier
print resultat
myfile.close()
def translate(mot):
"""translate the dokuwiki vocabulary to the gource one
C -> A
E -> M
other -> M
"""
if mot == "C":
return "A"
elif mot == "E":
return "M"
else:
return "M"

def main(argv):
"""principal function
"""
try:
opts, args = getopt.getopt(argv, "hd:", ["help", "dokuwiki="])
except getopt.GetoptError:
usage()
sys.exit(2)
for opt, arg in opts:
if opt in ("-h","--help"):
usage()
sys.exit()
elif opt in ("-d","--dokuwiki"):
print listdirectory2(arg)


def usage():
"""this function will display how to use this script
"""
print "This script will output change logs of a dokuwiki"
print "in a friendly way for gource"
print "how to use it :"
print "python gourcedoku.py -d ~/Sites/MyDokuwiki/ | sort > dokusort.log"
print "and then :"
print "gource --log-format custom dokusort.log --stop-position 1.0 \ "
print "--stop-on-idle --file-idle-time 10000000"
print "---"
print "-h : help "
print "-d : meta directory of your dokuwiki"


#print listdirectory2(sys.argv[1])

if __name__ == "__main__":
main(sys.argv[1:])
Pour le lancer, rien de plus simple : il suffit de se placer dans l'arborescence de son magnifique dokuwiki et la commande magique :
python gourcedoku.py -d ~/Sites/MyDokuwiki/ | sort > dokusort.log
puis visualiser le résultat avec Gource avec la commande suivante :
gource --log-format custom dokusort.log --stop-position 1.0 --stop-on-idle --file-idle-time 10000000
Je vais essayer de mettre ce code sur le site de Gource pour la communauté ;-) N'hésitez pas à me poser des questions ou à améliorer mon script.

1/24/2010

Chromoxy

Je viens de parcourir l'article de LifeHacker sur comment bloquer les publicités dans le navigateur Chrome de Goolge... ce serait un peu comme l'extension AdBlock Plus pour Chrome ;-) voir même encore un peu plus que seulement filtrer les publicités sur Chrome... Je me suis dit que c'est pas mal mais pas très automatique ;-) j'ai donc écrit un petit script pour cela :

#!/bin/sh

# Demarrage de Privoxy
cd /Applications/privoxy/
./privoxy &

# demarrage de Chrome
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --proxy-server="http://127.0.0.1:8118"

# retour maison
cd
et en utilisant Platypus, il devient super facile de créer ensuite une véritable application :

Facile non ;-) si vous êtes intéressés, je peux continuer à développer cette "application". J'attends vos retours