Arxiu de la categoria: General

Millorar les fotos del mòbil

Coll de JouEs tracta d’aplicar un fitre com els que trobem a Instagram. Si vull automatitzar-ho, puc fer servir Imagemagick, que és una navalla suïssa per a la transformació d’imatges.

Al final he trobat la pàgina de fmwconcepts.com, que ofereix molts filtres en forma de script. A mi el que m’interessa i que em pot donar molt bon resultat és un filtre que s’anomena levels, que es tracta de modificar (fer un stretch) dels nivells, igual que faríem amb Gimp: Colors > Nivells. Amb el Gimp també em dóna un bon resultat fer Colors > Corbes, i veig que també hi ha el script (filtre) curbes. Per tant, també el podria provar, aquest.

Vull automatitzar el procés de generar imatges millorades de les imatges contingudes en una carpeta. Per tant, el meu script haurà d’anar imatge per imatge (primer bucle). I dins de cada imatge, fer un escombrat de paràmetres, de manera que per cada imatge generem 4 fotos. Finalment, haurem d’escollir quina és la foto que ha quedat millor, que ha quedat més contrastada i amb colors vius.

El script:

RUTA=/home/joan/projectes/OSM/marker_animation/filtre_levels
RUTAPICS=/home/joan/projectes/OSM/marker_animation/res/ribes-taga-ogassa-camprodon-ribes/prov
RUTARESULTATS=/home/joan/projectes/OSM/marker_animation/res/ribes-taga-ogassa-camprodon-ribes/prov/resultats
FILTRE=levels

clear
cd $RUTAPICS

for f in *.jpg
do
	cp $RUTAPICS/$f $RUTARESULTATS
	LEFT=0
	RIGHT=100
	START=0
	i=$START
	echo $f
	name=$(echo "$f" | cut -f 1 -d '.')
	for i in 0 1 2 3
	do
		LEFT=$(($LEFT+5))
		RIGHT=$(($RIGHT-5))
		i=$(($i+1))
		your_options="-C global -i $LEFT,$RIGHT $RUTAPICS/$f $RUTARESULTATS/$name-$i.jpg"
		FILTREAMBOPCIONS="levels $your_options"
		$RUTA/$FILTREAMBOPCIONS

	done
done

Més informació:

El nom Gal·la i la validació de formularis

validació formulari amb punt volatHe vist en el twitter una noia que té problemes per demanar un certificat, perquè es diu Gal·la i la validació del formulari no accepta noms amb punt volat. Això no és nou, he vist aquesta notícia d’una cas semblant que ja passava el 2004.

Tècnicament no és cap problema, només cal incloure el punt volat en l’expressió regular per validar el nom, per exemple:

