Schlagwort-Archive: PGraphics

Weichzeichnen (Blur)


Objekte weichzeichnen zu können ist, ein Muss, will man ansprechende Graphiken erstellen. Die Processing eigene weichzeichen-Funktion blur() hat einen entscheidenden Nachteil. Sie ist sehr langsam. Will man Objekte in einer Animation (in Echtzeit) weichzeichnen ist sie somit obsolet.

Mario Klingemann hat einen sehr schnellen Weichzeichen-Algorithmus geschrieben, welcher wiederum von PhiLho erweitert wurde, so dass er nun auch mit dem Alpha Kanal umgehen kann. Damit hat man die Möglichkeit auch mit transparentem Hintergrund zu arbeiten.

// ==================================================
// fastblur, reworked by PhiLho from the Processing Forum
// by Mario Klingemann http://incubator.quasimondo.com/processing/superfast_blur.php
// ==================================================
void fastBlur(PImage img, int radius){
if (radius<1){
return;
}
int w=img.width;
int h=img.height;
int wm=w-1;
int hm=h-1;
int wh=w*h;
int div=radius+radius+1;
int a[]=new int[wh]; // i've added this
int r[]=new int[wh];
int g[]=new int[wh];
int b[]=new int[wh];
int asum,rsum,gsum,bsum,x,y,i,p,p1,p2,yp,yi,yw; // and the asum here
int vmin[] = new int[max(w,h)];
int vmax[] = new int[max(w,h)];
int[] pix=img.pixels;
int dv[]=new int[256*div];
for (i=0;i<256*div;i++){
dv[i]=(i/div);
}

yw=yi=0;

for (y=0;y<h;y++){
asum=rsum=gsum=bsum=0; // asum
for(i=-radius;i<=radius;i++){
p=pix[yi+min(wm,max(i,0))];
asum+=(p>>24) & 0xff;
rsum+=(p & 0xff0000)>>16;
gsum+=(p & 0x00ff00)>>8;
bsum+= p & 0x0000ff;
}
for (x=0;x<w;x++){
a[yi]=dv[asum];
r[yi]=dv[rsum];
g[yi]=dv[gsum];
b[yi]=dv[bsum];

if(y==0){
vmin[x]=min(x+radius+1,wm);
vmax[x]=max(x-radius,0);
}
p1=pix[yw+vmin[x]];
p2=pix[yw+vmax[x]];

asum+=((p1>>24) & 0xff)-((p2>>24) & 0xff); // asum
rsum+=((p1 & 0xff0000)-(p2 & 0xff0000))>>16;
gsum+=((p1 & 0x00ff00)-(p2 & 0x00ff00))>>8;
bsum+= (p1 & 0x0000ff)-(p2 & 0x0000ff);
yi++;
}
yw+=w;
}

for (x=0;x<w;x++){
asum=rsum=gsum=bsum=0;
yp=-radius*w;
for(i=-radius;i<=radius;i++){
yi=max(0,yp)+x;
asum+=a[yi]; // asum
rsum+=r[yi];
gsum+=g[yi];
bsum+=b[yi];
yp+=w;
}
yi=x;
for (y=0;y<h;y++){
pix[yi] = (dv[asum]<<24) | (dv[rsum]<<16) | (dv[gsum]<<8) | dv[bsum];
if(x==0){
vmin[y]=min(y+radius+1,hm)*w;
vmax[y]=max(y-radius,0)*w;
}
p1=x+vmin[y];
p2=x+vmax[y];

asum+=a[p1]-a[p2]; // asum
rsum+=r[p1]-r[p2];
gsum+=g[p1]-g[p2];
bsum+=b[p1]-b[p2];

yi+=w;
}
}
}

Wie setzt man den Algorithmus ein?

Wie wir der ersten Zeile entnehmen können, verlangt die Funktion beim Aufruf ein PImage und einen Integer als Parameter. Wir können nun also ein *.jpg laden und dieses, bevor wir es am Bildschirm ausgeben, mit dem Algorithmus weichzeichnen.

Beispiel FotoBlur:   starte Applet

Image

PImage img;

void setup() {
img=loadImage("blume.JPG");
size(img.width, img.height);
}

void draw() {
img=loadImage("blume.JPG");
fastBlur(img,mouseX/5);
image(img, 0, 0);
}

Wollen wir aber von Processing gezeichnete Objekte weichzeichen, müssen wir diese in einen sog. FrameBuffer zeichnen. Siehe hochauflösende Bilder ausgeben.

Beispiel  Bluring selbst gezeichneter Objekte: Starte Applet

Hier wird ein Graphik-Objekt (ellipse()) in einen Offscreen Buffer gezeichnet und dieser dann mit fastBlur() weichgezeichnet.

Image


/*---------------------------------------------------------
By Thomas Koberger
https://lernprocessing.wordpress.com/
---------------------------------------------------------*/

PImage img;
PGraphics pg;

void setup() {
img=loadImage("blume.JPG");
size(img.width, img.height);
}

void draw() {
image(img, 0, 0);
pg= createGraphics(width, height, P2D);
pg.beginDraw();
pg.noFill();
pg.strokeWeight(8);
pg.stroke(50, 100, 250);
pg.ellipse(width/2, height/2, 200, 200);
pg.loadPixels();
fastBlur(pg,mouseX/10);
pg.endDraw();
image(pg, 0, 0);
}

Beispiel Agenten weichzeichnen: starte Applet

Hier werden Agenten in kleine FrameBuffer gerendert, weichgezeichnet und dann angezeigt. Außerdem wird das ganze Bild, jeweils weichgezeichnet und im nächsten Frame als Hintergrund verwendet.

ImageImage

SourceCode siehe Applet!

Hochauflösende Bilder ausgeben


Will man einen Sketch hochauflösend (z.B. für den Druck) ausgeben, kann man alles, was in einem draw() Durchlauf gezeichnet wird, in einen sog. offScreen Buffer zeichnen und dann als Graphik speichern. Diese Technik wird auch „Double Buffering “ genannt.

Dafür erstellt man erst ein PGraphics Objekt. Dafür gibt man Breite, Höhe und den Renderer an.

PGraphics pg = createGraphics(width, height, JAVA2D);

Image

// from http://amnonp5.wordpress.com/2012/01/28/25-life-saving-tips-for-processing/

void setup() {
size(500, 500);
}

void draw() {
background(255);
smooth();
strokeWeight(10);
fill(255, 0, 0);
ellipse(width/2, height/2, 200, 200);
}

void keyPressed() {
if (key == 's') {
save("normal.png");
saveHiRes(5);
exit();
}
}

void saveHiRes(int scaleFactor) {

// erstellt neues PGraphics Objekt
PGraphics hires = createGraphics(width*scaleFactor, height*scaleFactor, JAVA2D);

//alles ab hier wird in das PGraphics Objekt gezeichnet
beginRecord(hires);
//und skaliert
hires.scale(scaleFactor);
draw();
endRecord();
//das PGraphics Objekt wird als .png gespeichert
hires.save("hires.png");
}

Anstatt wie hier alle Zeichenvorgänge von draw() in das PGraphics Objekt zu rendern, kann man mit folgenden Anweisungen auch direkt darauf zeichnen.

hires.strokeWeight(10);PGraphics
hires.fill(255, 0, 0);
hires.ellipse(width/2, height/2, 200, 200);