> let patt = /^[a-z\u00C0-\u017F, .·'-]+$/i;
> let nom = 'Gal·la';
> console.log(patt.test(nom));
true

I és que tenim un estat al darrera que no contempla la possibilitat de què hi ha gent que vol viure plenament en català, a tot arreu, a tota hora i amb tothom. Altres noms que es poden trobar en la mateixa situacuió: Gal·la, Gal·lo, Marcel·la, Marcel·lí, Avel·lí, Estel·la, Apel·les, Marcel·lí i Sibil·la. I com a cognom he trobat Al·lès. El nom de Gal·lo, tot i que estrany, a mi m’és familiar perquè un germà del meu avi se’n deia, tot i que no crec que l’hagués escrit mai amb ela geminada, si bé la pronúncia segur que era exquisida.

Openlayers: Point, LineString, MultiLineString, Icon. Exemple canònic

Exemple canònic OpenlayersAnem a mostrar un exemple mínim d’Openlauers que aclareixi els conceptes de dibuixar un punt, una línia, una multilínia i una icona. I com aplicar estils a aquests elements.

Definim primer aquests elements (punts, línies, multilínies, icones) a partir de les dades d’exemple (coordenades). Aleshores definim features a partir d’aquests elements, que afegim a un array de features. Cada feature pot tenir el seu estil.

Definim després el vectorSource a partir de l’array de features. Després definim el VectorLayer a partir del vectorSource. I finalment afegim al mapa els layers que volem pintar.

Aquest és el codi inicial i previ per a un petit projecte que vull fer, que tracta d’una aplicació mòbil per enviar les coordenades de posició a una RestAPI on hi ha una base de dades (MongoDB), i amb una aplicació web (front-end, que és la part que aquí es comença a explicar) poder visualitzar el recorregut del ciclista (la idea del projecte és poder fer el tracking d’un ciclista en una primera etapa; i en una etapa posterior poder fer el tracking de tots els ciclistes que participen en una cursa o sortida).

El codi final:

import 'ol/ol.css';
import Feature from 'ol/Feature';
import Map from 'ol/Map';
import VectorSource from 'ol/source/Vector';
import View from 'ol/View';
import {Icon, Circle as CircleStyle, Fill, Stroke, Style} from 'ol/style';
import {LineString, MultiLineString, Point} from 'ol/geom';
import {getVectorContext} from 'ol/render';
import {fromLonLat} from 'ol/proj';
import {Tile as TileLayer, Vector as VectorLayer} from 'ol/layer';
import OSM from 'ol/source/OSM';

//dades
var json_points = [
{'lon':1.4234,'lat':41.2344,'name':'punt 0'},
{'lon':1.4235,'lat':41.2345,'name':'punt 1'},
{'lon':1.4235,'lat':41.2346,'name':'punt 2'},
{'lon':1.4236,'lat':41.2346,'name':'punt 3'},
{'lon':1.4236,'lat':41.2347,'name':'punt 4'},
{'lon':1.4238,'lat':41.2349,'name':'punt 4'},
{'lon':1.4239,'lat':41.2350,'name':'punt 4'}
];

// estils
var styles = {
'Point': new Style({
image: new CircleStyle({
fill: new Fill({
color: 'rgba(100,100,100,.8)',
}),
radius: 3,
stroke: new Stroke({
color: '#000000',
width: 2,
}),
}),
}),
'LineString': new Style({
stroke: new Stroke({
color: '#f00',
width: 3,
}),
}),
'MultiLineString': new Style({
stroke: new Stroke({
color: '#000000',
width: .8,
}),
}),
'icona': new Style({
image: new Icon({
anchor: [0.5,20],
anchorXUnits: 'fraction',
anchorYUnits: 'pixels',
src: 'img/circle_red_8.png'
})
})
};

// points
var features_points = new Array();

var feature_point0 = new Feature({
'geometry': new Point(fromLonLat([json_points[0].lon,json_points[0].lat])),
'name': json_points[0].name,
});

var feature_point1 = new Feature({
'geometry': new Point(fromLonLat([json_points[1].lon,json_points[1].lat])),
'name': json_points[0].name,
});

var feature_point2 = new Feature({
'geometry': new Point(fromLonLat([json_points[2].lon,json_points[2].lat])),
'name': json_points[0].name,
});

var feature_point3 = new Feature({
'geometry': new Point(fromLonLat([json_points[3].lon,json_points[3].lat])),
'name': json_points[0].name,
});

var feature_point4 = new Feature({
'geometry': new Point(fromLonLat([json_points[4].lon,json_points[4].lat])),
'name': json_points[0].name,
});

features_points.push(feature_point0)
features_points.push(feature_point1)
features_points.push(feature_point2)
features_points.push(feature_point3)
features_points.push(feature_point4)

// línies
//Create a feature and add geometry as a thing
var track1 = new MultiLineString([
[[json_points[0].lon,json_points[0].lat],[json_points[1].lon,json_points[1].lat]],
[[json_points[1].lon,json_points[1].lat],[json_points[2].lon,json_points[2].lat]],
[[json_points[2].lon,json_points[2].lat],[json_points[3].lon,json_points[3].lat]],
[[json_points[3].lon,json_points[3].lat],[json_points[4].lon,json_points[4].lat]]
]).transform('EPSG:4326','EPSG:3857');

var feature_multilinestring = new Feature({
geometry: track1,
name: 'nom track 1'
});

var line1 = new LineString([
[json_points[5].lon,json_points[5].lat],[json_points[6].lon,json_points[6].lat]
]).transform('EPSG:4326','EPSG:3857');

var feature_linestring = new Feature({
geometry: line1,
name: 'nom línia 1'
});

var features_strings = new Array();

features_strings.push(feature_multilinestring)
features_strings.push(feature_linestring)

//icones
var features_icones = new Array();

let feature_icona1 = new Feature({
geometry: new Point(fromLonLat([json_points[5].lon,json_points[5].lat])),
name: 'Inici',
});

let feature_icona2 = new Feature({
geometry: new Point(fromLonLat([json_points[6].lon,json_points[6].lat])),
name: 'Final',
});

feature_icona1.setStyle(styles.icona); //no cal si defineixo el estil en el layer.
feature_icona2.setStyle(styles.icona); //però definiré l'estil en la icona si cada icona ha de tenir un estil diferent

features_icones.push(feature_icona1);
features_icones.push(feature_icona2);

// vectorSources
var vectorSourcePoints = new VectorSource({
features: features_points,
wrapX: false,
});

var vectorSourceStrings = new VectorSource({
features: features_strings,
wrapX: false,
});

var vectorSourceIcones = new VectorSource({
features: features_icones,
wrapX: false,
});

// layers
var layerPoints = new VectorLayer({
source: vectorSourcePoints,
style: styles.Point,
});

var layerStrings = new VectorLayer({
source: vectorSourceStrings,
style: styles.MultiLineString,
});

var layerIcones = new VectorLayer({
source: vectorSourceIcones,
style: styles.icona,
});

var map = new Map({
layers: [
new TileLayer({
source: new OSM({
layer: 'OSM'
})
}),
layerPoints,
layerStrings,
layerIcones
],
target: 'map',
view: new View({
center: fromLonLat([1.4234, 41.2344]),
zoom: 18
})
});

Paraulògic

Fa dies que tothom per aquí va al darrere d’aquesta aplicació del Paraulògic

A partir d’un tweet d’avui s’ha posat en evidència la senzillesa de l’aplicatiu, totes les paraules del dia estan en el codi html i en text pla. Pensava que l’aplicació es connectaria a alguna API del diccionari del DIEC, la qual cosa seria molt interessant que existís aquesta API i que fos d’accés lliure.
Però no, la cosa és molt més senzilla: totes les paraules del dia es poden veure fent el típic Ctrl-U (Veure codi font), i allà tens totes les paraules sense codificar, i d’aquesta manera és molt senzill tenir la màxima puntuació i poder-te lluir davant de la gent i dels familiars. El que es pot fer per evitar-ho és una encriptació fàcil a Base64, almenys per posar-ho més difícil als curiosos del html.

Llàstima que les vacances de Nadal ja s’han acabat i ja no podrem dedicar massa temps a això del Paraulògic

rutesgps, versió 16

Aquí una nova versió de rutesgps.joanillo.org, implementant unes poques opcions que tenia ganes de fer:

  • Cada excursió té una url que la identifica. Per exemple, la última ruta que he fet: Igualada-Calaf-Manresa-Igualada: igualada-manresa-igualada
  • Un botonet per copiar directament l’enllaç de l’excursió.
  • He afegit dos markers, per tal de què quedi clar on comença la ruta i on acaba

Referències:

Geometria computacional

Fa un parell d’anys vaig estar treballant amb el TSP (Travelling salesman problem), i vaig fer una ruta visitant arbres singulars de Barcelona. La unió dels arbres es feia amb línies rectes.

Partint d’aquella idea, vull fer un camí que uneixi tots els punts, però amb suavitat. Per això es fa servir la interpolació (com les cubic-splines, per exemple). Vaig amb la idea de fer dibuixos d’un sol traç (single line drawing, dibuixos que tessel·len tota una superfície amb suavitat. Hi ha artistes que estan fent dibuixo seguint aquesta idea. I això es podria traslladar a la CNC per fer coses xules i divertides.

Rutes GPS: implementació de la cerca de rutes

Una nova versió de rutesgps.joanillo.org. Hi ha dues millores que fa temps que volia fer. Primer, que les rutes estiguin ordenades alfabèticament. Segon, la implementació d’un cercador de rutes, doncs ara ja n’hi ha bastantes i era necessari.

Aquesta és una app totalment Javascript. No hi ha res de BD ni PHP. Tot és Javascript i JSON, i els continguts i els mapes es generen dinàmicament.

Bot de Twitter de català revifat

Comença un nou curs, i projectes nous. Durant 10 anys he estat recopilant informació de paraules que m’agrades, i que malauradament estan caient en desús. A més, el Jordi Badia acaba de publicar el llibre Salvem els Mots que precisament va sobre aquesta problemàtica.

Ja feia temps que em rondava fer un bot de Twitter. Així doncs, el que he fet és agafar la informació que tinc, i estructurar-la en una base de dades (recordem: informació > coneixement). I utilitzant el paquet Tweepy de Python, i registrant-te a Tweeter com a desenvolupador, després d’un procés més o menys ràpid, ja tinc el meu bot de Twitter en marxa.

Es tracta de moment d’enviar un missatge dia si dia no, amb un contingut humorístic i picant, relacionat amb paraules i expressions del català que ens agradaria recuperades i normalitzades. El compte de Twitter és @CatalaRevifat

Referències:

RutesGPS, nova versió

S’ha publicat la nova versió de les meves rutes amb bici. De la v5 a la v7 hi ha molts canvis significatius: canvi total del disseny, responsive, Javascript amb mòduls, Openlayers v6 en la part de mapes, s’ha eliminat tota la part de PHP (és una webapp).

La llista de rutes s’havia fet molt llarga, i per tant ara les rutes s’agrupen per zones geogràfiques, que és un desplegable. Podem filtrar per les rutes que s’han fet, i distingir-les de les rutes ToDo, que són les que volem fer properament, si tot va bé. Les capes de render que s’han triat són el estàndard de OSM, el TOPOTRESC, la OrtoFoto del ICGC, i el estàndard del ICGC.
La única funcionalitat que queda per implementar és la Cerca de rutes, a veure si ho puc fer abans de les vacances.

Tot el codi està penjat en el github. En la foto es pot apreciar el canvi de disseny de la versió anterior a l’actual. Una altra millora important que s’ha implementat és l’automatització del desplegament al servidor, de manera que ara és més fàcil i està més documentat publicar els canvis en la nova versió.

Referències: